[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# editorconfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Matches multiple files with brace expansion notation\n# Set default charset\n[*]\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\n\n[*.{gleam, erl, hrl, ex, mjs, js, ts, sh}]\nmax_line_length = 80\n\n[*.{rs, .erl, .hrl}]\nindent_size = 4\n\n[Makefile]\nindent_style = tab\nindent_size = 4\n"
  },
  {
    "path": ".gitattributes",
    "content": "[attr]generated linguist-generated=true diff=generated\n\n# Tests:\ntest-package-compiler/src/generated_tests.rs generated\n\n# Lock files:\nCargo.lock generated\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Something isn't working\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n<!--\nPlease include the following:\n- Steps and code to reproduce the problem\n- Versions for Gleam, OS, the runtime and any other software used\n- Logs from running Gleam with the `GLEAM_LOG` environment variable set to `trace`\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n<!--\nGleam is post-v1, so breaking changes are not possible.\n\nAny new addition to the language itself needs to enable something that is not possible in Gleam today, and solve existing pain-points.\n\nFor anything other than trivial and uncontroversial additions please make a GitHub discussion before making an issue. https://github.com/gleam-lang/gleam/discussions/categories/ideas-suggestions\n-->\n"
  },
  {
    "path": ".github/actions/build-container/action.yml",
    "content": "name: \"Build Gleam\"\ndescription: \"Build Gleam Container\"\ninputs:\n  version:\n    description: \"Build Version\"\n    required: true\n  release-id:\n    description: \"Release ID\"\n    required: true\n\nruns:\n  using: composite\n  steps:\n  - name: Download Gleam release assets\n    uses: robinraju/release-downloader@v1\n    with:\n      releaseId: \"${{ inputs.release-id }}\"\n      fileName: \"gleam-${{ inputs.version }}-{x86_64-unknown-linux-musl,aarch64-unknown-linux-musl}.*\"\n\n  - name: \"Unpack release files into correct location\"\n    shell: bash\n    run: |\n      declare -A ARCH\n      ARCH[\"amd64\"]=\"x86_64-unknown-linux-musl\"\n      ARCH[\"arm64\"]=\"aarch64-unknown-linux-musl\"\n\n      for SHORT in \"${!ARCH[@]}\"; do\n        LONG=\"${ARCH[$SHORT]}\"\n\n        # Unpack Release\n        tar xf \"gleam-$VERSION-$LONG.tar.gz\"\n\n        # Move files into place\n        mv gleam \"gleam-$SHORT\"\n\n        # The SBoM is added to the images so that the Docker Scout Scanner is\n        # able to find the info about the gleam binary since it was not\n        # installed by the operating system package manager.\n        mv \"gleam-$VERSION-$LONG.tar.gz.sbom.spdx.json\" \"gleam-$SHORT.sbom.spdx.json\"\n\n        # Delete Unused Files\n        rm -rf \"gleam-$VERSION-$LONG*\"\n      done\n    env:\n      VERSION: \"${{ inputs.version }}\"\n\n  - name: Authenticate with GitHub container registry\n    uses: docker/login-action@v3\n    with:\n      registry: ghcr.io\n      username: ${{ github.actor }}\n      password: ${{ github.token }}\n\n  - name: Set up Docker Buildx\n    uses: docker/setup-buildx-action@v3\n\n  - name: Build version and tags\n    shell: bash\n    id: versions\n    run: |\n      # Strip `v` prefix from version\n      BARE_VERSION=$(echo \"$VERSION\" | sed -e 's|^v/\\(.*\\)|\\1|')\n\n      # Build version with platform\n      PLATFORM_VERSION=$BARE_VERSION-${{ matrix.base-image }}\n\n      # Build container tag\n      TAG=ghcr.io/${{ github.repository }}:$PLATFORM_VERSION\n\n      echo \"platform-version=$PLATFORM_VERSION\" >> $GITHUB_OUTPUT\n      echo \"container-tag=$TAG\" >> $GITHUB_OUTPUT\n    env:\n      VERSION: \"${{ inputs.version }}\"\n\n  - name: Build and push\n    uses: docker/build-push-action@v6\n    with:\n      context: .\n      platforms: linux/amd64,linux/arm64\n      file: containers/${{ matrix.base-image }}.dockerfile\n      push: true\n\n      # Enabling `provenance` will cause the action to create SLSA build\n      # provenance and push it alongside the tagged image. In practical terms,\n      # we're adding info to the tag that attests to where, when, and how the\n      # asset and image was built.\n      #\n      # For more info on Docker Attestations, see:\n      # https://docs.docker.com/build/ci/github-actions/attestations/\n      provenance: true\n\n      # Enabling `sbom` will trigger an SBoM Scan using Docker Scout:\n      # https://docs.docker.com/scout/how-tos/view-create-sboms/\n      # The scan will detect any operating system packages as well as the Gleam\n      # Build SBoM added into the Docker Container.\n      #\n      # Why is this helpful?\n      # * If you build services on top of these container images, you can track\n      #   all dependencies that ship with Gleam, plus the rest of your stack in\n      #   the image.\n      # * This makes it easier to do image-level vulnerability scans and\n      #   compliance checks.\n      #\n      # For more info on Docker SBoMs, see:\n      # https://docs.docker.com/build/metadata/attestations/sbom/\n      sbom: true\n      tags: ${{ steps.versions.outputs.container-tag }}\n      labels: |\n        org.opencontainers.image.title=gleam\n        org.opencontainers.image.url=https://gleam.run\n        org.opencontainers.image.source=https://github.com/gleam-lang/gleam\n        org.opencontainers.image.version=${{ steps.versions.outputs.platform-version }}\n        org.opencontainers.image.licenses=Apache-2.0\n"
  },
  {
    "path": ".github/actions/build-release/action.yml",
    "content": "name: \"Build Gleam\"\ndescription: \"Build Gleam Release\"\ninputs:\n  version:\n    description: \"Build Version\"\n    required: true\n  toolchain:\n    description: \"Cargo Toolchain\"\n    required: true\n  target:\n    description: \"Cargo Installation Target\"\n    required: true\n  cargo-tool:\n    description: \"Cargo Tool used for Build (for example, `cross`)\"\n    required: true\n  expected-binary-architecture:\n    description: \"Expected Binary Architecture\"\n    required: false\n    default: \"\"\n  azure-tenant-id:\n    description: \"Azure Tenant ID for Windows Code Signing\"\n    required: false\n  azure-subscription-id:\n    description: \"Azure Subscription ID for Windows Code Signing\"\n    required: false\n  azure-client-id:\n    description: \"Azure Client ID for Windows Code Signing\"\n    required: false\n  azure-trusted-signing-account-name:\n    description: \"Azure Trusted Signing Account Name for Windows Code Signing\"\n    required: false\n  azure-certificate-profile-name:\n    description: \"Azure Certificate Profile Name for Windows Code Signing\"\n    required: false\n\noutputs:\n  archive:\n    description: \"Path to build asset\"\n    value: \"${{ steps.build.outputs.archive }}\"\n  files:\n    description: \"Path to all files\"\n    value: |\n      ${{ steps.build.outputs.archive }}\n      ${{ steps.build.outputs.archive }}.sha256\n      ${{ steps.build.outputs.archive }}.sha512\n      ${{ steps.build.outputs.archive }}.sigstore\n      ${{ steps.build.outputs.archive }}.sbom.spdx.json\n      ${{ steps.build.outputs.archive }}.sbom.cyclonedx.json\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Install Rust toolchain\n      uses: actions-rust-lang/setup-rust-toolchain@v1\n      with:\n        toolchain: ${{ inputs.toolchain }}\n        target: ${{ inputs.target }}\n        cache-key: v1-${{ inputs.target }}\n\n    - name: Install Cargo SBoM\n      shell: bash\n      # The `cargo-sbom` version is specified in the next line. Change it to\n      # keep it up-to-date.\n      run: cargo install cargo-sbom@~0.9.1\n\n    - name: Build WASM release binary\n      if: ${{ inputs.target != 'wasm32-unknown-unknown' }}\n      uses: clechasseur/rs-cargo@v3\n      with:\n        command: build\n        args: --release --target ${{ inputs.target }}\n        tool: ${{ inputs.cargo-tool }}\n\n    - name: Install wasm-pack\n      if: ${{ inputs.target == 'wasm32-unknown-unknown' }}\n      shell: bash\n      run: curl -sSL https://rustwasm.github.io/wasm-pack/installer/init.sh | sh\n\n    - name: Build WASM release binary\n      if: ${{ inputs.target == 'wasm32-unknown-unknown' }}\n      shell: bash\n      run: wasm-pack build --release --target web compiler-wasm\n\n    - name: Verify binary architecture\n      if: ${{ inputs.expected-binary-architecture }}\n      shell: bash\n      run: |\n        BINARY_PATH=\"target/${{ inputs.target }}/release/gleam\"\n        if [[ \"${{ inputs.target }}\" == *\"windows\"* ]]; then\n          BINARY_PATH=\"${BINARY_PATH}.exe\"\n        fi\n\n        if ! file -b \"$BINARY_PATH\" | grep -iq \"${{ inputs.expected-binary-architecture }}\"; then\n          echo \"error: Architecture mismatch\"\n          echo \"Expected architecture: '${{ inputs.expected-binary-architecture }}'\"\n          echo \"Found binary type: '$(file -b \"$BINARY_PATH\")'\"\n          exit 1\n        fi\n        echo \"ok: Architecture match\"\n\n    # We use Azure Trusted Signing to sign the Windows binaries.\n    # This is done to ensure that the binaries are trusted and can be\n    # verified by users and systems that require signed code.\n    #\n    # Why is this helpful?\n    # * It provides a way to verify the authenticity and integrity of the\n    #   binaries distributed by Gleam.\n    # * It helps prevent tampering with the binaries, ensuring that users\n    #   can trust the code they are running.\n    #\n    # For more information, see:\n    # * https://github.com/Azure/trusted-signing-action\n    # * https://azure.microsoft.com/en-us/products/trusted-signing\n    - name: Log in to Azure\n      if: ${{ contains(inputs.target, '-windows-') && inputs.azure-tenant-id && inputs.azure-subscription-id && inputs.azure-client-id && inputs.azure-trusted-signing-account-name && inputs.azure-certificate-profile-name }}\n      uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0\n      with:\n        client-id: ${{ inputs.azure-client-id }}\n        tenant-id: ${{ inputs.azure-tenant-id }}\n        subscription-id: ${{ inputs.azure-subscription-id }}\n    - name: Windows Code Signing\n      if: ${{ contains(inputs.target, '-windows-') && inputs.azure-tenant-id && inputs.azure-subscription-id && inputs.azure-client-id && inputs.azure-trusted-signing-account-name && inputs.azure-certificate-profile-name }}\n      uses: azure/trusted-signing-action@0d74250c661747df006298d0fb49944c10f16e03 # v0.5.1\n      with:\n        endpoint: https://eus.codesigning.azure.net/\n        trusted-signing-account-name: ${{ inputs.azure-trusted-signing-account-name }}\n        certificate-profile-name: ${{ inputs.azure-certificate-profile-name }}\n        files: ${{ github.workspace }}\\target\\${{ inputs.target }}\\release\\gleam.exe\n        file-digest: SHA256\n        timestamp-rfc3161: http://timestamp.acs.microsoft.com\n        timestamp-digest: SHA256\n\n    - name: Build archive\n      id: build\n      shell: bash\n      run: |\n        case \"$TARGET\" in\n          *windows*)\n            ARCHIVE=\"gleam-$VERSION-$TARGET.zip\"\n            cp \"target/$TARGET/release/gleam.exe\" \"gleam.exe\"\n            7z a \"$ARCHIVE\" \"gleam.exe\"\n            rm gleam.exe\n            ;;\n          wasm*)\n            ARCHIVE=\"gleam-$VERSION-browser.tar.gz\"\n            tar -C compiler-wasm/pkg/ -czvf $ARCHIVE .\n            rm -rf compiler-wasm/pkg/\n            ;;\n          *)\n            ARCHIVE=\"gleam-$VERSION-$TARGET.tar.gz\"\n            cp \"target/$TARGET/release/gleam\" \"gleam\"\n            tar -czvf \"$ARCHIVE\" \"gleam\"\n            rm gleam\n            ;;\n        esac\n\n        echo \"archive=$ARCHIVE\" >> $GITHUB_OUTPUT\n      env:\n        TARGET: \"${{ inputs.target }}\"\n        VERSION: \"${{ inputs.version }}\"\n\n    - name: Ensure binary successfully boots\n      if: ${{ inputs.expected-binary-architecture }}\n      shell: bash\n      run: |\n        case \"$TARGET\" in\n          *windows*)\n            7z x \"$ARCHIVE\"\n            ./gleam.exe --version\n            ;;\n          aarch64*)\n            echo \"We cannot test an ARM binary on a AMD64 runner\"\n            ;;\n          *)\n            tar -xvzf \"$ARCHIVE\"\n            ./gleam --version\n            ;;\n        esac\n      env:\n        TARGET: \"${{ inputs.target }}\"\n        ARCHIVE: \"${{ steps.build.outputs.archive }}\"\n\n    # By using `cargo-sbom``, we create two formats of Build SBoMs\n    # (SPDX and CycloneDX) for the gleam build.\n    # We store those files alongside the build artifacts on the GitHub Release\n    # page and also use them to create Container SBoMs for Docker images.\n    #\n    # Why is this helpful?\n    # * It gives us and our users complete visibility into which dependencies\n    #   and which versions are present in the build / container image.\n    # * The SBoM can be fed into vulnerability scanners so that anyone can check\n    #   if any dependencies have known security issues.\n    - name: Generate Build SBoM\n      shell: bash\n      run: |\n        cargo-sbom \\\n          --output-format spdx_json_2_3 \\\n          > \"$ARCHIVE.sbom.spdx.json\"\n\n        cargo-sbom \\\n          --output-format cyclone_dx_json_1_4 \\\n          > \"$ARCHIVE.sbom.cyclonedx.json\"\n      env:\n        ARCHIVE: \"${{ steps.build.outputs.archive }}\"\n\n    - name: Hash Build Archive\n      shell: bash\n      run: |\n        openssl dgst -r -sha256 -out \"$ARCHIVE\".sha256 \"$ARCHIVE\"\n        openssl dgst -r -sha512 -out \"$ARCHIVE\".sha512 \"$ARCHIVE\"\n      env:\n        ARCHIVE: \"${{ steps.build.outputs.archive }}\"\n\n    # We provide SLSA Provenance for the distribution build. This attests to\n    # where, when, and how the asset or image was built.\n    #\n    # Why is this helpful?\n    # * It provides a record of the exact Git commit (git sha) and GitHub\n    #   Actions workflow used to produce a release.\n    # * Users or automated systems can verify that the artifact you’re\n    #   downloading was indeed built from the official Gleam repo, on a\n    #   particular date, using the correct pipeline and not tampered with later.\n    # * The attestation is published to a transparency log for extra\n    #   verification: https://github.com/gleam-lang/gleam/attestations/\n    #\n    # For more information, see:\n    # * https://github.com/actions/attest\n    # * https://github.com/actions/attest-sbom\n    - name: Attest Distribution Assets with SBoM\n      id: attest-sbom\n      uses: actions/attest-sbom@v2\n      with:\n        subject-path: |\n          ${{ steps.build.outputs.archive }}\n          ${{ steps.build.outputs.archive }}.sbom.spdx.json\n          ${{ steps.build.outputs.archive }}.sbom.cyclonedx.json\n        sbom-path: \"${{ steps.build.outputs.archive }}.sbom.spdx.json\"\n\n    # The provenanve information is stored alongside the built artifact with\n    # the `.sigstore` file extension.\n    - name: \"Copy SBoM provenance\"\n      id: sbom-provenance\n      shell: bash\n      run: |\n        cp \"$ATTESTATION\" \"$ARCHIVE.sigstore\"\n      env:\n        ARCHIVE: \"${{ steps.build.outputs.archive }}\"\n        ATTESTATION: \"${{ steps.attest-sbom.outputs.bundle-path }}\"\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v6\n      with:\n        name: release-${{ matrix.target }}\n        path: |\n          ${{ steps.build.outputs.archive }}\n          ${{ steps.build.outputs.archive }}.sha256\n          ${{ steps.build.outputs.archive }}.sha512\n          ${{ steps.build.outputs.archive }}.sigstore\n          ${{ steps.build.outputs.archive }}.sbom.spdx.json\n          ${{ steps.build.outputs.archive }}.sbom.cyclonedx.json\n        overwrite: true\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: github-actions\n  directory: \"/\"\n  labels: []\n  schedule:\n    interval: monthly\n  open-pull-requests-limit: 10\n\n# Rust:\n- package-ecosystem: \"cargo\"\n  directory: \"/\"\n  labels: []\n  schedule:\n    interval: \"monthly\"\n- package-ecosystem: \"cargo\"\n  directory: \"/compiler-cli\"\n  labels: []\n  schedule:\n    interval: \"monthly\"\n- package-ecosystem: \"cargo\"\n  directory: \"/compiler-core\"\n  labels: []\n  schedule:\n    interval: \"monthly\"\n- package-ecosystem: \"cargo\"\n  directory: \"/compiler-wasm\"\n  labels: []\n  schedule:\n    interval: \"monthly\"\n- package-ecosystem: \"cargo\"\n  # Does not have any custom deps right now,\n  # but can add them in the future:\n  directory: \"/test-package-compiler\"\n  labels: []\n  schedule:\n    interval: \"monthly\"\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "- [ ] The changes in this PR have been discussed beforehand in an issue\n- [ ] The issue for this PR has been linked\n- [ ] Tests have been added for new behaviour\n- [ ] The changelog has been updated for any user-facing changes\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "name: ci\non:\n  pull_request:\n    paths-ignore:\n      - \"CHANGELOG.md\"\n      - \"docs/**\"\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUSTFLAGS: \"-D warnings\"\n  CARGO_INCREMENTAL: 0\n  CARGO_PROFILE_DEV_DEBUG: 0\n  CARGO_PROFILE_TEST_DEBUG: 0\n  CROSS_CONTAINER_UID: 0\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    name: test\n    runs-on: ${{ matrix.os }}\n    timeout-minutes: 30\n    strategy:\n      fail-fast: false\n      matrix:\n        toolchain: [stable]\n        target:\n          - x86_64-unknown-linux-gnu\n          - x86_64-unknown-linux-musl\n          - aarch64-unknown-linux-gnu\n          - aarch64-unknown-linux-musl\n          - x86_64-apple-darwin\n          - x86_64-pc-windows-msvc\n        include:\n          - os: ubuntu-latest\n            target: x86_64-unknown-linux-gnu\n            binary: x86-64\n            cargo-tool: cargo\n            run-integration-tests: true\n          - os: ubuntu-latest\n            target: x86_64-unknown-linux-musl\n            binary: x86-64\n            cargo-tool: cross\n            run-integration-tests: true\n          - os: ubuntu-latest\n            target: aarch64-unknown-linux-gnu\n            binary: aarch64\n            cargo-tool: cross\n            run-integration-tests: false # Cannot run aarch64 binaries on x86_64\n          - os: ubuntu-latest\n            target: aarch64-unknown-linux-musl\n            binary: aarch64\n            cargo-tool: cross\n            run-integration-tests: false # Cannot run aarch64 binaries on x86_64\n          - os: macos-15-intel # intel\n            target: x86_64-apple-darwin\n            binary: x86_64\n            cargo-tool: cargo\n            run-integration-tests: true\n          - os: macos-latest # aarch64\n            toolchain: stable\n            target: aarch64-apple-darwin\n            binary: arm64\n            cargo-tool: cargo\n            run-integration-tests: true\n          - os: windows-2022\n            target: x86_64-pc-windows-msvc\n            binary: x86-64\n            cargo-tool: cargo\n            run-integration-tests: true\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install musl-tools incl. musl-gcc\n        uses: awalsh128/cache-apt-pkgs-action@v1\n        with:\n          # musl-tools provide `musl-gcc` which is required for `ring` which is required for `rustls` et al.\n          packages: musl-tools\n          version: 1.1\n        if: ${{ matrix.target == 'x86_64-unknown-linux-musl'}}\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: ${{ matrix.toolchain }}\n          target: ${{ matrix.target }}\n\n      - name: Install Erlang\n        uses: erlef/setup-beam@v1\n        with:\n          otp-version: \"28.0.1\"\n          elixir-version: \"1.18\"\n          rebar3-version: \"3\"\n\n      - name: Setup Node\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"20\"\n\n      - name: Setup Deno\n        uses: denoland/setup-deno@v2\n        with:\n          deno-version: \"2.2\"\n\n      - name: Setup Bun\n        uses: oven-sh/setup-bun@v2\n        with:\n          bun-version: \"1.2\"\n\n      - name: Handle Rust dependencies caching\n        uses: Swatinem/rust-cache@v2\n        with:\n          key: v1-${{ matrix.target }}\n\n      - name: Install Gleam\n        uses: clechasseur/rs-cargo@v4\n        with:\n          command: install\n          args: \"--path gleam-bin --target ${{ matrix.target }} --debug --locked --force\"\n          tool: ${{ matrix.cargo-tool }}\n        if: ${{ matrix.run-integration-tests }}\n\n      - name: Verify binary architecture\n        shell: bash\n        run: |\n          BINARY_PATH=\"${CARGO_HOME}/bin/gleam\"\n          if [[ \"${{ matrix.target }}\" == *\"windows\"* ]]; then\n            BINARY_PATH=\"${BINARY_PATH}.exe\"\n          fi\n\n          if ! file -b \"$BINARY_PATH\" | grep -q \"${{ matrix.binary }}\"; then\n            echo \"error: Architecture mismatch\"\n            echo \"Expected architecture: '${{ matrix.binary }}'\"\n            echo \"Found binary type: '$(file -b \"$BINARY_PATH\")'\"\n            exit 1\n          fi\n          echo \"ok: Architecture match\"\n        if: ${{ matrix.run-integration-tests }}\n\n      - name: Run tests\n        uses: clechasseur/rs-cargo@v4\n        with:\n          command: test\n          # We only want to run the `test-output` when running integration tests.\n          # There's a caveat though: when `cargo-tool` is `cross` it uses a container\n          # and would result in these integration tests failing due to not finding\n          # the escript binary. So, in case `cargo-tool != cargo` we'll skip the\n          # `test-output` tests as well.\n          args: >-\n            --workspace\n            --target ${{ matrix.target }}\n            ${{ ((matrix.run-integration-tests && matrix.cargo-tool == 'cargo')\n                  && ' ')\n                  || '--exclude test-output' }}\n          tool: ${{ matrix.cargo-tool }}\n\n      - name: test/project_erlang (non-windows)\n        run: |\n          gleam run && cd src && gleam run && cd ..\n          gleam check\n          gleam test && cd src && gleam test && cd ..\n          gleam docs build\n        working-directory: ./test/project_erlang\n        if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }}\n\n      - name: test/project_erlang (windows)\n        run: |\n          gleam run && cd src && gleam run && cd ..\n          gleam check\n          gleam test && cd src && gleam test && cd ..\n          gleam docs build\n        working-directory: ./test/project_erlang_windows\n        if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }}\n\n      - name: test/project_erlang export erlang-shipment (non-windows)\n        run: |\n          gleam export erlang-shipment\n          ./build/erlang-shipment/entrypoint.sh run\n        working-directory: ./test/project_erlang\n        if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }}\n\n      - name: test/project_erlang export erlang-shipment (windows)\n        run: |\n          gleam export erlang-shipment\n          .\\build\\erlang-shipment\\entrypoint.ps1 run\n        working-directory: ./test/project_erlang_windows\n        if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }}\n\n      - name: test/project_erlang export package-interface (non-windows)\n        run: |\n          gleam export package-interface --out=\"interface.json\"\n          cat interface.json\n        working-directory: ./test/project_erlang\n        if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }}\n\n      - name: test/project_erlang export package-interface (windows)\n        run: |\n          gleam export package-interface --out=\"interface.json\"\n          cat interface.json\n        working-directory: ./test/project_erlang_windows\n        if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }}\n\n      - name: test/project_erlang export package-information\n        run: |\n          gleam export package-information --out=\"gleam.json\"\n          cat gleam.json\n        working-directory: ./test/project_erlang\n        if: ${{ matrix.run-integration-tests }}\n\n      - name: test/external_only_javascript\n        run: ./test.sh\n        working-directory: ./test/external_only_javascript\n        if: ${{ matrix.run-integration-tests }}\n        env:\n          GLEAM_COMMAND: gleam\n\n      - name: test/external_only_erlang\n        run: ./test.sh\n        working-directory: ./test/external_only_erlang\n        if: ${{ matrix.run-integration-tests }}\n        env:\n          GLEAM_COMMAND: gleam\n\n      - name: test/root_package_not_compiled_when_running_dep\n        run: ./test.sh\n        working-directory: ./test/root_package_not_compiled_when_running_dep\n        if: ${{ matrix.run-integration-tests }}\n        env:\n          GLEAM_COMMAND: gleam\n\n      - name: test/erlang_shipment_no_dev_deps\n        run: ./test.sh\n        working-directory: ./test/erlang_shipment_no_dev_deps\n        if: ${{ matrix.run-integration-tests }}\n        env:\n          GLEAM_COMMAND: gleam\n\n      - name: test/project_javascript\n        run: |\n          gleam run\n          gleam check\n          gleam test\n          gleam docs build\n        working-directory: ./test/project_javascript\n        if: ${{ matrix.run-integration-tests }}\n\n      - name: test/project_path_deps\n        run: |\n          gleam update\n          gleam check\n        working-directory: ./test/project_path_deps/project_a\n        if: ${{ matrix.run-integration-tests }}\n\n      - name: test/project_git_deps\n        run: |\n          gleam update\n          gleam check\n        working-directory: ./test/project_git_deps\n        if: ${{ matrix.run-integration-tests }}\n\n      - name: Test project generation\n        run: |\n          gleam new lib_project\n          cd lib_project\n          gleam run\n          gleam test\n\n          # Test adding of deps\n          gleam add exception    # No specifier\n          gleam add gleam_http@4 # Version specifier\n          gleam test\n\n          # Test documentation generation\n          gleam docs build\n\n          # Assert that module metadata has been written\n          ls build/dev/erlang/lib_project/_gleam_artefacts/lib_project.cache\n\n          # Assert that HTML docs and their assets have been written\n          ls build/dev/docs/lib_project/index.html\n          ls build/dev/docs/lib_project/lib_project.html\n          ls build/dev/docs/lib_project/css/atom-one-light.min.css\n          ls build/dev/docs/lib_project/css/atom-one-dark.min.css\n          ls build/dev/docs/lib_project/css/index.css\n          ls build/dev/docs/lib_project/js/highlight.min.js\n          ls build/dev/docs/lib_project/js/highlightjs-gleam.js\n          ls build/dev/docs/lib_project/js/highlightjs-erlang.min.js\n          ls build/dev/docs/lib_project/js/highlightjs-elixir.min.js\n          ls build/dev/docs/lib_project/js/highlightjs-javascript.min.js\n          ls build/dev/docs/lib_project/js/highlightjs-typescript.min.js\n          ls build/dev/docs/lib_project/js/lunr.min.js\n          ls build/dev/docs/lib_project/js/index.js\n          ls build/dev/docs/lib_project/fonts/karla-v23-bold-latin-ext.woff2\n          ls build/dev/docs/lib_project/fonts/karla-v23-bold-latin.woff2\n          ls build/dev/docs/lib_project/fonts/karla-v23-regular-latin-ext.woff2\n          ls build/dev/docs/lib_project/fonts/karla-v23-regular-latin.woff2\n          ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-cyrillic-ext.woff2\n          ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-cyrillic.woff2\n          ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-greek-ext.woff2\n          ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-greek.woff2\n          ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-latin-ext.woff2\n          ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-latin.woff2\n        if: ${{ matrix.run-integration-tests }}\n\n  test-wasm:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: stable\n          target: wasm32-unknown-unknown\n\n      - uses: actions/setup-node@v6\n        with:\n          node-version: \"20\"\n\n      - name: Install wasm-pack\n        run: |\n          curl -sSL https://rustwasm.github.io/wasm-pack/installer/init.sh | sh\n\n      - name: Run wasm tests\n        run: wasm-pack test --node compiler-wasm\n\n  rustfmt:\n    name: rustfmt\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: stable\n          components: rustfmt\n\n      - run: cargo fmt --all -- --check\n\n  validate:\n    name: validate\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Ensure no merge commits\n        uses: NexusPHP/no-merge-commits@v2.2.1\n        if: github.event_name == 'pull_request'\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: stable\n\n      - name: Install cargo-deny\n        run: |\n          set -e\n          curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.18.6/cargo-deny-0.18.6-x86_64-unknown-linux-musl.tar.gz | tar xzf -\n          mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny\n          echo `pwd` >> $GITHUB_PATH\n\n      - name: Validate deps\n        run: cargo deny check\n\n  lint-build:\n    name: lint-build\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: stable\n          components: clippy\n\n      - name: Handle Rust dependencies caching\n        uses: Swatinem/rust-cache@v2\n        with:\n          key: v1-linux-gnu\n\n      - name: Run linter\n        run: cargo clippy --workspace\n\n      - run: cargo build\n\n      - name: Upload artifact (Ubuntu)\n        uses: actions/upload-artifact@v7\n        with:\n          name: gleam\n          path: target/debug/gleam\n\n  test-projects:\n    name: test-projects\n    needs: lint-build\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Deno\n        uses: denoland/setup-deno@v2\n        with:\n          deno-version: v2.x\n\n      - name: Install Bun\n        uses: oven-sh/setup-bun@v2\n\n      - name: Install Erlang\n        uses: erlef/setup-beam@v1\n        with:\n          otp-version: \"26.1\"\n          elixir-version: \"1.16.1\"\n          rebar3-version: \"3\"\n\n      - name: Download Gleam binary from previous job\n        uses: actions/download-artifact@v8\n        with:\n          name: gleam\n          path: ./test\n\n      - name: Configure test projects to use Gleam binary\n        run: |\n          echo $PWD/ >> $GITHUB_PATH\n          chmod +x ./gleam\n          sed -i 's/cargo run --quiet --/gleam/' */Makefile\n          sed -i 's/cargo run --/gleam/' */Makefile\n        working-directory: ./test\n\n      - name: test/language Erlang\n        run: make clean erlang\n        working-directory: ./test/language\n\n      - name: test/language JavaScript with NodeJS\n        run: make clean nodejs\n        working-directory: ./test/language\n\n      - name: test/language JavaScript with Deno\n        run: make clean deno\n        working-directory: ./test/language\n\n      - name: test/language JavaScript with Bun\n        run: make clean bun\n        working-directory: ./test/language\n\n      - name: test/compile_package0\n        run: make\n        working-directory: ./test/compile_package0\n\n      - name: test/compile_package1\n        run: make\n        working-directory: ./test/compile_package1\n\n      - name: Test JavaScript prelude\n        run: make\n        working-directory: ./test/javascript_prelude\n\n      - name: Test export of hex tarball\n        run: make test\n        working-directory: ./test/hextarball\n\n      - name: test/running_modules\n        run: make test-all\n        working-directory: ./test/running_modules\n\n      - name: test/multi_namespace\n        run: ./test.sh\n        working-directory: ./test/multi_namespace\n\n      - name: test/multi_namespace_not_top_level\n        run: ./test.sh\n        working-directory: ./test/multi_namespace_not_top_level\n\n      - name: Test FFI in subdirectories\n        run: make\n        working-directory: ./test/subdir_ffi\n\n      - name: test/unicode_path\n        run: make\n        working-directory: ./test/unicode_path ⭐\n\n      - name: test/assert\n        run: make test-all\n        working-directory: ./test/assert\n\n      - name: Test publishing with default main\n        run: ./test.sh\n        working-directory: ./test/publishing_default_main\n"
  },
  {
    "path": ".github/workflows/release-containers.yaml",
    "content": "name: release-containers\non:\n  release:\n    types:\n      - \"published\"\n\npermissions:\n  packages: write\n  id-token: write\n  attestations: write\n\njobs:\n  publish-container-images:\n    name: publish-container-images\n    runs-on: ubuntu-latest\n    # Covered by `release-nightly.yaml`\n    if: ${{ github.event.release.tag_name != 'nightly' }}\n    strategy:\n      matrix:\n        base-image:\n          - scratch\n          - erlang\n          - erlang-slim\n          - erlang-alpine\n          - elixir\n          - elixir-slim\n          - elixir-alpine\n          - node\n          - node-slim\n          - node-alpine\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          sparse-checkout: |\n            .github/actions\n            containers\n\n      - name: \"Build & Push Container\"\n        uses: \"./.github/actions/build-container\"\n        with:\n          release-id: ${{ github.event.release.id }}\n          version: ${{ github.ref_name }}\n"
  },
  {
    "path": ".github/workflows/release-nightly.yaml",
    "content": "name: release-nightly\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"45 0 * * *\"\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUSTFLAGS: \"-D warnings\"\n\npermissions:\n  contents: write\n  packages: write\n  id-token: write\n  attestations: write\n\njobs:\n  # Check if the actions already ran in the last 24 hours\n  # * If yes: Don't run again\n  # * If no: Clean out existing release assets\n  prepare-nightly:\n    runs-on: ubuntu-latest\n    name: Prepare Nightly Release\n    outputs:\n      should-run: ${{ steps.should-run.outputs.should-run }}\n    # TODO: Re-add\n    # if: ${{ github.repository == 'gleam-lang/gleam' }}\n    steps:\n      - uses: actions/checkout@v6\n      - name: print latest_commit\n        run: echo ${{ github.sha }}\n\n      - id: should-run\n        continue-on-error: true\n        name: check latest commit is less than a day\n        if: ${{ github.event_name == 'schedule' }}\n        run: test -z $(git rev-list --after=\"24 hours\" ${{ github.sha }}) && echo \"should-run=false\" >> $GITHUB_OUTPUT\n\n      - name: Delete old release assets\n        uses: mknejp/delete-release-assets@v1\n        if: ${{ steps.should-run != 'false' }}\n        with:\n          token: ${{ github.token }}\n          tag: nightly\n          fail-if-no-assets: false\n          fail-if-no-release: false\n          assets: |\n            *.zip\n            *.tar.gz\n            *.sha256\n            *.sha512\n            *.sigstore\n            *.sbom.*.json\n\n  build-release:\n    name: build-release\n    runs-on: ${{ matrix.os }}\n    environment: release\n    outputs:\n      release-id: ${{ steps.release.outputs.id }}\n    strategy:\n      matrix:\n        target:\n          - x86_64-unknown-linux-musl\n          - aarch64-unknown-linux-musl\n          - x86_64-apple-darwin\n          - aarch64-apple-darwin\n          - x86_64-pc-windows-msvc\n          - aarch64-pc-windows-msvc\n        toolchain: [ stable ]\n        include:\n          - os: ubuntu-latest\n            target: x86_64-unknown-linux-musl\n            expected-binary-architecture: x86-64\n            cargo-tool: cross\n          - os: ubuntu-latest\n            target: aarch64-unknown-linux-musl\n            expected-binary-architecture: aarch64\n            cargo-tool: cross\n          - os: macos-15-intel\n            target: x86_64-apple-darwin\n            expected-binary-architecture: x86_64\n            cargo-tool: cargo\n          - os: macos-latest\n            target: aarch64-apple-darwin\n            expected-binary-architecture: arm64\n            cargo-tool: cargo\n          - os: windows-2022\n            target: x86_64-pc-windows-msvc\n            expected-binary-architecture: x86-64\n            cargo-tool: cargo\n          - os: windows-11-arm\n            target: aarch64-pc-windows-msvc\n            expected-binary-architecture: arm64\n            cargo-tool: cargo\n          - os: ubuntu-latest\n            target: wasm32-unknown-unknown\n            cargo-tool: wasm-pack\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Update versions\n        shell: bash\n        run: ./bin/add-nightly-suffix-to-versions.sh\n\n      - name: \"Build Archive\"\n        id: build\n        uses: \"./.github/actions/build-release\"\n        with:\n          version: nightly\n          toolchain: ${{ matrix.toolchain }}\n          target: ${{ matrix.target }}\n          cargo-tool: ${{ matrix.cargo-tool }}\n          expected-binary-architecture: ${{ matrix.expected-binary-architecture }}\n          azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n          azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}\n          azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}\n          azure-trusted-signing-account-name: ${{ vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}\n          azure-certificate-profile-name: ${{ vars.AZURE_CERTIFICATE_PROFILE_NAME }}\n\n      - name: Upload release archive\n        id: release\n        # https://github.com/softprops/action-gh-release/issues/445\n        # uses: softprops/action-gh-release@v2\n        uses: softprops/action-gh-release@f2352b97da0095b4dbbd885a81023e3deabf4fef\n        with:\n          draft: false\n          prerelease: true\n          fail_on_unmatched_files: true\n          files: \"${{ steps.build.outputs.files }}\"\n          tag_name: nightly\n          name: \"Nightly\"\n          body: |\n            A build that runs every night following changes to the main branch. Contains all the latest features and changes, but there is a higher chance of instability, bugs, and unfinished features.\n\n            The assets are updated but the tag is not, so if you view the commit or download the source from below you will not get the correct code.\n\n  build-container-images:\n    name: build-container-images\n    needs: [ prepare-nightly, build-release ]\n    runs-on: ubuntu-latest\n    if: ${{ needs.prepare-nightly.outputs.should-run != 'false' }}\n    strategy:\n      matrix:\n        base-image:\n          - scratch\n          - erlang\n          - erlang-slim\n          - erlang-alpine\n          - elixir\n          - elixir-slim\n          - elixir-alpine\n          - node\n          - node-slim\n          - node-alpine\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          sparse-checkout: |\n            .github/actions\n            containers\n\n      - name: \"Build & Push Container\"\n        uses: \"./.github/actions/build-container\"\n        with:\n          version: nightly\n          release-id: ${{ needs.build-release.outputs.release-id }}\n"
  },
  {
    "path": ".github/workflows/release.yaml",
    "content": "name: release\non:\n  push:\n    tags:\n      - \"v*\"\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUSTFLAGS: \"-D warnings\"\n\npermissions:\n  contents: read\n\njobs:\n  build-release:\n    name: build-release\n    runs-on: ${{ matrix.os }}\n    environment: release\n    permissions:\n      id-token: write\n      attestations: write\n    strategy:\n      matrix:\n        target:\n          - x86_64-unknown-linux-musl\n          - aarch64-unknown-linux-musl\n          - x86_64-apple-darwin\n          - aarch64-apple-darwin\n          - x86_64-pc-windows-msvc\n          - aarch64-pc-windows-msvc\n        toolchain: [ stable ]\n        include:\n          - os: ubuntu-latest\n            target: x86_64-unknown-linux-musl\n            expected-binary-architecture: x86-64\n            cargo-tool: cross\n          - os: ubuntu-latest\n            target: aarch64-unknown-linux-musl\n            expected-binary-architecture: aarch64\n            cargo-tool: cross\n          - os: macos-15-intel\n            target: x86_64-apple-darwin\n            expected-binary-architecture: x86_64\n            cargo-tool: cargo\n          - os: macos-latest\n            target: aarch64-apple-darwin\n            expected-binary-architecture: arm64\n            cargo-tool: cargo\n          - os: windows-2022\n            target: x86_64-pc-windows-msvc\n            expected-binary-architecture: x86-64\n            cargo-tool: cargo\n          - os: windows-11-arm\n            target: aarch64-pc-windows-msvc\n            expected-binary-architecture: arm64\n            cargo-tool: cargo\n          - os: ubuntu-latest\n            target: wasm32-unknown-unknown\n            cargo-tool: wasm-pack\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: \"Build Archive\"\n        id: build\n        uses: \"./.github/actions/build-release\"\n        with:\n          version: ${{ github.ref_name }}\n          toolchain: ${{ matrix.toolchain }}\n          target: ${{ matrix.target }}\n          cargo-tool: ${{ matrix.cargo-tool }}\n          expected-binary-architecture: ${{ matrix.expected-binary-architecture }}\n          azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n          azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}\n          azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}\n          azure-trusted-signing-account-name: ${{ vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}\n          azure-certificate-profile-name: ${{ vars.AZURE_CERTIFICATE_PROFILE_NAME }}\n\n  create-release:\n    name: create-release\n\n    needs: ['build-release']\n\n    runs-on: ubuntu-latest\n\n    environment: release\n\n    permissions:\n      contents: write\n\n    steps:\n      - name: Download Artifacts\n        uses: actions/download-artifact@v8\n        with:\n          pattern: release-*\n          merge-multiple: true\n\n      - name: Create release\n        env:\n          GITHUB_TOKEN: '${{ github.token }}'\n          REPOSITORY: '${{ github.repository }}'\n          TITLE: '${{ github.ref_name }}'\n          TAG_NAME: '${{ github.ref_name }}'\n          NOTES: '${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/CHANGELOG.md'\n        run: |\n          gh release create \\\n            --repo \"$REPOSITORY\" \\\n            --title \"$TITLE\" \\\n            --notes \"$NOTES\" \\\n            --draft \\\n            --verify-tag \\\n            ${{ contains(github.ref_name, '-rc') && '--prerelease' || '' }} \\\n            \"$TAG_NAME\" \\\n            gleam-*\n"
  },
  {
    "path": ".gitignore",
    "content": "**/*.rs.bk\n**/*.beam\n/target/\n/tmp\n.idea/\n.idea/*\nerl_crash.dump\n*.lock\nnode_modules/\ncompiler-cli/build/\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  // Don't show these files in search\n  \"search.exclude\": {\n    // Test snapshots\n    \"**/*.snap\": true,\n\n    // Generated code\n    \"compiler-core/generated/**\": true,\n\n    // Images\n    \"images/**\": true\n  },\n  \"cSpell.words\": [\n    \"camino\",\n    \"cksum\",\n    \"codegen\",\n    \"ecow\",\n    \"flate\",\n    \"hardlinking\",\n    \"HEXPM\",\n    \"insta\",\n    \"itertools\",\n    \"NOCOLOUR\",\n    \"reqwest\",\n    \"rustfmt\",\n    \"subpackage\",\n    \"Telem\",\n    \"Unretire\",\n    \"Untar\",\n    \"walkdir\"\n  ],\n  \"cSpell.language\": \"en,uk,en-GB,en-US\"\n}\n"
  },
  {
    "path": ".well-known/funding-manifest-urls",
    "content": "https://gleam.run/funding.json\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## Unreleased\n\n### Compiler\n\n- The compiler now supports list prepending in constants. For example:\n\n  ```gleam\n  pub const viviparous_mammals = [\"dog\", \"cat\", \"human\"]\n\n  pub const all_mammals = [\"platypus\", \"echidna\", ..viviparous_mammals]\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The analysis of record update expressions is now fault tolerant, meaning the\n  compiler will no longer stop reporting errors at the first invalid field it\n  finds.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Build tool\n\n- When publishing, the package manager now uses the full term instead of the\n  shorthand \"MFA\" in the prompt and error message.\n  ([Luka Ivanović](https://github.com/luka-hash))\n\n### Language server\n\n- The \"extract variable\" code action can now pick better names for variables in\n  case branches and blocks, ignoring unrelated names of variables in other\n  branches.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now has a code action to replace a `_` in a type\n  annotation with the corresponding type. For example:\n\n  ```gleam\n  pub fn load_user(id: Int) -> Result(_, Error) {\n    //                                ^\n    //      Triggering the code action here\n    sql.find_by_id(id)\n    |> result.map_error(CannotLoadUser)\n  }\n  ```\n\n  Triggering the code action over the `_` will result in the following code:\n\n  ```gleam\n  pub fn load_user(id: Int) -> Result(User, Error) {\n    sql.find_by_id(id)\n    |> result.map_error(CannotLoadUser)\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now shows completions for the labelled argument of a\n  record when writing a record update.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Formatter\n\n### Bug fixes\n\n- Fixed a bug where the compiler would crash when trying to read the cache for\n  modules containing large constants.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where `BitArray$BitArray$data` constructed a `DataView` with\n  incorrect byte length instead of the slice's actual size, causing sliced bit\n  arrays to include extra bytes from the underlying buffer on JavaScript.\n  ([John Downey](https://github.com/jtdowney))\n\n- The compiler now parses UTF-8 source files with a byte-order mark correctly,\n  instead of raising an error.\n  ([Lucy McPhail](https://github.com/lucymcphail))\n\n## v1.15.1 - 2026-03-17\n\n### Bug fixes\n\n- Fixed a bug where `BitArray$BitArray$data` constructed a `DataView` with\n  offset 0 instead of the slice's actual byte offset, causing sliced bit arrays\n  to read from the wrong position in the underlying buffer on JavaScript.\n  ([John Downey](https://github.com/jtdowney))\n\n- Fixed a bug where the \"Add missing type parameter\" code action could be\n  triggered on types that do not exist instead of type variables.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "\n# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official email address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nhello@gleam.run.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Gleam\n\nThanks for contributing to Gleam!\n\nBefore continuing please read our [code of conduct][code-of-conduct] which all\ncontributors are expected to adhere to.\n\n[code-of-conduct]: https://github.com/gleam-lang/gleam/blob/main/CODE_OF_CONDUCT.md\n\n\n## Contributing bug reports\n\nIf you have found a bug in Gleam please check to see if there is an open\nticket for this problem on [our GitHub issue tracker][issues]. If you cannot\nfind an existing ticket for the bug please open a new one.\n\n[issues]: https://github.com/gleam-lang/gleam/issues\n\nA bug may be a technical problem such as a compiler crash or an incorrect\nreturn value from a library function, or a user experience issue such as\nunclear or absent documentation. If you are unsure if your problem is a bug\nplease open a ticket and we will work it out together.\n\n\n## Contributing code changes\n\nBefore working on code it is suggested that you read the\n[docs/compiler/README.md](docs/compiler/README.md) file.\nIt outlines fundamental components and design of this project.\n\nCode changes to Gleam are welcomed via the process below.\n\n1. Find or open a GitHub issue relevant to the change you wish to make and\n   comment saying that you wish to work on this issue. If the change\n   introduces new functionality or behaviour this would be a good time to\n   discuss the details of the change to ensure we are in agreement as to how\n   the new functionality should work.\n2. Update the [CHANGELOG.md](CHANGELOG.md) file with your changes.\n3. Open a GitHub pull request with your changes and ensure the tests and build\n   pass on CI.\n4. A Gleam team member will review the changes and may provide feedback to\n   work on. Depending on the change there may be multiple rounds of feedback.\n5. Once the changes have been approved the code will be rebased into the\n   `main` branch.\n\n## Local development\n\nTo run the compiler tests. This will require a recent stable version of Rust,\nErlang, Elixir, NodeJS, Deno, and Bun to be installed.\n\nIf you are using the Nix package manager, there's a [gleam-nix flake](https://github.com/vic/gleam-nix)\nyou can use for running any Gleam version or quickly obtaining a development\nenvironment for Gleam.\n\n```sh\ncargo test\n\n# Or if you have watchexec installed you can run them automatically\n# when files change\nmake test-watch\n```\n\nTo run the language integration tests. This will require a recent stable\nversion of Rust, Erlang, and NodeJS to be installed.\n\n```sh\nmake language-test\n```\n\nIf you don't have Rust or Cargo installed you can run the above command in a\ndocker sandbox. Run the command below from this directory.\n\n```sh\ndocker run -v $(pwd):/opt/app -it -w /opt/app rust:latest bash\n```\n\n## Rust development\n\nHere are some tips and guidelines for writing Rust code in the Gleam compiler:\n\nThe `GLEAM_LOG` environment variable can be used to cause the compiler to\nprint more information for debugging and introspection. i.e.\n`GLEAM_LOG=trace`.\n\n### Clippy linter\n\nYour PR may fail on CI due to clippy errors. Clippy can be run locally like so:\n\n```sh\ncargo clean -p gleam\ncargo clippy\n```\n\nIf you have lint errors on CI but not locally upgrade your Rust version to the\nlatest stable.\n\n```sh\nrustup upgrade stable\n```\n\n## Operating system specific code\n\nThis project is used on FreeBSD, Linux, MacOS, OpenBSD, Windows, and presumably\nother operating systems, so there is some amount of code that needs to be\ndifferent depending on which is it running on. So far this is hidden inside\ndependencies, with the exception of some code for working with file paths in\ntests and for setting file permissions, which is different on Windows. If you\nare working in this area then you may get a CI failure relating to this for\nyour first attempt. If you need help resolving any issues do not hesitate to\nask.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nresolver = \"2\"\nmembers = [\n  \"gleam-bin\",\n  \"compiler-cli\",\n  \"compiler-core\",\n  \"compiler-wasm\",\n  \"language-server\",\n  \"test-helpers-rs\",\n  \"test-output\",\n  \"test-package-compiler\",\n  \"test-project-compiler\",\n  \"language-server\",\n  \"hexpm\",\n]\n\n# common dependencies\n[workspace.dependencies]\n# Immutable data structures\nim = { version = \"15\", features = [\"serde\"] }\n# Extra iter methods\nitertools = \"0\"\n# Parsing\nregex = \"1\"\n# Colours in terminal\ntermcolor = \"1\"\n# Data (de)serialisation\nserde = { version = \"1\", features = [\"derive\", \"rc\"] }\nserde_json = \"1\"\n# toml config file parsing\ntoml = \"0.9\"\n# Enum trait impl macros\nstrum = { version = \"0\", features = [\"derive\"] }\n# Creation of tar file archives\ntar = \"0\"\n# gzip compression\nflate2 = \"1\"\n# Logging\ntracing = \"0\"\n# Macro to work around Rust's traits not working with async. Sigh.\nasync-trait = \"0\"\n# HTTP types\nhttp = \"1\"\nhttp-serde = \"2.1.1\"\n# Async combinators for futures\nfutures = \"0\"\n# Little helper to omit fields that cannot be debug printed\ndebug-ignore = \"1\"\n# base encoding\nbase16 = \"0\"\n# Language server protocol server plumbing\nlsp-server = \"0\"\nlsp-types = \"=0.95.1\"\n# Compact clone-on-write vector & string type\necow = \"0\"\n# Drop in replacement for std::path but with only utf-8\ncamino = \"1\"\n# std::error::Error definition macro\nthiserror = \"2\"\n# Test assertion errors with diffs\npretty_assertions = \"1\"\n# Snapshot testing to make test maintenance easier\ninsta = { version = \"1\", features = [\"glob\"] }\n# A transitive dependency needed to compile into wasm32-unknown-unknown\n# See https://docs.rs/getrandom/latest/getrandom/index.html#webassembly-support\ngetrandom = { version = \"0.2\", features = [\"js\"] }\n# Non-empty vectors\nvec1 = \"1\"\n# Pubgrub dependency resolution algorithm\npubgrub = \"0.3\"\n# Open the user's web browser\nopener = \"0\"\n"
  },
  {
    "path": "Cross.toml",
    "content": "[target.x86_64-unknown-linux-musl]\nimage = \"clux/muslrust:stable\"\n"
  },
  {
    "path": "LICENCE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2016 - present Louis Pilfold\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "#\n# Goals to be specified by user\n#\n\n.PHONY: help\nhelp:\n\t@cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-30s\\033[0m %s\\n\", $$1, $$2}'\n\n.PHONY: build\nbuild: ## Build the compiler\n\tcargo build --release\n\n.PHONY: install\ninstall: ## Build the Gleam compiler and place it on PATH\n\tcd gleam-bin && cargo install --path . --force --locked\n\n.PHONY: test\ntest: ## Run the compiler unit tests\n\tcargo test --quiet\n\tcargo clippy\n\tcd test/language && make\n\tcd test/javascript_prelude && make test\n\tcd test/project_erlang && cargo run clean && cargo run check && cargo run test\n\tcd test/project_javascript && cargo run clean && cargo run check && cargo run test\n\tcd test/project_deno && cargo run clean && cargo run check && cargo run test\n\tcd test/hextarball && make test\n\tcd test/running_modules && make test\n\tcd test/subdir_ffi && make\n\n.PHONY: insta-check-unused\ninsta-check-unused: ## Check for unused cargo insta snapshots\n\tcargo insta test --unreferenced=warn\n\n.PHONY: insta-fix-unused\ninsta-fix-unused: ## Remove unused cargo insta snapshots\n\tcargo insta test --unreferenced=delete\n\n.PHONY: language-test\nlanguage-test: ## Run the language integration tests for all targets\n\tcd test/language && make\n\n.PHONY: language-test-watch\nlanguage-test-watch: ## Run the language integration tests for all targets when files change\n\twatchexec \"cd test/language && make\"\n\n.PHONY: javascript-prelude-test\njavascript-prelude-test: ## Run the JavaScript prelude core tests\n\tcd test/javascript_prelude && make test\n\n.PHONY: javascript-prelude-test-watch\njavascript-prelude-test-watch: ## Run the JavaScript prelude core tests when files change\n\twatchexec \"cd test/javascript_prelude && make test\"\n\n.PHONY: test-watch\ntest-watch: ## Run compiler tests when files change\n\twatchexec -e rs,toml,gleam,html \"cargo test --quiet\"\n\n.PHONY: export-hex-tarball-test\nexport-hex-tarball-test: ## Run `gleam export hex-tarball` and verify it is created\n\tcd test/hextarball && make test\n\n.PHONY: benchmark\nbenchmark: ## Run the benchmarks\n\tcd benchmark/list && make\n\n# Debug print vars with `make print-VAR_NAME`\nprint-%: ; @echo $*=$($*)\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img src=\"images/lucy.png\" alt=\"Lucy, Gleam's mascot\">\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/gleam-lang/gleam/releases\"><img src=\"https://img.shields.io/github/release/gleam-lang/gleam\" alt=\"GitHub release\"></a>\n  <a href=\"https://discord.gg/Fm8Pwmy\"><img src=\"https://img.shields.io/discord/768594524158427167?color=blue\" alt=\"Discord chat\"></a>\n</p>\n\n<!-- A spacer -->\n<div>&nbsp;</div>\n\nGleam is a friendly language for building type-safe systems that scale! For more\ninformation see [the website](https://gleam.run).\n\n## Support Gleam!\n\nGleam is not owned by a corporation, instead it is kindly supported by its\nsponsors. If you like Gleam please consider [sponsoring the project or members\nof the core team](https://gleam.run/sponsor).\n\nThank you so much! 💖\n"
  },
  {
    "path": "RELEASE.md",
    "content": "# Release checklist\n\n1. Update the version in each `Cargo.toml`.\n2. Update versions in `src/new.rs` for stdlib etc if required.\n3. Run `make test build`.\n4. Git commit, tag, push, push tags.\n5. Wait for CI release build to finish.\n6. Publish release on GitHub from draft made by CI.\n7. Update version in `Cargo.toml` to next-dev.\n8. Update clone target version in `getting-started.md` in `website`.\n"
  },
  {
    "path": "benchmark/list/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "benchmark/list/Makefile",
    "content": ".PHONY: build\nbuild: clean erlang nodejs deno bun\n\n.PHONY: clean\nclean:\n\trm -rf build\n\n.PHONY: erlang\nerlang:\n\t@echo test/language on Erlang\n\tcargo run --quiet -- test --target erlang\n\n.PHONY: nodejs\nnodejs:\n\t@echo test/language on JavaScript with Node\n\tcargo run --quiet -- test --target javascript --runtime nodejs\n\n.PHONY: deno\ndeno:\n\t@echo test/language on JavaScript with Deno\n\tcargo run --quiet -- test --target javascript --runtime deno\n\n.PHONY: bun\nbun:\n\t@echo test/language on JavaScript with Bun\n\tcargo run --quiet -- test --target javascript --runtime bun\n"
  },
  {
    "path": "benchmark/list/gleam.toml",
    "content": "name = \"list\"\nversion = \"1.0.0\"\ndescription = \"Benchmarks for lists\"\nlicenses = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = \"~> 0.28\"\ngleamy_bench = \">= 0.6.0 and < 1.0.0\"\n"
  },
  {
    "path": "benchmark/list/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.59.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"F8FEE9B35797301994B81AF75508CF87C328FE1585558B0FFD188DC2B32EAA95\" },\n  { name = \"gleamy_bench\", version = \"0.6.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleamy_bench\", source = \"hex\", outer_checksum = \"DEF68E4B097A56781282F0F9D48371A0ABBCDDCF89CAD05B28C3BEDD6B2E8DF3\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \"~> 0.28\" }\ngleamy_bench = { version = \">= 0.6.0 and < 1.0.0\" }\n"
  },
  {
    "path": "benchmark/list/src/list.gleam",
    "content": "pub fn main() {\n  Nil\n}\n"
  },
  {
    "path": "benchmark/list/test/benchmarks.gleam",
    "content": "import gleamy/bench\n\nimport gleam/io\nimport gleam/list\n\npub fn print_results(results: List(bench.BenchResults)) {\n  results\n  |> list.map(fn(result) {\n    result\n    |> bench.table([bench.IPS, bench.Min, bench.P(99)])\n    |> io.println()\n  })\n}\n"
  },
  {
    "path": "benchmark/list/test/list_test.gleam",
    "content": "import benchmarks.{print_results}\nimport gleam/list\nimport gleamy/bench\n\npub fn main() {\n  print_results([bench_odd_nums_between(), bench_count_ones(), bench_slice()])\n}\n\nfn bench_odd_nums_between() -> bench.BenchResults {\n  let odd_nums_between = fn(args) {\n    let #(start, end) = args\n    odd_nums_between(start, end, [])\n  }\n\n  bench.run(\n    [\n      bench.Input(\"[0, 100)\", #(0, 100)),\n      bench.Input(\"[0, 1000)\", #(0, 1000)),\n      bench.Input(\"[0, 10_000)\", #(0, 10_000)),\n      bench.Input(\"[0, 100_000)\", #(0, 100_000)),\n      bench.Input(\"[0, 1_000_000)\", #(0, 1_000_000)),\n    ],\n    [bench.Function(\"odd_nums_between\", odd_nums_between)],\n    [bench.Duration(1000), bench.Warmup(100)],\n  )\n}\n\n/// Returns a list of numbers from `start` up to, but not including, `end`.\nfn odd_nums_between(start: Int, end: Int, acc: List(Int)) -> List(Int) {\n  case start {\n    start if start >= end -> list.reverse(acc)\n    _ -> {\n      let acc = case start {\n        n if n % 2 == 1 -> [n, ..acc]\n        _ -> acc\n      }\n      odd_nums_between(start + 1, end, acc)\n    }\n  }\n}\n\nfn bench_count_ones() -> bench.BenchResults {\n  let create_list = fn(size) {\n    list.range(0, size)\n    |> list.map(fn(n) {\n      case n {\n        _ if n % 3 == 0 -> 1\n        _ -> 0\n      }\n    })\n  }\n\n  let count_ones = fn(list) { count_ones(list, 0) }\n\n  bench.run(\n    [\n      bench.Input(\"100 numbers\", create_list(100)),\n      bench.Input(\"1000 numbers\", create_list(1000)),\n      bench.Input(\"10_000 numbers\", create_list(10_000)),\n      bench.Input(\"100_000 numbers\", create_list(100_000)),\n      bench.Input(\"1_000_000 numbers\", create_list(1_000_000)),\n    ],\n    [bench.Function(\"count_ones\", count_ones)],\n    [bench.Duration(1000), bench.Warmup(100)],\n  )\n}\n\n/// Counts the number of ones in a list.\nfn count_ones(list: List(Int), count: Int) -> Int {\n  case list {\n    [] -> count\n    [1, ..tail] -> count_ones(tail, count + 1)\n    [_, ..tail] -> count_ones(tail, count)\n  }\n}\n\nfn bench_slice() -> bench.BenchResults {\n  let list = list.range(0, 1_000_000)\n\n  let slice = fn(args) {\n    let #(list, start, end) = args\n    slice(list, start, end, [])\n  }\n\n  bench.run(\n    [\n      bench.Input(\"[0, 1000)\", #(list, 0, 1000)),\n      bench.Input(\"[0, 10_000)\", #(list, 0, 10_000)),\n      bench.Input(\"[0, 100_000)\", #(list, 0, 100_000)),\n      bench.Input(\"[999_000, 1_000_000)\", #(list, 999_000, 1_000_000)),\n      bench.Input(\"[990_000, 1_000_000)\", #(list, 990_000, 1_000_000)),\n      bench.Input(\"[900_000, 1_000_000)\", #(list, 900_000, 1_000_000)),\n      bench.Input(\"[0, 1_000_000)\", #(list, 0, 1_000_000)),\n    ],\n    [bench.Function(\"slice\", slice)],\n    [bench.Duration(1000), bench.Warmup(100)],\n  )\n}\n\n/// Slices a list.\nfn slice(list: List(Int), start: Int, end: Int, acc: List(Int)) -> List(Int) {\n  case list {\n    // If the first element is before the slice, skip it.\n    [_, ..tail] if start > 0 -> {\n      slice(tail, start - 1, end - 1, acc)\n    }\n    // If the first element is within the slice, add it to the accumulator.\n    [head, ..tail] if end > 0 -> {\n      slice(tail, start - 1, end - 1, [head, ..acc])\n    }\n    // Otherwise, return the accumulator.\n    _ -> list.reverse(acc)\n  }\n}\n"
  },
  {
    "path": "bin/add-nightly-suffix-to-versions.sh",
    "content": "#!/bin/sh\n\n#\n# Add the `-nightly-YYYYMMDD` suffix the version of all Rust crates in the\n# workspace. Used by the nightly build.\n#\n\nset -e\n\nfind . -name Cargo.toml -exec \\\n  sed -i \"\" -e \"s/^version = \\\"\\([^\\\"]*\\)\\\"$/version = \\\"\\1-nightly-$(date +%Y%m%d)\\\"/\" {} \\;\n"
  },
  {
    "path": "changelog/v1.1.md",
    "content": "# Changelog\n\n## v1.1.0 - 2024-04-16\n\n### Formatter\n\n- Fixed a bug where the first subject of a case expression clause would be\n  indented more than necessary.\n\n## v1.1.0-rc3 - 2024-04-12\n\n### Formatter\n\n- Fixed a bug where the `@internal` annotation wouldn't be displayed.\n- Fixed a bug where a record update's arguments would be incorrectly split on\n  multiple lines.\n\n## v1.1.0-rc2 - 2024-04-10\n\n### Compiler\n\n- Fixed a bug on the JavaScript target where variables named `debugger`, which\n  is a JavaScript keyword, were not being renamed, leading to runtime errors.\n\n### Formatter\n\n- Fixed a bug where comments would be moved out of an empty bit array.\n- Fixed a bug where the formatter could add a trailing comma inside empty\n  bit arrays, generating invalid syntax.\n- Revert the warning about internal types being exposed in a package's public\n  API.\n\n### Build tool\n\n- Revert the change that would make the build tool refuse to publish a package\n  that exposes an internal type in its public API.\n\n## v1.1.0-rc1 - 2024-04-08\n\n### Compiler\n\n- The `@internal` attribute can now be used to annotate definitions.\n  This will hide those definitions from the generated documentation,\n  autocompletions and the exported module interface.\n- Prepending to lists in JavaScript (`[x, ..xs]` syntax) has been optimised.\n- Function stubs are no longer generated for functions that do not have an\n  implementation for the current targeting being compiled for.\n- Fixed a bug where some functions would not result in a compile error when\n  compiled for a target that they do not support.\n- Fixed a bug where sometimes a warning would not be emitted when a result is\n  discarded.\n- Fixed a bug with JavaScript code generation of pattern matching guards.\n- URLs in error messages have been updated for the new language tour.\n- Improved error message when erroneously trying to append items to a list using\n  the spread syntax (like `[..rest, last]`).\n- Generate [type references](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types-)\n  when compiling to JavaScript with TypeScript definitions enabled.\n- Fix a bug where JavaScript code generation would not properly return the\n  result of nested blocks.\n- Fix a bug where JavaScript code generation would not properly handle functions\n  returned by blocks.\n- Fix a bug where Erlang code generation would not properly handle list case\n  patterns with no head and a spread tail.\n- The compiler will now raise a warning if you're pattern matching on tuple\n  literals and suggest you use multiple subjects instead.\n- Fixed a bug where JavaScript code generation would incorrectly parenthesise a\n  return statement.\n- Nested tuple access (`tuple.0.1`) now parses successfully.\n- Error messages are more clear about expecting values instead of types.\n- Fixed a bug where pattern matching on a string would cause the program to\n  crash on the JavaScript target.\n- A warning is now emitted when defining an opaque external type.\n- Improve error message when using incorrect quotes (`'`) to define a string\n- Fixed a bug where Erlang string prefix patterns could generate invalid Erlang.\n- Fixed string prefix matching producing wrong results on the JavaScript target\n  when the prefix had a Unicode codepoint escape sequence (`\\u{...}`).\n- Improved error message for wrong patterns using constructors from other\n  modules.\n- Fixed a bug on the JavaScript target where variables bound by patterns, if\n  used within a bit array literal inside a `case` clause's guard, would be used\n  before they were defined, leading to a runtime error when evaluating the\n  `case` expression.\n- Improved error messages when failing to parse a series of things.\n- A warning is now raised for unused binary operations, records, record access\n  and record updates.\n- Fixed a bug when using constant as the size option parameter\n  for `BitArray` caused unknown variable exception.\n- Improved recommendations on error messages.\n- Improved error message for `BitArray` segment sizes.\n- A warning is now raised when an internal type is accidentally exposed in a\n  package's public API.\n- Fixed the error message when using `panic` on the JavaScript target: it now\n  correctly identifies the error variant as a `panic` instead of a `todo`.\n- Fixed a bug on the JavaScript target where empty lists with little space\n  available could compile to a conversion from the array `[ , ]`, causing them\n  to wrongly have a length of one (the array has a single `undefined` element).\n\n### Formatter\n\n- The formatting of case expressions with multiple subjects has been improved.\n- Fixed a bug where the formatter would move comments from the end of bounded\n  expressions like lists, tuples, case expressions or function calls.\n- Fixed a bug where a record update's arguments would not be indented correctly.\n- Fixed a bug where function call arguments, tuple items and list items would be\n  needlessly indented if preceded by a comment.\n- Line endings other than `\\n` are now handled by the formatter, preserving\n  blank lines and converting them to `\\n`.\n- The formatter can now format groups of imports alphabetically.\n- Fixed a bug where comments would be moved out of an empty list.\n- Fixed a bug where pipes and binary operations in function calls would be\n  nested more than necessary.\n- Improved formatting of comments in binary operation chains.\n\n### Build tool\n\n- Added support for the [Bun](https://bun.sh/) runtime when compiling to\n  JavaScript by using `gleam run --target javascript --runtime bun`\n- Allow compilation of packages that require `\"rebar\"` using the rebar3\n  compiler.\n- A warning is now emitted if there is a `.gleam` file with a path that would be\n  invalid as a module name.\n- The `~> x.y` version constraint syntax has been dropped in favour of\n  `> x.y.z and <= xx.0.0` syntax in `gleam add` and `gleam new`, for clarity.\n- New projects are created with the GitHub `actions/checkout` v4 action.\n- Fixed a bug where bit arrays would break syntax highlighting in the generated\n  HTML documentation.\n- Dependencies that use Erlang-only bit options can now compile on JavaScript,\n  though the functions that use them will not be available for use in the root\n  package.\n- The output format of the command line help messages have been changed\n  slightly.\n- The command line help text now lists valid targets and runtimes.\n- Generated documentation no longer exposes the constructors of opaque types,\n  no longer exposes the values of constants, and indicates which types are\n  opaque.\n- Generated HTML documentation now includes a link to the package on Hex.\n- Terminal colors can now be forced by setting the `FORCE_COLOR` environment\n  variable to any non-empty value.\n- Rust's Reqwest's `webpki-roots` are now used for TLS verification.\n- Update Deno config to allow passing `--location` runtime flag.\n- Fixed a bug with dependency resolution of exact versions of RC releases.\n- Fixed a bug where the documentation of a labelled record constructor could be\n  assigned to the wrong definition in the doc site.\n- Fixed a bug where the code blocks in the generated documentation's site would\n  have a wrong indentation.\n- Fixed a bug where the compiler would panic when it cannot get current\n  directory.\n- Improved error message for non-UTF-8 paths encountered during Gleam commands.\n  Now includes the path that caused the error for better diagnostics.\n- Fixed a bug where on windows local packages had absolute paths in the manifest\n  instead of relative.\n- The `gleam publish` command now asks for confirmation if the package\n  repository URL doesn't return a successful status code.\n- `gleam publish` can now optionally use a Hex API key to authorise publishing\n  and retiring packages, set via the environment variable `HEXPM_API_KEY`.\n- `gleam publish` will now refuse to publish placeholder packages, to prevent\n  name squatting which is against the Hex terms of service.\n- If a package leaks an internal type in its public API, then the build tool\n  will now refuse to publish it to Hex.\n- Monospaced links in the generated documentation now have the same color as\n  common links.\n- Fixed a bug where the `export package interface` command would always\n  recompile the project ignoring the cache.\n\n### Language Server\n\n- Update messages from the client are now batched to avoid doing excess\n  compilation work in the language server, improving performance. This makes a\n  large difference in low power machines where the language server could\n  struggle to keep up with the edits from the client.\n- The `Compiling Gleam` message is no longer emitted each time code is compiled.\n  This is to reduce noise in editors that show this message prominently such as\n  Neovim.\n- Fixed a bug where hovering over an expression in the middle of a pipe would\n  give the wrong node.\n- Go to definition now works for values in dependency Gleam modules.\n- Completions are now provided for module imports.\n\n## v1.0.0 - 2024-03-04\n\n### Language changes\n\n- Comments have been added to the JavaScript prelude to indicate which members\n  are in the public API and which are internal.\n\n### Build tool\n\n- Fixed a bug where the exported package interface would not have a module's\n  documentation.\n\n## v1.0.0-rc2 - 2024-02-14\n\n### Bug fixes\n\n- Fixed a bug where the exhaustiveness checker could crash for some generic\n  types.\n\n### Formatter\n\n- The format used by the formatter has been improved in some niche cases.\n- Improved the formatting of long case guards.\n\n## v1.0.0-rc1 - 2024-02-10\n\n### Language changes\n\n- Using a reserved word is now a compile error, not a warning.\n- Inexhaustive matches are now compile errors, not warnings.\n- The warning for an unused module alias now shows how to not assign a name to\n  the module.\n- Type aliases with unused type parameters now emit an error.\n- Type definitions with duplicate type parameters now emit an error.\n\n### Formatter\n\n- Now the formatter will nest pipelines and binary operators that are used as\n  function arguments, list items or as tuple items.\n- The format function literals used as the last argument in a function call\n  on long lines has been improved.\n\n### Build tool\n\n- If a package contains a `todo` expression then the build tool will now refuse\n  to publish it to Hex.\n- `gleam export` now takes a `package-interface` option to export a json file\n  containing metadata about the root package.\n- `gleam docs build` now creates a json file containing metadata about the root\n  package.\n- The order of dependencies in `manifest.toml` is now in alphabetical order.\n- The search bar in generated docs now has a darker background color.\n- The generated docs no longer shows whether an argument is discarded or\n  not in a function signature.\n- It is now possible to use `gleam run -m` to run a dependency module even if\n  that dependency uses a compile target that your project does not support.\n\n### Bug fixes\n\n- Fixed a bug the build tool could be make to attempt to run a main function\n  that does not support the current target in some circumstances.\n- Fixed a bug where the exhaustiveness checker could crash when checking nested\n  values inserted into the parent type using type parameters.\n- Fixed a bug where `functionname(_name)` would incorrectly parse as a function\n  capture instead of a syntax error.\n- Fixed a bug where external only functions would \"successfully\" compile for a\n  target they do not support, leading to a runtime error.\n\n## v0.34.1 - 2023-01-17\n\n### Build tool changes\n\n- Support has been added for using SourceHut as a repository.\n\n### Bug fixes\n\n- Fixed a bug where long function headers with external implementations could\n  format incorrectly.\n- The `@deprecated` attribute can now be used to annotate module constants.\n  This will cause a warning to be emitted when the constant is used.\n\n## v0.34.0 - 2023-01-16\n\n## v0.34.0-rc3 - 2023-01-12\n\n### Language changes\n\n- \"echo\" is now a reserved word.\n- A warning is no longer emitted when a function has a Gleam implementation as\n  well as external implementations for both targets. This is because having a\n  default Gleam implementation means the code is future-proof and continues to\n  be cross platform even if a new target is added.\n\n### Bug fixes\n\n- Fixed a bug where function heads would go over the line limit in the\n  formatter.\n\n## v0.34.0-rc2 - 2023-01-11\n\n### Bug fixes\n\n- Fixed a bug where `gleam run` would fail when the current directory is not\n  the root of the project and using the JavaScript target.\n- Fixed a bug where the compiler would in some cases fail to error when an\n  application uses functions that do not support the current compilation\n  target.\n\n## v0.34.0-rc1 - 2024-01-07\n\n### Language changes\n\n- Warn about function body not being used, because it already has external\n  implementations for all targets.\n- It's now possible to compile a project with external functions in dependency\n  packages that are not supported by the compilation target so long as they are\n  not used on the current target.\n- The error message for when one imports a constructor instead of an homonymous\n  type has been improved.\n\n### Language Server Changes\n\n- Added a `View on HexDocs` link on function hover.\n\n### Formatter\n\n- Fixed some quirk with the formatting of binary operators.\n- Fixed a bug where the formatter would move a function call's closed\n  parentheses on a new line instead of splitting the function's arguments.\n- Now the formatter will format tuples as if they were functions, trying to\n  first split just the last element before splitting the whole tuple.\n- Improved the formatting of multiline strings in string concatenation.\n\n### Build tool changes\n\n- The `gleam new` command now accepts any existing path, as long as there are\n  no conflicts with already existing files. Examples: `gleam new .`, `gleam new\n..`, `gleam new ~/projects/test`.\n- The format for the README created by `gleam new` has been altered.\n- The `gleam.toml` created by `gleam new` now has a link to the full reference\n  for its available options.\n- The `gleam` binary is now statically linked on Windows.\n- New projects are created requiring between versions of v0.34.0 inclusive and\n  exclusive v2.0.0.\n- The `repository` section now supports additional VCS types in the form of\n  codeberg, forgejo and gitea allowing a `user`, `repo` and additionally a\n  `host` url.\n- TypeScript declaration for the prelude exports previously missing functions\n  and classes. Additionally, swaps interfaces for classes and adds missing\n  attributes to classes.\n- `gleam` commands now look in parent directories for a `gleam.toml` file.\n\n### Bug fixes\n\n- Fixed a bug where `gleam add` would not update `manifest.toml` correctly.\n- Fixed a bug where `fn() { Nil }()` could generate invalid JavaScript code.\n- Fixed a bug where the build tool would make unnecessary calls to the Hex API\n  when path dependencies are used.\n- Fixed a bug where `gleam new` would generate a gitignore with `build` rather\n  than `/build`.\n- Fixed where the types of generic constants could be incorrectly inferred.\n- `Utf8Codepoint` has been renamed to `UtfCodepoint` in `prelude.d.mts`.\n- Fixed a bug where `gleam deps list` would look in filesystem root instead of\n  the current directory.\n- Fixed a bug with the `isEqual` function in `prelude.js` where RegExps were\n  being incorrectly structurally compared and being falsely reported as being\n  equal.\n- JavaScript: export from `prelude.d.mts` in `gleam.d.mts` to fix the error:\n  \"Type 'Result' is not generic\".\n- Not providing a definition after some attributes is now a parse error.\n\n## v0.33.0 - 2023-12-18\n\n## v0.33.0-rc4 - 2023-12-17\n\n- The deprecated bit array options `binary` and `bit_string` have been removed.\n- The deprecated ambiguous type import syntax has been removed.\n- The deprecated `BitString` type has been removed.\n- The deprecated `inspect` functions and `BitString` type has been removed from\n  the JavaScript prelude.\n\n## v0.33.0-rc3 - 2023-12-17\n\n### Formatter\n\n- The formatter now tries to split long chains of binary operations around the\n  operator itself, rather than around other elements like lists or function\n  calls.\n\n### Bug fixes\n\n- Fixed a bug where string prefix aliases defined in alternative case branches\n  would all be bound to the same constant.\n\n## v0.33.0-rc2 - 2023-12-07\n\n### Language changes\n\n- The `\\e` string escape sequence has been removed. Use `\\u{001b}` instead.\n- Generated Erlang now disabled redundant case clause warnings as these are now\n  redundant due to exhaustiveness checking.\n\n### Bug fixes\n\n- Fixed a bug where the `\\u` string escape sequence would not work with\n  on Erlang on the right hand side of a string concatenation.\n\n## v0.33.0-rc1 - 2023-12-06\n\n### Formatter\n\n- The formatter now tries to keep a function body and its arguments on a single\n  line by first trying to split only its last argument on multiple lines.\n- Fixed a bug where the formatter would move comments out of blocks.\n- `gleam format` now ignores the Gleam build directory by default, even when not\n  in a git repository.\n\n### Language changes\n\n- Gleam now has full exhaustiveness checking. Exhaustiveness issues have been\n  downgraded from errors to warnings so that existing Gleam code can be\n  upgraded to be exhaustive without breaking existing code. In a future version\n  they will be upgraded to errors.\n- The `!` operator can now be used in clause guards.\n- The words `auto`, `delegate`, `derive`, `else`, `implement`, `macro`, and\n  `test` are now reserved for future use. If used they will emit a warning. In\n  a future version this may be upgraded to an error.\n- The `\\u{...}` syntax can be used in strings to specify unicode codepoints via a\n  hexadecimal number with 1 to 6 digits.\n- The `todo as` and `panic as` syntaxes now accept an expression that evaluates\n  to a string rather than just a string literal.\n\n### Build tool changes\n\n- The `gleam run` and `gleam test` commands gain the `-t` flag, which is an\n  alias of the `--target` flag.\n- The `gleam build`, `gleam check`, `gleam run` and `gleam test` commands now\n  also accept `js` and `erl` as values for the `--target` flag.\n- The `gleam new` command now creates packages at version 1.0.0.\n- The `gleam publish` command now asks for confirmation if the package being\n  published is not yet version 1.0.0.\n- The `gleam publish` command now asks for confirmation if the package name is\n  one that implies the package is maintained by the Gleam core team.\n- The error messages shown when dependency resolution fails have been improved.\n\n### Compiler WASM API\n\n- The WASM API for the compiler has been rewritten to be simpler.\n- The WASM API for the compiler now exposes warnings.\n\n### HTML documentation generator\n\n- Searching in rendered HTML documentation now also matches words that do not\n  start with the input but do contain it.\n\n### Bug fixes\n\n- Fixed a bug where the JavaScript code generator could generate invalid code\n  when pretty printing a zero arity function call when the line is over 80\n  columns wide.\n- Fixed a bug where the build directory could be left in an invalid state if\n  there is Elixir code to compile and running on Windows without permission to\n  create symlinks.\n- Fixed a bug where numbers with preceding zeros could generate incorrect\n  JavaScript.\n- The Erlang code generated by the `/.` operator no longer generates a warning\n  for the upcoming negative zero float change in Erlang OTP 27.\n- Fixed a bug where using only types from an aliased import, wouldn't stop the\n  compiler from emitting an unused alias warning for that import.\n- Fixed a bug where the formatter would remove the ` as name` from string prefix\n  patterns.\n- Fixed a bug where the formatter would misplace comments at the start of a\n  block.\n- Fixed a bug where using a string prefix pattern in `let assert` would generate\n  incorrect JavaScript.\n\n## v0.32.4 - 2023-11-09\n\n### Build tool changes\n\n- The build tool now supports rebar3 and mix hex packages where the package name\n  differs from the otp application name.\n\n### bug fixes\n\n- Fixed a bug where invalid javascript code could be generated when a module\n  function calls another function that was passed as an argument and the\n  argument has the same name as the module function.\n- Fixed the `target` property of `gleam.toml` being ignored for local path\n  dependencies by `gleam run -m module/name`\n\n## v0.32.3 - 2023-11-07\n\n### Language changes\n\n- Imported modules can now be discarded by giving them an alias starting with `_`.\n\n### Build tool changes\n\n- New projects are now generated with the call to `gleam format` coming last in\n  the GitHub Actions workflow. This is so that feedback from tests is presented\n  even if formatting is incorrect.\n- Added Windows support for the `gleam export erlang-shipment` command.\n\n### Bug fixes\n\n- Fixed a bug where some nested pipelines could fail to type check.\n\n## v0.32.2 - 2023-11-03\n\n### Build tool changes\n\n- New Gleam projects are created with `gleam_stdlib` v0.32 and `gleeunit` v1.0.\n\n### Bug fixes\n\n- Fixed a bug where `gleam fix` would not produce correct results for code that\n  shadowed a prelude name with an import of the same name but a different kind.\n- Fixed a bug where documentation would not publish to Hexdocs for packages with\n  a number in the name.\n- Fixed a bug where aliased unqualified types and values of the same name could\n  produce an incorrect error.\n\n## v0.32.1 - 2023-11-02\n\n### Bug fixes\n\n- Fixed a bug where `gleam fix` would not produce correct results for code that\n  shadowed a prelude name with an import of the same name but a different kind.\n- Fixed a bug where incorrect JavaScript could be generated due to backwards\n  compatibility with the deprecated import syntax.\n\n## v0.32.0 - 2023-11-01\n\n### Bug fixes\n\n- Fixed a bug where running `gleam fix` multiple times could produce incorrect\n  results.\n\n## v0.32.0-rc3 - 2023-10-26\n\n### Bug fixes\n\n- Fixed a bug where `gleam fix` would fail to update the deprecated type import\n  syntax for aliased unqualified types.\n\n## v0.32.0-rc2 - 2023-10-26\n\n### Bug fixes\n\n- Fixed a bug where the backward compatibility for the deprecated import syntax\n  could result in an import error with some valid imports.\n\n## v0.32.0-rc1 - 2023-10-25\n\n### Language changes\n\n- Using `import module.{TypeName}` to import a type has been deprecated,\n  replaced by `import module.{type TypeName}`. In a future version of Gleam the\n  old syntax will only import the value of the same name. Run `gleam fix` to\n  update your code.\n- The `BitString` type has been renamed to `BitArray`. Run `gleam fix` to update\n  your code.\n- The `binary` and `bit_string` bit array modifier have been deprecated in favour\n  of `bytes` and `bits`.\n- The error message for when one element in a list doesn't match the others has\n  been improved.\n- The error message for when the elements of a list's tail don't match the\n  previous ones has been improved.\n- The error message for when one tries to access an unknown field has been\n  improved.\n- The `__gleam_prelude_variant__` property has been removed from the classes\n  defined in the JavaScript prelude.\n- The deprecated `todo(\"...\")` syntax has been removed.\n- Module access can now be used in case clause guards.\n- The JS target now supports bit syntax for module constants.\n- The Erlang compiler will no longer emit a duplicate warning for unused\n  functions.\n- The `@deprecated` attribute can now be used with type definitions.\n- A warning is now emitted if a module alias is unused.\n\n### Language server changes\n\n- The language server now has a code action for removing unused items.\n- The language server now shows the type of variables defined using `use` on\n  hover.\n\n### Build tool changes\n\n- The `gleam check` command supports the `target` flag.\n- The `gleam fix` command updates code to use `BitArray` rather than `BitString`.\n- The `gleam fix` command updates code to use the new import type syntax.\n- `gleam fix` sets the `gleam` version constraint in `gleam.toml` to `>= 0.32.0`.\n- The `gleam` version constraint field in `gleam.toml` now disregards pre and\n  build components when checking for compatibility.\n- The prelude is no longer rendered once per package when compiling to\n  JavaScript, instead one copy is rendered for the entire project. If you are\n  using the `gleam compile-package` API you now need to give a path to the\n  prelude using the `--javascript-prelude` flag.\n- The `gleam export javascript-prelude` and `gleam export typescript-prelude`\n  commands have been added to export a copy of the prelude. This command may be\n  useful for build tools that use the compiler via the `gleam compile-package`\n  API.\n- Fixed a bug where some deprecation messages would not be printed.\n- The content has been made wider in rendered HTML documentation.\n- Dependencies that can be built with both `mix` and `rebar3` are now built\n  with `mix` if it exists on the system, and with `rebar3` if it doesn't.\n\n### Bug fixes\n\n- \"Compiling $package\" is now only printed when a package has new changes to\n  compile.\n- The main process started with `gleam run` no longer traps exits on Erlang.\n- The formatting of code in rendered HTML documentation has been improved.\n- The formatter no longer moves trailing comments out of custom type definitions.\n- Fixed a bug where some hexadecimal numbers would generate incorrect Erlang.\n- Fixed a bug where markdown tables would not render correctly in HTML\n  documentation.\n- The float 0.0 is now rendered in Erlang as `+0.0` to silence warnings in\n  Erlang/OTP 27.\n\n## v0.31.0 - 2023-09-25\n\n- New Gleam projects are created with `gleam_stdlib` v0.31, `actions/checkout`\n  v3.\\*, and `erlef/setup-beam` v1.\\*.\n- A note is included in the generated HTML documentation if a function is\n  deprecated.\n\n## v0.31.0-rc1 - 2023-09-18\n\n- The `@deprecated(\"...\")` attribute can be used to mark a function as\n  deprecated. This will cause a warning to be emitted when the function is used.\n- A warning is now emitted if a module from a transitive dependency is imported.\n- Record access can now be used in case clause guards.\n- Fixed a bug where `manifest.toml` could contain absolute paths for path\n  dependencies.\n- The `as` keyword can now be used to assign the literal prefix to a variable\n  when pattern matching on a string.\n- The `if` conditional compilation, `external fn`, and `external type` syntaxes\n  have been removed.\n- The `description` flag for the `gleam new` command has been removed.\n- The highlight.js grammar included with generated HTML documentation has been\n  updated for the latest syntax.\n- Packages are no longer precompiled to Erlang when publishing to Hex if the\n  package target is set to JavaScript.\n- An exception is now raised if JavaScript code uses the `BitString` class\n  constructor and passes in the incorrect argument type.\n- Fixed a bug where mutually recursive functions could be incorrectly inferred\n  as having an overly general type.\n- Fixed a bug where recursive type constructors could incorrectly infer a type\n  error.\n- Fixed a bug where some mutually recursive functions would be inferred as\n  having too general a type.\n- Fixed a bug where constants where not being correctly inlined when used in the\n  size option of a bit string pattern match.\n- Fixed a bug where anonymous functions could parse successfully when missing a\n  body.\n- Fixed a bug where incorrect unused variable warnings could be emitted for code\n  that doesn't type check.\n- Fixed a bug where packages defaulting to the JavaScript target could have\n  modules missing from their HTML documentation when published.\n- Corrected some outdated links in error messages.\n- Hovering over a function definition will now display the function signature,\n  or the type of the hovered argument.\n- Use `import type` for importing types from typescript declarations.\n- Use `.d.mts` extension for typescript declarations to match `.mjs`.\n- Prefix module names with dollar sign in typescript to avoid name collisions.\n\n## v0.30.4 - 2023-07-26\n\n- External implementations are always referenced directly in generated code, to\n  avoid the overhead of an extra function call.\n- Fixed a bug where the compiler could infer incorrect generic type parameters\n  when analysing a module without type annotations with self recursive\n  functions that reference themselves multiple times.\n\n## v0.30.3 - 2023-07-23\n\n- Fixed a bug where JavaScript module path such as `node:fs` would be rejected.\n- New Gleam projects are created with `gleam_stdlib` v0.30, Erlang OTP v26.0.2,\n  Elixir v1.15.4, actions/checkout v3.5.1, and erlef/setup-beam v1.16.0.\n\n## v0.30.2 - 2023-07-20\n\n- Fixed a bug where the compiler could infer incorrect generic type parameters\n  when analysing a module without type annotations with self recursive\n  functions.\n- Fixed a bug where the formatter would incorrectly format external functions\n  by breaking the return annotation instead of the function arguments.\n\n## v0.30.1 - 2023-07-13\n\n- Fixed a bug where the language server could fail to import path dependencies\n  in monorepos.\n\n## v0.30.0 - 2023-07-12\n\n- A warning is now emitted for the deprecated external fn syntax.\n\n## v0.30.0-rc4 - 2023-07-10\n\n- An error is now emitted for invalid JavaScript external implementations.\n- Fixed a bug where Erlang external implementations could generate invalid code.\n\n## v0.30.0-rc3 - 2023-07-05\n\n- Fixed a bug where `gleam fix` would fail to parse command line flags.\n\n## v0.30.0-rc2 - 2023-07-03\n\n- Fixed a bug where `gleam fix` would merge external functions of the same name\n  but incompatible types.\n- Fixed a bug where external function arguments would incorrectly be marked as\n  unused.\n\n## v0.30.0-rc1 - 2023-06-29\n\n- The new `@target(erlang)` and `@target(javascript)` attribute syntax has been\n  added for conditional compilation. The existing `if` conditional compilation\n  syntax has been deprecated. Run `gleam fix` to update your code.\n- The new `type TypeName` syntax syntax replaces the `external type TypeName`\n  syntax. The existing external type syntax has been deprecated. Run `gleam format`\n  to update your code.\n- Adding a new dependency now unlocks the target package. This helps avoid\n  failing to find a suitable version for the package due to already being\n  locked.\n- A custom message can now be specified for `panic` with `panic as \"...\"`.\n- The syntax for specifying a custom message for `todo` is now `todo as \"...\"`.\n- The Erlang error raised by `let assert` is now tagged `let_assert`.\n- Types named `Dynamic` are now called `dynamic_` in Erlang to avoid a clash\n  with the new Erlang `dynamic` type introduced in OTP26.\n- Dependencies can now be loaded from paths using the\n  `packagename = { path = \"...\" }` syntax in `gleam.toml`.\n- The `javascript.deno.unstable` field in `gleam.toml` can now be used to\n  enable Deno's unstable APIs when targeting JavaScript.\n- Blockquotes are now styled in rendered HTML documentation.\n- The `gleam` property can be set in `gleam.toml` can be set to a version\n  requirement to specify the version of Gleam required to build the project.\n- Type aliases can now refer to type aliases defined later in the same module.\n- Fixed a bug where unapplied record constructors in constant expressions would\n  generate invalid Erlang.\n- Fixed a bug where the prescedence of `<>` and `|>` would clash.\n- Fixed a bug where `gleam docs build` would print an incorrect path upon\n  completion.\n- Warnings from dependency packages are no longer surfaced in the language\n  server.\n- A warning is now emitted when a Gleam file is found with an invalid name.\n- A warning is now emitted when using `list.length` to check for the empty list,\n  which is slow compared to checking for equality or pattern matching (#2180).\n- The new `gleam remove <package_name>` can be used to remove dependencies\n  from a Gleam project.\n- Fixed a bug where the formatter could crash.\n- Fixed a bug where invalid Erlang would be generated when piping into `panic`.\n- The `gleam docs build` command gains the `--open` flag to open the docs after\n  they are generated (#2188).\n- Fixed a bug where type annotations for constants could not be written with\n  type annotations.\n- Updated font loading in generated HTML documentation to fix an issue with\n  fonts not loading properly in some browsers (#2209).\n\n## v0.29.0 - 2023-05-23\n\n- New projects now require `gleam_stdlib` v0.29.\n\n## v0.29.0-rc2 - 2023-05-22\n\n- The `gleam lsp` command is no longer hidden from the help output.\n- Fixed a bug where some language server clients would show autocompletion\n  suggestions too eagerly.\n\n## v0.29.0-rc1 - 2023-05-16\n\n- The language server will now provide autocomplete suggestions for types and\n  values either imported or defined at the top level of the current module.\n- Fixed a bug where record patterns using the spread operator (`..`) to discard\n  unwanted arguments would not type check correctly when the record had no\n  labelled fields.\n- Add support for using sized binary segments in pattern matches when targeting\n  JavaScript.\n- A warning is now emitted for double unary negation on ints (`--`) and bools\n  (`!!`) as this does nothing but return the original value.\n- Previously the build tool would discard the entire build directory when dependencies\n  were changed. Now it will only discard the build artefacts for removed\n  dependencies.\n- The errors emitted when a name is reused in a module have been made clearer.\n- Fixed an incorrect URL in the error message for failing to parse a let binding\n  with a type annotation.\n- Fixed a bug where shadowing a prelude type name could result in incorrect\n  errors in exhaustiveness checking.\n- Fixed a bug where the language server would in some scenarios not remove an\n  error diagnostic after it becomes outdated.\n- Fixed a bug where the formatter would incorrectly format blocks with a comment\n  before them that were the only argument to a function call.\n- Fixed a bug where the language server would not reset the build directory when\n  it was created by a different version of Gleam.\n- New Gleam projects are created with `erlef/setup-beam@v1.15.4` in their GitHub\n  actions CI configuration.\n- Running a module now uses the dependency's target and runtime in its `gleam.toml`.\n\n## v0.28.3 - 2023-04-17\n\n- Fixed a bug where the language server would show outdated error diagnostics\n  when a new one was emitted in a different module.\n- Fixed a bug where the language server would attempt to analyse Gleam modules\n  that were outside of the `src` or `test` directories.\n- New Gleam projects are created with `actions/checkout@v3.5.1` and\n  `erlef/setup-beam@1.15.3` in their GitHub actions CI configuration.\n\n## v0.28.2 - 2023-04-10\n\n- Fixed a bug where comments above a `use` expression would be formatted\n  incorrectly.\n- Fixed a bug where the formatter would fail to preserve empty lines after a\n  block.\n- Fixed a bug where the formatter would fail to preserve empty lines after an\n  anonymous function with a return annotation.\n\n## v0.28.1 - 2023-04-05\n\n- Fixed a bug where the language server would unset too many error diagnostics\n  when multiple projects are open, more than one have errors, and one of them is\n  successfully compiled.\n- Fixed a bug where the language server would unset error diagnostics when\n  displaying information on hover.\n- Added support for type annotations in use statements.\n\n## v0.28.0 - 2023-04-03\n\n- New projects now require `gleam_stdlib` v0.28.\n\n## v0.28.0-rc3 - 2023-03-31\n\n- Fixed a bug where source links would be incorrect in HTML documentation.\n\n## v0.28.0-rc2 - 2023-03-27\n\n- Fixed a bug where single statement blocks inside binary operators could\n  generate invalid JavaScript.\n- Fixed a bug where the formatter could incorrectly place comments.\n- Fixed a bug where the language server would show outdated diagnostics when a\n  file with an error reverts to the previous valid version, causing the compiler\n  to use the cached version of the file.\n\n## v0.28.0-rc1 - 2023-03-26\n\n- The language server now analyzes files on edit rather than on save, providing\n  feedback faster.\n- The language server now supports editor sessions that span multiple projects.\n  This is useful for mono-repos and projects with both a frontend and backend in\n  Gleam.\n- The language server now also shows documentation on hover for expressions.\n- The language server now shows types and documentation on hover for patterns.\n- Added support for negation of integers with the new `-` unary operator.\n- Variable assignments are now only permitted within a function or a block, not\n  anywhere that an expression is permitted.\n- The deprecated `try` expression has been removed.\n- The deprecated `assert ... = ...` syntax has been removed.\n- Semicolons are no longer whitespace. An error will be emitted if one is\n  encountered.\n- Warnings are now immediately emitted rather than being buffered until the end\n  of the compilation.\n- The `--warnings-as-errors` flag is now supported by `gleam build`.\n- Blocks are now preserved by the formatter when they only have a single\n  expression within them.\n- Generated docs now export more meta data to improve the developer experience,\n  accessibility and search engine discoverability.\n- Files are now only recompiled if they have changed since the last compilation,\n  detected by file hash and modification time. Previously only the modification\n  time was used.\n- Autocompletion of module imports was removed due to a buggy implementation.\n- Fixed a bug where the formatter would incorrectly remove `{ ... }` from bit\n  string segment value expressions.\n- Fixed a bug where TypeScript type definitions files could include incorrect\n  type names.\n- Fixed a bug where the compiler used VSCode specific behaviour in the language\n  server which was incompatible with Helix.\n- Fixed a bug where string concatenation patterns on strings with escape\n  characters would generate javascript code with wrong slice index.\n- Fixed a bug where blocks could parse incorrectly.\n- Allow modules to be run with the `gleam run --module` command.\n\n## v0.27.0 - 2023-03-01\n\n- Fixed a bug where `panic` could generate incorrect JavaScript code.\n- New projects now require `gleam_stdlib` v0.27.\n\n## v0.27.0-rc1 - 2023-02-26\n\n- The new `panic` keyword can be used to crash the program. This may be useful\n  for situations in which a program has got into an unrecoverable invalid state.\n- `try` expressions are now deprecated and will be removed in a future version.\n- The new `gleam fix` command can be used to automatically convert `try`\n  expressions to `use` expressions.\n- `let assert ... = ...` is now the syntax for assertion assignments. The\n  `assert ... = ...` syntax is deprecated and will be removed in a future\n  version. Run `gleam format` to automatically update your code.\n- `gleam export hex-tarball` can be used to create a tarball suitable for\n  uploading to a Hex compatible package repository.\n- The unused private type and constructor detection has been improved.\n- The argument `--runtime` now accepts `nodejs` as the name for that runtime.\n  The previous name `node` is still accepted.\n- Patterns can now be used in `use` expressions.\n- Fixed a bug where string concatenation patterns could generate javascript\n  code with wrong slice index due to ut8/ut16 length mismatch.\n- The Erlang compiler will no longer emit a duplicate warning for unused\n  variables.\n- Fixed a bug where typescript type definitions for types with unlabelled\n  arguments where generated with an invalid identifier and unlabelled fields\n  were generated with a name that didn't match the javascript implementation.\n- Fixed a bug in the type inferrer were unannotated functions that were\n  used before they were defined in a module could in rare cased be inferred\n  with a more general type than is correct.\n- Fixed a bug where the LSP would fail to show type information on hover for\n  expressions after a use expression.\n- Fixed a bug where imported constants could generated incorrect JavaScript\n  code.\n- Fixed a bug where the LSP would perform codegen for dependencies.\n- Fixed a bug where the LSP would compile native dependencies needlessly.\n- Fixed a bug where integer division with large numbers on JavaScript could\n  produce incorrect results.\n- Fixed a bug where pattern matches on custom types with mixed labelled and\n  unlabelled arguments could not be compiled when targeting JavaScript.\n- Fixed a bug where local variables in case guard constant expressions caused\n  the compiler to panic.\n- The formatter now truncates meaningless zeroes of floats' fractional parts.\n- Anonymous functions may now have an empty body. The compiler will emit a\n  warning for functions without a body, and these functions will crash at\n  runtime if executed.\n- Fixed bug where raised errors on JS would have an extra stack frame recorded\n  in them.\n\n## v0.26.2 - 2023-02-03\n\n- The formatter now wraps long `|` patterns in case clauses over multiple lines.\n- Fixed a bug where unlabelled function arguments could be declared after\n  labelled ones.\n- A broken link was removed from the error messages.\n- Fixed a bug where using a qualified imported record constructor function as a\n  value would produce invalid Erlang code if the name of the record variant was\n  an Erlang reserved word.\n\n## v0.26.1 - 2023-01-22\n\n- New projects now require `gleeunit` v0.10.\n- Rebar3 dependency projects are now compiled in-place. This fixes an issue\n  where some NIF using projects would fail to boot due to some paths not being\n  copied to the `build` directory.\n- An error is now emitted if a list spread expression is written without a tail\n  value.\n- An error is now emitted when a function is defined with multiple arguments\n  with the same name.\n- The error message emitted when a `let` does not match all possible values has\n  been improved.\n- Fixed a bug where the language server wouldn't analyse test code.\n- Fixed a bug where `assert` expressions can generate invalid Erlang.\n  warning.\n- Fixed a bug where arguments would be passed incorrectly to Deno.\n- Fixed a bug where defining variables that shadow external functions could\n  generate invalid JavaScript.\n\n## v0.26.0 - 2023-01-19\n\n[Release blog post](https://gleam.run/news/v0.26-incremental-compilation-and-deno/)\n\n- New projects require `gleam_stdlib` v0.26 and `gleeunit` v0.9.\n- Fixed a bug where JavaScript default projects would fail to publish to Hex.\n\n## v0.26.0-rc1 - 2023-01-12\n\n- Added support for Deno runtime for JavaScript target.\n- Scientific notation is now available for float literals.\n- The compiler now supports incremental compilation at the module level. If a\n  module or its dependencies have not been changed then it will not be\n  recompiled.\n- The format used by the formatter has been improved.\n- 4 digit integers are now always formatted without underscores.\n- Running `gleam new` will skip `git init` if the new project directory is\n  already part of a git work tree.\n- Generated HTML documentation now includes all static assets, including web\n  fonts, so that it can be accessed offline and in future once CDNs would 404.\n- Generated HTML documentation now supports TypeScript syntax highlighting.\n- New Gleam projects are created using GitHub actions erlef/setup-beam@v1.15.2.\n- Some modules can now be hidden from the docs by specifying a list of glob\n  patterns in `internal_modules` in `gleam.toml`. The default value for this\n  list is `[\"$package_name/internal\", \"$package_name/internal/*\"]`.\n- The `gleam new` command gains the `--skip-git` flag to skip creation of\n  `.git/*`, `.gitignore` and `.github/*` files.\n- The `gleam new` command gains the `--skip-github` flag to skip creation of\n  `.github/*` files.\n- Fixed a bug where no error would be emitted if a `src` module imported a\n  `test` module.\n- Fixed a bug where comments in list prepending expressions could be formatted\n  incorrectly.\n- Fixed a bug where comments in record update expressions could be formatted\n  incorrectly.\n- Fixed a bug where long `use` expressions could be formatted incorrectly.\n- Fixed a bug integer multiplication would overflow large integers when\n  compiling to JavaScript.\n- Fixed `int` and `float` formatting in `const`s and patterns.\n- Fixed a bug where piping into a function capture expression with a pipe as one\n  of the arguments would produce invalid Erlang code.\n- Formatter no longer removes new lines in expression blocks within case branches\n\n## v0.25.3 - 2022-12-16\n\n- 4 digit integers are no longer automatically formatted with underscores.\n\n## v0.25.2 - 2022-12-16\n\n- Updated `actions/checkout` from `actions/checkout@v3.0.0` to `@v3.2.0` for\n  projects created via `gleam new`.\n- Fixed a bug where `gleam new` would set a `Rebar3` version to `25.1`\n  instead of the latest stable `3`.\n- Updated following runtime versions set via `gleam new`: `Erlang/OTP`\n  to `25.2`, and `Elixir` to `1.14.2`.\n- The formatter now inserts underscores into larger `Int`s and the larger\n  integer parts of `Float`s.\n- Added support for top level TypeScript file inclusion in builds.\n- The build tool will now favour using rebar3 over Mix for packages that support\n  both. This fixes an issue where some packages could not be compiled without\n  Elixir installed even though it is not strictly required.\n\n## v0.25.1 - 2022-12-11\n\n- New Gleam projects are now configured to explicitly install rebar3 using\n  GitHub actions erlef/setup-beam.\n- A better error message is now shown when attempting to use a function within a\n  constant expression.\n- Changed float size limit in bit string expressions to 16, 32 or 64, when static.\n  Also allowed dynamic size.\n- New Gleam projects are created using GitHub actions erlef/setup-beam@v1.15.0.\n- Fixed a bug where returning an anonymous function from a pipeline and calling\n  it immediately without assigning it to a variable would produce invalid Erlang\n  code.\n- Fixed a bug where the formatter would remove the braces from negating boolean\n  expressions.\n\n## v0.25.0 - 2022-11-24\n\n[Release blog post](https://gleam.run/news/v0.25-introducing-use-expressions/)\n\n## v0.25.0-rc2 - 2022-11-23\n\n- Fixed a bug where Gleam dependency packages with a `priv` directory could fail\n  to build.\n- Fixed a regression where Elixir and Erlang Markdown code blocks in generated\n  documentation would not be highlighted.\n\n## v0.25.0-rc1 - 2022-11-19\n\n- Generated HTML documentation now includes the `theme-color` HTML meta tag.\n- The `use` expression has been introduced. This is a new syntactic sugar that\n  permits callback using code to be written without indentation.\n- Nightly builds are now also published as OCI container images hosted on\n  GitHub.\n- Fixed a bug where the build tool would not hook up stdin for Gleam programs it\n  starts.\n- Fixed a bug where using a record constructor as a value could generate a\n  warning in Erlang.\n- Fixed a bug where the build tool would use precompiled code from Hex packages\n  rather than the latest version, which could result in incorrect external\n  function usage in some cases.\n- Fixed a bug where the warning for `todo` would not print the type of the code\n  to complete.\n- Fixed a bug where `try` expressions inside blocks could generate incorrect\n  JavaScript.\n- Generated HTML documentation now includes all static assets (but the web\n  fonts), so that it can be accessed offline or in far future once CDNs would 404.\n- New Gleam projects are created using GitHub actions erlef/setup-beam@v1.14.0\n- The `javascript.typescript_declarations` field in `gleam.toml` now applies to\n  the entire project rather than just the top level package.\n- The formatter now adds a `0` to floats ending with `.` (ie `1.` => `1.0`).\n- New projects require `gleam_stdlib` v0.25.\n\n## 0.24.0 - 2022-10-25\n\n[Release blog post](https://gleam.run/news/gleam-v0.24-released/)\n\n## 0.24.0-rc4 - 2022-10-23\n\n- Fixed a bug where the string concatenate operator could produce invalid Erlang\n  code when working with pipe expressions.\n\n## 0.24.0-rc3 - 2022-10-20\n\n- Fixed a bug where the OOP method call error hint would be shown on too many\n  errors.\n- Fixed a bug where the string concatenate operator could produce invalid Erlang\n  code when working with constant values.\n\n## 0.24.0-rc2 - 2022-10-18\n\n- Fixed a bug where imported and qualified record constructors used in constant\n  expressions could fail to resolve.\n\n## 0.24.0-rc1 - 2022-10-15\n\n- Gleam can now compile Elixir files within a project's `src` directory.\n- The `<>` operator can now be used for string concatenation and for string\n  prefix pattern matching.\n- Fixed a bug where TypeScript definitions may have incorrect type parameters.\n- New projects depend on `gleam_stdlib` v0.24.\n- New projects' GitHub Actions config specifies Erlang/OTP 25.1 and suggest\n  Elixir 1.14.1.\n- If you attempt to use the method call syntax (`thing.method()`) on a value\n  without that field the error message will now include a hint explaining that\n  Gleam is not object oriented and does not have methods.\n- Fixed a bug in the formatter where multiple line documentation comments for\n  custom type constructor fields could be formatted incorrectly.\n- Fixed a bug where tail call optimisation could be incorrectly applied when\n  compiling to JavaScript in some situations.\n- Fixed a bug where the remainder operator would return NaN results when the\n  right hand side was zero when compiling to JavaScript.\n- Fixed a bug where Elixir dependencies would fail to compile on Windows.\n- Fixed a bug where images added to HTML documentation via documentation\n  comments would not have a max width.\n\n## v0.23.0 - 2022-09-15\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.23-released/)\n\n## v0.23.0-rc2 - 2022-09-15\n\n- New Gleam projects are created using GitHub actions erlef/setup-beam@v1.13.0\n  and actions/checkout@v3.0.0.\n- New Gleam projects are created using version v0.23.0 of the stdlib.\n- Fixed a bug where LSP hovering would fail to locate the expression.\n\n## v0.23.0-rc1 - 2022-09-01\n\n- Gleam can now build dependency packages that are managed using Mix.\n- Compiler performance has been improved by buffering disc writing and by lazily\n  loading TLS certs. In testing this doubles performance when compiling the\n  standard library.\n- The `gleam publish` command now adds the `priv` directory and any `NOTICE`\n  file to the tarball.\n- The `gleam update` command can now be used to update dependency packages to\n  their latest versions.\n- Module functions with empty bodies are no longer syntax errors.\n- The format used by the formatter has been improved.\n- OpenSSL swapped out for RustTLS.\n- Generated HTML documentation now includes a search bar.\n- The LSP will now provide autocompletion for imports.\n- A helpful error message is now returned when assignments are missing either a\n  keyword or a value.\n- Qualifiers are now used when multiple types have the same name in an error\n  message.\n- In JavaScript, if an object has defined an `equals` method in its prototype,\n  Gleam will now use this method when checking for equality.\n- Functions can now be defined and referenced in constant expressions.\n- An error is now raised if the record update syntax is used with a custom type\n  that has multiple constructors.\n- An error is now raised if a module is imported multiple times.\n- Fixed a bug where defining a type named `CustomeType` would product invalid\n  JavaScript.\n- Fixed a bug where defining a variable with the same name as an unqualified\n  import would produce invalid JavaScript.\n- Fixed a bug where piping to `todo` would generate invalid Erlang code.\n- Fixed a bug where inspecting a JavaScript object with a null prototype would\n  crash.\n- Fixed a bug where the formatter could crash if source code contained 3 or more\n  empty lines in a row.\n- Fixed a bug where the formatter would remove braces from blocks used as the\n  subject of a case expression.\n- Fixed a bug alternative patterns with a clause containing a pipe with a pipe\n  after the case expression could render incorrect Erlang.\n- Fixed a bug where formatter would strip curly braces around case guards even\n  when they are required to specify boolean precedence.\n- Fixed a bug where `gleam new` would in some situations not validate the\n  target directory correctly.\n- Fixed a bug where pipes inside record update subjects could generate invalid\n  Erlang.\n- Fixed a bug where pipes inside record access could generate invalid Erlang.\n\n## v0.22.1 - 2022-06-27\n\n- The `gleam publish` confirmation prompt now accepts both \"Y\" and \"y\".\n- Fixed a bug where `todo` would not emit the correct line number to the LSP while.\n\n## v0.22.0 - 2022-06-12\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.22-released/)\n\n- New projects are created with `gleam_stdlib` v0.22.\n\n## v0.22.0-rc1 - 2022-06-12\n\n- Fixed a bug where doc comments would dissociate from their statements when\n  generating html documentation.\n- You are now allowed to use named accessors on types with multiple constructors if the\n  accessor's name, position and type match (among the constructors) (#1610).\n- Added the ability to replace a release up to one hour after it is published\n  using `gleam publish --replace`.\n- `gleam publish`, `gleam docs publish`, `gleam docs remove`, `gleam hex retire`,\n  and `gleam hex unretire` now have access to environment variables for\n  username (default key `HEXPM_USER`) and password (default key `HEXPM_PASS`)\n- The `gleam publish` command gains the `-y/--yes` flag to disable the \"are you\n  sure\" prompt.\n- Clear outdated files from the build directory after compilation.\n- Fixed a bug where immediately calling the value that a case expression\n  evaluates to could generate invalid JavaScript.\n- Fixed a bug where the default project target is set to JavaScript,\n  but the project would run on target Erlang instead.\n- The compiler is now able to generate TypeScript declaration files on target\n  JavaScript (#1563). To enable this edit `gleam.toml` like so:\n\n  ```toml\n  [javascript]\n  typescript_declarations = true\n  ```\n\n- Fixed a bug where argument labels were allowed for anonymous functions.\n- Fixed a bug where JavaScript code could be invalid if a variable is defined\n  inside an anonymous function with a parameter with the same name as the\n  variable.\n- Fixed a bug where importing a JavaScript function named \"then\" could produce\n  invalid code.\n- Fixed a bug where constants that reference locally defined custom types could\n  render invalid JavaScript.\n- The project generator will no longer permit use of the reserved `gleam_`\n  prefix.\n- Generated HTML docs easter egg updated.\n- `gleam export erlang-shipment` can be used to create a directory of compiled\n  Erlang bytecode that can be used as a deployment artefact to get your\n  application live.\n- `gleam format` will now preserve (up to one) empty lines between consecutive\n  comments, as well as between comments and any following expression\n- The deprecated rebar3 integration has been removed.\n- Fixed a bug where `gleam format` would output an unwanted newline at the top\n  of documents that only contain simple `//` comments.\n- No longer add `dev_dependencies` to generated `.app` Erlang files unless\n  we're compiling the root project (#1569).\n- Fixed a bug where the formatter could render a syntax error with lists on long\n  unbreakable lines.\n- Fixed a bug where JavaScript variable names could be incorrectly reused.\n- Fixed a bug where `gleam format` would remove the braces around a tuple index\n  access when accessing a field of the returned element.\n- Fixed a bug case clause guards could render incorrect JavaScript if a variable\n  name was rebinded in the clause body.\n- The `gleam compile-package` command no longer generates a `.app` file. This\n  should now be done by the build tool that calls this command as it is\n  responsible for handling dependencies.\n- Fixed a bug where piping a list tail would create invalid Erlang code (#1656).\n\n## v0.21.0 - 2022-04-24\n\n[Release Blog Post](https://gleam.run/news/v0.21-introducing-the-gleam-language-server/)\n\n- New projects are created with `gleam_stdlib` v0.21.\n\n## v0.21.0-rc2 - 2022-04-20\n\n- Added the ability to replace a release up to one hour after it is published\n  using `gleam publish --replace`.\n- The language server will now enter a degraded mode that only performs\n  formatting if running in a directory that is not a Gleam project with a\n  `gleam.toml`.\n\n## v0.21.0-rc1 - 2022-04-16\n\n- The Gleam language server is here! This will provide IDE like features for\n  code editors that support LSP, including but not limited to VSCode, Neovim,\n  Emacs, Eclipse, Visual Studio, and Atom. This first version includes these\n  features:\n  - Project compilation.\n  - Inline errors and warnings.\n  - Type information on hover.\n  - Go-to definition.\n  - Code formatting.\n- Fixed a bug in generated JavaScript code where functions named `then` would\n  cause errors when dynamically imported.\n- Initialize `git` repo when creating a new project.\n- Log messages controlled with `GLEAM_LOG` now print to standard error.\n- Log message colours can be disabled by setting the `GLEAM_LOG_NOCOLOUR`\n  environment variable.\n- You can now specify multiple packages when using `gleam add`.\n- Bools can now be negated with the `!` unary operator.\n- If the compiler version changes we now rebuild the project from scratch on\n  next build command to avoid issues arising from reading metadata in an old\n  format (#1547).\n- Updated the \"Unknown label\" error message to match other error messages\n  (#1548).\n- Type holes are now permitted in function arguments and return annotations\n  (#1519).\n- Unused module imports now emit a warning (#1553).\n- The error message for failing to parse a multiline clauses without curly\n  braces has been improved with a hint on how to fix the issue (#1555).\n- The error messages for when rebar3 or Erlang are missing from the machine has\n  been improved with a tip on how to install them (#1567).\n- Corrected the hint given with certain int and float binary operator type\n  errors.\n- Add support for `int` and `float` bit string type when compiling to JavaScript.\n- Add support for specifying size of integers in a bit string. Supports only exact binaries,\n  i.e. length is a multiple of 8.\n- Fixed compilation of rebar3 based dependencies on Windows.\n\n## v0.20.1 - 2022-02-24\n\n- The type checker has been improved to enable use of the record access syntax\n  (`record.field`) in anonymous functions passed into higher order functions\n  without additional annotations.\n\n## v0.20.0 - 2022-02-23\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.20-released/)\n\n- New projects are created with `gleam_stdlib` v0.20.\n\n## v0.20.0-rc1 - 2022-02-20\n\n- Type unification errors involving user annotated types now refer to the names\n  specified by the user instead of internal rigid-type ids.\n- The build tool now validates that listed licenses are valid SPDX expressions.\n- A WebAssembly version of the compile is now available for use in JavaScript\n  and other WebAssembly environments.\n- New projects include Hex badges and a link to Hexdocs.\n- Enhance type mismatch errors in the presence of try.\n- Enhance type mismatch error for an inconsistent try.\n- Enhance type mismatch error for pipe expressions to show the whole pipeline\n  and not only its first line.\n- Fixed a bug where sometimes type variable could be reused result in incorrect\n  non-deterministic type errors.\n- Built in support for the Mix build tool has been removed. The `mix_gleam`\n  plugin is to be used instead.\n- Introduce a limited form of exhaustiveness checking for pattern matching\n  of custom types, which only checks that all constructor tags are covered\n  at the top level of patterns.\n- The `ebin` directory is now copied to the build directory for rebar3 managed\n  dependencies if present before compilation.\n- The format used by the formatter has been improved.\n- Package names in `gleam.toml` are validated when the config is read.\n- The `priv` directory is linked into the build directory for Gleam projects\n  managed by the build tool.\n- Fixed a bug where type errors from pipes could show incorrect information.\n- Fixed a bug where types could not be imported if they had the same name as a\n  value in the prelude.\n\n## v0.19.0 - 2022-01-12\n\nDedicated to the memory of Muhammad Shaheer, a good and caring man.\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.19-released/)\n\n## v0.19.0-rc4 - 2022-01-10\n\n- New projects are created with `gleam_stdlib` v0.19 and `gleeunit` v0.6.\n- Fixed a bug where external functions could be specified with the wrong module\n  name in generated Erlang when imported from a nested module in another\n  package.\n- Fixed a bug where warnings wouldn't get printed.\n\n## v0.19.0-rc3 - 2022-01-07\n\n- Fixed a bug where precompiled packages would fail to compile due to Erlang\n  files being compiled twice concurrently.\n\n## v0.19.0-rc2 - 2022-01-06\n\n- Erlang modules are now compiled in a multi-core fashion.\n- New projects are created with `erlef/setup-beam` v1.9.0 instead of\n  `gleam-lang/setup-erlang` and `gleam-lang/setup-gleam`.\n- Fixed a bug where tail call optimisation could generate incorrect code when\n  the function has argument names that are JavaScript keywords.\n- Fixed a bug where the build would continue when dependency packages failed to\n  compile.\n- Fixed a bug where `include` directories would not be accessible by the Erlang\n  compiler during Gleam compilation.\n\n## v0.19.0-rc1 - 2022-01-03\n\n- The build tool now supports the JavaScript target. The target can be specified\n  in either `gleam.toml` or using the `--target` flag.\n- The `gleam check` command has been introduced for rapidly verifying the types\n  of Gleam code without performing codegen.\n- `true` and `false` can no longer be used as pattern matching variables, to\n  avoid accidental uses of incorrect syntax that is popular in other languages.\n  An error will hint about using Gleam's `True` and `False` values instead.\n- You can now remove build artifacts using the new `gleam clean` command.\n- The `compile-package` can now generate `package.app` files and compile source\n  modules to `.beam` bytecode files.\n- The flags that `compile-package` accepts have changed.\n- Published Hex packages now include precompiled Erlang files.\n- Erlang record headers are now written to the `include` directory within the\n  package build directory.\n- The format used by the formatter has been improved.\n- Fixed a bug where tail recursion could sometimes generated incorrect\n  JavaScript code.\n- Performance of code generators has been slightly improved.\n- Allow the record in a record expansion to be an expression that returns a\n  record.\n- Fixed a bug where external function module names would not be escaped\n  correctly if they contained special characters and were assigned to a\n  variable.\n- A helpful error message is shown if Erlang is not installed.\n\n## v0.18.2 - 2021-12-12\n\n- Erlang applications are now automatically started when the VM is started by\n  `gleam run` and `gleam test`.\n\n## v0.18.1 - 2021-12-12\n\n- Fixed a bug where pipe expressions in record updates and operator expressions\n  could generate incorrect Erlang code.\n- The `priv` directory is now copied to the output directory for rebar3 packages\n  prior to compilation. This is required for some packages to compile.\n- Fixed a bug where deps that fail to compile would be skipped when compilation\n  would next be attempted, resulting the project being in an invalid state.\n\n## v0.18.0 - 2021-12-06\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.18-released/)\n\n- New projects now include `gleeunit`.\n\n## v0.18.0-rc3 - 2021-12-05\n\n- URL format in gleam.toml is now validated.\n- The `gleam deps list` command has been added.\n- Fixed a bug where changing requirements in `gleam.toml` would not cause deps\n  to be re-resolved.\n- Fixed a bug where locked deps would cause incompatible package requirements to\n  be discarded.\n- Development dependencies are now included in the applications listed in the\n  generated OTP `.app` file.\n- `gleam.toml` now includes an `erlang.extra_applications` key to specify extra\n  OTP applications that need to be started.\n\n## v0.18.0-rc2 - 2021-11-26\n\n- Fixed a bug where OTP .app files would be generated with invalid syntax.\n- Removed extra whitespace from newly generated projects.\n\n## v0.18.0-rc1 - 2021-11-25\n\n- Gleam can now compile Gleam projects.\n- Gleam can now run tests with the `gleam eunit` command.\n- Gleam can now run programs with the `gleam run` command.\n- Gleam can now run an Erlang shell with the `gleam shell` command.\n- Gleam can now resolve package versions for a Gleam project's dependency tree.\n- Gleam can now download Hex packages.\n- Gleam can now build dependency packages that are managed using Gleam or\n  rebar3.\n- Gleam is now the default build tool for new projects.\n- The template names for `gleam new` have been changed.\n- Fixed a bug where the error message for a record update with an unknown field\n  would point to all the fields rather than the unknown one.\n- Improved styling for inline code in generated documentation.\n- New projects use v0.18 of the stdlib.\n\n## v0.17.0 - 2021-09-20\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.17-released/)\n\n- Functions now get special handling when being printed from JavaScript.\n\n## v0.17.0-rc2 - 2021-09-19\n\n- Errors thrown when no case clause or assignment pattern matches the subject\n  value now include more debugging information when targeting JavaScript.\n- New projects are generated using `gleam_stdlib` v0.17.1.\n\n## v0.17.0-rc1 - 2021-09-11\n\n- Redesigned the Gleam prelude to be a module of core classes when compiling to\n  JavaScript. This improves the resulting generated code and makes debugging and\n  interop easier.\n- Projects without rebar3 can be generated using the `gleam-lib` template.\n- JavaScript modules are imported using a camel case variable name to avoid name\n  collisions with variables.\n- Pipelines now use assignments in the generated code in order to preserve the\n  order of any side effects.\n- Fixed a bug where the compiler would crash rather than raise an error if a\n  project contained a single module and attempted to import another.\n- Special variable naming has been made more consistent in rendered Erlang and\n  JavaScript.\n- Conditional compilation can now be used to have different code within a module\n  when compiling to a specific target.\n- Fixed a bug where `todo` caused values not to be returned in JavaScript.\n- Fixed a bug where multiple discarded function arguments generated invalid\n  JavaScript.\n- Fixed a bug where using JavaScript reserved words as function argument names\n  caused generated invalid JavaScript.\n- Fixed a bug where a case expression of just a catch-all pattern generated\n  invalid JavaScript.\n- Fixed a bug where the formatter would incorrectly render extra newlines below\n  try expressions.\n- Fixed a bug where tail recursive functions with arguments with the same name\n  as JavaScript reserved words generated the wrong JavaScript.\n- Fixed a bug where list equality would be incorrectly reported in JavaScript.\n- Multiple subjects are now supported for case expressions in JavaScript.\n- Fixed a bug where matching using a Bool or Nil literal as the subject for a\n  case expression would produce invalid code when compiling to JavaScript.\n- Unsupported feature error messages now include file path and line numbers for\n  debugging.\n- Bit string literals with no segment options or just the `bit_string`, `utf8`\n  or `utf8_codepoint` options can be constructed when compiling to JavaScript.\n- The format of generated JavaScript has been improved.\n- Fixed a bug where rendered JavaScript incorrectly incremented variables when\n  reassigned in patterns.\n- Added `eval` and `arguments` to JavaScript reserved words.\n- Support for the deprecated `tuple(x, y, ...)` syntax has been removed in favor\n  of the more concise (`#(x, y, ...)`). Use `gleam format` with the previous\n  version of the compiler to auto-migrate.\n- New OTP projects are generated using `gleam_otp` v0.1.6.\n- Fixed a bug where the equality operators could return the incorrect value for\n  records when compiling to JavaScript.\n- Fixed a bug where `todo` could sometimes render invalid JavaScript when used\n  as an expression in the generated code.\n- An error is now emitted if the list spread syntax is used with no prepended\n  elements `[..xs]`.\n- Fixed a bug where type errors inside piped expressions would be incorrectly be\n  reported as being an incorrect usage of the pipe operator.\n- Gleam modules with no public exports no longer render private members in\n  Erlang.\n- Fixed a bug where discard variables used in assert assignments would generate\n  invalid Erlang code.\n- Fixed a bug where some expressions as case subjects would generate invalid\n  JavaScript code.\n- Fixed a bug where some assignments as the final expression in a function would\n  not return the correct value in JavaScript.\n- Gleam packages imported in JavaScript now have the path prefix\n  `gleam-packages`. This can be served from your web server or aliased in your\n  `package.json` for NodeJS projects.\n- Fixed a bug where the type checker would fail to generalise some type\n  variables, causing module metadata writing to fail.\n- Fixed a bug where tail call optimisation when compiling to JavaScript could\n  result in incorrect code.\n- Fixed a bug where variable names could be rendered incorrectly in closures.\n- An error is now emitted if alternative patterns fail to define all the\n  variables defined by the first pattern.\n- New projects are generated using `gleam_stdlib` v0.17.0.\n- New projects are generated using `gleam_otp` v0.2.0.\n\n## v0.16.1 - 2021-06-21\n\n- Values which are being imported more than once in an unqualified fashion now\n  cause an error to be reported.\n- Argument docs for custom type constructors are now rendered in the HTML\n  documentation.\n- Patterns can be used with `try` expressions when compiling to JavaScript.\n- Types and record constructors can now be aliased with an uppercase name when\n  imported. Aliasing them with a lowercase name is no longer permitted.\n- Fixed a bug where nested import paths could be rendered incorrectly in\n  JavaScript.\n\n## v0.16.0 - 2021-06-17\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.16-released/)\n\n## v0.16.0-rc4 - 2021-06-17\n\n- Fixed a bug where if a JavaScript global function was imported as an external\n  function with the same name the generated code would diverge.\n\n## v0.16.0-rc3 - 2021-06-17\n\n- New projects are generated using `gleam_stdlib` v0.16.0.\n\n## v0.16.0-rc2 - 2021-06-08\n\n- Gleam now supports alternative patterns in case expressions for the JavaScript target.\n- The `gleam` prelude module can now be imported when compiling to JavaScript.\n- Fixed a bug where the prelude module could not be imported when using the old\n  build compiler API.\n- Fixed a bug where if a JavaScript global function was imported as an external\n  function with the same name the generated code would diverge.\n- Type error messages coming from pipe usage have been improved.\n\n## v0.16.0-rc1 - 2021-06-04\n\n- Gleam can now compile to JavaScript! Specify the `--target javascript` flag to\n  `gleam compile-package` to use it today.\n- A compile time error is now raised when multiple module level constants with\n  the same name are defined.\n- Fixed a bug where declaring a type constructor using reserved erlang keyword\n  in its fields results in invalid erlang code being generated.\n- Fixed a bug where calling a function with discarded labelled arguments\n  incorrectly results in a compile error.\n- Fixed a bug where assert statements return the wrong value.\n- The `gleam new` command requires a root folder param, project name is\n  optional and if not provided the project name will be inferred from\n  the folder name.\n- Generated Erlang record header files now contain Erlang type information.\n- New OTP application projects depend on `gleam_otp` v0.1.5.\n- The output of the formatter has been improved.\n\n## v0.15.1 - 2021-05-07\n\n- Fixed a bug where blocks that contained try expressions could be formatted\n  incorrectly.\n\n## v0.15.0 - 2021-05-06\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.15-released/)\n\n## v0.15.0-rc1 - 2021-05-05\n\n- Syntax highlighting of Gleam code in generated HTML documentation has been\n  improved.\n- Fixed a bug where markdown tables in rendered HTML documentation would have\n  the incorrect background colour on every other row.\n- Tuples now have a new, concise syntax variant: `#(x, y, ...)`. Existing code\n  can be auto-migrated to the new syntax by running `gleam format`.\n- Fixed a bug where customt type constructors with Erlang keywords as names\n  would generate invalid Erlang code.\n- Gleam now supports `\\e` string escapes.\n- Values and types from the prelude can now be used in a qualified fashion by\n  importing the `gleam` module.\n- Empty lists can now be used in constants.\n- Compiler performance has been improved when working with lists.\n- Compiler performance has been improved when working with sequences of\n  expressions.\n- Assignments using `let` and `assert` are now expressions and no longer require\n  a following expression in their containing block. They are now themselves\n  expressions.\n- Fixed a bug where tuple indexing could incorrectly claim a tuple is not of\n  type tuple in some circumstances.\n- Glean `new` command now checks if target folder exists, if so it returns\n  an error.\n- A compile time error is now raised if a module is defined with the name `gleam`.\n- A compile time error is now raised if a module is defined with the a keyword\n  in the name.\n- New projects are generated using `gleam_stdlib` v0.15.0.\n- New projects are generated at v0.1.0.\n\n## v0.14.4 - 2021-03-27\n\n- The Gleam compiler has been updated to compile with the new Rust v1.51.0.\n- New project's `gleam.toml` has a comment that shows how to add a\n  `repository` field.\n- New projects no longer include a licence field in `src/$APP.app.src` by\n  default.\n\n## v0.14.3 - 2021-03-20\n\n- Added an error hint when joining string using the `+` or `+.` operator.\n- New projects are created with `setup-erlang` v1.1.2 and Erlang/OTP v23.2.\n- Fixed a bug where the compiler would be unable to locate an imported module\n  if a value from a nested module is used in a qualified fashion.\n\n## v0.14.2 - 2021-03-02\n\n- Project names can now contain numbers.\n\n## v0.14.1 - 2021-02-27\n\n- The error message for binary operators has been given more detail and\n  hints.\n- Fixed a bug where alternative patterns would incorrectly report unused\n  variables.\n- Fixed a bug where private types shadowed shadowed by values would\n  incorrectly report unused variables.\n\n## v0.14.0 - 2021-02-18\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.14-released/)\n\n## v0.14.0-rc2 - 2021-02-18\n\n- New projects are created with `gleam_stdlib` v0.14.0.\n\n## v0.14.0-rc1 - 2021-02-14\n\n- Gleam now generates Erlang typespecs.\n- New projects no longer include a licence file by default.\n- New projects can be created using the new `escript` template to generate a\n  command line tool style program.\n- A warning is emitted when a literal value is constructed but not used.\n- Automatically generate a link to repository in docs if available.\n- Code in HTML documentation is has highlighted syntax.\n- Gleam now only supports `\\r`, `\\n`, `\\t`, `\\\"`, and `\\\\` string escapes.\n- A set of OCI container images are built automatically for each release.\n- New compile time checks for invalid bit string literals and patterns have\n  been added.\n- The error messages for syntax errors in names have been improved.\n- Fixed a bug where the repo URL would render incorrectly in HTML docs.\n- Fixed a bug where piping a block can render invalid Erlang.\n- New compile time warnings on unused types, functions and variables.\n- The runtime error emitted by the `todo` keyword now carries additional\n  information.\n- The runtime error emitted by the `assert` keyword now carries additional\n  information.\n- Fixed a bug where bit string patterns would not correctly unify with the\n  subject being pattern matches on.\n- Documentation dark mode.\n- Fixed a bug where some app.src properties were incorrectly named.\n- `--warnings-as-errors` flag added to `gleam build` command.\n\n## v0.13.2 - 2021-01-14\n\n- `ring` dep upgraded to enable compilation on Apple M1 ARM processors.\n\n## v0.13.1 - 2021-01-13\n\n- Fix off-by-one error in message messages.\n\n## v0.13.0 - 2021-01-13\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.13-released/)\n\n- New Gleam projects use stdlib v0.13.0.\n\n## v0.13.0-rc2 - 2021-01-12\n\n- The `version` property in `gleam.toml` is now optional again.\n\n## v0.13.0-rc1 - 2021-01-09\n\n- Variable names now only have 1st letter capitalized when converted to erlang.\n- Records defined in other modules can now be used in module constants.\n- Documentation can link from functions, types & constants to their source\n  code definitions on popular project hosting sites.\n- Documentation hosted on HexDocs now has a version selector.\n- Fixed a bug where the `app` project template rendered invalid code.\n- Newly generated projects use stdlib v0.12.0.\n- Named subexpressions in patterns now render correct Erlang.\n- The anonymous function syntax now successfully parses with whitespace\n  between `fn` and `(`.\n- Fixed a bug where the formatter would incorrectly remove blocks around some\n  binary operators.\n- Constants can now be defined after they are used in functions\n- The parser has been rewritten from scratch, dramatically improving error\n  messages and compilation times.\n- `1-1` and `a-1` are now parsed as `1 - 1` and `a - 1`\n- Further information has been added to the error messages when a function\n  returns the wrong type.\n- Further information has been added to the error messages when case clauses\n  return different types.\n- Fixed a bug where imported record constructors without labels used as an\n  anonymous function generates incorrect Erlang.\n\n## v0.12.1 - 2020-11-15\n\n- The compiler can now discriminate between record access and module access\n  for shadowed names\n- The `new` command will no longer permit projects to be made with names that\n  clash with Erlang standard library modules.\n- The formatter now correctly treats lines of only whitespace as empty.\n- The styling of tables in rendered HTML documentation has been improved.\n- Rendered HTML documentation has regained its max-width styling.\n\n## v0.12.0 - 2020-10-31\n\n[Release Blog Post](https://gleam.run/news/gleam-v0.12-and-gleam-otp-v0.1-released/)\n\n## v0.12.0-rc4 - 2020-10-31\n\n- The rendered module documentation sidebar can now scroll independently to\n  the page.\n- Application projects now have the correct `mod` value in the generated\n  `.app.src`.\n- Records without fields can now be used in module constants.\n- New application projects are now created used Gleam's type safe OTP pulled\n  from Hex.\n\n## v0.12.0-rc3 - 2020-10-24\n\n## v0.12.0-rc2 - 2020-10-24\n\n## v0.12.0-rc1 - 2020-10-24\n\n- The utf8, utf16, and utf32 type specifiers are now only available in bit\n  string construction, matching must be done with the codepoint versions.\n- Functions may now be called before they are defined in a module. This\n  enabled mutually recursive functions!\n- Discarded variable names may now include numbers.\n- Fixed a bug where discarded variables might generate incorrect Erlang.\n- Added support tuple access in clause guards.\n- New projects are created with version 1.0.2 of the setup-gleam GitHub\n  action.\n- New application projects are now created used Gleam's type safe OTP.\n- Comments are now correctly handled on platforms that use \\r\\n line endings,\n  such as Windows.\n\n## v0.11.2 - 2020-09-01\n\n- Fixed a bug where an imported constructor would emit an unused constructor\n  warning when only used in pattern matching.\n\n## v0.11.1 - 2020-08-31\n\n- The formatter style has been improved to render function type arguments on\n  a single line when possible, even if the return type will not fit on a\n  single line.\n- The format for printed types in error messages has been improved.\n- Fixed a bug where the formatter would strip a constructor pattern spread\n  when no fields are given.\n- Fixed a bug where assigning the result of a block to a variable would\n  generate incorrect Erlang.\n- The formatter style has been improved for function calls that take a single\n  block as an argument.\n- Reserved words are no longer incorrectly permitted as project names.\n\n## v0.11.0 - 2020-08-28\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.11-released/)\n\n## v0.11.0-rc3 - 2020-08-27\n\n- Bit strings now support non-literal strings as segment values.\n- Fixed a bug where Erlang variables could be generated with incorrect names\n  when defining an anonymous function.\n\n## v0.11.0-rc2 - 2020-08-24\n\n- The formatter style has been improved to render some single argument calls\n  in a more compact style.\n\n## v0.11.0-rc1 - 2020-08-22\n\n- Field access now works before the custom type is defined.\n- The error message returned by the compiler when the user tries to use unknown\n  labelled arguments now handles multiple labels at once, and does not suggest\n  labels they have already supplied.\n- The formatter style has been improved to use a trailing comma on imports\n  broken over multiple lines.\n- The formatter style has been improved to wrap lists and bit strings over as\n  few lines as possible if the elements are Ints, Floats, or Strings.\n- The formatter style has been improved to preserve comments on labelled\n  call arguments.\n- The formatter style has been improved to preserve empty lines in assignments.\n- The performance of the formatter has been improved.\n- Records can be updated using the spread syntax. A warning is emitted if no\n  fields are updated when using this syntax.\n- Fixed a bug where type parameters can leak between different type\n  definitions in a module.\n- Markdown tables, footnotes, strikethroughs, and tasklists are now supported\n  in documentation.\n- Fixed a bug where generic types may be incorrectly unified.\n- Ints and floats can now be written with underscores for clarity.\n- The warning for a `todo` now includes the required type of the\n  not-yet-implemented expression.\n- Holes can be used in type annotations to specify part of a type, leaving the\n  rest for inference.\n- The incorrect arity error now prints any missing labelled arguments.\n- Fixed a bug where Erlang variables could be generated with incorrect names\n  when directly calling an anonymous function.\n- A warning is emitted when a type is imported or created but not used.\n- Fixed a bug where Erlang variables names could clash when rebinding\n  variables while similarly named variables ending in a number are in scope.\n- Fixed a bug in the pretty printer which prevented the formatter from\n  rendering sub-expressions in a single line when later code would not fit on\n  the same line.\n- The formatter style has been improved to render some single argument calls\n  in a more compact style.\n- Gleam now supports hex, octal, and binary literals.\n- Rebar3 hex packages now include `gleam.toml` and `gen`.\n- Newly generated projects use stdlib v0.11.0.\n\n## v0.10.1 - 2020-07-15\n\n- Fixed a bug where the compiler failed to return an error when type checking\n  a tuple with the wrong arity in a pattern.\n- The error message for a duplicate module member now shows the location of\n  both definitions.\n- Fix compiler bug where labelled arguments were being reordered incorrectly.\n\n## v0.10.0 - 2020-07-01\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.10-released/)\n\n- Newly generated projects use stdlib v0.10.1.\n- Fixed a bug where discards inside bit string patterns generated invalid\n  code.\n\n## v0.10.0-rc2 - 2020-06-30\n\n- Fixed a bug where variables names would be incorrectly generated when using\n  alternative patterns.\n\n## v0.10.0-rc1 - 2020-06-29\n\n- Single letter module names are now permitted.\n- Added support for bit string syntax.\n- Support for the deprecated list prepend syntax has been removed.\n- Added module level constants that are inlined at compile time.\n- Public module level constants generate documentation.\n- The formatter style has been improved to wrap and sort imports.\n- The formatter now permits comments at the end of module function bodies.\n- The formatter now skips files that match patterns defined in ignore files\n  such as .gitignore and .ignore.\n- Error message diagnostic code previews for type errors when using the the\n  pipe operator have been made more accurate.\n- Added support for list literals in clause guards.\n- Fixed bug when reassigning a variable inside a case clause with alternative\n  patterns.\n- Todos can now take an optional label.\n\n## v0.9.1 - 2020-06-12\n\n- Fixed a bug where binary operators may lose required `{ }`s when formatted.\n\n## v0.9.0 - 2020-06-01\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.9-released/)\n\n- Newly generated projects use stdlib v0.9.0.\n- Additional information is printed to the console when generating HTML\n  documentation from Gleam code.\n- Fixed a bug where blocks on either side of a binary operator would be\n  rendered without `{ }`.\n\n## v0.9.0-rc1 - 2020-05-26\n\n- The formatter style has been improved.\n- Numbers are now permitted in module names.\n- Emitted Erlang code correctly adds parentheses around binary subexpressions\n  to preserve precedence.\n- Record names and fields are now escaped in `.hrl` files if they conflict\n  with Erlang reserved words\n- Annotations are now supported on `let` and `assert` expressions\n- Formatter now accepts comments for the fields of a custom type's constructors\n- Added opaque custom types, which have constructors that cannot be accessed\n  from outside their own modules.\n- Additional (arbitrary) markdown documentation pages can now be added and\n  built with `docs build`.\n- Fix code generation when calling functions returned through either record\n  or tuple access\n- Add lookup for Gleam source code in Mix's `deps` directory.\n- Newly generated Gleam projects use the GitHub action\n  `gleam-lang/setup-erlang` v1.1.0.\n- Added support for custom type record literals in guards.\n- Type variables are now correctly preserved within nested scopes.\n\n## v0.8.1 - 2020-05-19\n\n- The formatter now correctly handles unicode comments.\n\n## v0.8.0 - 2020-05-07\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.8-released/)\n\n- The `docs build`, `docs publish`, and `docs remove` commands can be used to\n  compile HTML documentation locally, publish them to HexDocs, and remove them\n  from HexDocs respectively.\n- Type error reporting has been improved when using the pipe operator.\n- Newly generated projects use stdlib v0.8.0.\n- The compiler can now emit warnings. Currently there are warnings for using\n  the old '|' syntax in lists and for todos.\n- Will give a clearer error when a function given as an argument to another\n  function doesn't match the type of the parameter.\n- Fixed bug where imported type constructors had the incorrect arity.\n- Fixed bug where a doing an unqualified import of a type constructor and\n  giving it an alias would use the wrong name if it contained any values.\n- Fixed a bug trying to access an imported constructor which contained values.\n- Fixed a compiler crash that occurred when trying to unify a tuple with something\n  other than another tuple or a variable.\n- Added support for tuple literals in guards.\n\n## v0.8.0-rc1 - 2020-04-28\n\n- Strings are now encoded as utf8 binaries in the generated Erlang.\n- HTML documentation can now be generated from Gleam code by running `gleam build --doc`.\n- Gleam code can be formatted using the `gleam format` command.\n- The pipe operator `|>` will now attempt to insert the left hand side as the\n  first argument to the right hand side if the right hand side is a call,\n  removing the need for function capture boilerplate.\n- A `record.label` syntax can now be used to access the fields of a custom\n  type that have a single record variant.\n- Anonymous functions can now have return type annotations.\n- There is a `todo` keyword for type checking functions that have not yet been\n  implemented.\n- Tuples can be indexed into using the `var.1` syntax.\n- `>`, `>=`, `<`, and `<=` operators are now supported in case clause guards\n  and can be used to check the ordering of integers.\n- `>.`, `>=.`, `<.`, and `<=.` operators are now supported in case clause\n  guards and can be used to check the ordering of floats.\n- The list prepend syntax is now `[x, ..y]`. The old `[x | y]` syntax is\n  deprecated but will continue to work for now. The formatter will rewrite the\n  old syntax to the new.\n- Add new assert syntax for binding variables `assert Ok(x) = result`. In the\n  future this will allow you to use a pattern that does not match all values.\n- Added support for int and float literals in guards.\n- Color codes are now only emitted in error output for interactive terminal\n  sessions.\n- Added a new `..` syntax for discarding the remaining fields of a record.\n- Using the same variable name multiple times in the same pattern will now\n  raise an error.\n- Discard can now be omitted in list tails in patterns, ie `[x, ..]` is the\n  same as `[x, .._]`. The former is the preferred version and is emitted by the\n  formatter.\n\n## v0.7.1 - 2020-03-03\n\n- Projects generated with `gleam new` use `stdlib` version 0.7.0.\n\n## v0.7.0 - 2020-03-01\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.7-released/)\n\n## v0.7.0-rc1 - 2020-02-28\n\n- Type aliases can be defined to give concise names to frequently used types.\n- Case expression clauses may have guards which can be used to require\n  equality between specified variables in order for the clause to match.\n- Case expression clauses may have alternative patterns, enabling one clause\n  to match for multiple different possible patterns.\n- Types may now be used before they are defined within their defining module.\n- Fixed a bug where import paths would not be correctly resolved on Windows.\n- Added job to create precompiled binary for 64-bit Windows when releasing.\n- `gleam new` now creates a project that uses `actions/checkout@v2.0.0` in its\n  GitHub actions workflow.\n- Labelled argument in functions may now be discarded by prefixing the name\n  with an underscore, like unlabelled arguments.\n- Sub-patterns can have names assigned to them within a pattern using the `as`\n  keyword.\n- The format of compiler error messages printed to the console has been\n  improved by upgrading to a newer version of the codespan-reporting library.\n- Type variables in the given and expected types will now be printed with the\n  same name in type error messages if they are equivalent.\n- A friendly error message is rendered when a case expression clause has the\n  incorrect number of patterns for the subjects.\n- A friendly error message is rendered when a .gleam file cannot be read.\n- A friendly error message is rendered when the `gleam new` command fails to\n  write the new project to the file system.\n- A friendly error message is rendered when there is a cycle formed by module\n  imports.\n- Top level types are now printed in error messages for type parameter mismatches.\n- The `gen` directory is now deleted before each compilation.\n- `gleam new` now includes installation instructions for Hex packages in the\n  generated README.\n- `gleam new` now accepts a `--description` flag for including a description of\n  the project in the README and `.app.src` file.\n- Fixed a bug where variable names would be incorrectly generated in some\n  situations when variable names are reused during and after a case\n  expression.\n- Performance of the Erlang code generator has been improved by removing some\n  vector allocations.\n- An error is emitted when multiple types with the same name are defined in or\n  imported into a module.\n\n## v0.6.0 - 2019-12-25 🎄\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.6-released/)\n\n- Function capture syntax now supports labelled arguments.\n\n## v0.6.0-rc1 - 2019-12-23\n\n- Syntax for defining structs and enums have been unified into a singular\n  custom type definition statement. Instances of these custom types are called\n  records.\n- Anonymous structs have been renamed tuples.\n- Values and types can be given a new name when imported in the unqualified\n  fashion using the `import mod.{value as name}` syntax.\n- An error will be emitted if multiple values constructors are defined with\n  the same name in a module.\n\n## v0.5.1 - 2019-12-23\n\n- Fixed a bug where invalid Erlang would be generated when using a local\n  private function as a value.\n\n## v0.5.0 - 2019-12-16\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.5-released/)\n\n- Enum constructor arguments can now be labelled, allowing arguments to be\n  given by name at the call site.\n- An Erlang header file with a record definition is generated for each Gleam\n  struct defined.\n- `gleam new` creates a project at v1.0.0.\n- Function calls are now properly escaped when the function name conflicts\n  with an Erlang keyword.\n- References to unqualified imported functions now generate correct Erlang\n  code.\n- Fixed a bug where variable rebinding would generate incorrect code in some\n  case expressions.\n- Fixed a bug where variable rebinding of function arguments would generate\n  incorrect code.\n\n## v0.5.0-rc1 - 2019-11-26\n\n- Function arguments can be labelled, allowing arguments to be given by name\n  at the call site.\n- `case` expressions now accept multiple subjects, enabling pattern matching\n  on multiple values simultaneously.\n- Values and types can be imported from modules and references in an\n  unqualified fashion.\n- Named structs now have their name as the first element in the generated\n  Erlang code. This enabled easier use from Erlang by defining records for\n  them, as well as slightly clearer printf debugging.\n- Anonymous structs have been introduced, serving as a quick and generic\n  alternative to declared structs and as a format for interop with Erlang\n  tuples.\n- `gleam new` now accepts a `--template` flag to generate different styles of\n  project. An OTP application template has been added alongside the existing\n  OTP library template.\n- `gleam new` now creates configuration for GitHub Actions, making Gleam\n  projects ready for continuous integration out of the box.\n- The syntax for defining enums, case expressions, and blocks has been changed\n  to a syntax closer to that found in the C family of languages.\n- The source code preview for functions that return a type incompatible with\n  the functions annotations has been improved to be more precise.\n- A helpful error message is rendered if an enum field contains a generic type\n  that has not been declared.\n- A bug has been fixed in which type mismatch errors originating from pattern\n  matching would sometimes display the incorrect expected type.\n\n## v0.4.2 - 2019-10-22\n\n- Fixed a crash when an incorrect number of labelled struct arguments are\n  given.\n- Fixed a struct labelled argument being incorrect reported as already given.\n\n## v0.4.1 - 2019-09-29\n\n- Struct types with parameterised fields are now registered with the correct\n  number of type parameters.\n\n## v0.4.0 - 2019-09-19\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.4-released/)\n\n- The struct data type has be introduced. Structs are pre-declared user\n  defined data types with named fields and constant access time.\n- The map and tuple data types has been removed, replaced by the struct data\n  type.\n- The generated code no longer contains export statements if no functions are\n  exported from a module.\n- Comparison operators have been specialised to operate only on Ints.\n- The `>.` `>=.` `<.` and `<=.` comparison operators have been added for\n  comparing Floats.\n- It is now an error to export an enum which has a constructor that takes a\n  private type as an argument.\n- The error messages for defining multiple modules with the same name and for\n  importing test modules into application code have been improved.\n- Numbers are now permitted in type names and constructors.\n- The `Nil` constructor will no longer erroneously be of type `Int`.\n\n## v0.3.0 - 2019-08-08\n\n[Release Blog Post](https://lpil.uk/blog/gleam-v0.3-released/)\n\n- New project structure can be generated with the `gleam new` command.\n- Functions can be annotated with their argument and return types. This may be\n  used to restrict the function to a less general type than inferred by the\n  compiler, or purely for documentation purposes.\n- External function names and their target functions are now escaped in the\n  generated code if they collide with Erlang keywords such as `catch` or `or`.\n- Type error arising from the arguments of function calls have more accurate\n  error diagnostics.\n- Precompiled Gleam binaries are now available on the GitHub release page.\n- Precompiled Docker images containing the Gleam binary are now available on\n  DockerHub.\n- The formatting of the Erlang code rendered by the compiler has been altered\n  to improve legibility.\n- A helpful error message is now rendered if the shorthand anonymous function\n  syntax is used with too many underscores.\n- A helpful error message is now rendered when attempting to import an unknown\n  module.\n\n## v0.2.0 - 2019-06-25\n\n- Modules can now live within namespaces such as `my_app/user/profile`.\n- The name of the variable created can be specified when importing a module\n  using the `import my_mod as name` syntax.\n- Function names and atoms are now escaped in the generated code if they\n  collide with Erlang keywords such as `catch` or `or`.\n- There is a shorthand syntax for prepending multiple elements to a list.\n  `[1, 2, 3 | my_list]`\n\n## v0.1.2 - 2019-05-12\n\n- Types containing more than 26 type variables will no longer render with\n  invalid type variable names.\n- Types in error messages no longer have extra indentation that increases as\n  the type gets larger.\n- There is a new type `Nil` which is occupied by a single value (`Nil`). This\n  type is used to represent the absence of a value and is commonly used with\n  `Result` to model a value that is either present (`Ok(value)`) or absent\n  (`Error(Nil)`).\n- Zero arity enum constructors now generate the correct Erlang when used in\n  modules other than the one they are defined in.\n\n## v0.1.1 - 2019-04-28\n\n- Error messages now display the path of the file containing the problem.\n- Maps and modules with erroneous extra fields now have a custom error\n  message.\n- Rows with tails that are unbound type variables are now correctly unified in\n  the type system. This fixes a bug in which maps and modules may sometimes\n  fail to type check when there is no error.\n\n## v0.1.0 - 2019-04-15\n\n[Release Blog Post](https://lpil.uk/blog/hello-gleam/)\n\n- Initial release!\n"
  },
  {
    "path": "changelog/v1.10.md",
    "content": "# Changelog\n\n## v1.10.0 - 2025-04-14\n\n### Bug fixes\n\n- Fixed a bug where the code action to unqualify types and values would add an\n  unqualified import even if it was already imported.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where numbers starting with `0x_`, `0o_` and `0b_` would cause\n  a syntax error when compiling to JavaScript.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## v1.10.0-rc1 - 2025-04-05\n\n### Compiler\n\n- On the JavaScript target, bit arrays can now use the `unit` option to control\n  the units of the `size` option.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler can now tell if string branches are unreachable. For example, the\n  following code:\n\n  ```gleam\n  case a_string {\n    \"Hello, \" <> name -> name\n    \"Hello, Jak\" -> \"Jak\"\n    _ -> \"Stranger\"\n  }\n  ```\n\n  Will raise the following warning:\n\n  ```\n  warning: Unreachable case clause\n    ┌─ /src/greet.gleam:7:5\n    │\n  7 │     \"Hello, Jak\" -> \"Jak\"\n    │     ^^^^^^^^^^^^^^^^^^^^^\n\n  This case clause cannot be reached as a previous clause matches the same\n  values.\n\n  Hint: It can be safely removed.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- On the JavaScript target, blocks and various other expressions no longer\n  compile to immediately invoked function expressions.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- On the JavaScript target, bit arrays can now use 16-bit floats in expressions\n  and patterns.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Improved the error message for unknown and missing target names in the\n  `@target` attribute.\n  ([Alexander Keleschovsky](https://github.com/AlecGhost))\n\n- The compiler now uses a call graph for detecting unused types and values.\n  This means that among other things, it can now detect unused recursive\n  functions. For example:\n\n  ```gleam\n  // warning: unused\n  fn some_recursive_function() {\n    some_recursive_function()\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler now emits a warning when using `let assert` to assert a value\n  whose variant has already been inferred. For example:\n\n  ```gleam\n  // warning: This will always crash\n  let assert Ok(_) = Error(\"Some error\")\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- It is now possible to omit the `:float` option for literal floats used in a\n  `BitArray` segment.\n\n  ```gleam\n  <<1.11>>\n  ```\n\n  Is the same as:\n\n  ```gleam\n  <<1.11:float>>\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Compilation of binary operators is now fault tolerant and won't stop at the\n  first type error.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now provides a better error message when using the wrong operator\n  to try and join two strings together. For example:\n\n  ```txt\n  error: Type mismatch\n    ┌─ /src/wibble.gleam:2:13\n    │\n  2 │   \"Hello, \" + \"Lucy\"\n    │             ^ Use <> instead\n\n  The + operator can only be used on Ints.\n  To join two strings together you can use the <> operator.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now provides a better error message when using an Int operator on\n  Float values, suggesting the correct replacement. For example:\n\n  ```txt\n  error: Type mismatch\n    ┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:2:7\n    │\n  2 │   1.0 + 2.0\n    │       ^ Use +. instead\n\n  The + operator can only be used on Ints.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now provides a better error message when using a Float operator\n  on Int values, suggesting the correct replacement. For example:\n\n  ```txt\n  error: Type mismatch\n    ┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:2:5\n    │\n  2 │   1 >. 2\n    │     ^^ Use > instead\n\n  The >. operator can only be used on Floats.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler no longer shows errors for a function's labels if the called\n  function itself doesn't exist.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Build tool\n\n- Include a type annotation for the `main` function generated by `gleam new`.\n  ([Drew Olson](https://github.com/drewolson))\n\n- Two entry point scripts are now always generated by `gleam export erlang-shipment`:\n\n  - `entrypoint.sh` for POSIX Shell\n  - `entrypoint.ps1` for PowerShell\n\n  ([Greg Burri](https://github.com/ummon))\n\n- The `gleam export` command now takes a `package-information` option to\n  export the project's `gleam.toml` as a JSON file.\n  ([Rodrigo Álvarez](https://github.com/Papipo))\n\n- Improved the error message when failing to encrypt or decrypt a local\n  Hex API key.\n  ([Samuel Cristobal](https://github.com/scristobal))\n\n- The `HEXPM_USER` and `HEXPM_PASS` environment variables when running\n  `gleam publish` have been deprecated in favour of `HEXPM_API_KEY`.\n  ([Samuel Cristobal](https://github.com/scristobal))\n\n- The \"functions\" and \"constants\" sections of generated HTML documentation have\n  been merged into one \"values\" section.\n  ([Sam Zanca](https://github.com/metruzanca))\n\n### Language server\n\n- The language server now allows renaming of functions, constants,\n  custom type variants and custom types across modules. For example:\n\n  ```gleam\n  // wibble.gleam\n  pub fn wibble() {\n    wibble()\n  //^ Trigger rename\n  }\n  // wobble.gleam\n  import wibble\n\n  pub fn main() {\n    wibble.wibble()\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  // wibble.gleam\n  pub fn wobble() {\n    wobble()\n  }\n  // wobble.gleam\n  import wibble\n\n  pub fn main() {\n    wibble.wobble()\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server can now offer a code action to replace a `..` in a pattern\n  with all the fields that are being ignored. For example triggering the code\n  action on this spread:\n\n  ```gleam\n  pub type Pokemon {\n    Pokemon(id: Int, name: String, moves: List(String))\n  }\n\n  pub fn main() {\n    let Pokemon(..) = todo\n    //          ^ If you put your cursor here\n  }\n  ```\n\n  Would generate the following code:\n\n  ```gleam\n  pub type Pokemon {\n    Pokemon(id: Int, name: String, moves: List(String))\n  }\n\n  pub fn main() {\n    let Pokemon(id:, name:, moves:) = todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The function generated by the \"Generate JSON encoder\" code action has been\n  slightly modified so that it will now fail to compile if the type has new\n  fields added, ensuring the programmer remembers to re-run the code action.\n  For example, for this type:\n\n  ```gleam\n  type Person {\n    Person(name: String, age: Int)\n  }\n  ```\n\n  The following code used to be generated:\n\n  ```gleam\n  fn encode_person(person: Person) -> json.Json {\n    json.object([\n      #(\"name\", json.string(person.name)),\n      #(\"age\", json.int(person.age)),\n    ])\n  }\n  ```\n\n  But now, this code is generated:\n\n  ```gleam\n  fn encode_person(person: Person) -> json.Json {\n    let Person(name:, age:) = person\n    json.object([\n      #(\"name\", json.string(name)),\n      #(\"age\", json.int(age)),\n    ])\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now supports finding references to values and types,\n  both within a module and across multiple modules.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now offers a code action to remove all `echo`s in a\n  module. For example:\n\n  ```gleam\n  pub fn main() {\n    [1, 2, 3]\n    |> echo\n    // ^^^^ If you put your cursor over here\n    |> list.filter(int.is_even)\n    |> echo\n  }\n  ```\n\n  Triggering the code action would remove all the `echo` pipeline steps:\n\n  ```gleam\n  pub fn main() {\n    [1, 2, 3]\n    |> list.filter(int.is_even)\n  }\n  ```\n\n  This also works with all the `echo`s used before an expression:\n\n  ```gleam\n  pub fn main() {\n    echo 1 + 2\n  //^^^^^^^^^^ If hovering anywhere over here\n  }\n  ```\n\n  Triggering the code action would remove the `echo`:\n\n  ```gleam\n  pub fn main() {\n    1 + 2\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers a code action to replace a Float operator used\n  on Int values with the correct operator. For example:\n\n  ```gleam\n  pub fn main() {\n    11 +. 1\n  //^^^^^^^ When hovering anywhere over here\n  }\n  ```\n\n  Triggering the code action would fix the compilation error by using the\n  correct Int operator:\n\n  ```gleam\n  pub fn main() {\n    11 + 1\n  }\n  ```\n\n  This also works the other way around:\n\n  ```gleam\n  pub fn main() {\n    1.1 + 10.0\n  //^^^^^^^^^^ If hovering anywhere over here\n  }\n  ```\n\n  Triggering the code action would replace the wrong operator with the correct\n  equivalent Float operator:\n\n  ```gleam\n  pub fn main() {\n    1.1 +. 10.0\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- If there's a compilation error because two strings are being joined with the\n  wrong `+` operator (instead of using `<>`), the language server now offers a\n  code action to fix the error automatically. For example:\n\n  ```gleam\n  pub fn main() {\n    \"Hello, \" + \"Jak\"\n  //^^^^^^^^^^^^^^^^^ When hovering anywhere over here\n  }\n  ```\n\n  Triggering the code action would fix the compilation error by using the\n  correct `<>` operator instead of `+`:\n\n  ```gleam\n  pub fn main() {\n    \"Hello, \" <> \"Jak\"\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers the option to lift expressions into consts.\n  For example, in two uses of the code action:\n\n  ```gleam\n  pub fn main() {\n    [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n    |> key_filter(\"a\")\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  const values = [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n\n  const string = \"a\"\n\n  pub fn main() {\n    values\n    |> key_filter(string)\n  }\n  ```\n\n  ([Matias Carlander](https://github.com/matiascr))\n\n- The language server will now only offer the code action to generate a JSON\n  encoder if the `gleam_json` package is installed as a dependency.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server will offer to wrap assignment or case clause values in\n  blocks. Useful when adding more expressions to an existing case clause or\n  variable assignment.\n\n  ```gleam\n  pub fn f(pokemon_type: PokemonType) {\n    case pokemon_type {\n      Water -> soak()\n      //       ^^^^^^ selecting the right-hand side of the `->` in a clause\n      Fire -> burn()\n    }\n  }\n  ```\n\n  Becomes\n\n  ```gleam\n  pub fn f(pokemon_type: PokemonType) {\n    case pokemon_type {\n      Water -> {\n        soak()\n      }\n      Fire -> burn()\n    }\n  }\n  ```\n\n  ([Matias Carlander](https://github.com/matiascr))\n\n- The \"Generate function\" code action now uses labels or variable names to improve\n  the names of generated arguments. For example:\n\n  ```gleam\n  pub fn main() {\n    let language = English\n    greet(language, name: \"Louis\")\n  }\n  ```\n\n  Will generate the following function:\n\n  ```gleam\n  pub fn greet(language: String, name name: String) -> a {\n    todo\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The \"Rewrite from `use`\" code action now only triggers if the cursor is on the\n  first line of the `use` expression to rewrite.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Formatter\n\n### Container images\n\n- Container images now contain Software Bill of Materials (SBoM) and SLSA\n  Provenance information.\n  ([Jonatan Männchen](https://github.com/maennchen))\n\n### Bug fixes\n\n- Fixed a bug where tuples with atoms in the first position could be\n  incorrectly formatted by `echo`.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where unlabelled arguments would be allowed after labelled\n  arguments in variant constructor definitions.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where using the \"Convert to pipe\" code action on a function whose\n  first argument is itself a pipe would result in invalid code.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where using the \"Convert to pipe\" code action on a function or\n  record capture produces invalid code.\n  ([Matias Carlander](https://github.com/matiascr))\n\n- Fixed a bug where a temporarily moved or removed file does not get recompiled,\n  even though its dependencies changed in the meanwhile.\n  ([Sakari Bergen](http://github.com/sbergen))\n\n- Fixed a bug where the \"Inline variable\" code action would not work properly\n  if used inside a record update.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where variant inference wouldn't work on `let assert` assignments.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the build tool could fail to lock the build directory but\n  not report an error.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the language server would be too eager to recompile modules\n  when it could use the cache from previous compilations.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where `let assert` would not assert that the given value matched\n  the pattern if it was the only expression inside a block.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the code generated for `echo` on JavaScript could have name\n  collisions if there are functions called `console` or `process`, or custom type\n  variants called `Object` or `Deno` defined in the module.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the language server would stop working if the build\n  directory was deleted e.g. as a result of `gleam clean`.\n  ([Sakari Bergen](https://github.com/sbergen))\n\n- Fixed a bug where the \"Rewrite to pipe\" code action could generate invalid\n  code when the piped argument was a binary operation.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where prelude types and values would be suggested in autocomplete\n  when part of a module select.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the check for multiple top-level modules when publishing\n  would incorrectly print a warning.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## v1.9.1 - 2025-03-10\n\n### Formatter\n\n- Improved the formatting of pipelines printed with `echo`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- Fixed a bug where `echo` used before a pipeline would generate invalid code\n  for the Erlang target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n"
  },
  {
    "path": "changelog/v1.11.md",
    "content": "# Changelog\n\n## v1.11.0 - 2025-06-02\n\n### Bug fixes\n\n- Fixed a bug where using a pipe operator on the right-hand side of an `assert`\n  statement would generate invalid code on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the build tool would try to run a module whose main\n  function is private.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would sometimes warn that an assertion was\n  unnecessary because it only asserted literal values, when that was not the case.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where using the \"generate function\" code action on a function\n  capture would generate an argument named `_capture`, using the internal\n  variable names of the compiler.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the language server would provide completions inside a\n  constant string.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a grammatical error in the bit array truncation warning message.\n  ([Louis Pilfold](https://github.com/lpil))\n\n## v1.11.0-rc2 - 2025-05-29\n\n### Compiler\n\n- The format of the `assert` and `let assert` location information has been\n  improved, and the file path of the source module has been added.\n  ([Louis Pilfold](https://github.com/lpil))\n\n### Language server\n\n- When using the \"remove `echo`\" code action, the language server will also\n  remove any literal expression being printed by `echo` statements. For example\n\n  ```gleam\n  pub fn main() {\n    echo \"Before\"\n    do_complex_stuff()\n    echo \"After\"\n    do_something_else()\n  }\n  ```\n\n  Will become:\n\n  ```gleam\n  pub fn main() {\n    do_complex_stuff()\n    do_something_else()\n  }\n  ```\n\n  Making it easier to get rid of debug printing messages once they're no longer\n  needed.\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- Fixed a bug where type constructors with many fields would not be formatted\n  properly in the generated documentation.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where fields name `x0` in records could cause invalid code to be\n  generated on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where exceptions on JavaScript could be sometimes missing the\n  function name metadata.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the missing patterns shown for an inexhaustive `case`\n  expression would include constructors of opaque types which were not available\n  in the current module, leading to invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the language server would offer completions for local\n  variables where the variables were not in scope, leading to invalid code being\n  produced if the completion was followed.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would crash when compiling `let assert`\n  statements which contained a bit array pattern inside a tuple pattern on the\n  JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where a zero-length segment of a bit array would never match\n  in a case expression on the JavaScript target.\n  ([Sakari Bergen](https://github.com/sbergen))\n\n## v1.11.0-rc1 - 2025-05-15\n\n### Compiler\n\n- The compiler can now tell if some branches with bit array patterns are\n  unreachable. For example, the following code:\n\n  ```gleam\n  case payload {\n    <<first_byte, _:bits>> -> first_byte\n    <<1, _:bits>> -> 1\n    _ -> 0\n  }\n  ```\n\n  Will raise the following warning:\n\n  ```\n  warning: Unreachable case clause\n    ┌─ /src/bit_array.gleam:4:5\n    │\n  4 │     <<1, _:bits>> -> 1\n    │     ^^^^^^^^^^^^^^^^^^\n  This case clause cannot be reached as a previous clause matches the same\n  values.\n  Hint: It can be safely removed.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The code generated for pattern matching on the JavaScript target has been\n  improved to be more efficient and perform as little checks as possible.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now raises a warning when it can tell that an int segment\n  with a literal value is going to be truncated. For example, if you wrote this:\n\n  ```gleam\n  <<258>>\n  ```\n\n  The compiler will now warn you:\n\n  ```txt\n  warning: Truncated bit array segment\n    ┌─ /src/main.gleam:4:5\n    │\n  4 │   <<258>>\n    │     ^^^ You can safely replace this with 2\n\n  This segment is 1 byte long, but 258 doesn't fit in that many bytes. It\n  would be truncated by taking its first byte, resulting in the value 2.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler will now include labels in the error message when a `case`\n  expression is inexhaustive. For example, this code:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n\n  pub fn classify(person: Person) {\n    case person {\n      Person(name: \"John\", age: 27) -> todo\n      Person(name: _, age: 42) -> todo\n    }\n  }\n  ```\n\n  Will produces this error:\n\n  ```\n  error: Inexhaustive patterns\n    ┌─ /src/main.gleam:6:3\n    │\n  6 │ ╭   case person {\n  7 │ │     Person(name: \"John\", age: 27) -> todo\n  8 │ │     Person(name: _, age: 42) -> todo\n  9 │ │   }\n    │ ╰───^\n\n  This case expression does not have a pattern for all possible values. If it\n  is run on one of the values without a pattern then it will crash.\n\n  The missing patterns are:\n\n      Person(name:, age:)\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The analysis of lists, tuples, negation operators, `panic`, `echo` and `todo`\n  is now fault tolerant, meaning that the compiler will not stop reporting\n  errors as soon as it finds one.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The error message for types used with the wrong number of arguments has been\n  improved. For example, this piece of code:\n\n  ```gleam\n  type Wibble(a)\n\n  type Wobble {\n    Wobble(Wibble)\n  }\n  ```\n\n  Produces the following error:\n\n  ```txt\n    error: Incorrect arity\n    ┌─ /src/one/two.gleam:5:10\n    │\n  5 │   Wobble(Wibble)\n    │          ^^^^^^ Expected 1 type argument, got 0\n\n  `Wibble` requires 1 type argument but none where provided.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- You can now use the `assert` keyword by itself to test a boolean expression.\n  If the expression evaluates to `False` at runtime, the `assert` statement\n  will cause the program to panic, with information about the expression that\n  was asserted.\n\n  For example:\n\n  ```gleam\n  pub fn ok_error_test() {\n    assert result.is_ok(Ok(10))\n    assert result.is_error(Error(\"Some error\"))\n    assert Ok(1) != Error(1)\n    assert result.is_error(Ok(42)) // panic: Assertion failed\n  }\n  ```\n\n  A custom panic message can also be provided in order to add extra information:\n\n  ```gleam\n  pub fn identity_test() {\n    assert function.identity(True) as \"Identity of True should never be False\"\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler will now emit a warning when the return value of a call to a\n  function without side effects is unused. For example the following code:\n\n  ```gleam\n  pub fn main() {\n    add(1, 2)\n    add(3, 4)\n  }\n  ```\n\n  Will produce the following warning:\n\n  ```\n  warning: Unused value\n    ┌─ /src/main.gleam:4:3\n    │\n  4 │   add(1, 2)\n    │   ^^^^^^^^^ This value is never used\n\n  This expression computes a value without any side effects, but then the\n  value isn't used at all. You might want to assign it to a variable, or\n  delete the expression entirely if it's not needed.\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler will now generate more efficient code for `let assert` on the\n  Erlang target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler will now reject bit array segment patterns whose constant size is\n  zero or negative. Previously a zero or negative sized segment would crash the\n  compiler.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler will not generate needless code for unused pattern variables.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Function parameters are now fault tolerant, meaning that type-checking can\n  continue to occur if a function references invalid type in its signature.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler is now fault tolerant when analysing patterns for custom types,\n  meaning it won't stop at the first error it encounters (for example if a\n  constructor is wrong).\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- On the JavaScript target, bit arrays now support UTf-16 and UTF-32 string\n  segments.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When an import with unqualified types and values is unused the compiler will\n  now raise a single warning for the entire import rather than warning for each\n  individual item.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Build tool\n\n- The build tool now supports placing modules in a directory called `dev`,\n  which like `test`, is only for development code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- There is now a new CLI command, `gleam dev`, which runs the `$PACKAGE_dev`\n  module, for running development entrypoints.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Updated the Erlang shipment POSIX entrypoint script to add an exec statement\n  so the Erlang process replaces the shell's process and can receive signals\n  when deployed.\n  ([Christopher De Vries](https://github.com/devries))\n\n- The build tool now provides additional information when printing warnings for\n  deprecated environment variables.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When generating documentation, the build tool now prints type variable using\n  the same names as were used in the code for function signatures. For example,\n  this code:\n\n  ```gleam\n  pub fn from_list(entries: List(#(key, value))) -> Dict(key, value) {\n    ...\n  }\n  ```\n\n  Previously would have been printed as:\n\n  ```gleam\n  pub fn from_list(entries: List(#(a, b))) -> Dict(a, b)\n  ```\n\n  But now is rendered as the following:\n\n  ```gleam\n  pub fn from_list(entries: List(#(key, value))) -> Dict(key, value)\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When generating documentation, types from other modules are now rendered with\n  their module qualifiers. Hovering over them shows the module name.\n  For example, this code:\n\n  ```gleam\n  import gleam/dynamic/decode\n\n  pub fn something_decoder() -> decode.Decoder(Something) {\n    ...\n  }\n  ```\n\n  Will now generate the following documentation:\n\n  ```gleam\n  pub fn something_decoder() -> decode.Decoder(Something)\n  ```\n\n  And hovering over the `decode.Decoder` text will show the following:\n\n  ```txt\n  gleam/dynamic/decode.{type Decoder}\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When generating documentation, types in rendered documentation code will now\n  link to their corresponding documentation pages.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- `gleam add` will now emit an error if you try to add a package as a dependency\n  of itself.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The build tool will now emit an error when compiling a package if the package\n  has a Gleam and Erlang file which would collide.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Language server\n\n- The code action to add missing labels to functions now also works in patterns:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int, job: String)\n  }\n\n  pub fn age(person: Person) {\n    let Person(age:) = person\n    age\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int, job: String)\n  }\n\n  pub fn age(person: Person) {\n    let Person(age:, name:, job:) = person\n    age\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The JSON encoding function that the language server code action generates is\n  now named `$TYPENAME_to_json` instead of `encode_$TYPENAME`. This is to remove\n  ambiguity with functions that encode to other formats, and to make the\n  function easier to discover by searching.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The code action to add missing patterns to a `case` expression now includes\n  labels in the generated patterns. For example:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n\n  pub fn classify(person: Person) {\n    case person {\n      Person(name: \"John\", age: 27) -> todo\n      Person(name: _, age: 42) -> todo\n    }\n  }\n  ```\n\n  Will now become:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n\n  pub fn classify(person: Person) {\n    case person {\n      Person(name: \"John\", age: 27) -> todo\n      Person(name: _, age: 42) -> todo\n      Person(name:, age:) -> todo\n    }\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now provides hover, autocomplete and goto definition\n  for constant definitions.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The \"generate function\" code action can now choose better names based on the\n  labels and variables used. For example if I write the following code:\n\n  ```gleam\n  pub fn main() -> List(Int) {\n    let list = [1, 2, 3]\n    let number = 1\n    remove(each: number, in: list)\n  //^^^^ This function doesn't exist yet!\n  }\n  ```\n\n  And ask the language server to generate the missing function, the generated\n  code will now look like this:\n\n  ```gleam\n  fn remove(each number: Int, in list: List(Int)) -> List(Int) {\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now provides autocomplete suggestions for labels after\n  part of the label has already been typed. For example, in this code:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, number: Int)\n  }\n\n  pub fn main() {\n    Person(n|)\n  }\n  ```\n\n  The language server will provide `name:` and `number:` as autocomplete\n  suggestions.\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now provides a code action to automatically generate a new\n  variant from incorrect code:\n\n  ```gleam\n  pub type Msg {\n    ServerSentResponse(Json)\n  }\n\n  pub fn view() -> Element(Msg) {\n    div([], [\n      button([on_click(UserPressedButton)], [text(\"Press me!\")])\n  //                   ^^^^^^^^^^^^^^^^^ This doesn't exist yet!\n    ])\n  }\n  ```\n\n  Triggering the code action on the `UserPressedButton` will add it to the `Msg`\n  type:\n\n  ```gleam\n  pub type Msg {\n    ServerSentResponse(Json)\n    UserPressedButton\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server can now remove unused imported values and types:\n\n  ```gleam\n  import a_module.{type Unused, unused, used}\n\n  pub fn main() {\n    used\n  }\n  ```\n\n  Triggering the code action will remove all unused types and values:\n\n  ```gleam\n  import a_module.{used}\n\n  pub fn main() {\n    used\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Formatter\n\n- Improved the formatting of `echo` when followed by long binary expressions.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Installation\n\n- Windows ARM64 pre-built binaries are now provided.\n  ([Jonatan Männchen](https://github.com/maennchen))\n\n### Bug fixes\n\n- Fixed a bug where `case` expressions in custom panic messages would compile\n  to invalid syntax on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where an underscore after a zero in a number would compile to\n  invalid syntax on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the \"generate function\" code action could generate invalid\n  code when the same variable was passed as an argument twice.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where replacing a Hex dependency with a Git dependency of the\n  same name would cause the build tool to fail.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where updating the remote URL of a Git dependency would fail to\n  update the remote in the local dependency, causing a caching issue.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fix slightly wrong error message for missing main function in test module.\n  ([Samuel Cristobal](https://github.com/scristobal))\n\n- Fixed a bug where the compiler would not properly warn for unreachable\n  patterns in a `case` expression when the clause matched on multiple\n  alternative patterns.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the language server would generate invalid code for the\n  \"fill in missing labels\" code action.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where referencing an earlier segment of the bit array in a bit\n  array pattern in a `let assert` assignment would generate invalid code on the\n  Erlang target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed instances where the \"Extract variable\" code action would produce invalid\n  code, most noticeable in code inside `case` clauses and `use` expressions.\n  ([Matias Carlander](https://github.com/matiascr))\n\n- Fixed a bug where the compiler would crash when type-checking code containing\n  an assignment pattern inside a bit-array pattern.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where using the pipe operator in the `size` option of a bit array\n  segment would generate invalid code on the Erlang target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the language server would generate invalid code for the\n  \"convert to use\" code action, when used on a function call with labelled\n  arguments.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where a reference to an imported external function with a\n  non-alphanumeric module name would compile to invalid syntax on the Erlang\n  target.\n  ([Mathieu Darse](https://github.com/mdarse))\n\n- Fixed a bug where the compiler would not correctly check the size of bit\n  arrays when doing bit array pattern matching on the JavaScript target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where using the pipe operator inside a record update would cause\n  the compiler to generate invalid code on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where some code actions would produce invalid code when a file\n  contained characters that were represented with more than one byte in UTF-8.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where LSP ranges would be incorrect when a file contained characters\n  that were represented with more than one byte in UTF-8.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Only print the user-friendly LSP message when stdin is a terminal to avoid\n  emitting redundant logs.\n  ([Ariel Parker](https://github.com/arielherself))\n\n- Fixed a bug where the language server would wrongly override local variables\n  if they were shadowing an unqualified module function.\n  ([Samuel Cristobal](https://github.com/scristobal))\n\n- Fixed a bug where renaming a local variable which is used in combination with\n  label shorthand syntax would produce invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the stack would overflow on Windows when type-checking\n  multiple nested `use` expressions.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where using a variable from a separate pattern inside a bit array\n  pattern would be allowed but generate invalid Erlang code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would crash if duplicate variables were defined\n  in alternative patterns.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n"
  },
  {
    "path": "changelog/v1.12.md",
    "content": "# Changelog\n\n## v1.12.0 - 2025-08-05\n\n### Bug fixes\n\n- Corrected an error message that used incorrect terminology.\n  ([Louis Pilfold](https://github.com/lpil))\n\n## v1.12.0-rc3 - 2025-07-31\n\n### Bug fixes\n\n- Fixed a bug where using `echo` in a module with a function named `process`\n  would result in a runtime error on JavaScript.\n  ([Peter Saxton](https://github.com/CrowdHailer))\n\n## v1.12.0-rc2 - 2025-07-24\n\n### Formatter\n\n- The formatter now allows more control over how bit arrays are split. By adding\n  a trailing comma at the end of a bit array that can fit on a single line, the\n  bit array will be split on multiple lines:\n\n  ```gleam\n  pub fn dgram() -> BitArray {\n    <<ip_version:4, header_length:4, service_type:8,>>\n  }\n  ```\n\n  Will be formatted as:\n\n  ```gleam\n  pub fn dgram() -> BitArray {\n    <<\n      ip_version:4,\n      header_length:4,\n      service_type:8,\n    >>\n  }\n  ```\n\n  By removing the trailing comma, the formatter will try and fit the bit array\n  on a single line again:\n\n  ```gleam\n  pub fn dgram() -> BitArray {\n    <<\n      ip_version:4,\n      header_length:4,\n      service_type:8\n    >>\n  }\n  ```\n\n  Will be formatted back to a single line:\n\n  ```gleam\n  pub fn dgram() -> BitArray {\n    <<ip_version:4, header_length:4, service_type:8>>\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The formatter now allows more control over how bit arrays are formatted.\n  If a bit array is split with multiple segments on the same line, removing the\n  trailing comma will make sure the formatter keeps each segment on its own\n  line:\n\n  ```gleam\n  pub fn dgram() -> BitArray {\n    <<\n      \"This bit array was formatted\", \"keeping segments on the same line\",\n      \"notice how the formatting changes by removing the trailing comma ->\",\n    >>\n  }\n  ```\n\n  Is formatted as:\n\n  ```gleam\n  pub fn dgram() -> BitArray {\n    <<\n      \"This bit array was formatted\",\n      \"keeping segments on the same line\",\n      \"notice how the formatting changes by removing the trailing comma ->\"\n    >>\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- Fixed a bug where the formatter would move a comment before `assert` to be\n  after it.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the message following an `echo`, `panic`, `todo`, `assert`,\n  or `let assert` would not be formatted properly when preceded by a comment.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would generate invalid code for an `assert`\n  using pipes on the JavaScript target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.12.0-rc1 - 2025-07-18\n\n### Compiler\n\n- It is now possible to add a custom message to be printed by `echo`, making it\n  easier to include additional context to be printed at runtime:\n\n  ```gleam\n  pub fn main() {\n    echo 11 as \"lucky number\"\n  }\n  ```\n\n  Will output to stderr:\n\n  ```txt\n  /src/module.gleam:2 lucky number\n  11\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Generated JavaScript functions, constants, and custom type constructors now\n  include any doc comment as a JSDoc comment, making it easier to use the\n  generated code and browse its documentation from JavaScript.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The code generated for a `case` expression on the JavaScript target is now\n  reduced in size in many cases.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The code generators now perform usage-based dead code elimination. Unused\n  definitions are not longer generated.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- `echo` now has better support for character lists, JavaScript errors, and\n  JavaScript circular references.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The look of errors and warnings has been improved. Additional labels providing\n  context for the error message are no longer highlighted with the same style as\n  the source of the problem.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Gleam will now emit a helpful message when attempting to import modules using\n  `.` instead of `/`.\n\n  ```txt\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:1:11\n    │\n  1 │ import one.two.three\n    │           ^ I was expecting either `/` or `.{` here.\n\n  Perhaps you meant one of:\n\n      import one/two\n      import one.{item}\n  ```\n\n  ([Zij-IT](https://github.com/zij-it))\n\n- The compiler now emits a warning when a top-level constant or function\n  declaration shadows an imported name in the current module.\n  ([Aayush Tripathi](https://github.com/aayush-tripathi))\n\n- The compiler can now tell when an unknown variable might be referring to an\n  ignored variable and provide an helpful error message highlighting it. For\n  example, this piece of code:\n\n  ```gleam\n  pub fn go() {\n    let _x = 1\n    x + 1\n  }\n  ```\n\n  Now results in the following error:\n\n  ```\n  error: Unknown variable\n    ┌─ /src/one/two.gleam:4:3\n    │\n  3 │   let _x = 1\n    │       -- This value is discarded\n  4 │   x + 1\n    │   ^ So it is not in scope here.\n\n  Hint: Change `_x` to `x` or reference another variable\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The code generated for pattern matching has been optimised on the JavaScript\n  target to reuse the matched variables when safe to do so. Take the following\n  snippet of Gleam code:\n\n  ```gleam\n  pub fn find_book() {\n    case ask_for_isbn() {\n      Ok(isbn) -> load_book(isbn)\n      Error(Nil) -> Error(Nil)\n    }\n  }\n  ```\n\n  Notice how in the `Error` case we're returning exactly the same value that is\n  being matched on! Now the compiler will generate the following JavaScript code\n  instead of allocating a new `Error` variant entirely:\n\n  ```js\n  export function find_book() {\n    let result = ask_for_isbn();\n    if (result instanceof Ok) {\n      let isbn = result[0];\n      return load_book(isbn);\n    } else {\n      // Previously this would have been: `return new Error(undefined);`!\n      return result;\n    }\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now raises a warning when performing a redundant comparison that\n  it can tell is always going to succeed or fail. For example, this piece of\n  code:\n\n  ```gleam\n  pub fn find_line(lines) {\n    list.find(lines, fn(x) { x == x })\n  }\n  ```\n\n  Would result in the following warning:\n\n  ```\n  warning: Redundant comparison\n    ┌─ /src/warning.gleam:2:17\n    │\n  1 │   list.find(lines, fn(x) { x == x })\n    │                            ^^^^^^ This is always `True`\n\n  This comparison is redundant since it always succeeds.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Attempting to use the list prefix syntax with two lists will now\n  show a helpful error message. For example, this snippet of code:\n\n  ```gleam\n  pub fn main() -> Nil {\n    let xs = [1, 2, 3]\n    let ys = [5, 6, 7]\n    [1, ..xs, ..ys]\n  }\n  ```\n\n  Would result in the following error:\n\n  ```\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:5:13\n    │\n  5 │   [1, ..xs, ..ys]\n    │       --    ^^ I wasn't expecting a second list here\n    │       │\n    │       You're using a list here\n\n  Lists are immutable and singly-linked, so to join two or more lists\n  all the elements of the lists would need to be copied into a new list.\n  This would be slow, so there is no built-in syntax for it.\n  ```\n\n  ([Carl Bordum Hansen](https://github.com/carlbordum)) and\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The error message one gets when calling a function with the wrong number of\n  arguments has been improved and now only suggests the relevant missing labels.\n  For example, this piece of code:\n\n  ```gleam\n  pub type Pokemon {\n    Pokemon(id: Int, name: String, moves: List(String))\n  }\n\n  pub fn best_pokemon() {\n    Pokemon(198, name: \"murkrow\")\n  }\n  ```\n\n  Would result in the following error, suggesting the missing labels:\n\n  ```txt\n  error: Incorrect arity\n    ┌─ /src/main.gleam:6:3\n    │\n  6 │   Pokemon(198, name: \"murkrow\")\n    │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected 3 arguments, got 2\n\n  This call accepts these additional labelled arguments:\n\n    - moves\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Code generators now reuse existing variables when possible for the record\n  update syntax, reducing the size of the generated code and number of\n  variables defined for both Erlang and JavaScript.\n\n  ```gleam\n  pub fn main() -> Nil {\n    let trainer = Trainer(name: \"Ash\", badges: 0)\n    battle(Trainer(..trainer, badges: 1))\n  }\n  ```\n\n  Previously this Gleam code would generate this Erlang code:\n\n  ```erlang\n  -spec main() -> nil.\n  main() ->\n      Trainer = {trainer, 0, <<\"Ash\"/utf8>>},\n      battle(\n          begin\n              _record = Trainer,\n              {trainer, 1, erlang:element(3, _record)}\n          end\n      ).\n  ```\n\n  Now this code will be generated instead:\n\n  ```erlang\n  -spec main() -> nil.\n  main() ->\n      Trainer = {trainer, 0, <<\"Ash\"/utf8>>},\n      battle({trainer, 1, erlang:element(3, Trainer)}).\n  ```\n\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The compiler now allows using bit array options to specify endianness when\n  constructing or pattern matching on UTF codepoints in bit arrays.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Calculations are now allowed in the size options of bit array patterns. For\n  example, the following code is now valid:\n\n  ```gleam\n  let assert <<size, data:bytes-size(size / 8 - 1)>> = some_bit_array\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- On the Erlang target each generated module enables inlining from the Erlang\n  compiler.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The code generated for division and modulo operators on the JavaScript target\n  has been improved to avoid performing needless checks.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Build tool\n\n- `gleam update`, `gleam deps update`, and `gleam deps download` will now print\n  a message when there are new major versions of packages available. For\n  example:\n\n  ```txt\n   $ gleam update\n    Resolving versions\n\n  The following dependencies have new major versions available:\n\n  gleam_http 1.7.0 -> 4.0.0\n  gleam_json 1.0.1 -> 3.0.1\n  lustre     3.1.4 -> 5.1.1\n  ```\n\n  ([Amjad Mohamed](https://github.com/andho))\n\n- The documentation generator now strips trailing slashes from Gitea/Forgejo\n  hosts so sidebar \"Repository\" and \"View Source\" links never include `//`, and\n  single-line \"View Source\" anchors emit `#Lx` instead of `#Lx-x`.\n  ([Aayush Tripathi](https://github.com/aayush-tripathi))\n\n- The build tool can now compile packages that will have already booted the\n  Erlang compiler application instead of failing.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- `gleam deps list` now uses a tab rather than a space as a separator.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The build tool now also supports `.cjs` files placed in the `src`, `dev` or\n  `test` directories.\n  ([yoshi](https://github.com/yoshi-monster))\n\n- The build tool now produces better error messages when version resolution\n  fails. For example:\n\n  ```\n  $ gleam add wisp@1\n  Resolving versions\n  error: Dependency resolution failed\n\n  There's no compatible version of `gleam_otp`:\n    - You require wisp >= 1.0.0 and < 2.0.0\n      - wisp requires mist >= 1.2.0 and < 5.0.0\n      - mist requires gleam_otp >= 0.9.0 and < 1.0.0\n    - You require lustre >= 5.2.1 and < 6.0.0\n      - lustre requires gleam_otp >= 1.0.0 and < 2.0.0\n\n  There's no compatible version of `gleam_json`:\n    - You require wisp >= 1.0.0 and < 2.0.0\n      - wisp requires gleam_json >= 3.0.0 and < 4.0.0\n    - You require gleam_json >= 2.3.0 and < 3.0.0\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The `repository` section in `gleam.toml` now allows specifying the\n  `tag-prefix` property, which is prepended to the default tag.\n  This makes it possible to have multiple packages with different versions in\n  the same repository (together with `path`), without breaking links to source\n  code in documentation.\n  ([Sakari Bergen](https://github.com/sbergen))\n\n### Language server\n\n- It is now possible to use the \"Pattern match on variable\" code action on\n  variables on the left hand side of a `use`. For example:\n\n  ```gleam\n  pub type User {\n    User(id: Int, name: String)\n  }\n\n  pub fn main() {\n    use user <- result.try(load_user())\n    //  ^^^^ Triggering the code action here\n    todo\n  }\n  ```\n\n  Would result in the following code:\n\n  ```gleam\n  pub type User {\n    User(id: Int, name: String)\n  }\n\n  pub fn main() {\n    use user <- result.try(load_user())\n    let User(id:, name:) = user\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"generate function\" and \"generate variant\" code actions are now\n  quickfixes, allowing them to be more easily applied to code which is producing\n  an error.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now offers a code action to remove needless blocks\n  wrapping a single expression. For example, in this code snippet:\n\n  ```gleam\n  case greeting {\n    User(name:) -> { \"Hello, \" <> name }\n    //             ^^^^^^^^^^^^^^^^^^^^^ Triggering the code action\n    //                                   with the cursor over this block.\n    Anonymous -> \"Hello, stranger!\"\n  }\n  ```\n\n  Would be turned into:\n\n  ```gleam\n  case greeting {\n    User(name:) -> \"Hello, \" <> name\n    Anonymous -> \"Hello, stranger!\"\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- It is now possible to trigger the \"Add type annotation\" code action anywhere\n  between the start of a function definition and the start of its body. For\n  example the action can trigger here while it previously wouldn't:\n\n  ```gleam\n  pub fn my_lucky_number() {\n    //                    ^^ The action can trigger here as well!\n    11\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Formatter\n\n- The formatter now allows more control over how lists are split. By adding a\n  trailing comma at the end of a list that can fit on a single line, the list\n  will be split on multiple lines:\n\n  ```gleam\n  pub fn my_favourite_pokemon() -> List(String) {\n    [\"natu\", \"chimecho\", \"milotic\",]\n  }\n  ```\n\n  Will be formatted as:\n\n  ```gleam\n  pub fn my_favourite_pokemon() -> List(String) {\n    [\n      \"natu\",\n      \"chimecho\",\n      \"milotic\",\n    ]\n  }\n  ```\n\n  By removing the trailing comma, the formatter will try and fit the list on a\n  single line again:\n\n  ```gleam\n  pub fn my_favourite_pokemon() -> List(String) {\n    [\n      \"natu\",\n      \"chimecho\",\n      \"milotic\"\n    ]\n  }\n  ```\n\n  Will be formatted back to a single line:\n\n  ```gleam\n  pub fn my_favourite_pokemon() -> List(String) {\n    [\"natu\", \"chimecho\", \"milotic\"]\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The formatter now allows more control over how lists are formatted.\n  If a list is split with multiple elements on the same line, removing the\n  trailing comma will make sure the formatter keeps each item on its own line:\n\n  ```gleam\n  pub fn my_favourite_pokemon() -> List(String) {\n    [\n      \"This list was formatted\", \"keeping multiple elements on the same line\",\n      \"notice how the formatting changes by removing the trailing comma ->\"\n    ]\n  }\n  ```\n\n  Is formatted as:\n\n  ```gleam\n  pub fn my_favourite_pokemon() -> List(String) {\n    [\n      \"This list was formatted\",\n      \"keeping multiple elements on the same line\",\n      \"notice how the formatting changes by removing the trailing comma ->\",\n    ]\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The formatter no longer removes empty lines between list items. In case an\n  empty line is added between list items they will all be split on multiple\n  lines. For example:\n\n  ```gleam\n  pub fn main() {\n    [\n      \"natu\", \"xatu\",\n\n      \"chimeco\"\n    ]\n  }\n  ```\n\n  Is formatted as:\n\n  ```gleam\n  pub fn main() {\n    [\n      \"natu\",\n      \"xatu\",\n\n      \"chimeco\",\n    ]\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- Fixed a bug where the language server would not show type-related code actions\n  for record fields in custom type definitions.\n  ([cysabi](https://github.com/cysabi))\n\n- Fixed a bug where the \"Inline variable\" code action would be offered for\n  function parameters and other invalid cases.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the \"Inline variable\" code action would not be applied\n  correctly to variables using label shorthand syntax.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would emit the same error twice for patterns\n  with the wrong number of labels.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the language server would generate invalid code when the\n  \"Extract variable\" code action was used on a `use` expression.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would crash when using the `utf8_codepoint`\n  bit array segment on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where `==` and `!=` would return incorrect output for some\n  JavaScript objects.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where specific combinations of options in bit array segments would\n  not be allowed on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where invalid code would be generated for `let assert` in some\n  cases on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where using the prelude `Ok` and `Error` values in a qualified\n  fashion could cause a conflict with user-defined `Ok` and `Error` values when\n  generating code on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the \"Import module\" code action would suggest importing\n  internal modules from other packages.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the language server would not rename variables defined in\n  alternative patterns.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where trying to rename a type or value from the Gleam prelude\n  would result in invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the generated documentation would not be formatted properly.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the language server wouldn't allow you to jump to the\n  definition of a record from a record update expression.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the language server would allow using the \"extract variable\"\n  code action on variables used in record updates.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where a record pattern with a spread `..` would not be formatted\n  properly.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where fields of custom types named `prototype` would not be\n  properly escaped on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## v1.11.1 - 2025-06-05\n\n### Compiler\n\n- The displaying of internal types in HTML documentation has been improved.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- A warning is now emitted when the same module is imported\n  multiple times into the same module with different aliases.\n  ([Louis Pilfold](https://github.com/lpil))\n\n### Bug fixes\n\n- Fixed a bug where a bit array segment matching on a floating point number\n  would match with `NaN` or `Infinity` on the JavaScript target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n"
  },
  {
    "path": "changelog/v1.13.md",
    "content": "# Changelog\n\n## v1.13.0 - 2025-10-19\n\n## v1.13.0-rc2 - 2025-10-06\n\n### Bug fixes\n\n- Fixed a bug where the \"Extract function\" code action would not properly\n  extract a `use` expression.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the \"Extract function\" code action would generate a function\n  with the wrong type when used on a use expression.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the error message for inexhaustive patterns could show\n  incorrect extra patterns in addition to the correct missing patterns.\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n- Fixed a bug where triggering the \"Generate function\" code action to generate\n  a function in a different module could cause the generated function to appear\n  in the middle of an existing function, resulting in invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the \"turn into pipe\" code action would not trigger inside\n  the final step of a pipeline.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the \"pattern match on variable\" code action would crash when\n  used on a variable followed by a case expression.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.13.0-rc1 - 2025-09-29\n\n### Compiler\n\n- The compiler now applies an optimisation known as \"interference based pruning\"\n  when compiling bit array pattern matching where matches are performed at the\n  start of bit arrays.\n  This optimisation drastically reduces compile times, memory usage and the\n  compiled code size, removing many redundant checks.\n  It is particularly important for network protocol applications where it is\n  typical to match on some fixed patterns at the start of the bitarray.\n  For example:\n\n  ```gleam\n  pub fn parser_headers(headers: BitArray, bytes: Int) -> Headers {\n    case headers {\n      <<\"CONTENT_LENGTH\" as header, 0, value:size(bytes), 0, rest:bytes>>\n      | <<\"QUERY_STRING\" as header, 0, value:size(bytes), 0, rest:bytes>>\n      | <<\"REQUEST_URI\" as header, 0, value:size(bytes), 0, rest:bytes>>\n      // ...\n      | <<\"REDIRECT_STATUS\" as header, 0, value:size(bytes), 0, rest:bytes>>\n      | <<\"SCRIPT_NAME\" as header, 0, value:size(bytes), 0, rest:bytes>>\n        -> [#(header, value), ..parse_headers(rest)]\n    }\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now raises a warning for unreachable clauses that are matching\n  on bit array segments that could never match. Consider this example:\n\n  ```gleam\n  pub fn get_payload(packet: BitArray) -> Result(BitArray, Nil) {\n    case packet {\n      <<200, payload:bytes>> -> Ok(payload)\n      <<404, _:bits>> -> Error(Nil)\n      _ -> Ok(packet)\n    }\n  }\n  ```\n\n  There's a subtle bug here. The second clause can never match since it's\n  impossible for the first byte of the bit array to have the value `404`.\n  The new error explains this nicely:\n\n  ```txt\n  warning: Unreachable pattern\n    ┌─ /src.gleam:4:5\n    │\n  4 │     <<404, _:bits>> -> Error(Nil)\n    │     ^^^^^^^^^^^^^^^\n    │       │\n    │       A 1 byte unsigned integer will never match this value\n\n  This pattern cannot be reached as it contains segments that will never\n  match.\n\n  Hint: It can be safely removed.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now raises a warning when a function's argument is only passed\n  along in a recursive call but not actually used for anything. For example:\n\n  ```gleam\n  import gleam/io\n\n  pub fn greet(x, times) {\n    case times {\n      0 -> Nil\n      _ -> {\n        io.println(\"Hello, Joe!\")\n        greet(x, times - 1)\n      }\n    }\n  }\n  ```\n\n  In this piece of code the `x` argument is actually never used, and the\n  compiler will raise the following warning:\n\n  ```txt\n  warning: Unused function argument\n    ┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:3:14\n    │\n  3 │ pub fn greet(x, times) {\n    │              ^ This argument is unused\n\n  This argument is passed to the function when recursing, but it's never used\n  for anything.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now emits a better error message for private types marked as\n  opaque. For example, the following piece of code:\n\n  ```gleam\n  opaque type Wibble {\n    Wobble\n  }\n  ```\n\n  Would result in the following error:\n\n  ```\n  error: Private opaque type\n    ┌─ /src/one/two.gleam:2:1\n    │\n  2 │ opaque type Wibble {\n    │ ^^^^^^ You can safely remove this.\n\n  Only a public type can be opaque.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The parsing of opaque private types is now fault tolerant: having a private\n  opaque type in a module no longer stops the compiler from highlighting other\n  errors.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now emits a single warning for multiple negations in a row, while\n  previously it would emit multiple comments highlighting increasingly longer\n  spans.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Redundant `_ as x` patterns are now deprecated in favour of `x`.\n  ([eutampieri](https://github.com/eutampieri))\n\n- The compiler will now raise warning for inefficient use of `list.length()`\n  when trying to check is list empty via `0 < list.length(list)` or\n  `list.length(list) > 0` as well as in other cases. For example, the following\n  code:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    let numbers = [1, 46]\n    let _ = 0 < list.length(numbers)\n    let _ = list.length(numbers) > 0\n  }\n  ```\n\n  Would result in following warnings:\n\n  ```\n  warning: Inefficient use of `list.length`\n    ┌─ /data/data/com.termux/files/home/test_gleam/src/test_gleam.gleam:5:13\n    │\n  5 │     let _ = 0 < list.length(numbers)\n    │             ^^^^^^^^^^^^^^^^^^^^^^^^\n\n  The `list.length` function has to iterate across the whole\n  list to calculate the length, which is wasteful if you only\n  need to know if the list is empty or not.\n\n  Hint: You can use `the_list != []` instead.\n\n  warning: Inefficient use of `list.length`\n    ┌─ /data/data/com.termux/files/home/test_gleam/src/test_gleam.gleam:6:13\n    │\n  6 │     let _ = list.length(numbers) > 0\n    │             ^^^^^^^^^^^^^^^^^^^^^^^^\n\n  The `list.length` function has to iterate across the whole\n  list to calculate the length, which is wasteful if you only\n  need to know if the list is empty or not.\n\n  Hint: You can use `the_list != []` instead.\n  ```\n\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- The compiler now provides an improved error message for when trying to define\n  a constant inside a function. For example, the following code:\n\n  ```gleam\n  pub fn deep_thought() -> Int {\n    const the_answer = 42\n    the_answer\n  }\n  ```\n\n  Will produce this error message:\n\n  ```txt\n    error: Syntax error\n    ┌─ /src/file.gleam:2:3\n    │\n  3 │   const the_answer = 43\n    │   ^^^^^ Constants are not allowed inside functions\n\n  All variables are immutable in Gleam, so constants inside functions are not\n  necessary.\n  Hint: Either move this into the global scope or use `let` binding instead.\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The code generated for blocks on the JavaScript target has been improved and\n  is now smaller in certain cases.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Writing a type name followed by `()` now emits an error during analysis\n  rather than parsing, so it no longer stops the compiler from reporting errors\n  further in the code.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now shows a specific syntax error when trying to use an\n  angle-bracket syntax for generic types or function definitions:\n\n  ```txt\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:2:12\n    │\n  2 │ type Either<a, b> {\n    │            ^ I was expecting `(` here.\n\n  Type parameters use lowercase names and are surrounded by parentheses.\n\n      type Either(a, b) {\n\n  See: https://tour.gleam.run/data-types/generic-custom-types/\n  ```\n\n  ([Aaron Christiansen](https://github.com/AaronC81))\n\n- Fault tolerance for analysis of labeled fields in variant patterns has\n  been improved.\n  ([sobolevn](https://github.com/sobolevn))\n\n- Compiler now adds a hint when `#`-styled comments are used. This code:\n\n  ```gleam\n  fn some() {\n    let a = 1\n    # let b = 2\n  }\n  ```\n\n  Now produces:\n\n  ```txt\n  error: Syntax error\n    ┌─ /src/main.gleam:3:5\n    │\n  3 │   # let b = 2\n    │     ^^^ I was not expecting this\n\n  Found the keyword `let`, expected one of:\n  - `(`\n  Hint: Maybe you meant to create a comment?\n  Comments in Gleam start with `//`, not `#`\n  ```\n\n  ([sobolevn](https://github.com/sobolevn))\n\n- The `erlang.application_start_argument` parameter has been added to\n  `gleam.toml`. This is a string containing an Erlang term that will be written\n  into the package's Erlang `.app` file if `erlang.application_start_module`\n  has been set, replacing the default argument of `[]`.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Generated code for the JavaScript target now includes a public API which can\n  be used for FFI interacting with Gleam custom types. For example, if you have\n  this Gleam code:\n\n  ```gleam\n  pub type Person {\n    Teacher(name: String, subject: String)\n    Student(name: String, age: Int)\n  }\n  ```\n\n  You can use the new API to use the `Person` type in FFI code:\n\n  ```javascript\n  import {...} from \"./person.mjs\";\n\n  // Constructing custom types\n  let teacher = Person$Teacher(\"Joe Armstrong\", \"Computer Science\");\n  let student = Person$Student(\"Louis Pilfold\");\n\n  let randomPerson = Math.random() > 0.5 ? teacher : student;\n\n  // Checking variants\n  let randomIsTeacher = Person$isTeacher(randomPerson);\n\n  // Getting fields\n  let teacherSubject = Person$Teacher$subject(teacher);\n\n  // The `name` field is shared so can be accessed from either variant\n  let personName = Person$name(randomPerson);\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Build tool\n\n- New projects are generated using OTP28 on GitHub Actions.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The build tool now has a new `hex owner transfer` subcommand to transfer\n  ownership of existing packages.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- `gleam add` now adds `dependencies` and `dev_dependencies` as tables instead\n  of inline tables if they are missing.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- After dependency resolution the build tool will now print all packages added\n  and removed, and any versions changed.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- `gleam publish` now blocks publishing packages that contain the default main\n  function to prevent accidental publishing of unmodified template code.\n  ([Joohoon Cha](https://github.com/jcha0713))\n\n- When generating documentation, the build tool will now print the names of\n  public type aliases instead of internal type names when annotating functions\n  and types. For example, for the following code:\n\n  ```gleam\n  import my_package/internal\n\n  pub type ExternalAlias = internal.InternalRepresentation\n\n  pub fn do_thing() -> ExternalAlias { ... }\n  ```\n\n  This is what the build tool used to generate:\n\n  ```gleam\n  pub fn do_thing() -> @internal InternalRepresentation\n  ```\n\n  Whereas now it will not use the internal name, and instead produce:\n\n  ```gleam\n  pub fn do_thing() -> ExternalAlias\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Support has been added for using Tangled as a repository.\n  ([Naomi Roberts](https://github.com/naomieow))\n\n### Language server\n\n- The language server now offers a code action to remove all the unreachable\n  clauses in a case expression. For example:\n\n  ```gleam\n  pub fn main() {\n    case find_user() {\n      Ok(user) -> todo\n      Ok(Admin) -> todo\n  //  ^^^^^^^^^ This clause is unreachable\n      Ok(User) -> todo\n  //  ^^^^^^^^ This clause is unreachable\n      Error(_) -> todo\n    }\n  }\n  ```\n\n  Hovering over one of the unreachable clauses and triggering the code action\n  would remove all the unreachable clauses:\n\n  ```gleam\n  pub fn main() {\n    case find_user() {\n      Ok(user) -> todo\n\n      Error(_) -> todo\n    }\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"pattern match on variable\" can now be triggered on lists. For example:\n\n  ```gleam\n  pub fn is_empty(list: List(a)) -> Bool {\n    //            ^^^^ Triggering the action here\n  }\n  ```\n\n  Triggering the action on the `list` argument would result in the following\n  code:\n\n  ```gleam\n  pub fn is_empty(list: List(a)) -> Bool {\n    case list {\n      [] -> todo\n      [first, ..rest] -> todo\n    }\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"pattern match on variable\" code action can now be triggered on variables\n  introduced by other patterns. For example:\n\n  ```gleam\n  pub fn main() {\n    let User(name:, role:) = find_user(\"lucy\")\n    //              ^^^^ Triggering the action here\n  }\n  ```\n\n  Triggering the action on another variable like `role` would result in the\n  following code:\n\n  ```gleam\n  pub fn main() {\n    let User(name:, role:) = find_user(\"lucy\")\n    case role {\n      Admin -> todo\n      Member -> todo\n    }\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"pattern match on variable\" code action can now be triggered on variables\n  in case expressions. For example:\n\n  ```gleam\n  pub fn main() {\n    case find_user() {\n      Ok(user) -> todo\n      Error(_) -> todo\n    }\n  }\n  ```\n\n  Triggering the action on the `user` variable would result in the following\n  code:\n\n  ```gleam\n  pub fn main() {\n    case find_user() {\n      Ok(Admin) -> todo\n      Ok(Member) -> todo\n      Error(_) -> todo\n    }\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers a quick fix to remove `opaque` from a private\n  type:\n\n  ```gleam\n  opaque type Wibble {\n  // ^^^ This is an error!\n    Wobble\n  }\n  ```\n\n  If you hover over the type and trigger the quick fix, the language server will\n  automatically remove the `opaque` keyword:\n\n  ```gleam\n  type Wibble {\n    Wobble\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers a code action to add the omitted labels in a\n  call. For example:\n\n  ```gleam\n  pub type User {\n    User(first_name: String, last_name: String, likes: List(String))\n  }\n\n  pub fn main() {\n    let first_name = \"Giacomo\"\n    User(first_name, \"Cavalieri\", [\"gleam\"])\n  //^^^^ Triggering the code action here\n  }\n  ```\n\n  Triggering the code action on the `User` constructor will result in the\n  following code:\n\n  ```gleam\n  pub type User {\n    User(first_name: String, last_name: String, likes: List(String))\n  }\n\n  pub fn main() {\n    let first_name = \"Giacomo\"\n    User(first_name:, last_name: \"Cavalieri\", likes: [\"gleam\"])\n  }\n  ```\n\n- The \"inline variable\" code action is now only suggested when hovering over the\n  relevant variable.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- When hovering over a record field in a record access expression, the language\n  sever will now show the documentation for that field, if present.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Renaming a variable from a label shorthand (`name:`) no longer includes the\n  colon in the rename dialog (`name:` -> `name`)\n  ([fruno](https://github.com/frunobulax-the-poodle))\n\n- The language server now offers a code action to collapse nested case\n  expressions. Take this example:\n\n  ```gleam\n  case user {\n    User(role: Admin, name:) ->\n      // Here the only thing we're doing is pattern matching on the\n      // `name` variable we've just defined in the outer pattern.\n      case name {\n        \"Joe\" -> \"Hello, Joe!\"\n        _ -> \"Hello, stranger\"\n      }\n\n    _ -> \"You're not an admin!\"\n  }\n  ```\n\n  We could simplify this case expression and reduce nesting like so:\n\n  ```gleam\n  case user {\n    User(role: Admin, name: \"Joe\") -> \"Hello, Joe!\"\n    User(role: Admin, name: _) -> \"Hello, stranger\"\n    _ -> \"You're not an admin!\"\n  }\n  ```\n\n  Now, if you hover over that pattern, the language server will offer the\n  \"collapse nested case\" action that will simplify your code like shown in the\n  example above.\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"Generate function\" code action now allows generating function in other\n  modules. For example, given the following code:\n\n  ```gleam\n  // maths.gleam\n  pub fn add(a: Int, b: Int) -> Int { a + b }\n\n  // main.gleam\n  import maths\n\n  pub fn main() -> Int {\n    echo maths.add(1, 2)\n    echo maths.subtract(from: 2, subtract: 1)\n    //         ^ Trigger the \"Generate function\" code action here\n  }\n  ```\n\n  The language sever will edit the `maths.gleam` file:\n\n  ```gleam\n  pub fn add(a: Int, b: Int) -> Int { a + b }\n\n  pub fn subtract(from from: Int, subtract subtract: Int) -> Int {\n    todo\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The \"Add type annotations\" and \"Generate function\" code actions now ignore\n  type variables defined in other functions, improving the generated code.\n  For example:\n\n  ```gleam\n  fn something(a: a, b: b, c: c) -> d { todo }\n\n  fn pair(a, b) { #(a, b) }\n  ```\n\n  Previously, when triggering the \"Add type annotations\" code action on the\n  `pair` function, the language server would have generated:\n\n  ```gleam\n  fn pair(a: e, b: f) -> #(e, f) { #(a, b) }\n  ```\n\n  However in 1.13, it will now generate:\n\n  ```gleam\n  fn pair(a: a, b: b) -> #(a, b) { #(a, b) }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- You can now go to definition, rename, etc. from alternative patterns!\n\n  ```gleam\n  case wibble {\n    Wibble | Wobble -> 0\n    //         ^- Previously you could not trigger actions from here\n  }\n\n  ```\n\n  ([fruno](https://github.com/fruno-bulax))\n\n- When showing types of values on hover, or adding type annotations, the language\n  server will now prefer public type aliases to internal types. For example, if\n  the \"Add type annotations\" code action was triggered on the following code:\n\n  ```gleam\n  import lustre/html\n  import lustre/element\n  import lustre/attribute\n\n  pub fn make_link(attribute, element) {\n    html.a([attribute], [elements])\n  }\n  ```\n\n  Previously, the following code would have been generated:\n\n  ```gleam\n  pub fn make_link(\n    attribute: vattr.Attribute,\n    element: vdom.Element(a)\n  ) -> vdom.Element(a) {\n     html.a([attribute], [elements])\n  }\n  ```\n\n  Which references internal types which should not be imported by the user.\n  However, now the language server will produce the following:\n\n  ```gleam\n  pub fn make_link(\n    attribute: attribute.Attribute,\n    element: element.Element(a)\n  ) -> element.Element(a) {\n     html.a([attribute], [elements])\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now offers the `convert to case` code action only if a\n  single `let assert` expression is selected.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers an \"Extract function\" code action to extract a\n  selected piece of code into a separate function. For example:\n\n  ```gleam\n  const head_byte_count = 256\n\n  pub fn get_head_of_file() {\n    let assert Ok(contents) = read_file()\n\n    case contents {\n  //^ Select from here\n      <<head:bytes-size(head_byte_count), _:bits>> -> Ok(head)\n      _ -> Error(Nil)\n    }\n  //^ Until here\n  }\n  ```\n\n  Would become:\n\n  ```gleam\n  const head_byte_count = 256\n\n  pub fn get_head_of_file() {\n    let assert Ok(contents) = read_file()\n\n    function(contents)\n  }\n\n  fn function(contents: BitArray) -> Result(BitArray, Nil) {\n    case contents {\n      <<head:bytes-size(head_byte_count), _:bits>> -> Ok(head)\n      _ -> Error(Nil)\n    }\n  }\n  ```\n\n  You can then use language server renaming to choose an appropriate name for\n  the new function.\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Formatter\n\n- The formatter now removes needless multiple negations that are safe to remove.\n  For example, this snippet of code:\n\n  ```gleam\n  pub fn useless_negations() {\n    let lucky_number = --11\n    let lucy_is_a_star = !!!False\n  }\n  ```\n\n  Is rewritten as:\n\n  ```gleam\n  pub fn useless_negations() {\n    let lucky_number = 11\n    let lucy_is_a_star = !False\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Redundant `_ as x` patterns are rewritten to `x`.\n  ([eutampieri](https://github.com/eutampieri))\n\n- The formatter no longer removes blocks from case clause guards.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The formatter now properly formats tuple return annotation with comments.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n### Bug fixes\n\n- Fixed a bug where literals using `\\u{XXXX}` syntax in bit array pattern\n  segments were not translated to Erlang's `\\x{XXXX}` syntax correctly.\n  ([Benjamin Peinhardt](https://github.com/bcpeinhardt))\n\n- Fixed a bug where `echo` could crash on JavaScript if the module contains\n  record variants with the same name as some built-in JavaScript objects.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the compiler would highlight an entire double negation\n  expression as safe to remove, instead of just highlighting the double\n  negation.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would crash if there was an invalid version\n  requirement in a project's `gleam.toml`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would suggest a discouraged project name as an\n  alternative to the reserved `gleam` name.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where Forgejo source URLs in the HTML documentation could be\n  incorrectly structured.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The compiler now emits an error when a module in the `src` directory imports\n  a dev dependency, while previously it would incorrectly let these\n  dependencies to be imported.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Erroneous extra fields in `gleam.toml` dependency specifications will no\n  longer be siltently ignored. An error is now returned highlighting the\n  problem instead.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where renaming a constant which is referenced in another module\n  inside a guard would generate invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where `echo .. as ..` message will be omitted in browser target.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- Fixed a bug where renaming a variable used in a record update would produce\n  invalid code in certain situations.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where adding `echo` to the subject of a `case` expression would\n  prevent variant inference from working correctly.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would suggest to use a discarded value defined\n  in a different function.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the formatter would format a panic message adding more\n  nesting than necessary.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the language server wouldn't offer the \"unqualify\" code\n  action if used on a type alias.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the language server would fail to rename an external\n  function with no body.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler allowed to write a guard with an empty clause.\n  ([Tristan-Mihai Radulescu](https://github.com/Courtcircuits))\n\n- Fixed a bug where switching from a hex dependency to a git dependency would\n  result in an error from the compiler.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would reference a redeclared variable in a let\n  assert message, instead of the original variable, on the Erlang target.\n  ([Danielle Maywood](https://github.com/DanielleMaywood))\n\n- Fixed a bug where the compiler would report an imported module as unused if it\n  were used by private functions only.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the \"Extract variable\" code action would shadow existing\n  variables, constants and function names.\n  ([Matias Carlander](https://github.com/matiascr))\n\n- Fixed a bug where the language server would not fill in the missing labels of\n  a pattern correctly, generating invalid code.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where invalid code was being generated when using the \"Extract\n  variable\" code action inside an anonymous function.\n  ([Matias Carlander](https://github.com/matiascr))\n\n- Fixed a bug where running `gleam update` would not properly update git\n  dependencies unless `gleam clean` was run first.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would produce wrong JavaScript code for binary\n  pattern matching expressions using literal strings and byte segments.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the build tool would crash when trying to add transitive dependency.\n  ([Andrey Kozhev](https://github.com/ankddev))\n"
  },
  {
    "path": "changelog/v1.14.md",
    "content": "# Changelog\n\n## v1.14.0 - 2025-12-25 🎁\n\n### Bug fixes\n\n- Fixed a bug where using bit array segments in guard clauses could cause\n  incorrect code to be generated on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## v1.14.0-rc3 - 2025-12-21\n\n### Bug fixes\n\n- Fixed a bug where checking for equality with a variant with no fields using\n  qualified syntax would generate invalid code on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## v1.14.0-rc2 - 2025-12-19\n\n### Bug fixes\n\n- Fixed a bug where the formatter would remove `@external` attributes from\n  custom types.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where updating records with unlabelled fields would result in\n  invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## v1.14.0-rc1 - 2025-12-15\n\n### Compiler\n\n- The output of `echo` when printing atoms has been updated to use\n  `atom.create(\"...\")` instead of `atom.create_from_string(\"...\")`.\n  ([Patrick Dewey](https://github.com/ptdewey))\n\n- Patterns aliasing a string prefix have been optimised to generate faster code\n  on the Erlang target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Type inference for constants is now fault tolerant, meaning the compiler won't\n  stop at the first error as it is typing constants.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Analysis is now fault tolerant in the presence of errors in field definitions\n  of custom type variants.\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n- The compiler now emits a warning when a module contains no public definitions\n  and prevents publishing packages with empty modules to Hex.\n  ([Vitor Souza](https://github.com/vit0rr))\n\n- The `@external` annotation is now supported for external types. It allows\n  users to point an external type definition to a specific Erlang or TypeScript\n  type. For example, the `dict.Dict` type from the standard library can now be\n  written as the following:\n\n  ```gleam\n  @external(erlang, \"erlang\", \"map\")\n  @external(javascript, \"../dict.d.mts\", \"Dict\")\n  pub type Dict(key, value)\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When matching the wrong number of subjects, the compiler now pinpoints the\n  error location instead of marking the entire branch.\n\n  ```gleam\n  case wibble {\n    0, _ -> 1\n    ^^^^ Expected 1 pattern, got 2\n    0 |  -> 1\n      ^ I was expecting a pattern after this\n  }\n  ```\n\n  ([fruno](https://github.com/fruno-bulax/))\n\n- Missing patterns in error messages and the \"Add missing patterns\" code action\n  are no longer sorted lexicographically. Instead, they now consider the order\n  in which variants were defined. As programmers often group \"related\" variants\n  together, this should mean less reshuffling after inserting missing patterns!\n  ([fruno](https://github.com/fruno-bulax/))\n\n- The performance of `==` and `!=` has been improved for fieldless custom type\n  variants when compiling to JavaScript. This was done by generating comparison\n  code specific to the custom type rather than using the generic equality check\n  code.\n  ([Nafi](https://github.com/re-masashi))\n\n- The lowercase bool pattern error is no longer a syntax error, but instead a\n  part of the analysis step. This allows the entire module to be analyzed,\n  rather than stopping at the syntax error.\n  ([mxtthias](https://github.com/mxtthias))\n\n- Exhaustiveness checks for ints and floats now correctly handle unreachable\n  cases in which the numbers contain underscores (i.e. `10` and `1_0`).\n  Float exhaustiveness checks also now correctly identify unreachable cases\n  containing scientific notation or trailing zeros (i.e. `100` and `1e2`).\n  ([ptdewey](https://github.com/ptdewey))\n\n- The compiler now emits a warning when a doc comment is not attached to a\n  definition due to a regular comment in between. For example, in the following\n  code:\n\n  ```gleam\n  /// This documentation is not attached\n  // This is not a doc comment\n  /// This is actual documentation\n  pub fn wibble() {\n    todo\n  }\n  ```\n\n  Will now produce the following warning:\n\n  ```txt\n    warning: Detached doc comment\n    ┌─ src/main.gleam:1:4\n    │\n  1 │ /// This documentation is not attached\n    │    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not attached to a definition\n\n  This doc comment is followed by a regular comment so it is not attached to\n  any definition.\n  Hint: Move the comment above the doc comment\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The [interference-based pruning](https://gleam.run/news/formalising-external-apis/#Improved-bit-array-exhaustiveness-checking)\n  from 1.13 has been extended to int segments!\n  Aside from the various performance improvements, this allows the compiler to\n  mark more branches as unreachable.\n\n  ```gleam\n  case bits {\n    <<\"a\">> -> 0\n    <<97>> -> 1\n    // ^- This branch is unreachable because it's equal to \"a\".\n\n    <<0b1:1, _:1>> -> 2\n    <<0b11:2>> -> 3\n    // ^- This branch is unreachable because the branch before it already covers it.\n\n    _ -> 99\n  }\n  ```\n\n  ([fruno](https://github.com/fruno-bulax/))\n\n- Comparison of record constructors with non-zero arity always produces `False`,\n  because under the hood during code generation they become anonymous functions:\n\n  ```gleam\n  pub type Wibble {\n    Wobble(String)\n  }\n\n  pub fn main() {\n    echo Wobble == Wobble // False\n  }\n  ```\n\n  Previously compiler produced false-positive redundant comparison warning, which\n  is now removed:\n\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n- Record update syntax can now be used in constant definitions. For example:\n\n  ```gleam\n  pub const base_http_config = HttpConfig(\n    host: \"0.0.0.0\",\n    port: 8080,\n    use_tls: False,\n    log_level: Info,\n  )\n\n  pub const dev_http_config = HttpConfig(\n    ..base_http_config,\n    port: 4000,\n    log_level: Debug,\n  )\n\n  pub const prod_http_config = HttpConfig(\n    ..base_http_config,\n    port: 80,\n    use_tls: True,\n    log_level: Warn,\n  )\n  ```\n\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n### Build tool\n\n- The help text displayed by `gleam dev --help`, `gleam test --help`, and\n  `gleam run --help` has been improved: now each one states which function it's\n  going to run.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The `--invert` and `--package` options of `gleam deps tree` are now mutually\n  exclusive; if both options are given the command will fail. Previously,\n  `--invert` would be silently ignored if given together with `--package`.\n  ([Evan Silberman](https://github.com/silby))\n\n- Updated to use the latest Elixir API, so a warning would not be shown when\n  compiling Elixir file in a Gleam project.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- The build tool now has a new `gleam deps outdated` command that shows outdated\n  versions for dependencies. For example:\n\n  ```sh\n  $ gleam deps outdated\n  Package  Current  Latest\n  -------  -------  ------\n  wibble   1.4.0    1.4.1\n  wobble   1.0.1    2.3.0\n  ```\n\n  ([Vladislav Shakitskiy](https://github.com/vshakitskiy))\n\n- The format used for `gleam deps list` and the notice of available major\n  version upgrades has been improved.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- `gleam new` now creates the project directory using the confirmed project\n  name when a suggested rename is accepted.\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n- The build tool now provides better error message when trying to build Git\n  dependencies without Git installed. Previously, it would show this error:\n\n  ```txt\n  error: Shell command failure\n\n  There was a problem when running the shell command `git`.\n\n  The error from the shell command library was:\n\n      Could not find the stdio stream\n  ```\n\n  Now it will show:\n\n  ```txt\n  error: Program not found\n\n  The program `git` was not found. Is it installed?\n\n  Documentation for installing Git can be viewed here:\n  https://git-scm.com/book/en/v2/Getting-Started-Installing-Git\n  ```\n\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n### Language server\n\n- The language server can now offer a code action to merge case clauses with\n  the same body. For example:\n\n  ```gleam\n  case user {\n    Admin(name:, ..) -> todo\n  //^^^^^^^^^^^^^^^^^^^^^^^^\n    Guest(name:, ..) -> todo\n  //^^^^^^^^^^^^^^^^ Selecting these two branches you can\n  //                 trigger the \"Merge case branches\" code action\n    _ -> todo\n  }\n  ```\n\n  Triggering the code action would result in the following code:\n\n  ```gleam\n  case user {\n    Admin(name:, ..) | Guest(name:, ..) -> todo\n    _ -> todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"generate function\" code action can now pick better names for arguments\n  that use the record access syntax. For example:\n\n  ```gleam\n  pub type User {\n    User(id: Int, name: String)\n  }\n\n  pub fn go(user: User) {\n    authenticate(user.id, user.name)\n    todo\n  }\n  ```\n\n  Having the language server generate the missing `authenticate` function will\n  produce the following code:\n\n  ```gleam\n  pub fn authenticate(id: Int, name: String) {\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"inline variable\" code action can now trigger when used over the `let`\n  keyword of a variable to inline.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"add omitted labels\" code action can now be used in function calls where\n  some of the labels have been provided already.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"generate function\" code action can now trigger when used over constant\n  values as well.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Grouping of related diagnostics should now work across more editors.\n  Warnings will display together with their hints and you no longer have\n  \"go to next diagnostic\" twice in a row. Zedlings rejoice!\n  ([fruno](https://github.com/fruno-bulax/))\n\n- The \"pattern match on variable\" code action can now pick better names when\n  used on tuples.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- When renaming, if the new name is invalid, the language server will produce an\n  error message instead of silently doing nothing.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- When providing autocomplete suggestions, the language server will now\n  prioritise values which match the expected type of the value being completed.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now offers code action to add type annotations to all\n  functions and constants. For example,\n\n  ```gleam\n  pub const answer = 42\n\n  pub fn add(x, y) {\n    x + y\n  }\n\n  pub fn add_one(thing) {\n    //     ^ Triggering \"Annotate all top level definitions\" code action here\n    let result = add(thing, 1)\n    result\n  }\n  ```\n\n  Triggering the \"Annotate all top level definitions\" code action over\n  the name of function `add_one` would result in following code:\n\n  ```gleam\n  pub const answer: Int = 42\n\n  pub fn add(x: Int, y: Int) -> Int {\n    x + y\n  }\n\n  pub fn add_one(thing: Int) -> Int {\n    let result = add(thing, 1)\n    result\n  }\n  ```\n\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- Qualify and unqualify code actions can now trigger when used over constant\n  values as well.\n  ([Vladislav Shakitskiy](https://github.com/vshakitskiy))\n\n### Formatter\n\n### Bug fixes\n\n- Fixed two bugs that made gleam not update the manifest correctly, causing\n  it to hit hex for version resolution on every operation and quickly reach\n  request limits in large projects.\n  ([fruno](https://github.com/fruno-bulax/))\n\n- Fixed a bug where renaming a variable from an alternative pattern would not\n  rename all its occurrences.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now reports an error for literal floats that are outside the\n  floating point representable range on both targets. Previously it would only\n  do that when compiling on the Erlang target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a typo in the error message emitted when trying to run a module that\n  does not have a main function.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the \"Generate function\" code action would be incorrectly\n  offered when calling a function unsupported by the current target, leading to\n  invalid code if the code action was accepted.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the formatter would not remove the right number of double\n  negations from literal integers.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a typo for the \"Invalid number of patterns\" error.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a stack overflow when type checking some case expressions with\n  thousands of branches.\n  ([fruno](https://github.com/fruno-bulax/))\n\n- The \"add omitted label\" code action no longer adds labels to arguments\n  being piped in or the callbacks of `use`.\n  ([fruno](https://github.com/fruno-bulax))\n\n- Fixed a bug that caused the compiler to incorrectly optimise away runtime\n  size checks in bit array patterns on the javascript target if they used\n  calculations in the size of a segment (`_:size(wibble - wobble)`).\n  ([fruno](https://github.com/fruno-bulax/))\n\n- Add a missing BitArray constructor return type in the prelude's TypeScript\n  definitions.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where the BEAM would be shut down abruptly once the program had\n  successfully finished running.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the \"pattern match on variable\" code action would generate\n  invalid code when applied on a list's tail.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the \"pattern match on variable\" code action would generate\n  invalid patterns by repeating a variable name already used in the same\n  pattern.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the \"generate function\" code action would pop up for\n  variants.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where useless comparison warnings for floats compared literal\n  strings, claiming for example that `1.0 == 1.` was always false.\n  ([fruno](https://github.com/fruno-bulax/))\n\n- Fixed a bug where pattern variables in case clause guards would incorrectly\n  shadow outer scope variables in other branches when compiling to JavaScript.\n  ([Elias Haider](https://github.com/EliasDerHai))\n\n- Fix invalid TypeScript definition being generated for variant constructors\n  with long names that take no arguments.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where the formatter would remove the `@deprecated` attribute from\n  constants.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where invalid code would be generated on the JavaScript target in\n  cases where an underscore followed the decimal point in a float literal.\n  ([Patrick Dewey](https://github.com/ptdewey))\n\n- Typos in the error message shown when trying to install a non-existent package\n  have been fixed.\n  ([Ioan Clarke](https://github.com/ioanclarke))\n\n- Fixed a bug where the compiler would generate invalid Erlang and TypeScript\n  code for unused opaque types referencing private types.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the type checker would allow invalid programs when a large\n  group of functions were all mutually recursive.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler now provides a clearer error message when a function's return\n  type is mistakenly declared using `:` instead of `->`.\n  ([Gurvir Singh](https://github.com/baraich))\n\n- Fixed a bug where the data generated for searching documentation was in the\n  wrong format, preventing it from being used by Hexdocs search.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the \"collapse nested case\" code action would produce invalid\n  code on a list tail pattern.\n  ([Matias Carlander](https://github.com/matiascr))\n\n- Fixed two bugs that made gleam not update the manifest correctly, causing\n  it to hit hex for version resolution on every operation and quickly reach\n  request limits in large projects.\n  ([fruno](https://github.com/fruno-bulax/))\n"
  },
  {
    "path": "changelog/v1.15.md",
    "content": "# Changelog\n\n## v1.15.0 - 2026-03-16\n\n- Fixed a bug where the language server wouldn't show the correct hover for some\n  patterns.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.15.0-rc2 - 2026-03-16\n\n### Bug fixes\n\n- Marked the `bitSize` and `bitOffset` fields of `BitArray$BitArray` TypeScript\n  definition as optional.\n  ([acandoo](https://github.com/acandoo))\n\n- Fixed invalid JavaScript code generation when ints or floats had prefixed `0`s\n  before and after an `_` (e.g. `000_001`).\n  ([Gavin Morrow](https://github.com/gavinmorrow))\n\n## v1.15.0-rc1 - 2026-03-04\n\n### Compiler\n\n- The compiler now reports an error when int and float binary operators are\n  used incorrectly in case expression guards.\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n- The compiler now supports string concatenation in clause guards:\n\n  ```gleam\n  case message {\n    #(version, action) if version <> \":\" <> action == \"v1:delete\" ->\n      handle_delete()\n    _ -> ignore()\n  }\n  ```\n\n  ([Adi Salimgereyev](https://github.com/abs0luty))\n\n- Improved the code generated on the Erlang target when dividing a `Float`\n  number by the literal number `0.0`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler no longer shows the structure of internal types when displaying\n  an \"Inexhaustive patterns\" error, making it harder to inadvertently rely on\n  internal implementation details.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The JavaScript prelude TypeScript API now contains the `BitArray$isBitArray`\n  and `BitArray$BitArray$data` functions.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The type-checking JavaScript functions for Gleam data structure now use the\n  `value is TypeName` TypeScript return type rather than `boolean`.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The compiler now shows better error message on passing unexpected labeled\n  arguments by taking into account, whether it's a function or a constructor.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n### Build tool\n\n- Upgraded `actions/checkout` from v4 to v6 in the GitHub Actions workflow used\n  by `gleam new`.\n  ([Christian Widlund](https://github.com/chrillep))\n\n- When adding a package that does not exist on Hex, the message is a bit\n  friendlier.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The `gleam.toml` format is now consistent. The two sausage-case fields\n  (`dev-dependencies` and `tag-prefix`) have been replaced by snake_case\n  versions. Files using the old names will continue to work.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The password used for encrypting new local Hex API keys must now be at least\n  8 characters in length.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The `gleam help add`, `gleam help deps`, and `gleam help docs` commands have\n  been improved with much more detailed documentation output.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- When attempting to publish a package on Hex with an already taken name,\n  the message is clearer.\n  ([vyacheslavhere](https://github.com/vyacheslavhere))\n\n- The build tool will now refuse to publish any package that has the default\n  README generated by the `gleam new` command.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The build tool now uses OAuth and time-based one-time-passwords for\n  authentication with Hex, improving security.\n  Any legacy API tokens previously stored will be revoked after authenticating\n  using OAuth.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The build tool will now refuse to publish any package that has no README, or\n  an empty README.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Language server\n\n- The language server now allows extracting the start of a pipeline into a\n  variable.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now shows hover information when hovering over custom type\n  definitions.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now shows hover information when hovering over a custom\n  type's constructors.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server is now smarter when producing autocompletions. Imagine\n  you're updating your code to fully qualify the uses of the `Json` type:\n\n  ```gleam\n  pub fn payload() -> js|Json\n  //                    ^ typing the module name\n  ```\n\n  Accepting the `json.Json` completion will now produce the correct `json.Json`\n  annotation rather than generating invalid code: `json.JsonJson`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests completions for keywords like `echo`,\n  `panic`, and `todo`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"Add missing patterns\" code action will insert a catch all pattern for\n  internal types, making it harder to inadvertently rely on internal\n  implementation details.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server will no longer show completions for the fields of internal\n  types outside the module they're defined in, making it harder to inadvertently\n  rely on internal implementation details.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a quick-fix code action for when a custom type\n  definition uses a type parameter in its variants that have not been declared in\n  its header.\n  ([Andi Pabst](https://github.com/andipabst))\n\n- The `Extract function` code action now provides more ergonomic/idiomatic\n  refactorings when used on anonymous functions.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- It's now possible to find references and rename variables in string prefix\n  patterns.\n\n  ```gleam\n  case wibble {\n    \"1\" as digit <> rest -> digit <> rest\n    //     ^^^^^    ^^^^\n    // You can now trigger \"Find references\" and \"Rename\" from here\n  }\n  ```\n\n  ([Igor Castejón](https://github.com/IgorCastejon))\n\n- The language server now offers a rename for module when the cursor is placed\n  over its import statement or when placed on its name or alias somewhere. For\n  example,\n\n  ```gleam\n  import lustre/element\n  import lustre/element/html\n  import lustre/event\n\n  fn view(model: Int) -> element.Element(Msg) {\n    //                     ^  Renaming module to `el` here\n    let count = int.to_string(model)\n\n    html.div([], [\n      html.button([event.on_click(Incr)], [element.text(\" + \")]),\n      html.p([], [element.text(count)]),\n      html.button([event.on_click(Decr)], [element.text(\" - \")]),\n    ])\n  }\n  ```\n\n  Using renaming when hovering on module name will would result in the\n  following code:\n\n  ```gleam\n  import lustre/element as el\n  import lustre/element/html\n  import lustre/event\n\n  fn view(model: Int) -> el.Element(Msg) {\n    let count = int.to_string(model)\n\n    html.div([], [\n      html.button([event.on_click(Incr)], [el.text(\" + \")]),\n      html.p([], [el.text(count)]),\n      html.button([event.on_click(Decr)], [el.text(\" - \")]),\n    ])\n  }\n  ```\n\n  ([Vladislav Shakitskiy](https://github.com/vshakitskiy))\n\n- The \"Fill labels\" code action now uses variables from scope when they match\n  the label name and expected type, using shorthand syntax (`name:`) instead of\n  `name: todo`.\n\n  ([Vladislav Shakitskiy](https://github.com/vshakitskiy))\n\n- The \"Interpolate String\" code action now lets the user \"cut out\" any portion\n  of a string, regardless of whether it is a valid Gleam identifier or not.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- When interpolating an expression at the very start or the very end\n  of a string, redundant empty strings are no longer added before/after the\n  interpolated expression.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- The language server now performs best-effort zero value generation for\n  `decode.failure` when using the `Generate Dynamic Decoder` code action.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- The `Generate Dynamic Decoder` and `Generate To-JSON Function` code action\n  now generate a decoder and an encoder, respectively, for `Nil` values.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- The language server now supports renaming, go to definition, hover, and\n  finding references from expressions in case clause guards.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now supports `textDocument/foldingRange`, enabling\n  folding for contiguous import blocks and multiline top-level definitions such\n  as function bodies, custom types, constants, and type aliases.\n\n  For example, this import block:\n\n  ```gleam\n  import gleam/int\n  import gleam/list\n  import gleam/string\n  ```\n\n  can now be folded in the editor to:\n\n  ```gleam\n  import gleam/int ...\n  ```\n\n  ([Aayush Tripathi](https://github.com/aayush-tripathi))\n\n- The function signature helper now displays original function definition\n  generic names when arguments are unbound. For example, in this code:\n\n  ```gleam\n  pub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\n\n  pub fn main() {\n      wibble( )\n          // ↑\n  }\n  ```\n\n  will show a signature help\n\n  ```gleam\n  wibble(something, fn() -> something, anything)\n\n  ```\n\n  instead of\n\n  ```gleam\n  wibble(a, fn() -> a, b) -> Nil\n  ```\n\n  ([Samuel Cristobal](https://github.com/scristobal))\n\n### Formatter\n\n- The formatter no longer wraps multiple tuple or field access into a block.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- The compiler now emits correctly-scoped JavaScript code for `case` expressions\n  whose subjects directly match one of the branches.\n  ([Justin Lubin](https://github.com/justinlubin))\n\n- Fixed a bug where some bit array patterns would erroneously be marked as\n  unreachable.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the Gleam standard library's `dict.each` function would\n  incorrectly be assumed to be pure.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now correctly tracks the minimum required version for constant\n  record updates to be `>= 1.14.0`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now correctly tracks the minimum required version for\n  expressions in `BitArray`s' `size` option to be `>= 1.12.0`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the formatter would not properly format some function calls\n  if the last argument was followed by a trailing comment.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would generate invalid code on the JavaScript\n  target when using a `case` expression as the right hand side of an equality\n  check in an `assert`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would generate invalid code on the JavaScript\n  target for some `case` expressions using clause guards.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The formatter no longer stack overflows trying to format lists with many\n  items.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the formatter would not be able to consistently format a\n  constant list with an `@internal` attribute.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The \"convert to pipe\" code action now works on nested function calls as well,\n  rather than always being applied to the outermost one.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would not detect and reject duplicate modules\n  in a project's dependencies.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server no longer shows completions when typing a number.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server no longer recommends the deprecated `@target` attribute.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- The compiler no longer crashes when trying to pattern match on a\n  `UtfCodepoint`.\n  ([Hari Mohan](https://github.com/seafoamteal))\n\n- Fixed a bug that would result in not being able to rename an aliased pattern.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed JavaScript codegen bug for `assert` when using `&&` with comparison\n  operators on the right side.\n  ([vyacheslavhere](https://github.com/vyacheslavhere))\n\n- Added an error message when attempting to update packages that are not\n  dependencies of the project, instead of failing silently.\n  ([Etienne Boutet](https://github.com/EtienneBoutet),\n  [Vladislav Shakitskiy](https://github.com/vshakitskiy))\n\n- The build tool now doesn't perform code generation when exporting package\n  interface.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- The \"Extract constant\" code action now correctly places new constant when\n  function has documentation. For example,\n\n  ```gleam\n  /// Wibble does some wobbling\n  pub fn wibble() {\n    let x = \"wobble\"\n    //  ^ Trigger \"Extract constant\" here\n    x\n  }\n  ```\n\n  Previously, it would incorrectly place it below doc comment:\n\n  ```gleam\n  /// Wibble does some wobbling\n  const x = \"wobble\"\n\n  pub fn wibble() {\n    x\n  }\n  ```\n\n  Now it will correctly place constant above doc comment:\n\n  ```gleam\n  const x = \"wobble\"\n\n  /// Wibble does some wobbling\n  pub fn wibble() {\n    x\n  }\n  ```\n\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- Fixed a bug where renaming would not work properly if there was an error in\n  target file.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where generics in custom types would not be properly generated\n  when emitting TypeScript declarations.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where dev dependencies would be compiled and included in\n  production builds such as `gleam export erlang-shipment`.\n  ([John Downey](https://github.com/jtdowney))\n\n- Fixed a bug where the package cache would not properly be reset when a version\n  of a package was replaced on Hex.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a crash (`bad_generator`) that could occur when a linked OTP process\n  exits with a non-standard exit reason.\n  ([John Downey](https://github.com/jtdowney))\n\n- Fixed a bug where diagnostic about incorrect `size` and `unit` options would\n  use incorrect error location.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- `gleam add` now adds correct constraints for pre-release versions.\n  ([Andrey Kozhev](https://github.com/ankddev))\n\n- Fixed a bug where changes to a path dependency's own dependencies were not\n  detected when rebuilding the root project, causing the compiler to report\n  errors about missing modules.\n  ([daniellionel01](https://github.com/daniellionel01))\n\n- Fixed a bug where the compiler would crash when type-checking record\n  updates if the constructor definition has a positional field defined after\n  labelled fields.\n  ([Hari Mohan](https://gituhub.com/seafoamteal))\n"
  },
  {
    "path": "changelog/v1.2.md",
    "content": "# Changelog\n\n## v1.2.0 - 2024-05-27\n\n## v1.2.0-rc2 - 2024-05-27\n\n### Bug fixes\n\n- Fixed a bug where the formatter would incorrectly move comments at the start\n  of an anonymous function to the end of the arguments.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Fixed a bug where the formatter would not indent a multiline function used\n  in a pipeline.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would raise a warning for matching on a literal\n  value if the case expression is used just for its guards.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where not all the analysis errors would be presented to the\n  programmer. ([Louis Pilfold](https://github.com/lpil))\n\n## v1.2.0-rc1 - 2024-05-23\n\n### Build tool\n\n- A helpful error message is now shown if the `manifest.toml` file has been\n  edited to be invalid in some way.\n\n  ```\n  error: Corrupt manifest.toml\n\n  The `manifest.toml` file is corrupt.\n\n  Hint: Please run `gleam update` to fix it.\n  ```\n\n  ([zahash](https://github.com/zahash))\n\n- The error message shown when unable to find package versions that satisfy all\n  the version constraints specified for a project's dependencies has been\n  greatly improved.\n\n  ```\n  error: Dependency resolution failed\n\n  An error occurred while determining what dependency packages and\n  versions should be downloaded.\n  The error from the version resolver library was:\n\n  Unable to find compatible versions for the version constraints in your\n  gleam.toml. The conflicting packages are:\n\n  - hellogleam\n  - lustre_dev_tools\n  - glint\n  ```\n\n  ([zahash](https://github.com/zahash))\n\n- A link to the package on Hex is no longer auto-added to the HTML documentation\n  when building them locally. It is still added when publishing to Hex.\n  ([Pi-Cla](https://github.com/Pi-Cla))\n\n- An error is now emitted when compiling to Erlang and there is a Gleam module\n  that would overwrite a built-in Erlang/OTP module, causing cryptic errors and\n  crashes.\n  ([Louis Pilfold](https://github.com/lpil))\n\n  ```\n  error: Erlang module name collision\n\n  The module `src/code.gleam` compiles to an Erlang module named `code`.\n\n  By default Erlang includes a module with the same name so if we were to\n  compile and load your module it would overwrite the Erlang one, potentially\n  causing confusing errors and crashes.\n\n  Hint: Rename this module and try again.\n  ```\n\n- New subcommand `gleam hex revert` added.\n\n  - You can specify the options like this:\n    `gleam hex revert --package gling --version 1.2.3`\n  - A new package can be reverted or updated within 24 hours of it's initial\n    publish, a new version of an existing package can be reverted or updated\n    within one hour.\n  - You could already update packages even before this release by running:\n    `gleam publish` again.\n\n  ([Pi-Cla](https://github.com/Pi-Cla))\n\n- When the user tries to replace a release without the `--replace` flag\n  the error message now mentions the lack of a `--replace` flag.\n\n  ```\n  error: Version already published\n\n  Version v1.0.0 has already been published.\n  This release has been recently published so you can replace it\n  or you can publish it using a different version number\n\n  Hint: Please add the --replace flag if you want to replace the release.\n  ```\n\n  ([Pi-Cla](https://github.com/Pi-Cla))\n\n### Compiler\n\n- The compiler will now raise a warning for `let assert` assignments where the\n  assertion is redundant.\n\n  ```\n  warning: Redundant assertion\n    ┌─ /home/lucy/src/app/src/app.gleam:4:7\n    │\n  4 │   let assert x = get_name()\n    │       ^^^^^^ You can remove this\n\n  This assertion is redundant since the pattern covers all possibilities.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Empty case expressions are no longer parse errors and will instead be\n  exhaustiveness errors.\n  ([Race Williams](https://github.com/raquentin))\n\n- Improve error message if importing type using the value import syntax or vice\n  versa.\n\n  ```\n  error: Unknown module field\n    ┌─ /src/one/two.gleam:1:19\n    │\n  1 │ import gleam/one.{One}\n    │                   ^^^ Did you mean `type One`?\n\n  `One` is only a type, it cannot be imported as a value.\n  ```\n\n  ```\n  error: Unknown module type\n    ┌─ /src/one/two.gleam:1:19\n    │\n  1 │ import gleam/two.{type Two}\n    │                   ^^^^^^^^ Did you mean `Two`?\n\n  `Two` is only a value, it cannot be imported as a type.\n  ```\n\n  ([Pi-Cla](https://github.com/Pi-Cla/))\n\n- The compiler will now raise a warning when you try to use `todo` or `panic` as\n  if they were functions: this could previously lead to a confusing behaviour\n  since one might expect the arguments to be printed in the error message.\n  The error message now suggests the correct way to add an error message to\n  `todo` and `panic`.\n\n  ```\n  warning: Todo used as a function\n    ┌─ /src/warning/wrn.gleam:2:16\n    │\n  2 │           todo(1)\n    │                ^\n\n  `todo` is not a function and will crash before it can do anything with\n  this argument.\n\n  Hint: if you want to display an error message you should write\n  `todo as \"my error message\"`\n  See: https://tour.gleam.run/advanced-features/todo/\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Improve error message when something that is not a function appears on the\n  right hand side of `<-` in a `use` expression.\n\n  ```txt\n  error: Type mismatch\n    ┌─ /src/one/two.gleam:2:8\n    │\n  2 │ use <- 123\n    │        ^^^\n\n  In a use expression, there should be a function on the right hand side of\n  `<-`, but this value has type:\n\n      Int\n\n  See: https://tour.gleam.run/advanced-features/use/\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Improve error message when a function with the wrong number of arguments\n  appears on the right hand side of `<-` in a `use` expression.\n\n  ```txt\n  error: Incorrect arity\n    ┌─ /src/one/two.gleam:3:8\n    │\n  3 │ use <- func\n    │        ^^^^ Expected no arguments, got 1\n\n  The function on the right of `<-` here takes no arguments.\n  But it has to take at least one argument, a callback function.\n\n  See: https://tour.gleam.run/advanced-features/use/\n  ```\n\n  ```txt\n  error: Incorrect arity\n    ┌─ /src/one/two.gleam:3:8\n    │\n  3 │ use <- f(1, 2)\n    │        ^^^^^^^ Expected 2 arguments, got 3\n\n  The function on the right of `<-` here takes 2 arguments.\n  All the arguments have already been supplied, so it cannot take the\n  `use` callback function as a final argument.\n\n  See: https://tour.gleam.run/advanced-features/use/\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Improve error message when the callback function of a `use` expression returns\n  a value with the wrong type.\n  Now the error will point precisely to the last statement and not complain\n  about the whole block saying it has the wrong function type.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler will now raise a warning when pattern matching on a literal value\n  like a list, a tuple, integers, strings, etc.\n\n  ```\n  warning: Redundant list\n    ┌─ /src/warning/wrn.gleam:2:14\n    │\n  2 │         case [1, 2] {\n    │              ^^^^^^ You can remove this list wrapper\n\n  Instead of building a list and matching on it, you can match on its\n  contents directly.\n  A case expression can take multiple subjects separated by commas like this:\n\n      case one_subject, another_subject {\n        _, _ -> todo\n      }\n\n  See: https://tour.gleam.run/flow-control/multiple-subjects/\n  ```\n\n  ```\n  warning: Match on a literal value\n    ┌─ /src/warning/wrn.gleam:4:8\n    │\n  4 │   case 1 {\n    │        ^ There's no need to pattern match on this value\n\n  Matching on a literal value is redundant since you can already tell which\n  branch is going to match with this value.\n\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler will now continue module analysis when there are errors in top\n  level definitions. This means that when these errors occur the compiler will\n  continue analysing the rest of the code to find other errors and type\n  information.\n\n  When using the build tool this means that the programmer will be shown\n  multiple error messages when there are multiple problems in a module.\n\n  When using the language server multiple error diagnostics will be shown, and\n  the compiler will get updated type information about the code even when there\n  are errors. This should improve the accuracy of feedback and suggestions from\n  the language server as its information about the code will be more up-to-date.\n  ([Ameen Radwan](https://github.com/Acepie)) and\n  ([Louis Pilfold](https://github.com/Acepie))\n\n- An informative error message is now emitted when attempting to use a function\n  from another module in a constant expression. Previously this would result in\n  a cryptic parse error.\n\n  ```\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:3:18\n    │\n  3 │ const wib: Int = wibble(1, \"wobble\")\n    │                  ^^^^^^^ Functions can only be called within other functions\n  ```\n\n  ([Nino Annighoefer](https://github.com/nino))\n\n- The compiler will now provide more helpful error messages when triple equals\n  are used instead of double equals.\n\n  ```\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:4:37\n    │\n  4 │   [1,2,3] |> list.filter(fn (a) { a === 3 })\n    │                                     ^^^ Did you mean `==`?\n\n  Gleam uses `==` to check for equality between two values.\n  See: https://tour.gleam.run/basics/equality\n  ```\n\n  ([Rabin Gaire](https://github.com/rabingaire))\n\n- The compiler will now raise a warning for unreachable code that comes after\n  a panicking expression.\n\n  ```\n  pub fn main() {\n    panic\n    \"unreachable!\"\n  }\n  ```\n\n  ```\n  warning: Unreachable code\n    ┌─ /src/warning/wrn.gleam:3:11\n    │\n  3 │    \"unreachable!\"\n    │    ^^^^^^^^^^^^^^\n\n  This code is unreachable because it comes after a `panic`.\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- JavaScript external module names may now include the character `@`.\n  ([Louis Pilfold](https://github.com/lpil))\n\n### Formatter\n\n- Redundant alias names for imported modules are now removed.\n\n  ```gleam\n  import gleam/result as result\n  ```\n\n  is formatted to\n\n  ```gleam\n  import gleam/result\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Comments are no longer moved out of constant lists, constant tuples and empty\n  tuples. You can now write this:\n\n  ```gleam\n  const values = [\n    // This is a comment!\n    1, 2, 3\n    // Another comment...\n    11,\n    // And a final one.\n  ]\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Comments at the end of an anonymous function are no longer moved out of it.\n  You can now write this:\n\n  ```gleam\n  fn() {\n    todo\n    // A comment here!\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Pipes can now be placed on a single line if they are short enough:\n\n  ```gleam\n  [1, 2, 3] |> list.map(int.to_string) |> string.join(with: \"\\n\")\n  ```\n\n  In addition you can also force the formatter to break a pipe on multiple lines\n  by manually breaking it. This:\n\n  ```gleam\n  [1, 2, 3]\n  // By putting a newline here I'm telling the formatter to split the pipeline\n  |> list.map(int.to_string) |> string.join(with: \"\\n\")\n  ```\n\n  Will turn into this:\n\n  ```gleam\n  [1, 2, 3]\n  |> list.map(int.to_string)\n  |> string.join(with: \"\\n\")\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Comments appearing after arguments are no longer moved to a different place.\n  You can now write all of those:\n\n  ```gleam\n  type Record {\n    Record(\n      field: String,\n      // comment_line_1: String,\n      // comment_line_2: String,\n    )\n  }\n  ```\n\n  ```gleam\n  pub fn main() {\n    fn(\n      a,\n      // A comment 2\n    ) {\n      1\n    }\n  }\n  ```\n\n  ```gleam\n  fn main() {\n    let triple = Triple(1, 2, 3)\n    let Triple(\n      a,\n      ..,\n      // comment\n    ) = triple\n    a\n  }\n  ```\n\n  ```gleam\n  type Record {\n    Record(\n      // comment_line_1: String,\n      // comment_line_2: String,\n    )\n  }\n  ```\n\n  ([Mateusz Ledwoń](https://github.com/Axot017))\n\n### Language Server\n\n- The code action to remove unused imports now removes the entire line is\n  removed if it would otherwise be left blank.\n  ([Milco Kats](https://github.com/katsmil))\n\n- Hover for type annotations is now separate from the thing being annotated.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Go to definition now works for direct type annotations.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Go to definition now works for import statements.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Hover now works for unqualified imports.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The language server now detects when the `gleam.toml` config file has changed\n  even if the client does not support watching files. This means that changes to\n  the default target, new dependencies, and other configuration will be\n  automatically detected.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Completions are now provided for values and types for use in unqualified\n  imports.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The character `.` is now advertised as a completion trigger character.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- A new code action has been added to remove redundant tuples around case\n  expression subjects and patterns when possible.\n  ([Nicky Lim](https://github.com/nicklimmm))\n\n  ```\n  case #(x, y) {\n    #(1, 2) -> 0\n    #(_, _) -> 1\n  }\n  ```\n\n  Is rewritten to:\n\n  ```\n  case x, y {\n    1, 2 -> 0\n    _, _ -> 1\n  }\n  ```\n\n- The language server will now register information about code even when there\n  was a type error or similar. This means that the language server will be able\n  to produce some up-to-date information about the project, even when errors are\n  present. This should greatly improve the experience using the language server.\n  ([Louis Pilfold](https://github.com/lpil))\n\n### Bug Fixes\n\n- Fixed [RUSTSEC-2021-0145](https://rustsec.org/advisories/RUSTSEC-2021-0145) by\n  using Rust's `std::io::IsTerminal` instead of the `atty` library.\n  ([Pi-Cla](https://github.com/Pi-Cla))\n\n- Fixed the generated `mod` property in the Erlang application file when using\n  the `application_start_module` property in `gleam.toml`.\n  ([Alex Manning](https://github.com/rawhat))\n\n- Fixed a confusing error message when using some reserved keywords.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed variables in constant expressions not being escaped correctly when\n  exporting to JavaScript.\n  ([PgBiel](https://github.com/PgBiel))\n\n- Fixed a typo when attempting to publish a package with non-Hex dependencies\n  ([inoas](https://github.com/inoas))\n\n- Fixed import completions not appearing in some editors due to the range being\n  longer than the line.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Fixed a bug where TypeScript definitions files would use `null` instead of\n  `undefined`.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where unreachable infinite cases would not be detected when\n  after a discard or variable pattern.\n  ([Ameen Radwan](https://github.com/Acepie)) and\n  ([Pi-Cla](https://github.com/Pi-Cla))\n\n- Fixed a bug where module imports in guard clauses would not be generated\n  correctly for js target.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Fixed a bug where formatting constant lists of tuples would force the\n  tuples to be broken across multiple lines, even when they could fit on a\n  single line.\n  ([Isaac Harris-Holt](https://github.com/isaacharrisholt))\n\n- Fixed a bug where floating points in scientific notation with no trailing\n  zeros would generate invalid Erlang code.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where having utf8 symbols in `gleam.toml`'s description value\n  would result in an HTTP 500 error when running `gleam publish`.\n  ([inoas](https://github.com/inoas))\n\n- Unicode `\\u{}` syntax in bit_array string segments now produce valid Erlang\n  unicode characters ([Pi-Cla](https://github.com/Pi-Cla))\n\n- Fixed a bug where using a constant defined in another module that referenced\n  a private function could generate invalid code on the Erlang target.\n  ([Shayan Javani](https://github.com/massivefermion))\n\n- Fixed a bug where the language server would dynamically request the client to\n  watch files even when the client has stated it does not support that.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where local path dependencies could be mishandled on Windows.\n  ([Francisco Montanez](https://github.com/Francisco-Montanez))\n\n- Fixed a bug where adding a comment to a case clause would cause it to break\n  on multiple lines.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where pattern matching on a string prefix containing an escape\n  code could generate incorrect Erlang code.\n  ([Nashwan Azhari](https://github.com/aznashwan))\n\n- Fixed a bug where the formatter would produce uneven indentation within\n  multi-line comments at the bottom of case blocks.\n  ([Race Williams](https://github.com/raquentin))\n"
  },
  {
    "path": "changelog/v1.3.md",
    "content": "# Changelog\n\n## v1.3.0 - 2024-07-09\n\n## v1.3.0-rc3 - 2024-07-08\n\n- Fixed a bug where not all pure function calls in constant definitions would be\n  annotated as `@__PURE__` when compiling to JavaScript.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.3.0-rc2 - 2024-07-06\n\n### Formatter\n\n- Fixed a bug when multiple subjects in a case would be split even if not\n  necessary.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.3.0-rc1 - 2024-06-30\n\n### Build tool\n\n- `gleam remove` will now present an error if a package being removed does not\n  exist as a dependency in the project.\n  ([Changfeng Lou](https://github.com/hnlcf))\n\n- `gleam add` now takes an optional package version specifier,\n  separated by a `@`, that resolves as follows:\n\n  ```sh\n  gleam add lustre@1.2.3 # \"1.2.3\"\n  gleam add lustre@1.2   # \">= 1.2.0 and < 2.0.0\"\n  gleam add lustre@1     # \">= 1.0.0 and < 2.0.0\"\n  ```\n\n  ([Rahul D. Ghosal](https://github.com/rdghosal))\n\n### Compiler\n\n- Added more an informative error message for when attempting to use the `..`\n  syntax to append to a list rather than prepend.\n\n  ```\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:4:14\n    │\n  4 │         [..rest, last] -> 1\n    │          ^^^^^^ I wasn't expecting elements after this\n\n  Lists are immutable and singly-linked, so to match on the end\n  of a list would require the whole list to be traversed. This\n  would be slow, so there is no built-in syntax for it. Pattern\n  match on the start of the list instead.\n  ```\n\n  ([Antonio Iaccarino](https://github.com/eingin))\n\n- The compiler now emits a warning for redundant function captures in a\n  pipeline:\n\n  ```\n  warning: Redundant function capture\n    ┌─ /src/warning/wrn.gleam:5:17\n    │\n  5 │     1 |> wibble(_, 2) |> wibble(2)\n    │                 ^ You can safely remove this\n\n  This function capture is redundant since the value is already piped as the\n  first argument of this call.\n\n  See: https://tour.gleam.run/functions/pipelines/\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The syntax `[a..b]` is now deprecated in favour of the `[a, ..b]` syntax.\n  This was to avoid it being mistaken for a range syntax, which Gleam does\n  not have.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Functions etc named `maybe` are now escaped in generated Erlang as it is now a\n  reserved word in Erlang/OTP 27.\n  ([Jake Barszcz](https://github.com/barszcz))\n\n- Functions, types and constructors named `maybe` and `else` are now\n  escaped in generated Erlang to avoid clashing with Erlang's keywords.\n  ([Jake Barszcz](https://github.com/barszcz)) and\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Non byte aligned arrays that use literals for size are now marked as an\n  Unsupported feature for Javascript since they would already cause\n  a runtime error on Javascript.\n\n  This means if you compile specifically for Javascript you will now receive\n  this error:\n\n  ```\n  error: Unsupported feature for compilation target\n    ┌─ /src/test/gleam_test.gleam:6:5\n    │\n  6 │   <<1:size(5)>>\n    │     ^^^^^^^^^\n\n  Non byte aligned array is not supported for JavaScript compilation.\n  ```\n\n  Else any functions which rely on this will not be compiled into Javascript.\n  ([Pi-Cla](https://github.com/Pi-Cla))\n\n- Compilation fault tolerance is now at a statement level instead of a function\n  level. This means that the compiler will attempt to infer the rest of the\n  statements in a function when there is an error in a previous one.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The JavaScript prelude is no-longer rewritten each time a project is compiled\n  to JavaScript.\n  ([Ofek Doitch](https://github.com/ofekd))\n\n- Compiler now supports arithmetic operations in guards.\n  ([Danielle Maywood](https://github.com/DanielleMaywood))\n\n- Import cycles now show the location where the import occur.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Error messages resulting from unexpected tokens now include information on\n  the found token's type. This updated message explains how the lexer handled\n  the token, so as to guide the user towards providing correct syntax.\n\n  Following is an example, where the error message indicates that the name of\n  the provided field conflicts with a keyword:\n\n  ```\n  3 │     A(type: String)\n    │       ^^^^ I was not expecting this\n\n  Found the keyword `type`, expected one of:\n  - `)`\n  - a constructor argument name\n  ```\n\n  ([Rahul D. Ghosal](https://github.com/rdghosal))\n\n- When compiling to JavaScript constants will now be annotated as `@__PURE__`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Formatter\n\n### Language Server\n\n- The language server will now suggest the \"Remove redundant tuple\" action even\n  if the case expression contains some catch all patterns:\n\n  ```\n  case #(a, b) {\n    #(1, 2) -> todo\n    _ -> todo\n  }\n  ```\n\n  Becomes:\n\n  ```\n  case a, b {\n    1, 2 -> todo\n    _, _ -> todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- LSP can now suggest completions for values and types from importable modules\n  and adds the import to the top of the file.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Diagnostics with extra labels now show the diagnostic in all locations\n  including across multiple files.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- LSP completions now use the \"text_edit\" language server API resulting in\n  better/more accurate insertions.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Completions are no longer provided inside comments.\n  ([Nicky Lim](https://github.com/nicklimmm))\n\n- The language server will now show all the ignored fields when hovering over\n  `..` in a record pattern.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug Fixes\n\n- Fixed a bug where the compiler would output a confusing error message when\n  trying to use the spread syntax to append to a list.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the formatter would strip empty lines out of the body of an\n  anonymous function passed as an argument.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would crash when a type was defined with\n  the same name as an imported type.\n  ([Gears](https://github.com/gearsdatapacks))\n\n- Fixed a bug where a horizontal scrollbar would appear on code blocks in built\n  documentation when they contained lines 79 or 80 characters long.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where importing a record constructor in an unqualified fashion and\n  aliasing it and then using it in a constant expression would generate invalid\n  JavaScript.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the compiler would crash because types weren't registered if\n  they referenced a non-existent type.\n  ([Gears](https://github.com/gearsdatapacks))\n\n- Fixed a bug where the compiler would generate invalid Erlang when pattern\n  matching on strings with an `as` pattern.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would warn that a module alias was unused when\n  it was only used in case patterns.\n  ([Michael Jones](https://github.com/michaeljones))\n\n## v1.2.1 - 2024-05-30\n\n### Bug Fixes\n\n- Fixed a bug where the compiler could fail to detect modules that would clash\n  with Erlang modules.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where dependency version resolution could crash for certain\n  release candidate versions.\n  ([Marshall Bowers](https://github.com/maxdeviant))\n\n- Fixed a bug where trailing comments would be moved out of a bit array.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n"
  },
  {
    "path": "changelog/v1.4.md",
    "content": "# Changelog\n\n## v1.4.0 - 2024-08-02\n\n### Bug Fixes\n\n- Fixed a bug where pipe function arity errors could have an incorrect error\n  message.\n  ([sobolevn](https://github.com/sobolevn))\n\n- Fixed a bug where the case of type parameters would not be checked.\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- Fixed a bug where the language server would still show completions when inside\n  a comment.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.4.0-rc1 - 2024-07-29\n\n### Build tool\n\n- `gleam docs build` now takes an optional `--target` flag to specify the target\n  platform for the generated documentation.\n  ([Jiangda Wang](https://github.com/frank-iii))\n\n- Warnings are now emitted each time the project is built, even if the module\n  the warnings originated from were loaded from the cache rather than\n  recompiling.\n  ([Louis Pilfold](https://github.com/lpil))\n\n### Compiler\n\n- Labelled arguments can now use the label shorthand syntax.\n  This means that when you're passing a variable as a labelled argument and it\n  happens to have the same name as the label, you can omit the variable name:\n\n  ```gleam\n  pub fn date(day day: Int, month month: Month, year year: Year) -> Date {\n    todo\n  }\n\n  pub fn main() {\n    let day = 11\n    let month = October\n    let year = 1998\n\n    date(year:, month:, day:)\n    // This is the same as writing\n    // date(year: year, month: month, day: day)\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Labelled pattern variables can now use the label shorthand syntax.\n  This means that when you're pattern matching on a record constructor and\n  binding its labelled fields to variables that happen to have the same name,\n  you can omit the variable name:\n\n  ```gleam\n  pub type Date\n    Date(day: Int, month: Month, year: Year)\n  }\n\n  pub fn main() {\n    case Date(11, October, 1998) {\n      Date(year:, month:, day:) -> todo\n      // This is the same as writing\n      // Date(year: year, month: month, day: day) -> todo\n    }\n\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The warning for the deprecated `[..]` pattern has been improved.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Record accessors are now fault tolerant. This means an invalid label can be\n  properly detected and won't invalidate the rest of the expression.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Erlang type spec generation has been improved to avoid new warnings emitted in\n  OTP27.\n  ([Damir Vandic](https://github.com/dvic))\n\n- Error messages for invalid record constructors now contain a restructured\n  example of what the user likely intended. This is especially helpful for\n  users coming from other languages, like Rust or Go.\n\n  For example, provided a User type:\n\n  ```gleam\n  pub type User {\n    name: String\n  }\n  ```\n\n  The compiler errors with the following message:\n\n  ```\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:3:5\n    │\n  3 │     name: String,\n    │     ^^^^ I was not expecting this\n\n  Each custom type variant must have a constructor:\n\n  pub type User {\n    User(\n      name: String,\n    )\n  }\n  ```\n\n  ([Rahul D. Ghosal](https://github.com/rdghosal))\n\n- The `<>` string concatenation operator can now be used in constant\n  expressions.\n  ([Thomas](https://github.com/DeviousStoat))\n\n- Function calls are now fault tolerant. This means that errors in the function\n  call arguments won't stop the rest of the call from being analysed.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The error message presented when a function is called in a guard has been\n  improved.\n  ([Thomas](https://github.com/DeviousStoat))\n\n- Case expressions are now fault tolerant. This means an subject, pattern,\n  guard, or then body can be properly detected and won't invalidate the rest\n  of the expression.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Documentation comments that come before a regular comment are no longer\n  clumped together with the documentation of the following definition.\n  Now commenting out a definition won't result in its documentation merging with\n  the following one's.\n\n  ```gleam\n  /// This doc comment will be ignored!\n  // a commented definition\n  // fn wibble() {}\n\n  /// Wibble's documentation.\n  fn wibble() { todo }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The `little` and `big` endianness options, the `signed` and `unsigned` integer\n  options, and sized floats (32-bit and 64-bit), can now be used in bit array\n  expressions and patterns on the JavaScript target.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- The `utf8` option can now be used with constant strings in bit array patterns\n  on the JavaScript target.\n  ([Richard Viney](https://github.com/richard-viney))\n\n### Formatter\n\n- The formatter will no longer move a documentation comment below a regular\n  comment following it. This snippet of code is left as it is by the formatter:\n\n  ```gleam\n  /// This doc comment will be ignored!\n  // a commented definition\n  // fn wibble() {}\n\n  /// Wibble's documentation.\n  fn wibble() {\n    todo\n  }\n  ```\n\n  While previously all documentation comments would be merged together into one,\n  ignoring the regular comment separating them:\n\n  ```gleam\n  // a commented definition\n  // fn wibble() {}\n\n  /// This doc comment will be ignored!\n  /// Wibble's documentation.\n  fn wibble() {\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Language Server\n\n- The language server can now show completions for fields if a record access is\n  being attempted.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The language server will now insert a blank line before the first statement\n  when inserting a new import and there are no other imports at the top of the\n  module.\n  ([Zhomart Mukhamejanov](https://github.com/Zhomart))\n\n- The language server now suggests a code a action to rename variables, types\n  and functions when they don't match the Gleam naming requirements:\n\n  ```gleam\n  let myNumber = 10\n  ```\n\n  Becomes:\n\n  ```gleam\n  let my_number = 10\n  ```\n\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- The language server can now suggest a code action to convert `let assert` into\n  a case expression:\n\n  ```gleam\n  let assert Ok(value) = get_result()\n  ```\n\n  Becomes:\n\n  ```gleam\n  let value = case get_result() {\n    Ok(value) -> value\n    _ -> panic\n  }\n  ```\n\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- The language server can now show signature help when writing functions.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now supports listing document symbols, such as functions\n  and constants, for the current Gleam file.\n  ([PgBiel](https://github.com/PgBiel))\n\n- The language server can now suggest a code action to automatically use\n  shorthand labels where possible:\n\n  ```gleam\n  case date {\n    Day(day: day, month: month, year: year) -> todo\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  case date {\n    Day(day:, month:, year:) -> todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server can now show completions for labels when writing a\n  function call or record construction.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- The language server can now suggest a code action to fill in the labels of a\n  function call:\n\n  ```gleam\n  pub type Date {\n    Date(year: Int, month: Int, day: Int)\n  }\n\n  pub fn main() {\n    Date()\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  pub type Date {\n    Date(year: Int, month: Int, day: Int)\n  }\n\n  pub fn main() {\n    Date(year: todo, month: todo, day: todo)\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Completions are now sorted by priority based on why the completion is in the\n  list. This means that more specific completions like labels and local\n  definitions will be shown before more broad completions like functions from a\n  not yet imported module.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n### Bug Fixes\n\n- Functions, types and constructors named `module_info` are now escaped\n  in generated Erlang code to avoid conflicts with the builtin\n  `module_info/0` and `module_info/1` functions.\n  ([Juraj Petráš](https://github.com/Hackder))\n\n- Fixed formatting of comments at the start of a case branch.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where a private type could be leaked from an internal module.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Fixed a bug where certain binops would not wrap their arguments properly\n  thus generating invalid JavaScript.\n  ([Ameen Radwan](https://github.com/Acepie))\n\n- Fixed formatting of function definitions marked as `@internal`\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where importing a record constructor in an unqualified fashion and\n  aliasing it and then using it in a case guard expression would generate\n  invalid JavaScript.\n  ([PgBiel](https://github.com/PgBiel))\n\n## v1.3.2 - 2024-07-11\n\n### Language Server\n\n- The language server no longer shows completions when inside a literal string.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug Fixes\n\n- Fixed a bug where the compiler would report errors for duplicate `@external`\n  attributes with inconsistent spans between Erlang and JavaScript.\n  ([Connor Szczepaniak](https://github.com/cszczepaniak))\n\n- Fixed a bug where `gleam add` would fail to parse version specifiers\n  correctly.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where single clause case expressions could generate JavaScript\n  code with incorrectly rewritten JavaScript variable names.\n  ([Louis Pilfold](https://github.com/lpil))\n\n## v1.3.1 - 2024-07-10\n\n### Bug Fixes\n\n- Fixes a bug with import cycle detection when there is more than 2 imports in\n  the cycle.\n  ([Ameen Radwan](https://github.com/Acepie))\n"
  },
  {
    "path": "changelog/v1.5.md",
    "content": "# Changelog\n\n## v1.5.0 - 2024-09-19\n\n## v1.5.0-rc2 - 2024-09-18\n\n### Bug Fixes\n\n- Fixed a bug where the formatter would not format nested tuple access properly.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where multi-variant custom type accessors wouldn't be properly\n  detected.\n  ([Louis Pilfold](https://github.com/lpil))\n\n\n## v1.5.0-rc1 - 2024-09-14\n\n### Build tool\n\n- The `--no-print-progress` flag has been added to prevent the build tool from\n  printing messages as the project is built.\n  ([Ankit Goel](https://github.com/crazymerlyn))\n\n- The compiler is now able to run a dependency's module using `gleam run -m`\n  even when there's compilation errors in your own project's code.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- HTML docs: make module names in sidebar wrap before a / when possible\n  ([Jiangda Wang](https://github.com/frank-iii))\n\n- The printing of runtime errors has been improved, including those from linked\n  processes.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- OTP application trees are now shut down gracefully when `main` exits.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The `gleam fix` command can now update a project's `gleam` version constraint\n  to make sure it respects the inferred minimum required version.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The build tool now refuses to publish a project where the `gleam` version\n  constraint would include a compiler version that doesn't support the features\n  used by the package.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- If a project doesn't specify a `gleam` version constraint, the build tool will\n  automatically infer it and add it to the project's `gleam.toml` before\n  publishing it.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Compiler\n\n- Compiler progress is now printed to stderr, instead of stdout.\n  ([Victor Kobinski](https://github.com/vkobinski))\n\n- It is now possible to omit the `:utf8` option for literal strings used in a\n  `BitArray` segment.\n\n  ```gleam\n  <<\"Hello\", \" \", \"world\">>\n  ```\n\n  Is the same as:\n\n  ```gleam\n  <<\"Hello\":utf8, \" \":utf8, \"world\":utf8>>\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- In inexhaustive pattern match errors the missing variants are now printed\n  using the correct syntax for the module the error is emitted in, rather than\n  the module it was defined in. For example, if you had this code:\n\n  ```gleam\n  import gleam/option\n\n  pub fn main() {\n    let an_option = option.Some(\"wibble!\")\n    case an_option {\n      option.None -> \"missing\"\n    }\n  }\n  ```\n\n  The error message would show the qualified `option.Some(_)` as the missing\n  pattern:\n\n  ```txt\n  error: Inexhaustive patterns\n    ┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:5:3\n    │\n  5 │ ╭   case an_option {\n  6 │ │     option.None -> \"missing\"\n  7 │ │   }\n    │ ╰───^\n\n  This case expression does not have a pattern for all possible values. If it\n  is run on one of the values without a pattern then it will crash.\n\n  The missing patterns are:\n\n      option.Some(_)\n  ```\n\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- Anonymous functions that are immediately called with a record or a tuple as an\n  argument are now inferred correctly without the need to add type annotations.\n  For example you can now write:\n\n  ```gleam\n  fn(x) { x.0 }(#(1, 2))\n  // ^ you no longer need to annotate this!\n  ```\n\n  ([sobolevn](https://github.com/sobolevn))\n\n- Anonymous functions that are being piped a record or a tuple as an argument\n  are now inferred correctly without the need to add type annotations. For\n  example you can now write:\n\n  ```gleam\n  pub type User {\n    User(name: String)\n  }\n\n  pub fn main() {\n    User(\"Giacomo\")\n    |> fn(user) { user.name }\n    //    ^^^^ you no longer need to annotate this!\n    |> io.debug\n  }\n  ```\n\n  ([sobolevn](https://github.com/sobolevn))\n\n- The record pattern matching syntax `Record(a ..)` is now deprecated in favour\n  of the `Record(a, ..)` syntax.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Adds a better error message when module names are used as values. For example\n  the following code:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    list\n  }\n  ```\n\n  Results in the error:\n\n  ```txt\n  error: Module `list` used as a value\n    ┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:4:3\n    │\n  4 │   list\n    │   ^^^^\n\n  Modules are not values, so you cannot assign them to variables, pass them to\n  functions, or anything else that you would do with a value.\n  ```\n\n  ([sobolevn](https://github.com/sobolevn))\n\n- An helpful error message has been added when the programmer attempts to write\n  a function within a custom type definition, likely trying to declare an OOP\n  class. For example:\n\n  ```gleam\n  pub type User {\n    User(name: String)\n\n    fn greet(user: User) -> String {\n      \"hello \" <> user.name\n    }\n  }\n  ```\n\n  Now results in the following error:\n\n  ```txt\n  error: Syntax error\n    ┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:8:3\n    │\n  8 │   fn greet(user: User) -> String {\n    │   ^^ I was not expecting this\n\n  Found the keyword `fn`, expected one of:\n  - `}`\n  - a record constructor\n  Hint: Gleam is not an object oriented programming language so\n  functions are declared separately from types.\n  ```\n\n  ([sobolevn](https://github.com/sobolevn))\n\n- The compiler now gives a hint to import a module when accessing modules that\n  aren't imported. It only suggests a module if it exports a type/value with\n  the same name as what the user was trying to access:\n\n  ```gleam\n  pub fn main() {\n    io.println(\"Hello, world!\")\n  }\n  ```\n\n  Produces the following error:\n\n  ```\n  error: Unknown module\n    ┌─ /src/file.gleam:2:3\n    │\n  2 │   io.println(\"Hello, world!\")\n    │   ^^\n\n  No module has been found with the name `io`.\n  Hint: Did you mean to import `gleam/io`?\n  ```\n\n  This code, however, produces no hint:\n\n  ```gleam\n  pub fn main() {\n    io.non_existent()\n  }\n  ```\n\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- The compiler now provides improved suggestions in the error for an\n  inexhaustive case expression. The following code:\n\n  ```gleam\n  let a = True\n  case a {}\n  ```\n\n  Now produces this error:\n\n  ```\n  error: Inexhaustive patterns\n    ┌─ /src/file.gleam:3:3\n    │\n  3 │   case a {}\n    │   ^^^^^^^^^\n\n  This case expression does not have a pattern for all possible values. If it\n  is run on one of the values without a pattern then it will crash.\n\n  The missing patterns are:\n\n      False\n      True\n  ```\n\n  Whereas before, it would suggest `_` as the only missing pattern.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Improve error message for using `@external` with unknown target\n  ([Jiangda Wang](https://github.com/frank-iii))\n\n- Improved error title when using an unknown module value.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now shows an helpful error message if you try writing an `if`\n  expression instead of a case. For example, this code:\n\n  ```gleam\n  pub fn main() {\n    let a = if wibble {\n      1\n    }\n  }\n  ```\n\n  Results in the following error:\n\n  ```txt\n  error: Syntax error\n    ┌─ /src/parse/error.gleam:3:11\n    │\n  3 │   let a = if wibble {\n    │           ^^ Gleam doesn't have if expressions\n\n  If you want to write a conditional expression you can use a `case`:\n\n      case condition {\n        True -> todo\n        False -> todo\n      }\n\n  See: https://tour.gleam.run/flow-control/case-expressions/\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler can now infer the minimum Gleam version needed for your code to\n  compile and emits a warning if the project's `gleam` version constraint\n  doesn't include it.\n  For example, let's say your `gleam.toml` has the constraint\n  `gleam = \">= 1.1.0\"` and your code is using some feature introduced in a later\n  version:\n\n  ```gleam\n  // Concatenating constant strings was introduced in v1.4.0!\n  pub const greeting = \"hello \" <> \"world!\"\n  ```\n\n  You would now get the following warning:\n\n  ```txt\n  warning: Incompatible gleam version range\n    ┌─ /Users/giacomocavalieri/Desktop/datalog/src/datalog.gleam:1:22\n    │\n  1 │ pub const greeting = \"hello \" <> \"world!\"\n    │                      ^^^^^^^^^^^^^^^^^^^^ This requires a Gleam version >= 1.4.0\n\n  Constant strings concatenation was introduced in version v1.4.0. But the\n  Gleam version range specified in your `gleam.toml` would allow this code to\n  run on an earlier version like v1.1.0, resulting in compilation errors!\n  Hint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n      gleam = \">= 1.4.0\"\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- On the JavaScript target, non-byte aligned integers in bit array patterns are\n  now reported as a compile-time error.\n\n  ([Richard Viney](https://github.com/richard-viney))\n\n### Formatter\n\n- The formatter now adds a `todo` after a `use` expression if it is the last\n  expression in a block. For example, the following code:\n\n  ```gleam\n  pub fn main() {\n    use user <- result.try(fetch_user())\n  }\n  ```\n\n  Is rewritten as:\n\n  ```gleam\n  pub fn main() {\n    use user <- result.try(fetch_user())\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Language Server\n\n- The language server can now show completions for local variables inside a function.\n  ([Ezekiel Grosfeld](https://github.com/ezegros))\n\n- The language server can now suggest a code action to assign an unused value to\n  `_`.\n  ([Jiangda Wang](https://github.com/frank-iii))\n\n- The language server can now suggest a code action to import modules for\n  existing code which references unimported modules:\n\n  ```gleam\n  pub fn main() {\n    io.println(\"Hello, world!\")\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  import gleam/io\n\n  pub fn main() {\n    io.println(\"Hello, world!\")\n  }\n  ```\n\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- The Language Server can now suggest a code action to fill in the missing\n  patterns of a case expression:\n\n  ```gleam\n  let a = True\n  case a {}\n  ```\n\n  Becomes:\n\n  ```gleam\n  let a = True\n  case a {\n    False -> todo\n    True -> todo\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Bug Fixes\n\n- Fixed a bug where the warnings were printed above the errors without any new\n  line between them.\n  ([Victor Kobinski](https://github.com/vkobinski))\n\n- Fixed a bug which caused the language server and compiler to crash when two\n  constructors of the same name were created.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where jumping to the definition of an unqualified function would\n  produce the correct location, but remain in the same file.\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- Fixed a bug where incorrect syntax error message were shown, when using `:` or\n  `=` in wrong positions in expressions.\n  ([Ankit Goel](https://github.com/crazymerlyn))\n\n- Fixed a bug where the compiler would crash when pattern matching on a type\n  which had constructors of duplicate names.\n  ([Surya Rose](https://github.com/gearsdatapacks))\n\n- Fixed a bug where referencing record constructors in JavaScript constants but\n  not calling them could produce invalid code.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where source links in HTML documentation would be incorrect for\n  Codeberg, SourceHut, and Gitea.\n  ([sobolevn](https://github.com/sobolevn))\n\n- Fixed a bug with Erlang code generation for discard utf8 patterns in bit\n  arrays.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug which affected inference of function calls in pipe expressions.\n  ([sobolevn](https://github.com/sobolevn))\n\n- Improved an error message when using variable names starting with an\n  underscore in expression like: `let some = _func()` or `case { 1 -> _func() }`\n  ([sobolevn](https://github.com/sobolevn))\n\n- Fixed a bug where the provided `REBAR_BARE_COMPILER_OUTPUT_DIR` env var would\n  use relative path instead of absolute path causing compilation errors in some\n  packages.\n  ([Gustavo Inacio](https://github.com/gusinacio))\n\n- Fixed a bug where the compiler would print incorrect missing patterns for\n  inexhaustive case expressions matching on more than one subject.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the compiler would not check the target support of a\n  function if it was imported and not used, and generate invalid code.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where an qualified unused constructor wouldn't be reported as\n  unused.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The Language Server now correctly shows completions for values in the Gleam\n  prelude.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the language server wouldn't let you jump to the definition\n  of a function with an external implementation defined in the same module.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.4.1 - 2024-08-04\n\n### Bug Fixes\n\n- Fix a bug that caused record accessors for private types to not be completed\n  by the LSP, even when in the same module.\n  ([Ameen Radwan](https://github.com/Acepie))\n"
  },
  {
    "path": "changelog/v1.6.md",
    "content": "# Changelog\n\n## v1.6.0 - 2024-11-18\n\n### Bug fixes\n\n- Fixed a bug where the language server would delete pieces of code when\n  applying a suggested autocompletion.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.6.0-rc2 - 2024-11-14\n\n### Build tool\n\n- The version of Erlang used in the GitHub Actions workflow created by\n  `gleam new` has been increased from v26.0.2 to v27.1.2.\n  ([Richard Viney](https://github.com/richard-viney))\n\n### Bug fixes\n\n- Fixed a bug where some reserved field names were not properly escaped in\n  custom types on the JavaScript target.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a bug where a warning about unsafe integers on the JavaScript target was\n  emitted when the enclosing function has an external JavaScript implementation.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where updating a dependency could break the build cache.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a bug where if the build directory was not writable then the build tool\n  would crash when trying to lock the build directory.\n  ([Zak Farmer](https://github.com/ZakFarmer))\n\n## v1.6.0-rc1 - 2024-11-10\n\n### Build tool\n\n- The `--template` flag for `gleam new` takes the values `erlang` and\n  `javascript` to specify what target to use, with `erlang` being the default.\n  ([Mohammed Khouni](https://github.com/Tar-Tarus))\n\n- The Erlang/Elixir compiler process is now reused for all packages, shaving\n  off 0.3-0.5s per compiled package.\n  ([yoshi](https://github.com/joshi-monster))\n\n- When a symlink cannot be made on Windows due to lack of permissions the error\n  now includes information on how to enable Windows' developer mode, enabling\n  symlinks.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The cli can now update individual dependencies.\n\n  `gleam update` and `gleam deps update` now take an optional list of package\n  names to update:\n\n  ```sh\n  gleam update package_a\n  gleam deps update package_b package_c\n  ```\n\n  This allows for selective updating of dependencies. When package names are\n  provided, only those packages and their unique dependencies are unlocked and\n  updated. If no package names are specified, the command behaves as before,\n  updating all dependencies.\n\n  ([Jason Sipula](https://github.com/SnakeDoc))\n\n- The `repository` config in `gleam.toml` can now optionally include a `path`\n  so that source links in generated documentation are correct for packages that\n  aren't located at the root of their repository:\n\n  ```toml\n  [repository]\n  type = \"github\"\n  user = \"gleam-lang\"\n  repo = \"gleam\"\n  path = \"packages/my_package\"\n  ```\n\n  ([Richard Viney](https://github.com/richard-viney))\n\n### Compiler\n\n- The compiler now prints correctly qualified or aliased type names when\n  printing type errors.\n\n  This code:\n\n  ```gleam\n  pub type Int\n\n  pub fn different_int_types(value: Int) {\n    value\n  }\n\n  pub fn main() {\n    different_int_types(20)\n  }\n  ```\n\n  Produces this error:\n\n  ```\n  error: Type mismatch\n    ┌─ /src/wibble.gleam:8:23\n    │\n  8 │   different_int_types(20)\n    │                       ^^\n\n  Expected type:\n\n      Int\n\n  Found type:\n\n      gleam.Int\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler can now suggest to pattern match on a `Result(a, b)` if it's\n  being used where a value of type `a` is expected. For example, this code:\n\n  ```gleam\n  import gleam/list\n  import gleam/int\n\n  pub fn main() {\n    let not_a_number = list.first([1, 2, 3])\n    int.add(1, not_a_number)\n  }\n  ```\n\n  Results in the following error:\n\n  ```txt\n  error: Type mismatch\n    ┌─ /src/one/two.gleam:6:9\n    │\n  6 │   int.add(1, not_a_number)\n    │              ^^^^^^^^^^^^\n\n  Expected type:\n\n      Int\n\n  Found type:\n\n      Result(Int, a)\n\n  Hint: If you want to get a `Int` out of a `Result(Int, a)` you can pattern\n  match on it:\n\n      case result {\n        Ok(value) -> todo\n        Error(error) -> todo\n      }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Improved the error message for unknown record fields, displaying an additional\n  note on how to have a field accessor only if it makes sense.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now ignores `optional` dependencies when resolving versions\n  unless explicitly specified.\n  ([Gustavo Inacio](https://github.com/gusinacio))\n\n- Improved the error message for using `@deprecated` with no deprecation message\n  ([Jiangda Wang](https://github.com/frank-iii))\n\n- Optimised creation of bit arrays on the JavaScript target.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- The compiler can now infer the variant of custom types within expressions that\n  construct or pattern match on them.\n\n  Using this information it can now be more precise with exhaustiveness\n  checking, identifying patterns for the other variants as unnecessary.\n\n  ```gleam\n  pub type Pet {\n    Dog(name: String, cuteness: Int)\n    Turtle(name: String, speed: Int, times_renamed: Int)\n  }\n\n  pub fn main() {\n    // We know `charlie` is a `Dog`...\n    let charlie = Dog(\"Charles\", 1000)\n\n    // ...so you do not need to match on the `Turtle` variant\n    case charlie {\n      Dog(..) -> todo\n    }\n  }\n  ```\n\n  This also means that the record update syntax can be used on multi-variant\n  custom types, so long as the variant can be inferred from the surrounding\n  code.\n\n  ```gleam\n  pub fn rename(pet: Pet, to name: String) -> Pet {\n    case pet {\n      Dog(..) -> Dog(..pet, name:)\n      Turtle(..) -> Turtle(..pet, name:, times_renamed: pet.times_renamed + 1)\n    }\n  }\n  ```\n\n  Variant specific fields can also be used with the accessor syntax.\n\n  ```gleam\n  pub fn speed(pet: Pet) -> Int {\n    case pet {\n      Dog(..) -> 500\n      Turtle(..) -> pet.speed\n    }\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When targeting JavaScript the compiler now emits a warning for integer\n  literals and constants that lie outside JavaScript's safe integer range:\n\n  ```txt\n  warning: Int is outside the safe range on JavaScript\n    ┌─ /Users/richard/Desktop/int_test/src/int_test.gleam:1:15\n    │\n  1 │ pub const i = 9_007_199_254_740_992\n    │               ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer on JavaScript\n\n  This integer value is too large to be represented accurately by\n  JavaScript's number type. To avoid this warning integer values must be in\n  the range -(2^53 - 1) - (2^53 - 1).\n\n  See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\n  properties for more information.\n  ```\n\n  ([Richard Viney](https://github.com/richard-viney))\n\n### Formatter\n\n- The formatter no longer removes the first argument from a function\n  which is part of a pipeline if the first argument is a capture\n  and it has a label. This snippet of code is left as is by the formatter:\n\n  ```gleam\n  pub fn divide(dividend a: Int, divisor b: Int) -> Int {\n    a / b\n  }\n\n  pub fn main() {\n    10 |> divide(dividend: _, divisor: 2)\n  }\n  ```\n\n  Whereas previously, the label of the capture variable would be lost:\n\n  ```gleam\n  pub fn divide(dividend a: Int, divisor b: Int) -> Int {\n    a / b\n  }\n\n  pub fn main() {\n    10 |> divide(divisor: 2)\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Language Server\n\n- The Language Server now displays correctly qualified or aliased type names\n  when hovering over a value in a Gleam file:\n\n  ```gleam\n  import gleam/option\n\n  const value = option.Some(1)\n  //    ^ hovering here shows `option.Option(Int)`\n  ```\n\n  ```gleam\n  import gleam/option.{type Option as Maybe}\n\n  const value = option.Some(1)\n  //    ^ hovering here shows `Maybe(Int)`\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The Language Server now suggests a code action to add type annotations to\n  local variables, constants and functions:\n\n  ```gleam\n  pub fn add_int_to_float(a, b) {\n    a +. int.to_float(b)\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  pub fn add_int_to_float(a: Float, b: Int) -> Float {\n    a +. int.to_float(b)\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The Language Server now suggests a code action to convert qualified imports to\n  unqualified imports, which updates all occurrences of the qualified name\n  throughout the module:\n\n  ```gleam\n  import option\n\n  pub fn main() {\n    option.Some(1)\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  import option.{Some}\n\n  pub fn main() {\n    Some(1)\n  }\n  ```\n\n  ([Jiangda Wang](https://github.com/Frank-III))\n\n- The Language Server now suggests a code action to convert unqualified imports\n  to qualified imports, which updates all occurrences of the unqualified name\n  throughout the module:\n\n  ```gleam\n  import list.{map}\n\n  pub fn main() {\n    map([1, 2, 3], fn(x) { x * 2 })\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  import list.{}\n\n  pub fn main() {\n    list.map([1, 2, 3], fn(x) { x * 2 })\n  }\n  ```\n\n  ([Jiangda Wang](https://github.com/Frank-III))\n\n### Bug Fixes\n\n- Fixed a bug in the compiler where shadowing a sized value in a bit pattern\n  would cause invalid erlang code to be generated.\n  ([Antonio Iaccarino](https://github.com/eingin))\n\n- Fixed a bug where the formatter would not format strings with big grapheme\n  clusters properly.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed the `BitArray` constructor not being present in the types for the\n  JavaScript prelude.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where generated TypeScript definitions were invalid for opaque\n  types that use a private type.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed the prelude re-export in generated TypeScript definitions.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where the compiler would incorrectly type-check and compile\n  calls to functions with labelled arguments in certain cases.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where importing type aliases that reference unimported modules\n  would generate invalid TypeScript definitions.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- When splitting a constant list made of records, the formatter will keep each\n  item on its own line to make things easier to read.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the compiler would crash when pattern matching on a type\n  which was defined with duplicate fields in one of its variants.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the WASM compiler would return incomplete JavaScript when\n  unsupported features were used. It now returns a compilation error.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where incorrect code would be generated for external function on\n  the Erlang target if any of their arguments were discarded.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug in the error message when using wrong values in a pipe where the\n  message would swap the \"Expected\" and \"Found\" types.\n  ([Markus Pettersson](https://github.com/MarkusPettersson98/))\n\n- Fixed a bug where the parser would incorrectly parse a record constructor with\n  no arguments.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where the parser would incorrectly parse a generic type\n  constructor with no arguments.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the parser would incorrectly parse a generic type definition\n  with no arguments.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the language server wouldn't show hints when hovering over\n  the tail of a list.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where attempting to jump to the definition of a type from the\n  annotation of a parameter of an anonymous function would do nothing.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where referencing record constructors in JavaScript guards but\n  not calling them could produce invalid code.\n  ([PgBiel](https://github.com/PgBiel))\n\n- Fixed a bug where using the label shorthand syntax inside of a record update\n  wouldn't emit a warning when the minimum specified Gleam version was < 1.4.0.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a bug where no error would be reported when duplicate labelled\n  arguments were supplied in a record update.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where an incorrect bit array would be generated on JavaScript for\n  negative `Int` values when the segment's `size` was wider than 48 bits or when\n  the `Int` value was less than the minimum representable value for the segment\n  size.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where an incorrect `Int` would be returned when pattern matching\n  to a negative value wider than 48 bits in a bit array.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where unused values coming from other modules wouldn't raise a\n  warning.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.5.1 - 2024-09-26\n\n### Bug Fixes\n\n- Fixed a bug where Erlang file paths would not be escaped on Windows.\n  ([Louis Pilfold](https://github.com/lpil))\n"
  },
  {
    "path": "changelog/v1.7.md",
    "content": "# Changelog\n\n## 1.7.0 - 2025-01-05\n\nHappy birthday Louis! 🎁\n\n## 1.7.0-rc3 - 2025-01-02\n\n### Formatter\n\n- Function captures are now formatted like regular function calls.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Record updates are now formatted like function calls.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- Fixed a bug where the \"convert from use\" code action would generate invalid\n  code with labelled arguments.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where private types would be allowed to be used in other modules.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n## 1.7.0-rc2 - 2024-12-30\n\n### Bug fixes\n\n- Fixed a bug on JavaScript where a trailing `:bytes` segment would give the\n  wrong pattern match result for a sliced bit array.\n  ([Richard Viney](https://github.com/richard-viney))\n\n## 1.7.0-rc1 - 2024-12-29\n\n### Compiler\n\n- Removed compiler hint about pattern matching a `Result(a, b)` when being used\n  where `a` is expected.\n  ([Kieran O'Reilly](https://github.com/SoTeKie))\n\n- Optimised code generated for record updates.\n  ([yoshi](https://github.com/joshi-monster))\n\n- The compiler now allows for record updates to change the generic type\n  parameters of the record:\n\n  ```gleam\n  type Box(value) {\n    Box(password: String, value: value)\n  }\n\n  fn insert(box: Box(a), value: b) -> Box(b) {\n    Box(..box, value:)\n  }\n  ```\n\n  ([yoshi](https://github.com/joshi-monster))\n\n- It is now allowed to write a block with no expressions. Like an empty function\n  body, an empty block is considered incomplete as if it contained a `todo`\n  expression.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The shorthand names for the two targets, `erl` and `js` are now\n  deprecated in code such as `@target`.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- A custom panic message can now be specified when asserting a value with\n  `let assert`:\n\n  ```gleam\n  let assert Ok(regex) = regex.compile(\"ab?c+\") as \"This regex is always valid\"\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- When targeting JavaScript the compiler now generates faster and smaller code\n  for `Int` values in bit array expressions and patterns by evaluating them at\n  compile time where possible.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Qualified records can now be used in clause guards.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler now allows deprecating specific custom type variants using the\n  `@deprecated` attribute:\n\n  ```gleam\n  pub type HashAlgorithm {\n    @deprecated(\"Please upgrade to another algorithm\")\n    Md5\n    Sha224\n    Sha512\n  }\n\n  pub fn hash_password(input: String) -> String {\n    hash(input:, algorithm: Md5) // Warning: Deprecated value used\n  }\n  ```\n\n  ([Iesha](https://github.com/wilbert-mad))\n\n- On the JavaScript target, taking byte-aligned slices of bit arrays is now an\n  O(1) operation instead of O(N), significantly improving performance.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Better error message for when an existing type constructor is used as a value\n  constructor.\n  ([Jiangda Wang](https://github.com/Frank-III))\n\n- Print better error messages when shell commands used by compiler cannot be\n  found.\n  ([wheatfox](https://github.com/enkerewpo))\n\n### Build tool\n\n- Improved the error message you get when trying to add a package that doesn't\n  exist with `gleam add`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- External files (such as `.mjs` and `.erl`) are now permitted in subdirectories\n  of `src/` and `test/`.\n  ([PgBiel](https://github.com/PgBiel))\n\n- `gleam publish` now requires more verbose confirmation for publishing Gleam\n  team packages and v0 packages.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- `gleam publish` now warns when publishing packages that define multiple\n  top-level modules, as this can lead to namespace pollution and conflicts for\n  consumers.\n  ([Aleksei Gurianov](https://github.com/guria))\n\n- New projects now require `gleam_stdlib` v0.44.0.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- `gleam remove` no longer requires a network connection.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Commands that work with the Hex package manager API now create and store an\n  API key rather than creating a new one each time. This API key is encrypted\n  with a local password, reducing risk of your Hex password being compromised.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- The build tool now sets the `REBAR_SKIP_PROJECT_PLUGINS` environment variable\n  when using rebar3 to compile Erlang dependencies. With future versions of\n  rebar3 this will cause it to skip project plugins, significantly reducing the\n  amount of code it'll need to download and compile, improving compile times.\n  ([Tristan Sloughter](https://github.com/tsloughter))\n\n### Language server\n\n- The language server now provides type information when hovering over argument\n  labels.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now suggests a code action to desugar a use expression\n  into the equivalent function call. For example, this snippet of code:\n\n  ```gleam\n  pub fn main() {\n    use profile <- result.try(fetch_profile(user))\n    render_welcome(user, profile)\n  }\n  ```\n\n  Will be turned into:\n\n  ```gleam\n  pub fn main() {\n    result.try(fetch_profile(user), fn(profile) {\n      render_welcome(user, profile)\n    })\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a code action to turn a function call into\n  the equivalent use expression. For example, this snippet of code:\n\n  ```gleam\n  pub fn main() {\n    result.try(fetch_profile(user) fn(profile) {\n      render_welcome(user, profile)\n    })\n  }\n  ```\n\n  Will be turned into:\n\n  ```gleam\n  pub fn main() {\n    use profile <- result.try(fetch_profile(user))\n    render_welcome(user, profile)\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now provides correct information when hovering over\n  patterns in use expressions.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now suggests a code action to convert an inexhaustive\n  `let` assignment into a `case` expression:\n\n  ```gleam\n  pub fn unwrap_result(result: Result(a, b)) -> a {\n    let Ok(inner) = result\n    inner\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  pub fn unwrap_result(result: Result(a, b)) -> a {\n    let inner = case result {\n      Ok(inner) -> inner\n      Error(_) -> todo\n    }\n    inner\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now provides an action to extract a value into a variable.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a code action to expand a function capture\n  into the equivalent anonymous function. For example, this snippet of code:\n\n  ```gleam\n  pub fn main() {\n    list.map([1, 2, 3], int.add(_, 11))\n  }\n  ```\n\n  Will be turned into:\n\n  ```gleam\n  pub fn main() {\n    list.map([1, 2, 3], fn(value) { int.add(value, 11) })\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a code action to generate a dynamic decoder\n  for a custom type. For example, this code:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n  ```\n\n  Will become:\n\n  ```gleam\n  import gleam/dynamic/decode\n\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n\n  fn person_decoder() -> decode.Decoder(Person) {\n    use name <- decode.field(\"name\", decode.string)\n    use age <- decode.field(\"age\", decode.int)\n    decode.success(Person(name:, age:))\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Formatter\n\n- The formatter now adds a `todo` inside empty blocks.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The formatter now formats lists the same in constants as in expressions.\n  ([Jiangda Wang](https://github.com/Frank-III))\n\n### Documentation\n\n- Canonical links created for documentation pages if published on Hex.\n  Previously published documentation would need to be updated.\n  Resolves versioned pages to point to latest page for search engines.\n  ([Dave Lage](https://github.com/rockerBOO))\n\n### Bug fixes\n\n- The compiler now throws an error when a float literal ends with an `e` and\n  is missing an exponent.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a crash with ENOTEMPTY (os error 39) when building on NTFS partitions.\n  ([Ivan Ermakov](https://github.com/ivanjermakov))\n\n- Fixed a bug where the compiler would crash when pattern matching on multiple\n  subjects and one of them being a constant record.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Variant inference on prelude types now works correctly if the variant is\n  constant.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where patterns in `use` expressions would not be checked to ensure\n  that they were exhaustive.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where a `module.mjs` file would be overwritten by a `module.gleam`\n  file of same name without warning. It now produces an error.\n  ([PgBiel](https://github.com/PgBiel))\n\n- Modules depending on removed or renamed modules now get automatically\n  recompiled.\n  ([Sakari Bergen](https://github.com/sbergen))\n\n- The compiler now raises a warning for unused case expressions, code blocks and\n  pipelines that would be safe to remove.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where assigning the prefix of a string pattern to a variable\n  nested inside another pattern would produce invalid code on Javascript.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a bug where expressions which use an unsafe integer on JavaScript would\n  not emit a warning if an external function had been referenced.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where nested tuple access would not be parsed correctly when\n  the left-hand side was a function call.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where Gleam would be unable to compile to BEAM bytecode on older\n  versions of Erlang/OTP.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a bug where the inferred variant of values was not properly cached,\n  leading to incorrect errors on incremental builds and in the language server.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where Gleam would be unable to compile to BEAM bytecode if the\n  project path contains a non-ascii character.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a bug where the compiler would display incorrect hints about ignoring\n  unused variables in certain cases.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the completer would not include braces in type import\n  completions when it should have.\n  ([Jiangda Wang](https://github.com/Frank-III))\n\n- Fixed a bug where `gleam new` would generate the github `test` workflow\n  configuration with incompatible Erlang OTP and Elixir versions.\n  ([John Strunk](https://github.com/jrstrunk))\n\n## v1.6.1 - 2024-11-19\n\n### Bug fixes\n\n- Fixed a bug where `gleam update` would fail to update versions.\n  ([Jason Sipula](https://github.com/SnakeDoc))\n"
  },
  {
    "path": "changelog/v1.8.md",
    "content": "# Changelog\n\nDedicated to the memory of Len Pilfold.\n\n## v1.8.0 - 2025-02-07\n\n## v1.8.0-rc1 - 2025-02-03\n\n### Compiler\n\n- Pipelines are now fault tolerant. A type error in the middle of a pipeline\n  won't stop the compiler from figuring out the types of the remaining pieces,\n  enabling the language server to show better suggestions for incomplete pipes.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Improved code generation for blocks in tail position on the Javascript target.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Function documentation comments and module documentation comments are now\n  included in the generated Erlang code and can be browsed from the Erlang\n  shell starting from OTP27.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Parsing of `case` expressions is now fault tolerant. If a `case` expressions\n  is missing its body, the compiler can still perform type inference. This also\n  allows the Language Server to provide completion hints for `case` subjects.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The compiler can now suggest to wrap a value in an `Ok` or `Error` if that can\n  solve a type mismatch error:\n\n  ```gleam\n  pub fn greet_logged_user() {\n    use <- bool.guard(when: !logged_in, return: Error(Nil))\n    \"Hello!\"\n  }\n  ```\n\n  Results in the following error:\n\n  ```txt\n  error: Type mismatch\n    ┌─ /main.gleam:7:3\n    │\n  7 │   \"Hello!\"\n    │   ^^^^^^^^ Did you mean to wrap this in an `Ok`?\n\n  Expected type:\n\n      Result(a, Nil)\n\n  Found type:\n\n      String\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The compiler now shows an improved error message when using an unknown type as a\n  variable name\n\n  ```txt\n  error: Unknown variable\n    ┌─ /src/one/two.gleam:4:3\n    │\n  4 │   X\n    │   ^\n  The custom type variant constructor `X` is not in scope here.\n  ```\n\n  ([Roeeeee](https://github.com/5c077m4n))\n\n- Erlang `file` module attributes now use paths relative to the root.\n  ([Kasim](https://github.com/oneness))\n\n### Build tool\n\n- `gleam new` now has refined project name validation - rather than failing on\n  invalid project names, it suggests a valid alternative and prompts for\n  confirmation to use it.\n  ([Diemo Gebhardt](https://github.com/diemogebhardt))\n\n- `gleam docs build` generated documentation site now focuses the search input\n  when \"Cmd/Ctrl + K\", \"s\" or \"/\" is pressed.\n  ([Sambit Sahoo](https://github.com/soulsam480))\n\n- `gleam deps` now supports `tree` operation that lists the dependency tree.\n\n  ```markdown\n  Usage: gleam deps tree [OPTIONS]\n\n  Options:\n    -p, --package <PACKAGE>  Package to be used as the root of the tree\n    -i, --invert <PACKAGE>   Invert the tree direction and focus on the given package\n    -h, --help               Print help\n  ```\n\n  For example, if the root project (`project_a`) depends on `package_b` and\n  `package_c`, and `package_c` also depends on `package_b`, the output will be:\n\n\n  ```markdown\n  $ gleam deps tree\n\n  project_a v1.0.0\n  ├── package_b v0.52.0\n  └── package_c v1.2.0\n      └── package_b v0.52.0\n\n  $ gleam deps tree --package package_c\n\n  package_c v1.2.0\n  └── package_b v0.52.0\n\n  $ gleam deps tree --invert package_b\n\n  package_b v0.52.0\n  ├── package_c v1.2.0\n  │   └── project_a v1.0.0\n  └── project_a v1.0.0\n\n  ```\n\n  ([Ramkarthik Krishnamurthy](https://github.com/ramkarthik))\n\n- The build tool now checks for modules that would collide with the new Erlang\n  `json` module in addition to the existing Erlang modules it already checked\n  for.\n  ([Louis Pilfold](https://github.com/lpil))\n\n### Language server\n\n- The language server can now generate the definition of functions that do not\n  exist in the current file. For example if I write the following piece of code:\n\n  ```gleam\n  import gleam/io\n\n  pub type Pokemon {\n    Pokemon(pokedex_number: Int, name: String)\n  }\n\n  pub fn main() {\n    io.println(to_string(pokemon))\n    //          ^ If you put your cursor over this function that is\n    //            not implemented yet\n  }\n  ```\n\n  Triggering the \"generate function\" code action, the language server will\n  generate the following function for you:\n\n  ```gleam\n  fn to_string(pokemon: Pokemon) -> String {\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server can now fill in the labels of any function call, even when\n  only some of the arguments are provided. For example:\n\n  ```gleam\n  import gleam/string\n\n  pub fn main() {\n    string.replace(\"wibble\")\n  }\n  ```\n\n  Will be completed to:\n\n  ```gleam\n  import gleam/string\n\n  pub fn main() {\n    string.replace(\"wibble\", each: todo, with: todo)\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a code action to pattern match on a\n  function's argument. For example:\n\n  ```gleam\n  pub type Pokemon {\n    Pokemon(pokedex_number: Int, name: String)\n  }\n\n  pub fn to_string(pokemon: Pokemon) {\n    //             ^ If you put your cursor over the argument\n    todo\n  }\n  ```\n\n  Triggering the code action on the `pokemon` argument will generate the\n  following code for you:\n\n  ```gleam\n  pub type Pokemon {\n    Pokemon(pokedex_number: Int, name: String)\n  }\n\n  pub fn to_string(pokemon: Pokemon) {\n    let Pokemon(pokedex_number:, name:) = pokemon\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a code action to pattern match on a variable.\n  For example:\n\n  ```gleam\n  pub fn main() {\n    let result = list.first(a_list)\n    //  ^ If you put your cursor over the variable\n    todo\n  }\n  ```\n\n  Triggering the code action on the `result` variable will generate the\n  following code for you:\n\n  ```gleam\n  pub fn main() {\n    let result = list.first(a_list)\n    case result {\n      Ok(value) -> todo\n      Error(value) -> todo\n    }\n    todo\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- When generating functions or variables, the language server can now pick\n  better names using the type of the code it's generating.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The Language Server now provides the ability to rename local variables.\n  For example:\n\n  ```gleam\n  pub fn main() {\n    let wibble = 10\n    //  ^ If you put your cursor here, and trigger a rename\n    wibble + 1\n  }\n  ```\n\n  Triggering a rename and entering `my_number` results in this code:\n\n\n  ```gleam\n  pub fn main() {\n    let my_number = 10\n    my_number + 1\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- `Unqualify` Action now get triggered when hovering over the module name\n  for record value constructor.\n  For example:\n\n  ```gleam\n  pub fn main() {\n    let my_option = option.Some(1)\n    //                 ^ would trigger \"Unqualify option.Some\"\n  }\n  ```\n  ([Jiangda Wang](https://github.com/Frank-III))\n\n### Formatter\n\n### Bug fixes\n\n- Fixed a bug where the \"convert from use\" code action would generate invalid\n  code for use expressions ending with a trailing comma.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where floats outside of Erlang's floating point range were not\n  causing errors.\n  ([shayan](https://github.com/massivefermion))\n\n- Fixed a bug where build tool could fail to add new dependencies when\n  dependencies with optional dependencies are present in the manifest.\n  ([Louis Pilfold](https://github.com/lpil))\n\n- Fixed a bug where a block expression containing a singular record update would\n  produce invalid erlang.\n  ([yoshi](https://github.com/joshi-monster))\n\n- Fixed a typo in the error message when trying to import a test module into an\n  application module.\n  ([John Strunk](https://github.com/jrstrunk))\n\n- Fixed a bug where the \"Extract variable\" code action would erroneously extract\n  a pipeline step as a variable.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where variables bound in `let assert` assignments would be allowed\n  to be used in the custom panic message.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n"
  },
  {
    "path": "changelog/v1.9.md",
    "content": "# Changelog\n\n## v1.9.0 - 2025-03-09\n\n## v1.9.0-rc2 - 2025-03-07\n\n### Compiler\n\n- Made runtime warnings regarding the use of deprecated BitArray properties in\n  JavaScript FFI code more compact. They are now one line instead of three.\n  ([Richard Viney](https://github.com/richard-viney))\n\n### Bug fixes\n\n- Fixed a bug that would result in displaying the wrong name when running\n  `gleam --version`.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug in the `generate json encoder` and `generate dynamic decoder` that\n  would result in generating invalid code for variants with no fields.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n## v1.9.0-rc1 - 2025-03-04\n\n### Compiler\n\n- You can now use the `echo` keyword to debug print any value: `echo` can be\n  followed by any expression and it will print it to stderr alongside the module\n  it comes from and its line number. This:\n\n  ```gleam\n  pub fn main() {\n    echo [1, 2, 3]\n  }\n  ```\n\n  Will output to stderr:\n\n  ```txt\n  /src/module.gleam:2\n  [1, 2, 3]\n  ```\n\n  `echo` can also be used in the middle of a pipeline. This:\n\n  ```gleam\n  pub fn main() {\n    [1, 2, 3]\n    |> echo\n    |> list.map(fn(x) { x * 2 })\n    |> echo\n  }\n  ```\n\n  Will output to stderr:\n\n  ```txt\n  /src/module.gleam:3\n  [1, 2, 3]\n  /src/module.gleam:5\n  [2, 4, 6]\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Generated Erlang `.app` files now include external modules written in Elixir\n  and Erlang.\n  ([LostKobrakai](https://github.com/lostkobrakai))\n\n- On the JavaScript target, bit array expressions and patterns no longer need to\n  be byte aligned, and the `bits` segment type is now supported in patterns.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- The code generated for list pattern matching on the JavaScript target is now\n  more efficient. Gleam code that relies heavily on list pattern matching can\n  now be up to twice as fast.\n  ([yoshi~](https://github.com/yoshi-monster))\n\n- On the JavaScript target, bit array patterns can now match segments of dynamic\n  size.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Build tool\n\n- The build tool now supports Git dependencies. For example:\n\n  ```\n  [dependencies]\n  gleam_stdlib = { git = \"https://github.com/gleam-lang/stdlib.git\", ref = \"957b83b\" }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The build tool now refuses to publish any incomplete package that has any\n  `echo` debug printing left.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- HexDocs documentation of Gleam packages now uses the ExDocs search data model,\n  allowing for global indexing of Gleam packages in HexDocs, and\n  making Gleam packages discoverable through global search of HexDocs.\n  ([Diemo Gebhardt](https://github.com/diemogebhardt))\n\n- Improved the styling of constructor argument descriptions in the generated\n  documentation.\n  ([Mikko Ahlroth](https://git.ahlcode.fi/nicd))\n\n- Allow users to set the `GLEAM_CACERTS_PATH` environment variable to specify a\n  path to a directory containing CA certificates to install Hex packages.\n  ([winstxnhdw](https://github.com/winstxnhdw))\n\n### Language server\n\n- The language server now has the ability to jump to the type definition of any\n  hovered value.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers a code action to convert the first step of a\n  pipeline to a regular function call. For example, this code:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    [1, 2, 3] |> list.map(fn(n) { n * 2 })\n  }\n  ```\n\n  Will be rewritten as:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    list.map([1, 2, 3], fn(n) { n * 2 })\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now offers a code action to convert a function call into\n  a pipeline. For example, this code:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    list.map([1, 2, 3], fn(n) { n * 2 })\n  }\n  ```\n\n  Will be rewritten as:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    [1, 2, 3] |> list.map(fn(n) { n * 2 })\n  }\n  ```\n\n  You can also pick which argument is going to be piped. In this case:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    list.map([1, 2, 3], fn(n) { n * 2 })\n    //                   ^ If you put your cursor over here\n  }\n  ```\n\n  The code will be rewritten as:\n\n  ```gleam\n  import gleam/list\n\n  pub fn main() {\n    fn(n) { n * 2 } |> list.map([1, 2, 3], _)\n  }\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now suggests a code action to generate a function to\n  encode a custom type as JSON using the `gleam_json` package. For example:\n\n  ```gleam\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n  ```\n\n  Will become:\n\n  ```gleam\n  import gleam/json\n\n  pub type Person {\n    Person(name: String, age: Int)\n  }\n\n  fn encode_person(person: Person) -> json.Json {\n    json.object([\n      #(\"name\", json.string(person.name)),\n      #(\"age\", json.int(person.age)),\n    ])\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now suggests a code action to inline a variable\n  which is only used once. For example, this code:\n\n  ```gleam\n  import gleam/io\n\n  pub fn main() {\n    let greeting = \"Hello!\"\n    io.println(greeting)\n  }\n  ```\n\n  Will be rewritten as:\n\n  ```gleam\n  import gleam/io\n\n  pub fn main() {\n    io.println(\"Hello!\")\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The code action to generate a dynamic decoder for a custom type can now\n  generate decoders for types with multiple variants. For example this code:\n\n  ```gleam\n  pub type Person {\n    Adult(age: Int, job: String)\n    Child(age: Int, height: Float)\n  }\n  ```\n\n  Becomes:\n\n  ```gleam\n  import gleam/dynamic/decode\n\n  pub type Person {\n    Adult(age: Int, job: String)\n    Child(age: Int, height: Float)\n  }\n\n  fn person_decoder() -> decode.Decoder(Person) {\n    use variant <- decode.field(\"type\", decode.string)\n    case variant {\n      \"adult\" -> {\n        use age <- decode.field(\"age\", decode.int)\n        use job <- decode.field(\"job\", decode.string)\n        decode.success(Adult(age:, job:))\n      }\n      \"child\" -> {\n        use age <- decode.field(\"age\", decode.int)\n        use height <- decode.field(\"height\", decode.float)\n        decode.success(Child(age:, height:))\n      }\n      _ -> decode.failure(todo as \"Zero value for Person\", \"Person\")\n    }\n  }\n  ```\n\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- The language server now suggests a code action to easily interpolate a value\n  into a string. If the cursor is inside a literal string the language server\n  will offer to split it:\n\n  ```gleam\n  \"wibble | wobble\"\n  //      ^ Triggering the action with the cursor\n  //        here will produce this:\n  \"wibble \" <> todo <> \" wobble\"\n  ```\n\n  And if the cursor is selecting a valid Gleam name, the language server will\n  offer to interpolate it as a variable:\n\n  ```gleam\n  \"wibble wobble woo\"\n  //      ^^^^^^ Triggering the code action if you're\n  //             selecting an entire name, will produce this:\n  \"wibble \" <> wobble <> \" woo\"\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- The language server now shows module documentation when hovering over a module\n  name.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n### Formatter\n\n- Redundant function captures that take no additional arguments are now\n  rewritten to not use the function capture syntax.\n\n  ```gleam\n  some_module.some_function(_)\n  ```\n\n  This code is reformatted like so:\n\n  ```gleam\n  some_module.some_function\n  ```\n\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n### Bug fixes\n\n- Fixed a bug where division and remainder operators would not work correctly\n  in guards on the JavaScript target.\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where the \"Generate function\" code action would ignore the\n  provided labels.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where the \"Pattern match on argument\" and\n  \"Pattern match on variable\" code actions would not allow to pattern match on a\n  private type used in the same module it's defined in.\n  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))\n\n- Fixed a bug where `gleam export package-interface` would not properly generate\n  the package interface file if some modules were cached.\n  ([Pedro Francisco](https://github.com/mine-tech-oficial)) and\n  ([Surya Rose](https://github.com/GearsDatapacks))\n\n- Fixed a bug where pattern matching using a UTF-8 string constant would not\n  work correctly on the JavaScript target when the string contained escape\n  characters.\n  ([Richard Viney](https://github.com/richard-viney))\n\n- Fixed a bug where `gleam publish` wouldn't include gitignored or nested native\n  files.\n  ([PgBiel](https://github.com/PgBiel))\n\n## v1.8.1 - 2025-02-11\n\n### Bug fixes\n\n- Fixed a metadata caching bug where accessors for opaque types could sometimes\n  be used in other modules.\n  ([Louis Pilfold](https://github.com/lpil))\n"
  },
  {
    "path": "compiler-cli/Cargo.toml",
    "content": "[package]\nname = \"gleam-cli\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\n# The pure compiler\ngleam-core = { path = \"../compiler-core\" }\n# The language server\ngleam-language-server = { path = \"../language-server\" }\n# OS SIGINT and SIGTERM signal handling\nctrlc = { version = \"3\", features = [\"termination\"] }\n# Command line interface\nclap = { version = \"4\", features = [\"derive\"] }\n# Recursively traversing directories\nignore = \"0\"\n# Allow user to type in sensitive information without showing it in the shell\nrpassword = \"7\"\n# Async runtime\ntokio = { version = \"1\", features = [\"rt\", \"rt-multi-thread\"] }\n# Further file system functions (i.e. copy directory)\nfs_extra = \"1\"\ntracing-subscriber = { version = \"0.3.20\", features = [\"fmt\", \"env-filter\"] }\n# HTTP client\nreqwest = { version = \"0\", default-features = false, features = [\"rustls-tls\"] }\n# Checksums\nsha2 = \"0\"\n# Getting hostname\nhostname = \"0\"\n# TOML parser/editor that preserves comments & formatting\ntoml_edit = \"0\"\n# File locking\nfslock = \"0\"\n# Provides a way to determine if two files are the same using filesystem node ids\nsame-file = \"1\"\n\nasync-trait.workspace = true\nbase16.workspace = true\ncamino = { workspace = true, features = [\"serde1\"] }\ndebug-ignore.workspace = true\necow.workspace = true\nflate2.workspace = true\nfutures.workspace = true\nhexpm = { path = \"../hexpm\" }\nhttp.workspace = true\nhttp-serde.workspace = true\nim.workspace = true\nitertools.workspace = true\nlsp-server.workspace = true\nlsp-types.workspace = true\nopener.workspace = true\nregex.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nstrum.workspace = true\ntar.workspace = true\ntermcolor.workspace = true\ntoml.workspace = true\ntracing.workspace = true\npubgrub.workspace = true\n\n[dev-dependencies]\n# Creation of temporary directories\ntempfile = \"3\"\n# Setting file modification times for tests\nfiletime = \"0.2\"\npretty_assertions.workspace = true\ninsta.workspace = true\n"
  },
  {
    "path": "compiler-cli/clippy.toml",
    "content": "disallowed-methods = [\n  { path = \"std::path::Path::new\", reason = \"Manually constructed paths should use camino::Utf8Path\" },\n  { path = \"std::path::PathBuf::new\", reason = \"Manually constructed pathbufs should use camino::Utf8Path\" },\n]"
  },
  {
    "path": "compiler-cli/src/add.rs",
    "content": "use camino::{Utf8Path, Utf8PathBuf};\n\nuse gleam_core::{\n    Error, Result,\n    error::{FileIoAction, FileKind},\n    paths::ProjectPaths,\n};\nuse hexpm::version::{Identifier, Version};\n\nuse crate::{\n    cli,\n    dependencies::{self, parse_gleam_add_specifier},\n    fs,\n};\n\npub fn command(paths: &ProjectPaths, packages_to_add: Vec<String>, dev: bool) -> Result<()> {\n    let config = crate::config::root_config(paths)?;\n    if packages_to_add.iter().any(|name| name == &config.name) {\n        return Err(Error::CannotAddSelfAsDependency {\n            name: config.name.clone(),\n        });\n    }\n\n    let mut new_package_requirements = Vec::with_capacity(packages_to_add.len());\n    for specifier in packages_to_add {\n        new_package_requirements.push(parse_gleam_add_specifier(&specifier)?);\n    }\n\n    // Insert the new packages into the manifest and perform dependency\n    // resolution to determine suitable versions\n    let manifest = dependencies::resolve_and_download(\n        paths,\n        cli::Reporter::new(),\n        Some((new_package_requirements.clone(), dev)),\n        Vec::new(),\n        dependencies::DependencyManagerConfig {\n            use_manifest: dependencies::UseManifest::Yes,\n            check_major_versions: dependencies::CheckMajorVersions::No,\n        },\n    )?;\n\n    // Read gleam.toml and manifest.toml so we can insert new deps into it\n    let mut gleam_toml = read_toml_edit(&paths.root_config())?;\n    let mut manifest_toml = read_toml_edit(&paths.manifest())?;\n\n    // Insert the new deps\n    for (added_package, _) in new_package_requirements {\n        let added_package = added_package.to_string();\n\n        // Pull the selected version out of the new manifest so we know what it is\n        let version = &manifest\n            .packages\n            .iter()\n            .find(|package| package.name == *added_package)\n            .expect(\"Added package not found in resolved manifest\")\n            .version;\n\n        tracing::info!(version=%version, \"new_package_version_resolved\");\n\n        // Produce a version requirement locked to the major version.\n        // i.e. if 1.2.3 is selected we want >= 1.2.3 and < 2.0.0\n        let range = format!(\n            \">= {} and < {}.0.0\",\n            version_to_string(version),\n            version.major + 1\n        );\n\n        // False positive. This package doesn't use the indexing API correctly.\n        #[allow(clippy::indexing_slicing)]\n        {\n            if dev {\n                let canonical_name = \"dev_dependencies\";\n                let deprecated_name = \"dev-dependencies\";\n                let has_canonical = gleam_toml.as_table().contains_key(canonical_name);\n                let has_deprecated = gleam_toml.as_table().contains_key(deprecated_name);\n                if !has_canonical && !has_deprecated {\n                    gleam_toml[\"dev_dependencies\"] = toml_edit::table();\n                }\n                let name = if has_deprecated {\n                    deprecated_name\n                } else {\n                    canonical_name\n                };\n                gleam_toml[name][&added_package] = toml_edit::value(range.clone());\n            } else {\n                if !gleam_toml.as_table().contains_key(\"dependencies\") {\n                    gleam_toml[\"dependencies\"] = toml_edit::table();\n                }\n                gleam_toml[\"dependencies\"][&added_package] = toml_edit::value(range.clone());\n            };\n            manifest_toml[\"requirements\"][&added_package][\"version\"] = range.into();\n        }\n    }\n\n    // Write the updated config\n    fs::write(&paths.root_config(), &gleam_toml.to_string())?;\n    fs::write(&paths.manifest(), &manifest_toml.to_string())?;\n\n    Ok(())\n}\n\nfn read_toml_edit(name: &Utf8Path) -> Result<toml_edit::DocumentMut, Error> {\n    fs::read(name)?\n        .parse::<toml_edit::DocumentMut>()\n        .map_err(|e| Error::FileIo {\n            kind: FileKind::File,\n            action: FileIoAction::Parse,\n            path: Utf8PathBuf::from(\"gleam.toml\"),\n            err: Some(e.to_string()),\n        })\n}\n\nfn version_to_string(version: &Version) -> String {\n    let mut text = String::new();\n    text.push_str(&format!(\n        \"{}.{}.{}\",\n        version.major, version.minor, version.patch\n    ));\n    if !version.pre.is_empty() {\n        text.push('-');\n        for (i, identifier) in version.pre.iter().enumerate() {\n            if i != 0 {\n                text.push('.');\n            }\n            match *identifier {\n                Identifier::Numeric(ref id) => text.push_str(&id.to_string()),\n                Identifier::AlphaNumeric(ref id) => text.push_str(id),\n            }\n        }\n    }\n    if let Some(build) = version.build.as_ref() {\n        text.push_str(&format!(\"+{build}\"));\n    }\n    text\n}\n\n#[test]\nfn displays_simple_version_correctly() {\n    let version = Version {\n        major: 1,\n        minor: 23,\n        patch: 4,\n        pre: vec![],\n        build: None,\n    };\n\n    let displayed = version_to_string(&version);\n\n    assert_eq!(displayed, \"1.23.4\");\n}\n\n#[test]\nfn displays_full_version_correctly() {\n    let version = Version {\n        major: 1,\n        minor: 23,\n        patch: 4,\n        pre: vec![\n            Identifier::Numeric(123),\n            Identifier::AlphaNumeric(\"123abc\".to_string()),\n        ],\n        build: Some(\"12345abc\".to_string()),\n    };\n\n    let displayed = version_to_string(&version);\n\n    assert_eq!(displayed, \"1.23.4-123.123abc+12345abc\");\n}\n"
  },
  {
    "path": "compiler-cli/src/beam_compiler.rs",
    "content": "use gleam_core::{\n    Result,\n    error::{Error, ShellCommandFailureReason},\n    io::{FileSystemWriter, Stdio},\n    paths,\n};\n\nuse crate::fs::get_os;\n\nuse std::{\n    collections::HashSet,\n    io::{self, BufRead, BufReader, Write},\n    process::{Child, ChildStdin, ChildStdout},\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse itertools::Itertools;\n\n#[derive(Debug)]\nstruct BeamCompilerInner {\n    process: Child,\n    stdin: ChildStdin,\n    stdout: BufReader<ChildStdout>,\n}\n\n#[derive(Debug, Default)]\npub struct BeamCompiler {\n    inner: Option<BeamCompilerInner>,\n}\n\nimpl BeamCompiler {\n    pub fn compile<IO: FileSystemWriter>(\n        &mut self,\n        io: &IO,\n        out: &Utf8Path,\n        lib: &Utf8Path,\n        modules: &HashSet<Utf8PathBuf>,\n        stdio: Stdio,\n    ) -> Result<Vec<String>, Error> {\n        let inner = match self.inner {\n            Some(ref mut inner) => match inner.process.try_wait() {\n                Ok(None) => inner,\n                _ => self.inner.insert(self.spawn(io, out)?),\n            },\n\n            None => self.inner.insert(self.spawn(io, out)?),\n        };\n\n        let args = format!(\n            \"{{\\\"{}\\\", \\\"{}\\\", [\\\"{}\\\"]}}\",\n            escape_path(lib),\n            escape_path(out.join(\"ebin\")),\n            modules\n                .iter()\n                .map(|module| escape_path(out.join(paths::ARTEFACT_DIRECTORY_NAME).join(module)))\n                .join(\"\\\", \\\"\")\n        );\n\n        tracing::debug!(args=?args, \"call_beam_compiler\");\n\n        writeln!(inner.stdin, \"{args}.\").map_err(|e| Error::ShellCommand {\n            program: \"escript\".into(),\n            reason: ShellCommandFailureReason::IoError(e.kind()),\n        })?;\n\n        let mut buf = String::new();\n        let mut accumulated_modules: Vec<String> = Vec::new();\n        while let (Ok(_), Ok(None)) = (inner.stdout.read_line(&mut buf), inner.process.try_wait()) {\n            match buf.trim() {\n                \"gleam-compile-result-ok\" => {\n                    // Return Ok with the accumulated modules\n                    return Ok(accumulated_modules);\n                }\n                \"gleam-compile-result-error\" => {\n                    return Err(Error::ShellCommand {\n                        program: \"escript\".into(),\n                        reason: ShellCommandFailureReason::Unknown,\n                    });\n                }\n                s if s.starts_with(\"gleam-compile-module:\") => {\n                    if let Some(module_content) = s.strip_prefix(\"gleam-compile-module:\") {\n                        accumulated_modules.push(module_content.to_string());\n                    }\n                }\n                _ => match stdio {\n                    Stdio::Inherit => print!(\"{buf}\"),\n                    Stdio::Null => {}\n                },\n            }\n\n            buf.clear()\n        }\n\n        // if we get here, stdout got closed before we got an \"ok\" or \"err\".\n        Err(Error::ShellCommand {\n            program: \"escript\".into(),\n            reason: ShellCommandFailureReason::Unknown,\n        })\n    }\n\n    fn spawn<IO: FileSystemWriter>(\n        &self,\n        io: &IO,\n        out: &Utf8Path,\n    ) -> Result<BeamCompilerInner, Error> {\n        let escript_path = out\n            .join(paths::ARTEFACT_DIRECTORY_NAME)\n            .join(\"gleam@@compile.erl\");\n\n        let escript_source = std::include_str!(\"../templates/gleam@@compile.erl\");\n        io.write(&escript_path, escript_source)?;\n\n        tracing::trace!(escript_path=?escript_path, \"spawn_beam_compiler\");\n\n        let mut process = std::process::Command::new(\"escript\")\n            .arg(escript_path)\n            .stdin(std::process::Stdio::piped())\n            .stdout(std::process::Stdio::piped())\n            .spawn()\n            .map_err(|e| match e.kind() {\n                io::ErrorKind::NotFound => Error::ShellProgramNotFound {\n                    program: \"escript\".into(),\n                    os: get_os(),\n                },\n                other => Error::ShellCommand {\n                    program: \"escript\".into(),\n                    reason: ShellCommandFailureReason::IoError(other),\n                },\n            })?;\n\n        let stdin = process.stdin.take().expect(\"could not get child stdin\");\n        let stdout = process.stdout.take().expect(\"could not get child stdout\");\n\n        Ok(BeamCompilerInner {\n            process,\n            stdin,\n            stdout: BufReader::new(stdout),\n        })\n    }\n}\n\nimpl Drop for BeamCompiler {\n    fn drop(&mut self) {\n        if let Some(mut inner) = self.inner.take() {\n            // closing stdin will cause the erlang process to exit.\n            drop(inner.stdin);\n            let _ = inner.process.wait();\n        }\n    }\n}\n\nfn escape_path<T: AsRef<str>>(path: T) -> String {\n    path.as_ref().replace(\"\\\\\", \"\\\\\\\\\")\n}\n"
  },
  {
    "path": "compiler-cli/src/build.rs",
    "content": "use std::{rc::Rc, time::Instant};\n\nuse gleam_core::{\n    Result,\n    build::{Built, Codegen, NullTelemetry, Options, ProjectCompiler, Telemetry},\n    manifest::Manifest,\n    paths::ProjectPaths,\n    warning::WarningEmitterIO,\n};\n\nuse crate::{\n    build_lock::BuildLock,\n    cli, dependencies,\n    fs::{self, ConsoleWarningEmitter},\n};\n\npub fn download_dependencies(paths: &ProjectPaths, telemetry: impl Telemetry) -> Result<Manifest> {\n    dependencies::resolve_and_download(\n        paths,\n        telemetry,\n        None,\n        Vec::new(),\n        dependencies::DependencyManagerConfig {\n            use_manifest: dependencies::UseManifest::Yes,\n            check_major_versions: dependencies::CheckMajorVersions::No,\n        },\n    )\n}\n\npub fn main(paths: &ProjectPaths, options: Options, manifest: Manifest) -> Result<Built> {\n    main_with_warnings(paths, options, manifest, Rc::new(ConsoleWarningEmitter))\n}\n\npub(crate) fn main_with_warnings(\n    paths: &ProjectPaths,\n    options: Options,\n    manifest: Manifest,\n    warnings: Rc<dyn WarningEmitterIO>,\n) -> Result<Built> {\n    let perform_codegen = options.codegen;\n    let root_config = crate::config::root_config(paths)?;\n    let telemetry: &'static dyn Telemetry = if options.no_print_progress {\n        &NullTelemetry\n    } else {\n        &cli::Reporter\n    };\n    let io = fs::ProjectIO::new();\n    let start = Instant::now();\n    let lock = BuildLock::new_target(\n        paths,\n        options.mode,\n        options.target.unwrap_or(root_config.target),\n    )?;\n\n    tracing::info!(\"Compiling packages\");\n    let result = {\n        let _guard = lock.lock(telemetry);\n        let compiler = ProjectCompiler::new(\n            root_config,\n            options,\n            manifest.packages,\n            telemetry,\n            warnings,\n            paths.clone(),\n            io,\n        );\n        compiler.compile()?\n    };\n\n    match perform_codegen {\n        Codegen::All | Codegen::DepsOnly => telemetry.compiled_package(start.elapsed()),\n        Codegen::None => telemetry.checked_package(start.elapsed()),\n    };\n\n    Ok(result)\n}\n"
  },
  {
    "path": "compiler-cli/src/build_lock.rs",
    "content": "use camino::Utf8PathBuf;\nuse gleam_core::{\n    Error, Result,\n    build::{Mode, Target, Telemetry},\n    error::{FileIoAction, FileKind},\n    paths::ProjectPaths,\n};\nuse strum::IntoEnumIterator;\n\n#[derive(Debug)]\npub(crate) struct BuildLock {\n    directory: Utf8PathBuf,\n    filename: String,\n}\n\nimpl BuildLock {\n    /// Lock the build directory for the specified mode and target.\n    pub fn new_target(paths: &ProjectPaths, mode: Mode, target: Target) -> Result<Self> {\n        let directory = paths.build_directory();\n        crate::fs::mkdir(&directory)?;\n        let target = match target {\n            Target::Erlang => \"erlang\",\n            Target::JavaScript => \"javascript\",\n        };\n        Ok(Self {\n            directory,\n            filename: format!(\"gleam-{mode}-{target}.lock\"),\n        })\n    }\n\n    /// Lock the packages directory.\n    pub fn new_packages(paths: &ProjectPaths) -> Result<Self> {\n        let directory = paths.build_packages_directory();\n        crate::fs::mkdir(&directory)?;\n        Ok(Self {\n            directory,\n            filename: \"gleam.lock\".to_string(),\n        })\n    }\n\n    /// Construct the lock file path\n    pub fn lock_path(&self) -> Utf8PathBuf {\n        self.directory.join(&self.filename)\n    }\n\n    /// Lock the directory specified by the lock\n    pub fn lock<Telem: Telemetry + ?Sized>(&self, telemetry: &Telem) -> Result<Guard> {\n        let lock_path = self.lock_path();\n        tracing::debug!(path=?lock_path, \"locking_directory\");\n\n        crate::fs::mkdir(&self.directory)?;\n\n        let mut file = fslock::LockFile::open(lock_path.as_str()).map_err(|e| Error::FileIo {\n            kind: FileKind::File,\n            path: lock_path.clone(),\n            action: FileIoAction::Create,\n            err: Some(e.to_string()),\n        })?;\n\n        if !file.try_lock_with_pid().expect(\"Trying directory locking\") {\n            telemetry.waiting_for_build_directory_lock();\n            file.lock_with_pid().expect(\"Directory locking\")\n        }\n\n        Ok(Guard(file))\n    }\n\n    /// Lock all build directories. Does not lock the packages directory.\n    pub fn lock_all_build<Telem: Telemetry>(\n        paths: &ProjectPaths,\n        telemetry: &Telem,\n    ) -> Result<Vec<Guard>> {\n        let mut locks = vec![];\n        for mode in Mode::iter() {\n            for target in Target::iter() {\n                locks.push(Self::new_target(paths, mode, target)?.lock(telemetry)?);\n            }\n        }\n\n        Ok(locks)\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct Guard(\n    // False positive. This is used in `drop`. Presumably the lint error is a\n    // bug in clippy.\n    #[allow(dead_code)] fslock::LockFile,\n);\n\n#[test]\nfn locking_global() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_packages(&paths).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n\n#[test]\nfn locking_dev_erlang() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_target(&paths, Mode::Dev, Target::Erlang).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n\n#[test]\nfn locking_prod_erlang() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_target(&paths, Mode::Prod, Target::Erlang).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n\n#[test]\nfn locking_lsp_erlang() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_target(&paths, Mode::Lsp, Target::Erlang).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n\n#[test]\nfn locking_dev_javascript() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_target(&paths, Mode::Dev, Target::JavaScript).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n\n#[test]\nfn locking_prod_javascript() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_target(&paths, Mode::Prod, Target::JavaScript).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n\n#[test]\nfn locking_lsp_javascript() {\n    let paths = crate::project_paths_at_current_directory_without_toml();\n    let lock = BuildLock::new_target(&paths, Mode::Lsp, Target::JavaScript).expect(\"make lock\");\n    let _guard1: Guard = lock.lock(&gleam_core::build::NullTelemetry).unwrap();\n    println!(\"Locked!\")\n}\n"
  },
  {
    "path": "compiler-cli/src/cli.rs",
    "content": "use ecow::EcoString;\nuse gleam_core::{\n    build::Telemetry,\n    error::{Error, StandardIoAction},\n    manifest::{Changed, ChangedGit, PackageChanges},\n};\nuse hexpm::version::Version;\nuse itertools::Itertools as _;\nuse std::{\n    io::{IsTerminal, Write},\n    time::{Duration, Instant},\n};\nuse termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};\n\n#[derive(Debug, Default, Clone)]\npub struct Reporter;\n\nimpl Reporter {\n    pub fn new() -> Self {\n        Self\n    }\n}\n\nimpl Telemetry for Reporter {\n    fn compiled_package(&self, duration: Duration) {\n        print_compiled(duration);\n    }\n\n    fn compiling_package(&self, name: &str) {\n        print_compiling(name);\n    }\n\n    fn checked_package(&self, duration: Duration) {\n        print_checked(duration);\n    }\n\n    fn checking_package(&self, name: &str) {\n        print_checking(name);\n    }\n\n    fn downloading_package(&self, name: &str) {\n        print_downloading(name)\n    }\n\n    fn packages_downloaded(&self, start: Instant, count: usize) {\n        print_packages_downloaded(start, count)\n    }\n\n    fn resolving_package_versions(&self) {\n        print_resolving_versions()\n    }\n\n    fn running(&self, name: &str) {\n        print_running(name);\n    }\n\n    fn waiting_for_build_directory_lock(&self) {\n        print_waiting_for_build_directory_lock()\n    }\n\n    fn resolved_package_versions(&self, changes: &PackageChanges) {\n        print_package_changes(changes)\n    }\n}\n\npub fn ask(question: &str) -> Result<String, Error> {\n    print!(\"{question}: \");\n    std::io::stdout().flush().expect(\"ask stdout flush\");\n    let mut answer = String::new();\n    let _ = std::io::stdin()\n        .read_line(&mut answer)\n        .map_err(|e| Error::StandardIo {\n            action: StandardIoAction::Read,\n            err: Some(e.kind()),\n        })?;\n    Ok(answer.trim().to_string())\n}\n\npub fn confirm(question: &str) -> Result<bool, Error> {\n    let answer = ask(&format!(\"{question} [y/n]\"))?;\n    match answer.as_str() {\n        \"y\" | \"yes\" | \"Y\" | \"YES\" => Ok(true),\n        _ => Ok(false),\n    }\n}\n\npub fn confirm_with_text(response: &str) -> Result<bool, Error> {\n    let answer = ask(&format!(\"Type '{response}' to continue\"))?;\n    Ok(response == answer)\n}\n\npub fn ask_password(question: &str) -> Result<EcoString, Error> {\n    let prompt = format!(\"{question} (will not be printed as you type): \");\n    rpassword::prompt_password(prompt)\n        .map_err(|e| Error::StandardIo {\n            action: StandardIoAction::Read,\n            err: Some(e.kind()),\n        })\n        .map(|s| EcoString::from(s.trim()))\n}\n\npub fn print_publishing(name: &str, version: &Version) {\n    print_colourful_prefix(\"Publishing\", &format!(\"{name} v{version}\"))\n}\n\npub fn print_published(detail: &str) {\n    print_colourful_prefix(\"Published\", detail)\n}\n\npub fn print_retired(package: &str, version: &str) {\n    print_colourful_prefix(\"Retired\", &format!(\"{package} {version}\"))\n}\n\npub fn print_unretired(package: &str, version: &str) {\n    print_colourful_prefix(\"Unretired\", &format!(\"{package} {version}\"))\n}\n\npub fn print_publishing_documentation() {\n    print_colourful_prefix(\"Publishing\", \"documentation\");\n}\n\nfn print_downloading(text: &str) {\n    print_colourful_prefix(\"Downloading\", text)\n}\n\nfn print_waiting_for_build_directory_lock() {\n    print_colourful_prefix(\"Waiting\", \"for build directory lock\")\n}\n\nfn print_resolving_versions() {\n    print_colourful_prefix(\"Resolving\", \"versions\")\n}\n\nfn print_compiling(text: &str) {\n    print_colourful_prefix(\"Compiling\", text)\n}\n\npub(crate) fn print_exported(text: &str) {\n    print_colourful_prefix(\"Exported\", text)\n}\n\npub(crate) fn print_checking(text: &str) {\n    print_colourful_prefix(\"Checking\", text)\n}\n\npub(crate) fn print_compiled(duration: Duration) {\n    print_colourful_prefix(\"Compiled\", &format!(\"in {}\", seconds(duration)))\n}\n\npub(crate) fn print_checked(duration: Duration) {\n    print_colourful_prefix(\"Checked\", &format!(\"in {}\", seconds(duration)))\n}\n\npub(crate) fn print_running(text: &str) {\n    print_colourful_prefix(\"Running\", text)\n}\n\npub(crate) fn print_package_changes(changes: &PackageChanges) {\n    for (name, version) in changes.added.iter().sorted() {\n        print_added(&format!(\"{name} v{version}\"));\n    }\n    for Changed { name, old, new } in changes.changed.iter().sorted_by_key(|p| &p.name) {\n        print_changed(&format!(\"{name} v{old} -> v{new}\"));\n    }\n    for ChangedGit {\n        name,\n        old_hash,\n        new_hash,\n    } in changes.changed_git.iter().sorted_by_key(|p| &p.name)\n    {\n        print_changed(&format!(\"{name} {old_hash} -> {new_hash}\"));\n    }\n    for name in changes.removed.iter().sorted() {\n        print_removed(name);\n    }\n}\n\nfn print_added(text: &str) {\n    print_colourful_prefix(\"Added\", text)\n}\n\nfn print_changed(text: &str) {\n    print_colourful_prefix(\"Changed\", text)\n}\n\nfn print_removed(text: &str) {\n    print_colourful_prefix(\"Removed\", text)\n}\n\npub(crate) fn print_generating_documentation() {\n    print_colourful_prefix(\"Generating\", \"documentation\")\n}\n\npub(crate) fn print_transferring_ownership() {\n    print_colourful_prefix(\"Transferring\", \"ownership\");\n}\n\npub(crate) fn print_transferred_ownership() {\n    print_colourful_prefix(\"Transferred\", \"ownership\");\n}\n\nfn print_packages_downloaded(start: Instant, count: usize) {\n    let elapsed = seconds(start.elapsed());\n    let msg = match count {\n        1 => format!(\"1 package in {elapsed}\"),\n        _ => format!(\"{count} packages in {elapsed}\"),\n    };\n    print_colourful_prefix(\"Downloaded\", &msg)\n}\n\npub fn seconds(duration: Duration) -> String {\n    format!(\"{:.2}s\", duration.as_millis() as f32 / 1000.)\n}\n\npub fn print_colourful_prefix(prefix: &str, text: &str) {\n    let buffer_writer = stderr_buffer_writer();\n    let mut buffer = buffer_writer.buffer();\n    buffer\n        .set_color(\n            ColorSpec::new()\n                .set_intense(true)\n                .set_fg(Some(Color::Magenta)),\n        )\n        .expect(\"print_green_prefix\");\n    write!(buffer, \"{prefix: >11}\").expect(\"print_green_prefix\");\n    buffer\n        .set_color(&ColorSpec::new())\n        .expect(\"print_green_prefix\");\n    writeln!(buffer, \" {text}\").expect(\"print_green_prefix\");\n    buffer_writer.print(&buffer).expect(\"print_green_prefix\");\n}\n\npub fn stderr_buffer_writer() -> BufferWriter {\n    // Don't add color codes to the output if standard error isn't connected to a terminal\n    BufferWriter::stderr(color_choice())\n}\n\nfn colour_forced() -> bool {\n    if let Ok(force) = std::env::var(\"FORCE_COLOR\") {\n        !force.is_empty()\n    } else {\n        false\n    }\n}\n\nfn color_choice() -> ColorChoice {\n    if colour_forced() {\n        ColorChoice::Always\n    } else if std::io::stderr().is_terminal() {\n        ColorChoice::Auto\n    } else {\n        ColorChoice::Never\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/compile_package.rs",
    "content": "use crate::{\n    CompilePackage, config,\n    fs::{self, ConsoleWarningEmitter, ProjectIO},\n};\nuse camino::Utf8Path;\nuse ecow::EcoString;\nuse gleam_core::{\n    Error, Result,\n    build::{\n        Mode, NullTelemetry, PackageCompiler, StaleTracker, Target, TargetCodegenConfiguration,\n    },\n    error::{FileIoAction, FileKind},\n    metadata,\n    paths::{self, ProjectPaths},\n    type_::ModuleInterface,\n    uid::UniqueIdGenerator,\n    warning::WarningEmitter,\n};\nuse std::{collections::HashSet, rc::Rc};\n\npub fn command(options: CompilePackage) -> Result<()> {\n    let ids = UniqueIdGenerator::new();\n    let mut type_manifests = load_libraries(&ids, &options.libraries_directory)?;\n    let mut defined_modules = im::HashMap::new();\n    let warnings = WarningEmitter::new(Rc::new(ConsoleWarningEmitter));\n    let paths = ProjectPaths::new(options.package_directory.clone());\n    let config = config::read(paths.root_config())?;\n\n    let target = match options.target {\n        Target::Erlang => TargetCodegenConfiguration::Erlang { app_file: None },\n        Target::JavaScript => TargetCodegenConfiguration::JavaScript {\n            emit_typescript_definitions: false,\n            prelude_location: options\n                .javascript_prelude\n                .ok_or_else(|| Error::JavaScriptPreludeRequired)?,\n        },\n    };\n\n    tracing::info!(\"Compiling package\");\n\n    let mut compiler = PackageCompiler::new(\n        &config,\n        Mode::Dev,\n        &options.package_directory,\n        &options.output_directory,\n        &options.libraries_directory,\n        &target,\n        ids,\n        ProjectIO::new(),\n    );\n    compiler.write_entrypoint = false;\n    compiler.write_metadata = true;\n    compiler.compile_beam_bytecode = !options.skip_beam_compilation;\n    compiler\n        .compile(\n            &warnings,\n            &mut type_manifests,\n            &mut defined_modules,\n            &mut StaleTracker::default(),\n            &mut HashSet::new(),\n            &NullTelemetry,\n        )\n        .into_result()\n        .map(|_| ())\n}\n\nfn load_libraries(\n    ids: &UniqueIdGenerator,\n    lib: &Utf8Path,\n) -> Result<im::HashMap<EcoString, ModuleInterface>> {\n    tracing::info!(\"Reading precompiled module metadata files\");\n    let mut manifests = im::HashMap::new();\n    for lib in fs::read_dir(lib)?.filter_map(Result::ok) {\n        let path = lib.path().join(paths::ARTEFACT_DIRECTORY_NAME);\n        if !path.is_dir() {\n            continue;\n        }\n        for module in fs::module_caches_paths(path)? {\n            let bytes = fs::read_bytes(module.clone())?;\n            let module = match metadata::decode(&bytes, ids.clone()) {\n                Ok(module) => module,\n                Err(e) => {\n                    return Err(Error::FileIo {\n                        kind: FileKind::File,\n                        action: FileIoAction::Parse,\n                        path: module,\n                        err: Some(e.to_string()),\n                    });\n                }\n            };\n            let _ = manifests.insert(module.name.clone(), module);\n        }\n    }\n\n    Ok(manifests)\n}\n"
  },
  {
    "path": "compiler-cli/src/config.rs",
    "content": "use camino::Utf8PathBuf;\n\nuse gleam_core::{\n    config::PackageConfig,\n    error::{Error, FileIoAction, FileKind},\n    manifest::{Manifest, ManifestPackage, ManifestPackageSource},\n    paths::ProjectPaths,\n};\n\n#[derive(Debug, Clone, Copy)]\npub enum PackageKind {\n    Dependency,\n    Root,\n}\n\n/// Get the config for a dependency module. Return the config for the current\n/// project if a dependency doesn't have a config file.\npub fn find_package_config_for_module(\n    mod_path: &str,\n    manifest: &Manifest,\n    project_paths: &ProjectPaths,\n) -> Result<(PackageConfig, PackageKind), Error> {\n    for package in &manifest.packages {\n        // Not a Gleam package\n        if !package.build_tools.contains(&\"gleam\".into()) {\n            continue;\n        }\n\n        let root = package_root(package, project_paths);\n        let mut module_path = root.join(\"src\").join(mod_path);\n        _ = module_path.set_extension(\"gleam\");\n\n        // This package doesn't have the module we're looking for\n        if !module_path.is_file() {\n            continue;\n        }\n\n        let configuration = read(root.join(\"gleam.toml\"))?;\n        return Ok((configuration, PackageKind::Dependency));\n    }\n\n    Ok((root_config(project_paths)?, PackageKind::Root))\n}\n\nfn package_root(package: &ManifestPackage, project_paths: &ProjectPaths) -> Utf8PathBuf {\n    match &package.source {\n        ManifestPackageSource::Local { path } => project_paths.root().join(path),\n\n        ManifestPackageSource::Hex { .. } | ManifestPackageSource::Git { .. } => {\n            project_paths.build_packages_package(&package.name)\n        }\n    }\n}\n\npub fn root_config(paths: &ProjectPaths) -> Result<PackageConfig, Error> {\n    read(paths.root_config())\n}\n\npub fn read(config_path: Utf8PathBuf) -> Result<PackageConfig, Error> {\n    let toml = crate::fs::read(&config_path)?;\n    let config: PackageConfig = toml::from_str(&toml).map_err(|e| Error::FileIo {\n        action: FileIoAction::Parse,\n        kind: FileKind::File,\n        path: config_path,\n        err: Some(e.to_string()),\n    })?;\n    config.check_gleam_compatibility()?;\n    Ok(config)\n}\n\npub fn ensure_config_exists(paths: &ProjectPaths) -> Result<(), Error> {\n    let path = paths.root_config();\n    if !path.is_file() {\n        return Err(Error::FileIo {\n            action: FileIoAction::Read,\n            kind: FileKind::File,\n            path,\n            err: Some(\"File not found\".into()),\n        });\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gleam_core::manifest::Base16Checksum;\n\n    #[test]\n    fn package_root_hex() {\n        let paths = ProjectPaths::new(Utf8PathBuf::from(\"/app\"));\n        let package = ManifestPackage {\n            name: \"the_package\".into(),\n            version: hexpm::version::Version::new(1, 0, 0),\n            build_tools: vec![\"gleam\".into()],\n            otp_app: None,\n            requirements: vec![],\n            source: ManifestPackageSource::Hex {\n                outer_checksum: Base16Checksum(vec![]),\n            },\n        };\n        assert_eq!(\n            package_root(&package, &paths),\n            Utf8PathBuf::from(\"/app/build/packages/the_package\")\n        );\n    }\n\n    #[test]\n    fn package_root_git() {\n        let paths = ProjectPaths::new(Utf8PathBuf::from(\"/app\"));\n        let package = ManifestPackage {\n            name: \"the_package\".into(),\n            version: hexpm::version::Version::new(1, 0, 0),\n            build_tools: vec![\"gleam\".into()],\n            otp_app: None,\n            requirements: vec![],\n            source: ManifestPackageSource::Git {\n                repo: \"repo\".into(),\n                commit: \"commit\".into(),\n            },\n        };\n        assert_eq!(\n            package_root(&package, &paths),\n            Utf8PathBuf::from(\"/app/build/packages/the_package\")\n        );\n    }\n\n    #[test]\n    fn package_root_local() {\n        let paths = ProjectPaths::new(Utf8PathBuf::from(\"/app\"));\n        let package = ManifestPackage {\n            name: \"the_package\".into(),\n            version: hexpm::version::Version::new(1, 0, 0),\n            build_tools: vec![\"gleam\".into()],\n            otp_app: None,\n            requirements: vec![],\n            source: ManifestPackageSource::Local {\n                path: Utf8PathBuf::from(\"../wibble\"),\n            },\n        };\n        assert_eq!(\n            package_root(&package, &paths),\n            Utf8PathBuf::from(\"/app/../wibble\")\n        );\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/dependencies/dependency_manager.rs",
    "content": "use ecow::EcoString;\nuse futures::future;\nuse gleam_core::{\n    Error, Result,\n    build::{Mode, Telemetry},\n    config::PackageConfig,\n    dependency,\n    manifest::{Manifest, ManifestPackageSource, PackageChanges, Resolved},\n    paths::ProjectPaths,\n    requirement::Requirement,\n};\nuse std::collections::HashMap;\n\nuse crate::{\n    build_lock::BuildLock,\n    dependencies::{pretty_print_major_versions_available, write_manifest_to_disc},\n    fs::ProjectIO,\n};\n\nuse super::{\n    CheckMajorVersions, LocalPackages, UseManifest, add_missing_packages, is_same_requirements,\n    lookup_package, path_dependency_configs_unchanged, provide_git_package, provide_local_package,\n    read_manifest_from_disc, remove_extra_packages, unlock_packages,\n};\n\n/// Verifies that all specified packages exist in the manifest.\npub fn ensure_packages_exist_locally(manifest: &Manifest, packages: &[EcoString]) -> Result<()> {\n    let missing_packages: Vec<EcoString> = packages\n        .iter()\n        .filter(|package_name| !manifest.packages.iter().any(|p| &p.name == *package_name))\n        .cloned()\n        .collect();\n\n    if !missing_packages.is_empty() {\n        return Err(Error::PackagesToUpdateNotExist {\n            packages: missing_packages,\n        });\n    }\n    Ok(())\n}\n\npub struct DependencyManagerConfig {\n    // If `Yes` we read the manifest from disc. If not set then we ignore any\n    // manifest which will result in the latest versions of the dependency\n    // packages being resolved (not the locked ones).\n    pub use_manifest: UseManifest,\n    /// When set to `Yes`, the cli will check for major version updates of direct dependencies and\n    /// print them to the console if the major versions are not upgradeable due to constraints.\n    pub check_major_versions: CheckMajorVersions,\n}\n\nimpl DependencyManagerConfig {\n    pub fn into_dependency_manager<Telem: Telemetry, P: dependency::PackageFetcher>(\n        self,\n        runtime: tokio::runtime::Handle,\n        package_fetcher: P,\n        telemetry: Telem,\n        mode: Mode,\n    ) -> DependencyManager<Telem, P> {\n        DependencyManager {\n            runtime,\n            package_fetcher,\n            telemetry,\n\n            mode,\n            use_manifest: self.use_manifest,\n            check_major_versions: self.check_major_versions,\n        }\n    }\n}\n\npub struct DependencyManager<Telem, P> {\n    runtime: tokio::runtime::Handle,\n    package_fetcher: P,\n    mode: Mode,\n    use_manifest: UseManifest,\n    telemetry: Telem,\n    check_major_versions: CheckMajorVersions,\n}\n\nimpl<Telem, P> DependencyManager<Telem, P>\nwhere\n    P: dependency::PackageFetcher,\n    Telem: Telemetry,\n{\n    /// Resolve the dependency versions used by a package.\n    ///\n    /// If the `use_manifest` configuration was set to `false` then it'll always resolve all the\n    /// versions, even if there are already versions locked in the manifest.\n    pub fn resolve_versions(\n        &self,\n        paths: &ProjectPaths,\n        config: &PackageConfig,\n        packages_to_update: Vec<EcoString>,\n    ) -> Result<Resolved> {\n        // If there's no manifest then the only thing we can do is attempt to update the versions.\n        if !paths.manifest().exists() {\n            tracing::debug!(\"manifest_not_present\");\n            let manifest = self.perform_version_resolution(paths, config, None, Vec::new())?;\n            ensure_packages_exist_locally(&manifest, &packages_to_update)?;\n            return Ok(Resolved::all_added(manifest));\n        }\n\n        let existing_manifest = read_manifest_from_disc(paths)?;\n        ensure_packages_exist_locally(&existing_manifest, &packages_to_update)?;\n\n        // If we have been asked not to use the manifest then\n        let (requirements_changed, manifest_for_resolver) = match self.use_manifest {\n            UseManifest::No => (true, None),\n            UseManifest::Yes => {\n                let config_dependencies = config.all_direct_dependencies()?;\n                let same_requirements = is_same_requirements(\n                    &existing_manifest.requirements,\n                    &config_dependencies,\n                    paths.root(),\n                )?;\n\n                // If the manifest is to be used and the requirements have not changed then there's\n                // no point in performing resolution, it'll always result in the same versions\n                // already specified in the manifest.\n                if packages_to_update.is_empty()\n                    && same_requirements\n                    && path_dependency_configs_unchanged(&config_dependencies, paths)?\n                {\n                    return Ok(Resolved::no_change(existing_manifest));\n                }\n\n                // Otherwise, use the manifest to inform resolution.\n                (!same_requirements, Some(&existing_manifest))\n            }\n        };\n\n        tracing::debug!(\"manifest_outdated\");\n        let new_manifest = self.perform_version_resolution(\n            paths,\n            config,\n            manifest_for_resolver,\n            packages_to_update,\n        )?;\n        let resolved = Resolved {\n            package_changes: PackageChanges::between_manifests(&existing_manifest, &new_manifest),\n            manifest: new_manifest,\n            requirements_changed,\n        };\n        Ok(resolved)\n    }\n\n    pub fn resolve_and_download_versions(\n        &self,\n        paths: &ProjectPaths,\n        new_package: Option<(Vec<(EcoString, Requirement)>, bool)>,\n        packages_to_update: Vec<EcoString>,\n    ) -> Result<Manifest> {\n        let span = tracing::info_span!(\"download_deps\");\n        let _enter = span.enter();\n\n        // We do this before acquiring the build lock so that we don't create the\n        // build directory if there is no gleam.toml\n        crate::config::ensure_config_exists(paths)?;\n\n        let lock = BuildLock::new_packages(paths)?;\n        let _guard = lock.lock(&self.telemetry);\n\n        let fs = ProjectIO::boxed();\n\n        // Read the project config\n        let mut config = crate::config::read(paths.root_config())?;\n        let project_name = config.name.clone();\n\n        // Insert the new packages to add, if it exists\n        if let Some((packages, dev)) = new_package {\n            for (package, requirement) in packages {\n                if dev {\n                    _ = config.dev_dependencies.insert(package, requirement);\n                } else {\n                    _ = config.dependencies.insert(package, requirement);\n                };\n            }\n        }\n\n        // Determine what versions we need\n        let resolved = self.resolve_versions(paths, &config, packages_to_update)?;\n        let local = LocalPackages::read_from_disc(paths)?;\n\n        // Remove any packages that are no longer required due to gleam.toml changes\n        remove_extra_packages(paths, &local, &resolved.manifest, &self.telemetry)?;\n\n        // Download them from Hex to the local cache\n        self.runtime.block_on(add_missing_packages(\n            paths,\n            fs,\n            &resolved.manifest,\n            &local,\n            project_name,\n            &self.telemetry,\n        ))?;\n\n        if resolved.any_changes() {\n            // Record new state of the packages directory\n            // TODO: test\n            tracing::debug!(\"writing_manifest_toml\");\n            write_manifest_to_disc(paths, &resolved.manifest)?;\n        }\n        LocalPackages::from_manifest(&resolved.manifest).write_to_disc(paths)?;\n\n        // Display the changes in versions to the user.\n        self.telemetry\n            .resolved_package_versions(&resolved.package_changes);\n\n        // If requested to do so, check if there are major upgrades that could be performed with\n        // more relaxed version requirements, and inform the user if so.\n        if let CheckMajorVersions::Yes = self.check_major_versions {\n            let major_versions_available = dependency::check_for_major_version_updates(\n                &resolved.manifest,\n                &self.package_fetcher,\n            );\n            if !major_versions_available.is_empty() {\n                eprintln!(\n                    \"{}\",\n                    pretty_print_major_versions_available(major_versions_available)\n                );\n            }\n        }\n        Ok(resolved.manifest)\n    }\n\n    fn perform_version_resolution(\n        &self,\n        project_paths: &ProjectPaths,\n        config: &PackageConfig,\n        manifest: Option<&Manifest>,\n        packages_to_update: Vec<EcoString>,\n    ) -> Result<Manifest, Error> {\n        self.telemetry.resolving_package_versions();\n        let dependencies = config.dependencies_for(self.mode)?;\n        let mut locked = config.locked(manifest)?;\n\n        if !packages_to_update.is_empty() {\n            unlock_packages(&mut locked, &packages_to_update, manifest)?;\n        }\n\n        // Packages which are provided directly instead of downloaded from hex\n        let mut provided_packages = HashMap::new();\n        // The version requires of the current project\n        let mut root_requirements = HashMap::new();\n\n        // Populate the provided_packages and root_requirements maps\n        for (name, requirement) in dependencies.into_iter() {\n            let version = match requirement {\n                Requirement::Hex { version } => version,\n                Requirement::Path { path } => provide_local_package(\n                    name.clone(),\n                    &path,\n                    project_paths.root(),\n                    project_paths,\n                    &mut provided_packages,\n                    &mut vec![],\n                )?,\n                Requirement::Git { git, ref_ } => {\n                    // If this package is locked and we already resolved a commit\n                    // hash for it, we want to use that hash rather than pulling\n                    // the latest commit.\n                    let ref_to_use = if locked.contains_key(&name)\n                        && let Some(manifest) = manifest\n                        && let Some(package) = manifest\n                            .packages\n                            .iter()\n                            .find(|package| package.name == name)\n                        && let ManifestPackageSource::Git { commit, .. } = &package.source\n                    {\n                        commit\n                    } else {\n                        // If the package is unlocked or we haven't resolved a version yet, we use\n                        // the ref specified in `gleam.toml`.\n                        &ref_\n                    };\n\n                    provide_git_package(\n                        name.clone(),\n                        &git,\n                        ref_to_use,\n                        project_paths,\n                        &mut provided_packages,\n                        &mut Vec::new(),\n                    )?\n                }\n            };\n            let _ = root_requirements.insert(name, version);\n        }\n\n        // Convert provided packages into hex packages for pub-grub resolve\n        let provided_hex_packages = provided_packages\n            .iter()\n            .map(|(name, package)| (name.clone(), package.to_hex_package(name)))\n            .collect();\n\n        let resolved = dependency::resolve_versions(\n            &self.package_fetcher,\n            provided_hex_packages,\n            config.name.clone(),\n            root_requirements.into_iter(),\n            &locked,\n        )?;\n\n        // Convert the hex packages and local packages into manifest packages\n        let manifest_packages = self.runtime.block_on(future::try_join_all(\n            resolved\n                .into_iter()\n                .map(|(name, version)| lookup_package(name, version, &provided_packages)),\n        ))?;\n\n        let manifest = Manifest {\n            packages: manifest_packages,\n            requirements: config.all_direct_dependencies()?,\n        };\n\n        Ok(manifest)\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/dependencies/snapshots/gleam_cli__dependencies__tests__pretty_print_major_versions_available.snap",
    "content": "---\nsource: compiler-cli/src/dependencies/tests.rs\nassertion_line: 1349\nexpression: output\nsnapshot_kind: text\n---\nThe following dependencies have new major versions available:\n\nPackage                 Current    Latest\n-------                 -------    ------\ngleam_stdlib            0.45.0     1.0.0\nshort_name              1.0.0      2.0.0\nvery_long_package_name  18.382.43  19.0.38\n"
  },
  {
    "path": "compiler-cli/src/dependencies/snapshots/gleam_cli__dependencies__tests__pretty_print_version_updates.snap",
    "content": "---\nsource: compiler-cli/src/dependencies/tests.rs\nassertion_line: 1373\nexpression: output\nsnapshot_kind: text\n---\nPackage                 Current   Latest\n-------                 -------   ------\ngleam_stdlib            0.45.0    0.46.0\nvery_long_package_name  12.12.12  120.12.12\nwisp                    2.1.0     2.1.1\n"
  },
  {
    "path": "compiler-cli/src/dependencies/tests.rs",
    "content": "use std::collections::HashMap;\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse pretty_assertions::assert_eq;\n\nuse gleam_core::{\n    Error,\n    build::Runtime,\n    config::{DenoConfig, DenoFlag, Docs, ErlangConfig, JavaScriptConfig},\n    manifest::{Base16Checksum, Manifest, ManifestPackage, ManifestPackageSource},\n    paths::ProjectPaths,\n    requirement::Requirement,\n};\n\nuse crate::dependencies::*;\n\n#[test]\nfn list_manifest_format() {\n    let mut buffer = vec![];\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"root\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n                },\n            },\n            ManifestPackage {\n                name: \"aaa\".into(),\n                version: Version::new(0, 4, 2),\n                build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                otp_app: Some(\"aaa_app\".into()),\n                requirements: vec![\"zzz\".into(), \"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n            ManifestPackage {\n                name: \"zzz\".into(),\n                version: Version::new(0, 4, 0),\n                build_tools: [\"mix\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n        ],\n    };\n    list_manifest_packages(&mut buffer, manifest).unwrap();\n    assert_eq!(\n        std::str::from_utf8(&buffer).unwrap(),\n        \"Package  Version\n-------  -------\nroot     1.0.0\naaa      0.4.2\nzzz      0.4.0\n\"\n    )\n}\n\n#[test]\nfn tree_format() {\n    let mut buffer = vec![];\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"deps_proj\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_regexp\".into(), \"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n                },\n            },\n            ManifestPackage {\n                name: \"gleam_stdlib\".into(),\n                version: Version::new(0, 52, 0),\n                build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                otp_app: Some(\"aaa_app\".into()),\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n            ManifestPackage {\n                name: \"gleam_regexp\".into(),\n                version: Version::new(1, 0, 0),\n                build_tools: [\"mix\".into()].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n        ],\n    };\n\n    let options = TreeOptions {\n        package: None,\n        invert: None,\n    };\n\n    let root_package_name = EcoString::from(\"deps_proj\");\n\n    list_package_and_dependencies_tree(\n        &mut buffer,\n        options,\n        manifest.packages.clone(),\n        root_package_name,\n    )\n    .unwrap();\n    assert_eq!(\n        std::str::from_utf8(&buffer).unwrap(),\n        r#\"deps_proj v1.0.0\n├── gleam_regexp v1.0.0\n│   └── gleam_stdlib v0.52.0\n└── gleam_stdlib v0.52.0\n\"#\n    )\n}\n\n#[test]\nfn tree_package_format() {\n    let mut buffer = vec![];\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"gleam_stdlib\".into(),\n                version: Version::new(0, 52, 0),\n                build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                otp_app: Some(\"aaa_app\".into()),\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n            ManifestPackage {\n                name: \"deps_proj\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_stdlib\".into(), \"gleam_regexp\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n                },\n            },\n            ManifestPackage {\n                name: \"gleam_regexp\".into(),\n                version: Version::new(1, 0, 0),\n                build_tools: [\"mix\".into()].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n        ],\n    };\n    let options = TreeOptions {\n        package: Some(\"gleam_regexp\".to_string()),\n        invert: None,\n    };\n\n    let root_package_name = EcoString::from(\"deps_proj\");\n\n    list_package_and_dependencies_tree(\n        &mut buffer,\n        options,\n        manifest.packages.clone(),\n        root_package_name,\n    )\n    .unwrap();\n    assert_eq!(\n        std::str::from_utf8(&buffer).unwrap(),\n        r#\"gleam_regexp v1.0.0\n└── gleam_stdlib v0.52.0\n\"#\n    )\n}\n\n#[test]\nfn tree_invert_format() {\n    let mut buffer = vec![];\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"gleam_stdlib\".into(),\n                version: Version::new(0, 52, 0),\n                build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                otp_app: Some(\"aaa_app\".into()),\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n            ManifestPackage {\n                name: \"deps_proj\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_stdlib\".into(), \"gleam_regexp\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n                },\n            },\n            ManifestPackage {\n                name: \"gleam_regexp\".into(),\n                version: Version::new(1, 0, 0),\n                build_tools: [\"mix\".into()].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n        ],\n    };\n    let options = TreeOptions {\n        package: None,\n        invert: Some(\"gleam_stdlib\".to_string()),\n    };\n\n    let root_package_name = EcoString::from(\"deps_proj\");\n\n    list_package_and_dependencies_tree(\n        &mut buffer,\n        options,\n        manifest.packages.clone(),\n        root_package_name,\n    )\n    .unwrap();\n    assert_eq!(\n        std::str::from_utf8(&buffer).unwrap(),\n        r#\"gleam_stdlib v0.52.0\n├── deps_proj v1.0.0\n└── gleam_regexp v1.0.0\n    └── deps_proj v1.0.0\n\"#\n    )\n}\n\n#[test]\nfn list_tree_invalid_package_format() {\n    let mut buffer = vec![];\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"gleam_stdlib\".into(),\n                version: Version::new(0, 52, 0),\n                build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                otp_app: Some(\"aaa_app\".into()),\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n            ManifestPackage {\n                name: \"gleam_regexp\".into(),\n                version: Version::new(1, 0, 0),\n                build_tools: [\"mix\".into()].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![3, 22]),\n                },\n            },\n            ManifestPackage {\n                name: \"root\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [].into(),\n                otp_app: None,\n                requirements: vec![\"gleam_regexp\".into(), \"gleam_stdlib\".into()],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n                },\n            },\n        ],\n    };\n    let options = TreeOptions {\n        package: Some(\"zzzzzz\".to_string()),\n        invert: None,\n    };\n\n    let root_package_name = EcoString::from(\"deps_proj\");\n\n    list_package_and_dependencies_tree(\n        &mut buffer,\n        options,\n        manifest.packages.clone(),\n        root_package_name,\n    )\n    .unwrap();\n    assert_eq!(\n        std::str::from_utf8(&buffer).unwrap(),\n        r#\"Package not found. Please check the package name.\n\"#\n    )\n}\n\n#[test]\nfn parse_gleam_add_specifier_invalid_semver() {\n    assert!(parse_gleam_add_specifier(\"some_package@1.2.3.4\").is_err());\n}\n\n#[test]\nfn parse_gleam_add_specifier_non_numeric_version() {\n    assert!(parse_gleam_add_specifier(\"some_package@not_a_version\").is_err());\n}\n\n#[test]\nfn parse_gleam_add_specifier_default() {\n    let provided = \"some_package\";\n    let expected = Requirement::hex(\">= 0.0.0\").unwrap();\n    let (package, version) = parse_gleam_add_specifier(provided).unwrap();\n    assert_eq!(version, expected);\n    assert_eq!(\"some_package\", package);\n}\n\n#[test]\nfn parse_gleam_add_specifier_major_only() {\n    let provided = \"wobble@1\";\n    let expected = Requirement::hex(\">= 1.0.0 and < 2.0.0\").unwrap();\n    let (package, version) = parse_gleam_add_specifier(provided).unwrap();\n    assert_eq!(version, expected);\n    assert_eq!(\"wobble\", package);\n}\n\n#[test]\nfn parse_gleam_add_specifier_major_and_minor() {\n    let provided = \"wibble@1.2\";\n    let expected = Requirement::hex(\">= 1.2.0 and < 2.0.0\").unwrap();\n    let (package, version) = parse_gleam_add_specifier(provided).unwrap();\n    assert_eq!(version, expected);\n    assert_eq!(\"wibble\", package);\n}\n\n#[test]\nfn parse_gleam_add_specifier_major_minor_and_patch() {\n    let provided = \"bobble@1.2.3\";\n    let expected = Requirement::hex(\"1.2.3\").unwrap();\n    let (package, version) = parse_gleam_add_specifier(provided).unwrap();\n    assert_eq!(version, expected);\n    assert_eq!(\"bobble\", package);\n}\n\n#[test]\nfn missing_local_packages() {\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"root\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n                },\n            },\n            ManifestPackage {\n                name: \"local1\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4, 5]),\n                },\n            },\n            ManifestPackage {\n                name: \"local2\".into(),\n                version: Version::parse(\"3.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4, 5]),\n                },\n            },\n        ],\n    };\n    let mut extra = LocalPackages {\n        packages: [\n            (\"local2\".into(), Version::parse(\"2.0.0\").unwrap()),\n            (\"local3\".into(), Version::parse(\"3.0.0\").unwrap()),\n        ]\n        .into(),\n    }\n    .missing_local_packages(&manifest, \"root\");\n    extra.sort();\n    assert_eq!(\n        extra,\n        [\n            &ManifestPackage {\n                name: \"local1\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4, 5]),\n                },\n            },\n            &ManifestPackage {\n                name: \"local2\".into(),\n                version: Version::parse(\"3.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4, 5]),\n                },\n            },\n        ]\n    )\n}\n\n#[test]\nfn extra_local_packages() {\n    let mut extra = LocalPackages {\n        packages: [\n            (\"local1\".into(), Version::parse(\"1.0.0\").unwrap()),\n            (\"local2\".into(), Version::parse(\"2.0.0\").unwrap()),\n            (\"local3\".into(), Version::parse(\"3.0.0\").unwrap()),\n        ]\n        .into(),\n    }\n    .extra_local_packages(&Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            ManifestPackage {\n                name: \"local1\".into(),\n                version: Version::parse(\"1.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![1, 2, 3, 4, 5]),\n                },\n            },\n            ManifestPackage {\n                name: \"local2\".into(),\n                version: Version::parse(\"3.0.0\").unwrap(),\n                build_tools: [\"gleam\".into()].into(),\n                otp_app: None,\n                requirements: vec![],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![4, 5]),\n                },\n            },\n        ],\n    });\n    extra.sort();\n    assert_eq!(\n        extra,\n        [\n            (\"local2\".into(), Version::new(2, 0, 0)),\n            (\"local3\".into(), Version::new(3, 0, 0)),\n        ]\n    )\n}\n\n#[test]\nfn provide_wrong_package() {\n    let mut provided = HashMap::new();\n    let project_paths = crate::project_paths_at_current_directory_without_toml();\n    let result = provide_local_package(\n        \"wrong_name\".into(),\n        Utf8Path::new(\"./test/hello_world\"),\n        Utf8Path::new(\"./\"),\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"subpackage\".into()],\n    );\n    match result {\n        Err(Error::WrongDependencyProvided {\n            expected, found, ..\n        }) => {\n            assert_eq!(expected, \"wrong_name\");\n            assert_eq!(found, \"hello_world\");\n        }\n        _ => {\n            panic!(\"Expected WrongDependencyProvided error\")\n        }\n    }\n}\n\n#[test]\nfn provide_existing_package() {\n    let mut provided = HashMap::new();\n    let project_paths = crate::project_paths_at_current_directory_without_toml();\n\n    let result = provide_local_package(\n        \"hello_world\".into(),\n        Utf8Path::new(\"./test/hello_world\"),\n        Utf8Path::new(\"./\"),\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"subpackage\".into()],\n    );\n    assert_eq!(\n        result,\n        Ok(hexpm::version::Range::new(\"== 0.1.0\".into()).unwrap())\n    );\n\n    let result = provide_local_package(\n        \"hello_world\".into(),\n        Utf8Path::new(\"./test/hello_world\"),\n        Utf8Path::new(\"./\"),\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"subpackage\".into()],\n    );\n    assert_eq!(\n        result,\n        Ok(hexpm::version::Range::new(\"== 0.1.0\".into()).unwrap())\n    );\n}\n\n#[test]\nfn provide_conflicting_package() {\n    let mut provided = HashMap::new();\n    let project_paths = crate::project_paths_at_current_directory_without_toml();\n    let result = provide_local_package(\n        \"hello_world\".into(),\n        Utf8Path::new(\"./test/hello_world\"),\n        Utf8Path::new(\"./\"),\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"subpackage\".into()],\n    );\n    assert_eq!(\n        result,\n        Ok(hexpm::version::Range::new(\"== 0.1.0\".into()).unwrap())\n    );\n\n    let result = provide_package(\n        \"hello_world\".into(),\n        Utf8PathBuf::from(\"./test/other\"),\n        ProvidedPackageSource::Local {\n            path: Utf8Path::new(\"./test/other\").to_path_buf(),\n        },\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"subpackage\".into()],\n    );\n    match result {\n        Err(Error::ProvidedDependencyConflict { package, .. }) => {\n            assert_eq!(package, \"hello_world\");\n        }\n        _ => {\n            panic!(\"Expected ProvidedDependencyConflict error\")\n        }\n    }\n}\n\n#[test]\nfn provided_is_absolute() {\n    let mut provided = HashMap::new();\n    let project_paths = crate::project_paths_at_current_directory_without_toml();\n    let result = provide_local_package(\n        \"hello_world\".into(),\n        Utf8Path::new(\"./test/hello_world\"),\n        Utf8Path::new(\"./\"),\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"subpackage\".into()],\n    );\n    assert_eq!(\n        result,\n        Ok(hexpm::version::Range::new(\"== 0.1.0\".into()).unwrap())\n    );\n    let package = provided.get(\"hello_world\").unwrap().clone();\n    match package.source {\n        ProvidedPackageSource::Local { path } => {\n            assert!(path.is_absolute())\n        }\n        _ => {\n            panic!(\"Provide_local_package provided a package that is not local!\")\n        }\n    }\n}\n\n#[test]\nfn provided_recursive() {\n    let mut provided = HashMap::new();\n    let project_paths = crate::project_paths_at_current_directory_without_toml();\n    let result = provide_local_package(\n        \"hello_world\".into(),\n        Utf8Path::new(\"./test/hello_world\"),\n        Utf8Path::new(\"./\"),\n        &project_paths,\n        &mut provided,\n        &mut vec![\"root\".into(), \"hello_world\".into(), \"subpackage\".into()],\n    );\n    assert_eq!(\n        result,\n        Err(Error::PackageCycle {\n            packages: vec![\"subpackage\".into(), \"hello_world\".into()],\n        })\n    )\n}\n\n#[test]\nfn provided_local_to_hex() {\n    let provided_package = ProvidedPackage {\n        version: Version::new(1, 0, 0),\n        source: ProvidedPackageSource::Local {\n            path: \"canonical/path/to/package\".into(),\n        },\n        requirements: [\n            (\n                \"req_1\".into(),\n                hexpm::version::Range::new(\"~> 1.0.0\".into()).unwrap(),\n            ),\n            (\n                \"req_2\".into(),\n                hexpm::version::Range::new(\"== 1.0.0\".into()).unwrap(),\n            ),\n        ]\n        .into(),\n    };\n\n    let hex_package = hexpm::Package {\n        name: \"package\".into(),\n        repository: \"local\".into(),\n        releases: vec![hexpm::Release {\n            version: Version::new(1, 0, 0),\n            retirement_status: None,\n            outer_checksum: vec![],\n            meta: (),\n            requirements: [\n                (\n                    \"req_1\".into(),\n                    hexpm::Dependency {\n                        requirement: hexpm::version::Range::new(\"~> 1.0.0\".into()).unwrap(),\n                        optional: false,\n                        app: None,\n                        repository: None,\n                    },\n                ),\n                (\n                    \"req_2\".into(),\n                    hexpm::Dependency {\n                        requirement: hexpm::version::Range::new(\"== 1.0.0\".into()).unwrap(),\n                        optional: false,\n                        app: None,\n                        repository: None,\n                    },\n                ),\n            ]\n            .into(),\n        }],\n    };\n\n    assert_eq!(\n        provided_package.to_hex_package(&\"package\".into()),\n        hex_package\n    );\n}\n\n#[test]\nfn provided_git_to_hex() {\n    let provided_package = ProvidedPackage {\n        version: Version::new(1, 0, 0),\n        source: ProvidedPackageSource::Git {\n            repo: \"https://github.com/gleam-lang/gleam.git\".into(),\n            commit: \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\".into(),\n        },\n        requirements: [\n            (\n                \"req_1\".into(),\n                hexpm::version::Range::new(\"~> 1.0.0\".into()).unwrap(),\n            ),\n            (\n                \"req_2\".into(),\n                hexpm::version::Range::new(\"== 1.0.0\".into()).unwrap(),\n            ),\n        ]\n        .into(),\n    };\n\n    let hex_package = hexpm::Package {\n        name: \"package\".into(),\n        repository: \"local\".into(),\n        releases: vec![hexpm::Release {\n            version: Version::new(1, 0, 0),\n            retirement_status: None,\n            outer_checksum: vec![],\n            meta: (),\n            requirements: [\n                (\n                    \"req_1\".into(),\n                    hexpm::Dependency {\n                        requirement: hexpm::version::Range::new(\"~> 1.0.0\".into()).unwrap(),\n                        optional: false,\n                        app: None,\n                        repository: None,\n                    },\n                ),\n                (\n                    \"req_2\".into(),\n                    hexpm::Dependency {\n                        requirement: hexpm::version::Range::new(\"== 1.0.0\".into()).unwrap(),\n                        optional: false,\n                        app: None,\n                        repository: None,\n                    },\n                ),\n            ]\n            .into(),\n        }],\n    };\n\n    assert_eq!(\n        provided_package.to_hex_package(&\"package\".into()),\n        hex_package\n    );\n}\n\n#[test]\nfn provided_local_to_manifest() {\n    let provided_package = ProvidedPackage {\n        version: Version::new(1, 0, 0),\n        source: ProvidedPackageSource::Local {\n            path: \"canonical/path/to/package\".into(),\n        },\n        requirements: [\n            (\n                \"req_1\".into(),\n                hexpm::version::Range::new(\"~> 1.0.0\".into()).unwrap(),\n            ),\n            (\n                \"req_2\".into(),\n                hexpm::version::Range::new(\"== 1.0.0\".into()).unwrap(),\n            ),\n        ]\n        .into(),\n    };\n\n    let manifest_package = ManifestPackage {\n        name: \"package\".into(),\n        version: Version::new(1, 0, 0),\n        otp_app: None,\n        build_tools: vec![\"gleam\".into()],\n        requirements: vec![\"req_1\".into(), \"req_2\".into()],\n        source: ManifestPackageSource::Local {\n            path: \"canonical/path/to/package\".into(),\n        },\n    };\n\n    assert_eq!(\n        provided_package.to_manifest_package(\"package\"),\n        manifest_package\n    );\n}\n\n#[test]\nfn provided_git_to_manifest() {\n    let provided_package = ProvidedPackage {\n        version: Version::new(1, 0, 0),\n        source: ProvidedPackageSource::Git {\n            repo: \"https://github.com/gleam-lang/gleam.git\".into(),\n            commit: \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\".into(),\n        },\n        requirements: [\n            (\n                \"req_1\".into(),\n                hexpm::version::Range::new(\"~> 1.0.0\".into()).unwrap(),\n            ),\n            (\n                \"req_2\".into(),\n                hexpm::version::Range::new(\"== 1.0.0\".into()).unwrap(),\n            ),\n        ]\n        .into(),\n    };\n\n    let manifest_package = ManifestPackage {\n        name: \"package\".into(),\n        version: Version::new(1, 0, 0),\n        otp_app: None,\n        build_tools: vec![\"gleam\".into()],\n        requirements: vec![\"req_1\".into(), \"req_2\".into()],\n        source: ManifestPackageSource::Git {\n            repo: \"https://github.com/gleam-lang/gleam.git\".into(),\n            commit: \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\".into(),\n        },\n    };\n\n    assert_eq!(\n        provided_package.to_manifest_package(\"package\"),\n        manifest_package\n    );\n}\n\n#[test]\nfn verified_requirements_equality_with_canonicalized_paths() {\n    let temp_dir = tempfile::tempdir().expect(\"Failed to create a temp directory\");\n    let temp_path = Utf8PathBuf::from_path_buf(temp_dir.path().to_path_buf())\n        .expect(\"Path should be valid UTF-8\");\n\n    let sub_dir = temp_path.join(\"subdir\");\n    std::fs::create_dir(&sub_dir).expect(\"Failed to create a subdir\");\n    let file_path = sub_dir.join(\"file.txt\");\n    fs::write(&file_path, \"content\").expect(\"Failed to write to file\");\n\n    let canonical_path = std::fs::canonicalize(&file_path).expect(\"Failed to canonicalize path\");\n    let relative_path = temp_path.join(\"./subdir/../subdir/./file.txt\");\n\n    let requirements1 = HashMap::from([(\n        EcoString::from(\"dep1\"),\n        Requirement::Path {\n            path: Utf8PathBuf::from(canonical_path.to_str().expect(\"Path should be valid UTF-8\")),\n        },\n    )]);\n\n    let requirements2 = HashMap::from([(\n        EcoString::from(\"dep1\"),\n        Requirement::Path {\n            path: Utf8PathBuf::from(relative_path.to_string()),\n        },\n    )]);\n\n    assert!(\n        is_same_requirements(&requirements1, &requirements2, &temp_path)\n            .expect(\"Requirements should be the same\")\n    );\n}\n\n#[test]\nfn test_path_dependency_config_updates() {\n    let temp_dir = tempfile::tempdir().expect(\"Failed to create a temp directory\");\n    let root_path = Utf8PathBuf::from_path_buf(temp_dir.path().to_path_buf())\n        .expect(\"Path should be valid UTF-8\");\n    let paths = ProjectPaths::new(root_path.clone());\n    let dep_path = root_path.join(\"dep\");\n    std::fs::create_dir_all(&dep_path).expect(\"Failed to create dependency directory\");\n    let build_packages_dir = root_path.join(\"build\").join(\"packages\");\n    std::fs::create_dir_all(&build_packages_dir)\n        .expect(\"Failed to create build/packages directory\");\n\n    let config = \"name = \\\"dep\\\"\nversion = \\\"1.0.0\\\"\n\n[dependencies]\n\";\n    let dep_config_path = dep_path.join(\"gleam.toml\");\n    fs::write(&dep_config_path, config).expect(\"Failed to write to manifest file\");\n\n    let requirements = HashMap::from([(\n        EcoString::from(\"dep\"),\n        Requirement::Path {\n            path: Utf8PathBuf::from(\"dep\"),\n        },\n    )]);\n\n    // Initial check testing\n\n    let unchanged = path_dependency_configs_unchanged(&requirements, &paths).unwrap();\n    assert!(!unchanged, \"fresh always needs resolution\");\n\n    let fingerprint_path = build_packages_dir.join(\"dep.config_fingerprint\");\n    assert!(fingerprint_path.exists(), \"fingerprint must exist\");\n\n    let unchanged = path_dependency_configs_unchanged(&requirements, &paths).unwrap();\n    assert!(unchanged, \"is unchanged\");\n\n    // Set fingerprint mtime to some time in the past. This causes the mtime check to fail,\n    // so it moves on to checking the fingerprint itself.\n    let past = std::time::SystemTime::now() - std::time::Duration::from_secs(10);\n    let past = filetime::FileTime::from_system_time(past);\n    filetime::set_file_mtime(&fingerprint_path, past).unwrap();\n\n    let unchanged = path_dependency_configs_unchanged(&requirements, &paths).unwrap();\n    assert!(unchanged, \"mtime is outdated, but content has not changed\");\n\n    // Writing new content means the mtime and the fingerprint checks will fail.\n    let config = \"name = \\\"dep\\\"\nversion = \\\"1.0.0\\\"\n\n[dependencies]\nblah = \\\">= 1.0.0\\\"\n\";\n    fs::write(&dep_config_path, config).unwrap();\n\n    let unchanged = path_dependency_configs_unchanged(&requirements, &paths).unwrap();\n    assert!(!unchanged, \"content has changed\");\n\n    // Run again, to ensure that the fingerprint has been updated.\n    let unchanged = path_dependency_configs_unchanged(&requirements, &paths).unwrap();\n    assert!(unchanged, \"no changes since last run\");\n\n    // Test that mtime is checked first, and that content is not checked when the mtime\n    // is still valid. We do this by having having content that would fail the fingerprint\n    // check, but having a fresh mtime so it never gets checked.\n    // This can never happen in reality as you can't update the content without updating\n    // the mtime, but we create the situation in this test to verify the short-circuiting\n    // behaviour.\n    let config = \"name = \\\"dep\\\"\nversion = \\\"1.0.0\\\"\n\n[dependencies]\nblah = \\\">= 1.0.0\\\"\nwub = \\\">= 1.0.0\\\"\n\";\n    fs::write(&dep_config_path, config).unwrap();\n    let future = std::time::SystemTime::now() + std::time::Duration::from_secs(10);\n    let future = filetime::FileTime::from_system_time(future);\n    filetime::set_file_mtime(&fingerprint_path, future).unwrap();\n\n    let unchanged = path_dependency_configs_unchanged(&requirements, &paths).unwrap();\n    assert!(unchanged, \"fingerprint is outdated, but mtime is not\");\n}\n\nfn create_testable_unlock_manifest(\n    packages: Vec<(EcoString, Version, Vec<EcoString>)>,\n    requirements: Vec<(EcoString, EcoString)>,\n) -> Manifest {\n    let manifest_packages = packages\n        .into_iter()\n        .map(|(name, version, requirements)| ManifestPackage {\n            name,\n            version,\n            build_tools: vec![\"gleam\".into()],\n            otp_app: None,\n            requirements,\n            source: ManifestPackageSource::Hex {\n                outer_checksum: Base16Checksum(vec![]),\n            },\n        })\n        .collect();\n\n    let root_requirements = requirements\n        .into_iter()\n        .map(|(name, range)| {\n            (\n                name,\n                Requirement::Hex {\n                    version: hexpm::version::Range::new(range.into()).unwrap(),\n                },\n            )\n        })\n        .collect();\n\n    Manifest {\n        packages: manifest_packages,\n        requirements: root_requirements,\n    }\n}\n\n#[test]\nfn test_unlock_package() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n        (\"package_d\".into(), Version::new(4, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into()],\n        ),\n        (\n            \"package_b\".into(),\n            Version::new(2, 0, 0),\n            vec![\"package_c\".into()],\n        ),\n        (\"package_c\".into(), Version::new(3, 0, 0), vec![]),\n        (\"package_d\".into(), Version::new(4, 0, 0), vec![]),\n    ];\n\n    let manifest = create_testable_unlock_manifest(packages, Vec::new());\n\n    let packages_to_unlock = vec![\"package_a\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(!locked.contains_key(\"package_b\"));\n    assert!(!locked.contains_key(\"package_c\"));\n    assert!(locked.contains_key(\"package_d\"));\n}\n\n#[test]\nfn test_unlock_package_without_manifest() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n    ]);\n\n    let packages_to_unlock = vec![\"package_a\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, None).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(locked.contains_key(\"package_b\"));\n    assert!(locked.contains_key(\"package_c\"));\n}\n\n#[test]\nfn test_unlock_nonexistent_package() {\n    let initial_locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into()],\n        ),\n        (\"package_b\".into(), Version::new(2, 0, 0), vec![]),\n    ];\n\n    let manifest = create_testable_unlock_manifest(packages, Vec::new());\n\n    let packages_to_unlock = vec![\"nonexistent_package\".into()];\n    let mut locked = initial_locked.clone();\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert_eq!(\n        initial_locked, locked,\n        \"Locked packages should remain unchanged\"\n    );\n}\n\n#[test]\nfn test_unlock_multiple_packages() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n        (\"package_d\".into(), Version::new(4, 0, 0)),\n        (\"package_e\".into(), Version::new(5, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into()],\n        ),\n        (\n            \"package_b\".into(),\n            Version::new(2, 0, 0),\n            vec![\"package_c\".into()],\n        ),\n        (\"package_c\".into(), Version::new(3, 0, 0), vec![]),\n        (\n            \"package_d\".into(),\n            Version::new(4, 0, 0),\n            vec![\"package_e\".into()],\n        ),\n        (\"package_e\".into(), Version::new(5, 0, 0), vec![]),\n    ];\n\n    let manifest = create_testable_unlock_manifest(packages, Vec::new());\n\n    let packages_to_unlock = vec![\"package_a\".into(), \"package_d\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(!locked.contains_key(\"package_b\"));\n    assert!(!locked.contains_key(\"package_c\"));\n    assert!(!locked.contains_key(\"package_d\"));\n    assert!(!locked.contains_key(\"package_e\"));\n}\n\n#[test]\nfn test_unlock_packages_empty_input() {\n    let initial_locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into()],\n        ),\n        (\"package_b\".into(), Version::new(2, 0, 0), vec![]),\n    ];\n\n    let manifest = create_testable_unlock_manifest(packages, Vec::new());\n\n    let packages_to_unlock: Vec<EcoString> = vec![];\n    let mut locked = initial_locked.clone();\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert_eq!(\n        initial_locked, locked,\n        \"Locked packages should remain unchanged when no packages are specified to unlock\"\n    );\n}\n\n#[test]\nfn test_unlock_package_preserve_shared_deps() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_c\".into()],\n        ),\n        (\n            \"package_b\".into(),\n            Version::new(2, 0, 0),\n            vec![\"package_c\".into()],\n        ),\n        (\"package_c\".into(), Version::new(3, 0, 0), vec![]),\n    ];\n\n    let manifest = create_testable_unlock_manifest(packages, Vec::new());\n\n    let packages_to_unlock: Vec<EcoString> = vec![\"package_a\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(locked.contains_key(\"package_b\"));\n    assert!(locked.contains_key(\"package_c\"));\n}\n\n#[test]\nfn test_unlock_package_with_root_dep() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into()],\n        ),\n        (\n            \"package_b\".into(),\n            Version::new(2, 0, 0),\n            vec![\"package_c\".into()],\n        ),\n        (\"package_c\".into(), Version::new(3, 0, 0), vec![]),\n    ];\n\n    let requirements = vec![(\"package_b\".into(), \">= 2.0.0\".into())];\n\n    let manifest = create_testable_unlock_manifest(packages, requirements);\n\n    let packages_to_unlock: Vec<EcoString> = vec![\"package_a\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(locked.contains_key(\"package_b\"));\n    assert!(locked.contains_key(\"package_c\"));\n}\n\n#[test]\nfn test_unlock_root_dep_package() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into()],\n        ),\n        (\"package_b\".into(), Version::new(2, 0, 0), vec![]),\n        (\"package_c\".into(), Version::new(3, 0, 0), vec![]),\n    ];\n\n    let requirements = vec![(\"package_a\".into(), \">= 1.0.0\".into())];\n\n    let manifest = create_testable_unlock_manifest(packages, requirements);\n\n    let packages_to_unlock: Vec<EcoString> = vec![\"package_a\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(!locked.contains_key(\"package_b\"));\n    assert!(locked.contains_key(\"package_c\"));\n}\n\n#[test]\nfn test_unlock_package_with_and_without_root_dep() {\n    let mut locked = HashMap::from([\n        (\"package_a\".into(), Version::new(1, 0, 0)),\n        (\"package_b\".into(), Version::new(2, 0, 0)),\n        (\"package_c\".into(), Version::new(3, 0, 0)),\n    ]);\n\n    let packages = vec![\n        (\n            \"package_a\".into(),\n            Version::new(1, 0, 0),\n            vec![\"package_b\".into(), \"package_c\".into()],\n        ),\n        (\"package_b\".into(), Version::new(2, 0, 0), vec![]),\n        (\"package_c\".into(), Version::new(3, 0, 0), vec![]),\n    ];\n\n    let requirements = vec![(\"package_b\".into(), \">= 2.0.0\".into())];\n\n    let manifest = create_testable_unlock_manifest(packages, requirements);\n\n    let packages_to_unlock: Vec<EcoString> = vec![\"package_a\".into()];\n    unlock_packages(&mut locked, &packages_to_unlock, Some(&manifest)).unwrap();\n\n    assert!(!locked.contains_key(\"package_a\"));\n    assert!(locked.contains_key(\"package_b\"));\n    assert!(!locked.contains_key(\"package_c\"));\n}\n\nfn manifest_package(name: &str, version: &str, requirements: Vec<EcoString>) -> ManifestPackage {\n    ManifestPackage {\n        name: name.into(),\n        version: Version::parse(version).unwrap(),\n        build_tools: [\"gleam\".into()].into(),\n        otp_app: None,\n        requirements,\n        source: ManifestPackageSource::Hex {\n            outer_checksum: Base16Checksum(vec![1, 2, 3, 4]),\n        },\n    }\n}\n\nfn package_config(\n    dependencies: HashMap<EcoString, Requirement>,\n    dev_dependencies: HashMap<EcoString, Requirement>,\n) -> PackageConfig {\n    PackageConfig {\n        name: \"the_package\".into(),\n        version: Version::parse(\"1.0.0\").unwrap(),\n        gleam_version: None,\n        licences: vec![],\n        description: \"\".into(),\n        documentation: Docs { pages: vec![] },\n        dependencies,\n        dev_dependencies,\n        repository: None,\n        links: vec![],\n        erlang: ErlangConfig {\n            application_start_module: None,\n            application_start_argument: None,\n            extra_applications: vec![],\n        },\n        javascript: JavaScriptConfig {\n            typescript_declarations: false,\n            runtime: Runtime::NodeJs,\n            deno: DenoConfig {\n                allow_env: DenoFlag::AllowAll,\n                allow_sys: true,\n                allow_hrtime: true,\n                allow_net: DenoFlag::AllowAll,\n                allow_ffi: true,\n                allow_read: DenoFlag::AllowAll,\n                allow_run: DenoFlag::AllowAll,\n                allow_write: DenoFlag::AllowAll,\n                allow_all: true,\n                unstable: true,\n                location: None,\n            },\n        },\n        target: Target::Erlang,\n        internal_modules: None,\n    }\n}\n\n#[test]\nfn test_remove_do_nothing() {\n    let config = package_config(\n        HashMap::from([(\"a\".into(), Requirement::hex(\"~>1.0\").unwrap())]),\n        HashMap::from([(\"b\".into(), Requirement::hex(\"~>2.0\").unwrap())]),\n    );\n\n    let mut manifest = Manifest {\n        requirements: HashMap::from([\n            (\"a\".into(), Requirement::hex(\"~>1.0\").unwrap()),\n            (\"b\".into(), Requirement::hex(\"~>2.0\").unwrap()),\n        ]),\n        packages: vec![\n            manifest_package(\"a\", \"1.0.0\", vec![]),\n            manifest_package(\"b\", \"2.0.8\", vec![]),\n        ],\n    };\n\n    let manifest_copy = manifest.clone();\n\n    remove_extra_requirements(&config, &mut manifest).unwrap();\n\n    assert_eq!(manifest.requirements, manifest_copy.requirements);\n    assert_eq!(manifest.packages, manifest_copy.packages);\n}\n\n#[test]\nfn test_remove_simple() {\n    let config = package_config(HashMap::new(), HashMap::new());\n\n    let mut manifest = Manifest {\n        requirements: HashMap::from([(\"a\".into(), Requirement::hex(\"~>1.0\").unwrap())]),\n        packages: vec![manifest_package(\"a\", \"1.0.0\", vec![])],\n    };\n\n    remove_extra_requirements(&config, &mut manifest).unwrap();\n\n    assert_eq!(manifest.requirements, config.dependencies);\n    assert_eq!(manifest.packages, vec![]);\n}\n\n#[test]\nfn test_remove_package_with_transitive_dependencies() {\n    let config = package_config(HashMap::new(), HashMap::new());\n\n    let mut manifest = Manifest {\n        requirements: HashMap::from([(\"a\".into(), Requirement::hex(\"~>1.0\").unwrap())]),\n        packages: vec![\n            manifest_package(\"a\", \"1.0.0\", vec![\"b\".into()]),\n            manifest_package(\"b\", \"1.2.3\", vec![\"c\".into()]),\n            manifest_package(\"c\", \"2.0.0\", vec![]),\n        ],\n    };\n\n    remove_extra_requirements(&config, &mut manifest).unwrap();\n\n    assert_eq!(manifest.requirements, config.dependencies);\n    assert_eq!(manifest.packages, vec![]);\n}\n\n#[test]\nfn test_remove_package_with_shared_transitive_dependencies() {\n    let config = package_config(\n        HashMap::from([(\"a\".into(), Requirement::hex(\"~>1.0\").unwrap())]),\n        HashMap::new(),\n    );\n\n    let mut manifest = Manifest {\n        requirements: HashMap::from([\n            (\"a\".into(), Requirement::hex(\"~>1.0\").unwrap()),\n            (\"b\".into(), Requirement::hex(\"~>1.0\").unwrap()),\n        ]),\n        packages: vec![\n            manifest_package(\"a\", \"1.0.0\", vec![\"c\".into()]),\n            manifest_package(\"b\", \"1.2.3\", vec![\"c\".into(), \"d\".into()]),\n            manifest_package(\"c\", \"2.0.0\", vec![]),\n            manifest_package(\"d\", \"0.1.0\", vec![]),\n        ],\n    };\n\n    remove_extra_requirements(&config, &mut manifest).unwrap();\n\n    assert_eq!(manifest.requirements, config.dependencies);\n    assert_eq!(\n        manifest.packages,\n        vec![\n            manifest_package(\"a\", \"1.0.0\", vec![\"c\".into()]),\n            manifest_package(\"c\", \"2.0.0\", vec![]),\n        ]\n    );\n}\n\n#[test]\nfn test_remove_package_that_is_also_a_transitive_dependency() {\n    let config = package_config(\n        HashMap::from([(\"a\".into(), Requirement::hex(\"~>1.0\").unwrap())]),\n        HashMap::new(),\n    );\n\n    let mut manifest = Manifest {\n        requirements: HashMap::from([\n            (\"a\".into(), Requirement::hex(\"~>1.0\").unwrap()),\n            (\"b\".into(), Requirement::hex(\"~>1.0\").unwrap()),\n        ]),\n        packages: vec![\n            manifest_package(\"a\", \"1.0.0\", vec![\"b\".into(), \"c\".into()]),\n            manifest_package(\"b\", \"1.2.3\", vec![\"c\".into(), \"d\".into()]),\n            manifest_package(\"c\", \"2.0.0\", vec![]),\n            manifest_package(\"d\", \"0.1.0\", vec![]),\n        ],\n    };\n\n    let manifest_copy = manifest.clone();\n\n    remove_extra_requirements(&config, &mut manifest).unwrap();\n\n    assert_eq!(manifest.requirements, config.dependencies);\n    assert_eq!(manifest.packages, manifest_copy.packages);\n}\n\n#[test]\nfn test_pretty_print_major_versions_available() {\n    let versions = vec![\n        (\n            \"very_long_package_name\".to_string(),\n            (Version::new(18, 382, 43), Version::new(19, 0, 38)),\n        ),\n        (\n            \"gleam_stdlib\".to_string(),\n            (Version::new(0, 45, 0), Version::new(1, 0, 0)),\n        ),\n        (\n            \"short_name\".to_string(),\n            (Version::new(1, 0, 0), Version::new(2, 0, 0)),\n        ),\n    ]\n    .into_iter()\n    .collect();\n\n    let output = pretty_print_major_versions_available(versions);\n\n    insta::assert_snapshot!(output);\n}\n\n#[test]\nfn test_pretty_print_version_updates() {\n    let versions = vec![\n        (\n            \"gleam_stdlib\".to_string(),\n            (Version::new(0, 45, 0), Version::new(0, 46, 0)),\n        ),\n        (\n            \"wisp\".to_string(),\n            (Version::new(2, 1, 0), Version::new(2, 1, 1)),\n        ),\n        (\n            \"very_long_package_name\".to_string(),\n            (Version::new(12, 12, 12), Version::new(120, 12, 12)),\n        ),\n    ]\n    .into_iter()\n    .collect();\n\n    let output = pretty_print_version_updates(versions);\n\n    insta::assert_snapshot!(output);\n}\n\n#[test]\nfn test_ensure_packages_exist_locally_all_present() {\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            manifest_package(\"package_a\", \"1.0.0\", vec![]),\n            manifest_package(\"package_b\", \"2.0.0\", vec![]),\n            manifest_package(\"package_c\", \"3.0.0\", vec![]),\n        ],\n    };\n\n    let packages_to_check = vec![\"package_a\".into(), \"package_b\".into()];\n    let result = dependency_manager::ensure_packages_exist_locally(&manifest, &packages_to_check);\n\n    assert!(result.is_ok(), \"All packages exist, should return Ok\");\n}\n\n#[test]\nfn test_ensure_packages_exist_locally_some_missing() {\n    let manifest = Manifest {\n        requirements: HashMap::new(),\n        packages: vec![\n            manifest_package(\"package_a\", \"1.0.0\", vec![]),\n            manifest_package(\"package_b\", \"2.0.0\", vec![]),\n        ],\n    };\n\n    let packages_to_check = vec![\n        \"package_a\".into(),\n        \"package_b\".into(),\n        \"missing_package\".into(),\n        \"another_missing\".into(),\n    ];\n    let result = dependency_manager::ensure_packages_exist_locally(&manifest, &packages_to_check);\n\n    match result {\n        Err(Error::PackagesToUpdateNotExist { packages }) => {\n            assert_eq!(packages.len(), 2);\n            assert!(packages.contains(&\"missing_package\".into()));\n            assert!(packages.contains(&\"another_missing\".into()));\n        }\n        _ => panic!(\"Expected PackagesToUpdateNotExist error\"),\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/dependencies.rs",
    "content": "mod dependency_manager;\n\nuse std::{\n    cell::RefCell,\n    collections::{HashMap, HashSet},\n    io::ErrorKind,\n    process::Command,\n    rc::Rc,\n    time::Instant,\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::{EcoString, eco_format};\nuse flate2::read::GzDecoder;\nuse gleam_core::{\n    Error, Result,\n    build::{Mode, SourceFingerprint, Target, Telemetry},\n    config::PackageConfig,\n    dependency::{self, PackageFetchError},\n    error::{FileIoAction, FileKind, ShellCommandFailureReason, StandardIoAction},\n    hex::{self, HEXPM_PUBLIC_KEY},\n    io::{HttpClient as _, TarUnpacker, WrappedReader},\n    manifest::{Base16Checksum, Manifest, ManifestPackage, ManifestPackageSource, PackageChanges},\n    paths::ProjectPaths,\n    requirement::Requirement,\n};\nuse hexpm::version::Version;\nuse itertools::Itertools;\nuse same_file::is_same_file;\nuse strum::IntoEnumIterator;\n\npub use dependency_manager::DependencyManagerConfig;\n\n#[cfg(test)]\nmod tests;\n\nuse crate::{\n    TreeOptions,\n    build_lock::{BuildLock, Guard},\n    cli,\n    fs::{self, ProjectIO},\n    http::HttpClient,\n    text_layout::space_table,\n};\n\nstruct Symbols {\n    down: &'static str,\n    tee: &'static str,\n    ell: &'static str,\n    right: &'static str,\n}\n\nstatic UTF8_SYMBOLS: Symbols = Symbols {\n    down: \"│\",\n    tee: \"├\",\n    ell: \"└\",\n    right: \"─\",\n};\n\n/// When set to `Yes`, the cli will check for major version updates of direct dependencies and\n/// print them to the console if the major versions are not upgradeable due to constraints.\n#[derive(Debug, Clone, Copy)]\npub enum CheckMajorVersions {\n    Yes,\n    No,\n}\n\npub fn list(paths: &ProjectPaths) -> Result<()> {\n    let (_, manifest) = get_manifest_details(paths)?;\n    list_manifest_packages(std::io::stdout(), manifest)\n}\n\npub fn tree(paths: &ProjectPaths, options: TreeOptions) -> Result<()> {\n    let (config, manifest) = get_manifest_details(paths)?;\n\n    // Initialize the root package since it is not part of the manifest\n    let root_package = ManifestPackage {\n        build_tools: vec![],\n        name: config.name.clone(),\n        requirements: config.all_direct_dependencies()?.keys().cloned().collect(),\n        version: config.version.clone(),\n        source: ManifestPackageSource::Local {\n            path: paths.root().to_path_buf(),\n        },\n        otp_app: None,\n    };\n\n    // Get the manifest packages and add the root package to the vec\n    let mut packages = manifest.packages.iter().cloned().collect_vec();\n    packages.append(&mut vec![root_package.clone()]);\n\n    list_package_and_dependencies_tree(std::io::stdout(), options, packages.clone(), config.name)\n}\n\nfn get_manifest_details(paths: &ProjectPaths) -> Result<(PackageConfig, Manifest)> {\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let config = crate::config::root_config(paths)?;\n    let package_fetcher = PackageFetcher::new(runtime.handle().clone());\n    let dependency_manager = DependencyManagerConfig {\n        use_manifest: UseManifest::Yes,\n        check_major_versions: CheckMajorVersions::No,\n    }\n    .into_dependency_manager(\n        runtime.handle().clone(),\n        package_fetcher,\n        cli::Reporter::new(),\n        Mode::Dev,\n    );\n    let manifest = dependency_manager\n        .resolve_versions(paths, &config, Vec::new())?\n        .manifest;\n    Ok((config, manifest))\n}\n\nfn list_manifest_packages<W: std::io::Write>(mut buffer: W, manifest: Manifest) -> Result<()> {\n    let packages = manifest\n        .packages\n        .into_iter()\n        .map(|package| vec![package.name.to_string(), package.version.to_string()])\n        .collect_vec();\n    let out = space_table(&[\"Package\", \"Version\"], packages);\n\n    write!(buffer, \"{out}\").map_err(|e| Error::StandardIo {\n        action: StandardIoAction::Write,\n        err: Some(e.kind()),\n    })\n}\n\nfn list_package_and_dependencies_tree<W: std::io::Write>(\n    mut buffer: W,\n    options: TreeOptions,\n    packages: Vec<ManifestPackage>,\n    root_package_name: EcoString,\n) -> Result<()> {\n    let mut invert = false;\n\n    let package: Option<&ManifestPackage> = if let Some(input_package_name) = options.package {\n        packages.iter().find(|p| p.name == input_package_name)\n    } else if let Some(input_package_name) = options.invert {\n        invert = true;\n        packages.iter().find(|p| p.name == input_package_name)\n    } else {\n        packages.iter().find(|p| p.name == root_package_name)\n    };\n\n    if let Some(package) = package {\n        let tree = Vec::from([eco_format!(\"{0} v{1}\", package.name, package.version)]);\n        let tree = list_dependencies_tree(\n            tree.clone(),\n            package.clone(),\n            packages,\n            EcoString::new(),\n            invert,\n        );\n\n        tree.iter()\n            .try_for_each(|line| writeln!(buffer, \"{line}\"))\n            .map_err(|e| Error::StandardIo {\n                action: StandardIoAction::Write,\n                err: Some(e.kind()),\n            })\n    } else {\n        writeln!(buffer, \"Package not found. Please check the package name.\").map_err(|e| {\n            Error::StandardIo {\n                action: StandardIoAction::Write,\n                err: Some(e.kind()),\n            }\n        })\n    }\n}\n\nfn list_dependencies_tree(\n    mut tree: Vec<EcoString>,\n    package: ManifestPackage,\n    packages: Vec<ManifestPackage>,\n    accum: EcoString,\n    invert: bool,\n) -> Vec<EcoString> {\n    let dependencies = packages\n        .iter()\n        .filter(|p| {\n            (invert && p.requirements.contains(&package.name))\n                || (!invert && package.requirements.contains(&p.name))\n        })\n        .cloned()\n        .collect_vec();\n\n    let dependencies = dependencies.iter().sorted().enumerate();\n\n    let deps_length = dependencies.len();\n    for (index, dependency) in dependencies {\n        let is_last = index == deps_length - 1;\n        let prefix = if is_last {\n            UTF8_SYMBOLS.ell\n        } else {\n            UTF8_SYMBOLS.tee\n        };\n\n        tree.push(eco_format!(\n            \"{0}{1}{2}{2} {3} v{4}\",\n            accum.clone(),\n            prefix,\n            UTF8_SYMBOLS.right,\n            dependency.name,\n            dependency.version\n        ));\n\n        let accum = accum.clone() + (if !is_last { UTF8_SYMBOLS.down } else { \" \" }) + \"   \";\n\n        tree = list_dependencies_tree(\n            tree.clone(),\n            dependency.clone(),\n            packages.clone(),\n            accum.clone(),\n            invert,\n        );\n    }\n\n    tree\n}\n\npub fn outdated(paths: &ProjectPaths) -> Result<()> {\n    let (_, manifest) = get_manifest_details(paths)?;\n\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let package_fetcher = PackageFetcher::new(runtime.handle().clone());\n\n    let version_updates = dependency::check_for_version_updates(&manifest, &package_fetcher);\n\n    if !version_updates.is_empty() {\n        print!(\"{}\", pretty_print_version_updates(version_updates));\n    }\n\n    Ok(())\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum UseManifest {\n    Yes,\n    No,\n}\n\npub fn update(paths: &ProjectPaths, packages: Vec<String>) -> Result<()> {\n    let use_manifest = if packages.is_empty() {\n        UseManifest::No\n    } else {\n        UseManifest::Yes\n    };\n\n    // Update specific packages\n    _ = resolve_and_download(\n        paths,\n        cli::Reporter::new(),\n        None,\n        packages.into_iter().map(EcoString::from).collect(),\n        DependencyManagerConfig {\n            use_manifest,\n            check_major_versions: CheckMajorVersions::Yes,\n        },\n    )?;\n\n    Ok(())\n}\n\n/// Edit the manifest.toml file in this proejct, removing all extra requirements and packages\n/// that are no longer present in the gleam.toml config.\npub fn cleanup<Telem: Telemetry>(paths: &ProjectPaths, telemetry: Telem) -> Result<Manifest> {\n    let span = tracing::info_span!(\"remove_deps\");\n    let _enter = span.enter();\n\n    // We do this before acquiring the build lock so that we don't create the\n    // build directory if there is no gleam.toml\n    crate::config::ensure_config_exists(paths)?;\n\n    let lock = BuildLock::new_packages(paths)?;\n    let _guard: Guard = lock.lock(&telemetry)?;\n\n    // Read the project config\n    let config = crate::root_config(paths)?;\n    let old_manifest = read_manifest_from_disc(paths)?;\n    let mut manifest = old_manifest.clone();\n\n    remove_extra_requirements(&config, &mut manifest)?;\n\n    // Remove any packages that are no longer required due to manifest changes\n    let local = LocalPackages::read_from_disc(paths)?;\n    remove_extra_packages(paths, &local, &manifest, &telemetry)?;\n\n    // Record new state of the packages directory\n    tracing::debug!(\"writing_manifest_toml\");\n    write_manifest_to_disc(paths, &manifest)?;\n    LocalPackages::from_manifest(&manifest).write_to_disc(paths)?;\n\n    let changes = PackageChanges::between_manifests(&old_manifest, &manifest);\n    telemetry.resolved_package_versions(&changes);\n\n    Ok(manifest)\n}\n\n/// Remove requirements and unneeded packages from manifest that are no longer present in config.\nfn remove_extra_requirements(config: &PackageConfig, manifest: &mut Manifest) -> Result<()> {\n    // \"extra requirements\" are all packages that are requirements in the manifest, but no longer\n    // part of the gleam.toml config.\n    let is_extra_requirement = |name: &EcoString| {\n        !config.dev_dependencies.contains_key(name) && !config.dependencies.contains_key(name)\n    };\n\n    // If a requirement is also used as a dependency, we do not want to force-unlock it.\n    // If the dependents get deleted as well, this transitive dependency will be dropped.\n    let is_unlockable_requirement = |name: &EcoString| {\n        manifest\n            .packages\n            .iter()\n            .all(|p| !p.requirements.contains(name))\n    };\n\n    let extra_requirements = manifest\n        .requirements\n        .keys()\n        .filter(|&name| is_extra_requirement(name) && is_unlockable_requirement(name))\n        .cloned()\n        .collect::<Vec<_>>();\n\n    manifest\n        .requirements\n        .retain(|name, _| !is_extra_requirement(name));\n\n    // Unlock all packages that we we want to remove - this removes them and all unneeded\n    // dependencies from `locked`.\n    let mut locked = config.locked(Some(manifest))?;\n    unlock_packages(&mut locked, extra_requirements.as_slice(), Some(manifest))?;\n    // Remove all unlocked packages from the manifest - these are truly no longer needed.\n    manifest\n        .packages\n        .retain(|package| locked.contains_key(&package.name));\n\n    Ok(())\n}\n\npub fn parse_gleam_add_specifier(package: &str) -> Result<(EcoString, Requirement)> {\n    let Some((package, version)) = package.split_once('@') else {\n        // Default to the latest version available.\n        return Ok((\n            package.into(),\n            Requirement::hex(\">= 0.0.0\").expect(\"'>= 0.0.0' should be a valid pubgrub range\"),\n        ));\n    };\n\n    // Parse the major and minor from the provided semantic version.\n    let parts = version.split('.').collect::<Vec<_>>();\n    let major = match parts.first() {\n        Some(major) => Ok(major),\n        None => Err(Error::InvalidVersionFormat {\n            input: package.to_string(),\n            error: \"Failed to parse semantic major version\".to_string(),\n        }),\n    }?;\n    let minor = match parts.get(1) {\n        Some(minor) => minor,\n        None => \"0\",\n    };\n\n    // Using the major version specifier, calculate the maximum\n    // allowable version (i.e., the next major version).\n    let Ok(num) = major.parse::<usize>() else {\n        return Err(Error::InvalidVersionFormat {\n            input: version.to_string(),\n            error: \"Failed to parse semantic major version as integer\".to_string(),\n        });\n    };\n\n    let max_ver = [&(num + 1).to_string(), \"0\", \"0\"].join(\".\");\n\n    // Pad the provided version specifier with zeros map to a Hex version.\n    let requirement = match parts.len() {\n        1 | 2 => {\n            let min_ver = [major, minor, \"0\"].join(\".\");\n            Requirement::hex(&[\">=\", &min_ver, \"and\", \"<\", &max_ver].join(\" \"))\n        }\n        3 => Requirement::hex(version),\n        n => {\n            return Err(Error::InvalidVersionFormat {\n                input: version.to_string(),\n                error: format!(\n                    \"Expected up to 3 numbers in version specifier (MAJOR.MINOR.PATCH), found {n}\"\n                ),\n            });\n        }\n    }?;\n\n    Ok((package.into(), requirement))\n}\n\npub fn resolve_and_download<Telem: Telemetry>(\n    paths: &ProjectPaths,\n    telemetry: Telem,\n    new_package: Option<(Vec<(EcoString, Requirement)>, bool)>,\n    packages_to_update: Vec<EcoString>,\n    config: DependencyManagerConfig,\n) -> Result<Manifest> {\n    // Start event loop so we can run async functions to call the Hex API\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let package_fetcher = PackageFetcher::new(runtime.handle().clone());\n\n    let dependency_manager = config.into_dependency_manager(\n        runtime.handle().clone(),\n        package_fetcher,\n        telemetry,\n        Mode::Dev,\n    );\n\n    dependency_manager.resolve_and_download_versions(paths, new_package, packages_to_update)\n}\n\nfn format_versions_and_extract_longest_parts(\n    versions: dependency::PackageVersionDiffs,\n) -> Vec<Vec<String>> {\n    versions\n        .iter()\n        .map(|(name, (v1, v2))| vec![name.to_string(), v1.to_string(), v2.to_string()])\n        .sorted()\n        .collect_vec()\n}\n\nfn pretty_print_major_versions_available(versions: dependency::PackageVersionDiffs) -> String {\n    let versions = format_versions_and_extract_longest_parts(versions);\n\n    format!(\n        \"\\nThe following dependencies have new major versions available:\\n\\n{}\",\n        space_table(&[\"Package\", \"Current\", \"Latest\"], &versions)\n    )\n}\n\nfn pretty_print_version_updates(versions: dependency::PackageVersionDiffs) -> EcoString {\n    let versions = format_versions_and_extract_longest_parts(versions);\n    space_table(&[\"Package\", \"Current\", \"Latest\"], &versions)\n}\n\nasync fn add_missing_packages<Telem: Telemetry>(\n    paths: &ProjectPaths,\n    fs: Box<ProjectIO>,\n    manifest: &Manifest,\n    local: &LocalPackages,\n    project_name: EcoString,\n    telemetry: &Telem,\n) -> Result<(), Error> {\n    let missing_packages = local.missing_local_packages(manifest, &project_name);\n\n    let mut num_to_download = 0;\n\n    let missing_git_packages = missing_packages\n        .iter()\n        .copied()\n        .filter(|package| package.is_git())\n        .inspect(|_| {\n            num_to_download += 1;\n        })\n        .collect_vec();\n\n    let mut missing_hex_packages = missing_packages\n        .iter()\n        .copied()\n        .filter(|package| package.is_hex())\n        .inspect(|_| {\n            num_to_download += 1;\n        })\n        .peekable();\n\n    // If we need to download at-least one package\n    if missing_hex_packages.peek().is_some() || !missing_git_packages.is_empty() {\n        let http = HttpClient::boxed();\n        let downloader = hex::Downloader::new(fs.clone(), fs, http, Untar::boxed(), paths.clone());\n        let start = Instant::now();\n        telemetry.downloading_package(\"packages\");\n        downloader\n            .download_hex_packages(missing_hex_packages, &project_name)\n            .await?;\n        for package in missing_git_packages {\n            let ManifestPackageSource::Git { repo, commit } = &package.source else {\n                continue;\n            };\n            let _ = download_git_package(&package.name, repo, commit, paths)?;\n        }\n        telemetry.packages_downloaded(start, num_to_download);\n    }\n\n    Ok(())\n}\n\nfn remove_extra_packages<Telem: Telemetry>(\n    paths: &ProjectPaths,\n    local: &LocalPackages,\n    manifest: &Manifest,\n    telemetry: &Telem,\n) -> Result<()> {\n    let _guard = BuildLock::lock_all_build(paths, telemetry)?;\n\n    for (package_name, version) in local.extra_local_packages(manifest) {\n        // TODO: test\n        // Delete the package source\n        let path = paths.build_packages_package(&package_name);\n        if path.exists() {\n            tracing::debug!(package=%package_name, version=%version, \"removing_unneeded_package\");\n            fs::delete_directory(&path)?;\n        }\n\n        // TODO: test\n        // Delete any build artefacts for the package\n        for mode in Mode::iter() {\n            for target in Target::iter() {\n                let name = manifest\n                    .packages\n                    .iter()\n                    .find(|p| p.name == package_name)\n                    .map(|p| p.application_name().as_str())\n                    .unwrap_or(package_name.as_str());\n                let path = paths.build_directory_for_package(mode, target, name);\n                if path.exists() {\n                    tracing::debug!(package=%package_name, version=%version, \"deleting_build_cache\");\n                    fs::delete_directory(&path)?;\n                }\n            }\n        }\n    }\n    Ok(())\n}\n\nfn read_manifest_from_disc(paths: &ProjectPaths) -> Result<Manifest> {\n    tracing::debug!(\"reading_manifest_toml\");\n    let manifest_path = paths.manifest();\n    let toml = fs::read(&manifest_path)?;\n    let manifest = toml::from_str(&toml).map_err(|e| Error::FileIo {\n        action: FileIoAction::Parse,\n        kind: FileKind::File,\n        path: manifest_path.clone(),\n        err: Some(e.to_string()),\n    })?;\n    Ok(manifest)\n}\n\nfn write_manifest_to_disc(paths: &ProjectPaths, manifest: &Manifest) -> Result<()> {\n    let path = paths.manifest();\n    fs::write(&path, &manifest.to_toml(paths.root()))\n}\n\n// This is the container for locally pinned packages, representing the current contents of\n// the `project/build/packages` directory.\n// For descriptions of packages provided by paths and git deps, see the ProvidedPackage struct.\n// The same package may appear in both at different times.\n#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]\nstruct LocalPackages {\n    packages: HashMap<String, Version>,\n}\n\nimpl LocalPackages {\n    pub fn extra_local_packages(&self, manifest: &Manifest) -> Vec<(String, Version)> {\n        let manifest_packages: HashSet<_> = manifest\n            .packages\n            .iter()\n            .map(|p| (&p.name, &p.version))\n            .collect();\n        self.packages\n            .iter()\n            .filter(|(n, v)| !manifest_packages.contains(&(&EcoString::from(*n), v)))\n            .map(|(n, v)| (n.clone(), v.clone()))\n            .collect()\n    }\n\n    pub fn missing_local_packages<'a>(\n        &self,\n        manifest: &'a Manifest,\n        root: &str,\n    ) -> Vec<&'a ManifestPackage> {\n        manifest\n            .packages\n            .iter()\n            // We don't need to download the root package\n            .filter(|p| p.name != root)\n            // We don't need to download local packages because we use the linked source directly\n            .filter(|p| !p.is_local())\n            // We don't need to download packages which we have the correct version of\n            .filter(|p| self.packages.get(p.name.as_str()) != Some(&p.version))\n            .collect()\n    }\n\n    pub fn read_from_disc(paths: &ProjectPaths) -> Result<Self> {\n        let path = paths.build_packages_toml();\n        if !path.exists() {\n            return Ok(Self {\n                packages: HashMap::new(),\n            });\n        }\n        let toml = fs::read(&path)?;\n        toml::from_str(&toml).map_err(|e| Error::FileIo {\n            action: FileIoAction::Parse,\n            kind: FileKind::File,\n            path: path.clone(),\n            err: Some(e.to_string()),\n        })\n    }\n\n    pub fn write_to_disc(&self, paths: &ProjectPaths) -> Result<()> {\n        let path = paths.build_packages_toml();\n        let toml = toml::to_string(&self).expect(\"packages.toml serialization\");\n        fs::write(&path, &toml)\n    }\n\n    pub fn from_manifest(manifest: &Manifest) -> Self {\n        Self {\n            packages: manifest\n                .packages\n                .iter()\n                .map(|p| (p.name.to_string(), p.version.clone()))\n                .collect(),\n        }\n    }\n}\n\nfn is_same_requirements(\n    requirements1: &HashMap<EcoString, Requirement>,\n    requirements2: &HashMap<EcoString, Requirement>,\n    root_path: &Utf8Path,\n) -> Result<bool> {\n    if requirements1.len() != requirements2.len() {\n        return Ok(false);\n    }\n\n    for (key, requirement1) in requirements1 {\n        if !same_requirements(requirement1, requirements2.get(key), root_path)? {\n            return Ok(false);\n        }\n    }\n\n    Ok(true)\n}\n\n/// Returns true if all path dependency configs are unchanged since last build.\n///\n/// If any of the path dependency configs have changed that means that we need to\n/// re-perform dependency resolution, as their dependencies could have changed\n/// themselves.\n///\n/// We use gleam.toml rather than manifest.toml as:\n///\n/// 1. The dependency requirements could have changed but resolution not have been\n///    run in that package yet, so the manifest would be the same, resulting in us\n///    failing to detect that resolution is required.\n///\n/// 2. Dependency manifests are not used in any way, so a change in the manifest\n///    may not have any impact on this package.\n///\n/// This does mean that changes unrelated to the path dependency's dependencies\n/// will trigger resolution, but gleam.toml is edited rarely, and no-change\n/// resolution is fast enough, so that's OK.\n///\n/// Note: This does not check path dependencies of path dependencies! Changes to\n/// their configs will fail to be picked up. To resolve this we would need to keep\n/// a list of all the path dependencies in the project, instead of only the direct\n/// path dependencies.\n///\nfn path_dependency_configs_unchanged(\n    requirements: &HashMap<EcoString, Requirement>,\n    paths: &ProjectPaths,\n) -> Result<bool> {\n    for (name, requirement) in requirements {\n        let Requirement::Path { path } = requirement else {\n            continue;\n        };\n\n        let config_path = paths.path_dependency_gleam_toml_path(path);\n        let fingerprint_path = paths.dependency_gleam_toml_fingerprint_path(name.as_str());\n\n        // Check mtimes before hashing, to avoid extra work\n        if fingerprint_path.exists() {\n            let config_time = fs::modification_time(&config_path)?;\n            let fingerprint_time = fs::modification_time(&fingerprint_path)?;\n            if config_time <= fingerprint_time {\n                continue;\n            }\n        };\n\n        let config_text = fs::read(&config_path)?;\n        let current_fingerprint = SourceFingerprint::new(&config_text).to_numerical_string();\n\n        // If cached hash file doesn't exist, this is the first time we're checking this dependency\n        if !fingerprint_path.exists() {\n            // Save the current hash for future comparisons\n            fs::write(&fingerprint_path, &current_fingerprint)?;\n            return Ok(false);\n        }\n\n        let previous_fingerprint = fs::read(&fingerprint_path)?;\n\n        if previous_fingerprint != current_fingerprint {\n            tracing::debug!(\"path_dependency_config_changed_forcing_rebuild\");\n            fs::write(&fingerprint_path, &current_fingerprint)?;\n            return Ok(false);\n        }\n    }\n\n    Ok(true)\n}\n\nfn same_requirements(\n    requirement1: &Requirement,\n    requirement2: Option<&Requirement>,\n    root_path: &Utf8Path,\n) -> Result<bool> {\n    let (left, right) = match (requirement1, requirement2) {\n        (Requirement::Path { path: path1 }, Some(Requirement::Path { path: path2 })) => {\n            let left = fs::canonicalise(&root_path.join(path1))?;\n            let right = fs::canonicalise(&root_path.join(path2))?;\n            (left, right)\n        }\n        (_, Some(requirement2)) => return Ok(requirement1 == requirement2),\n        (_, None) => return Ok(false),\n    };\n\n    Ok(left == right)\n}\n\n#[derive(Clone, Eq, PartialEq, Debug)]\nstruct ProvidedPackage {\n    version: Version,\n    source: ProvidedPackageSource,\n    requirements: HashMap<EcoString, hexpm::version::Range>,\n}\n\n#[derive(Clone, Eq, Debug)]\nenum ProvidedPackageSource {\n    Git { repo: EcoString, commit: EcoString },\n    Local { path: Utf8PathBuf },\n}\n\nimpl ProvidedPackage {\n    fn to_hex_package(&self, name: &EcoString) -> hexpm::Package {\n        let requirements = self\n            .requirements\n            .iter()\n            .map(|(name, version)| {\n                (\n                    name.as_str().into(),\n                    hexpm::Dependency {\n                        requirement: version.clone(),\n                        optional: false,\n                        app: None,\n                        repository: None,\n                    },\n                )\n            })\n            .collect();\n        let release = hexpm::Release {\n            version: self.version.clone(),\n            requirements,\n            retirement_status: None,\n            outer_checksum: vec![],\n            meta: (),\n        };\n        hexpm::Package {\n            name: name.as_str().into(),\n            repository: \"local\".into(),\n            releases: vec![release],\n        }\n    }\n\n    fn to_manifest_package(&self, name: &str) -> ManifestPackage {\n        let mut package = ManifestPackage {\n            name: name.into(),\n            version: self.version.clone(),\n            otp_app: None, // Note, this will probably need to be set to something eventually\n            build_tools: vec![\"gleam\".into()],\n            requirements: self.requirements.keys().cloned().collect(),\n            source: self.source.to_manifest_package_source(),\n        };\n        package.requirements.sort();\n        package\n    }\n}\n\nimpl ProvidedPackageSource {\n    fn to_manifest_package_source(&self) -> ManifestPackageSource {\n        match self {\n            Self::Git { repo, commit } => ManifestPackageSource::Git {\n                repo: repo.clone(),\n                commit: commit.clone(),\n            },\n            Self::Local { path } => ManifestPackageSource::Local { path: path.clone() },\n        }\n    }\n\n    fn to_toml(&self) -> String {\n        match self {\n            Self::Git { repo, commit } => {\n                format!(r#\"{{ repo: \"{repo}\", commit: \"{commit}\" }}\"#)\n            }\n            Self::Local { path } => {\n                format!(r#\"{{ path: \"{path}\" }}\"#)\n            }\n        }\n    }\n}\n\nimpl PartialEq for ProvidedPackageSource {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Self::Local { path: own_path }, Self::Local { path: other_path }) => {\n                is_same_file(own_path, other_path).unwrap_or(false)\n            }\n\n            (\n                Self::Git {\n                    repo: own_repo,\n                    commit: own_commit,\n                },\n                Self::Git {\n                    repo: other_repo,\n                    commit: other_commit,\n                },\n            ) => own_repo == other_repo && own_commit == other_commit,\n\n            (Self::Git { .. }, Self::Local { .. }) | (Self::Local { .. }, Self::Git { .. }) => {\n                false\n            }\n        }\n    }\n}\n\n/// Provide a package from a local project\nfn provide_local_package(\n    package_name: EcoString,\n    package_path: &Utf8Path,\n    parent_path: &Utf8Path,\n    project_paths: &ProjectPaths,\n    provided: &mut HashMap<EcoString, ProvidedPackage>,\n    parents: &mut Vec<EcoString>,\n) -> Result<hexpm::version::Range> {\n    let package_path = if package_path.is_absolute() {\n        package_path.to_path_buf()\n    } else {\n        fs::canonicalise(&parent_path.join(package_path))?\n    };\n\n    let package_source = ProvidedPackageSource::Local {\n        path: package_path.clone(),\n    };\n    provide_package(\n        package_name,\n        package_path,\n        package_source,\n        project_paths,\n        provided,\n        parents,\n    )\n}\n\nfn execute_command(command: &mut Command) -> Result<std::process::Output> {\n    let result = command.output();\n    match result {\n        Ok(output) if output.status.success() => Ok(output),\n        Ok(output) => {\n            let reason = match String::from_utf8(output.stderr) {\n                Ok(stderr) => ShellCommandFailureReason::ShellCommandError(stderr),\n                Err(_) => ShellCommandFailureReason::Unknown,\n            };\n            Err(Error::ShellCommand {\n                program: \"git\".into(),\n                reason,\n            })\n        }\n        Err(error) => Err(match error.kind() {\n            ErrorKind::NotFound => Error::ShellProgramNotFound {\n                program: \"git\".into(),\n                os: fs::get_os(),\n            },\n\n            other => Error::ShellCommand {\n                program: \"git\".into(),\n                reason: ShellCommandFailureReason::IoError(other),\n            },\n        }),\n    }\n}\n\n/// Downloads a git package from a remote repository. The commands that are run\n/// looks like this:\n///\n/// ```sh\n/// git init\n/// git remote remove origin\n/// git remote add origin <repo>\n/// git fetch origin\n/// git checkout <ref>\n/// git rev-parse HEAD\n/// ```\n///\n/// This is somewhat inefficient as we have to fetch the entire git history before\n/// switching to the exact commit we want. There a few alternatives to this:\n///\n/// - `git clone --depth 1 --branch=\"<ref>\"` This works, but only allows us to use\n///   branch names as refs, however we want to allow commit hashes as well.\n/// - `git fetch --depth 1 origin <ref>` Similarly, this imposes an unwanted\n///   restriction. `git fetch` only allows branch names or full commit hashes,\n///   but we want to allow partial hashes as well.\n///\n/// Since Git dependencies will be used quite rarely, this option was settled upon\n/// because it allows branch names, full and partial commit hashes as refs.\n///\n/// In the future we can optimise this more, for example first checking if we\n/// are already checked out to the commit stored in the manifest, or by only\n/// fetching the history without the objects to resolve partial commit hashes.\n/// For now though this is good enough until it become an actual performance\n/// problem.\n///\nfn download_git_package(\n    package_name: &str,\n    repo: &str,\n    ref_: &str,\n    project_paths: &ProjectPaths,\n) -> Result<EcoString> {\n    let package_path = project_paths.build_packages_package(package_name);\n\n    // If the package path exists but is not inside a git work tree, we need to\n    // remove the directory because running `git init` in a non-empty directory\n    // followed by `git checkout ...` is an error. See\n    // https://github.com/gleam-lang/gleam/issues/4488 for details.\n    if !fs::is_git_work_tree_root(&package_path) {\n        fs::delete_directory(&package_path)?;\n    }\n\n    fs::mkdir(&package_path)?;\n\n    let _ = execute_command(Command::new(\"git\").arg(\"init\").current_dir(&package_path))?;\n\n    // If this directory already exists, but the remote URL has been edited in\n    // `gleam.toml` without a `gleam clean`, `git remote add` will fail, causing\n    // the remote to be stuck as the original value. Here we remove the remote\n    // first, which ensures that `git remote add` properly add the remote each\n    // time. If this fails, that means we haven't set the remote in the first\n    // place, so we can safely ignore the error.\n    let _ = Command::new(\"git\")\n        .arg(\"remote\")\n        .arg(\"remove\")\n        .arg(\"origin\")\n        .current_dir(&package_path)\n        .output();\n\n    let _ = execute_command(\n        Command::new(\"git\")\n            .arg(\"remote\")\n            .arg(\"add\")\n            .arg(\"origin\")\n            .arg(repo)\n            .current_dir(&package_path),\n    )?;\n\n    let _ = execute_command(\n        Command::new(\"git\")\n            .arg(\"fetch\")\n            .arg(\"origin\")\n            .current_dir(&package_path),\n    )?;\n\n    let _ = execute_command(\n        Command::new(\"git\")\n            .arg(\"checkout\")\n            .arg(ref_)\n            .current_dir(&package_path),\n    )?;\n\n    let output = execute_command(\n        Command::new(\"git\")\n            .arg(\"rev-parse\")\n            .arg(\"HEAD\")\n            .current_dir(&package_path),\n    )?;\n\n    let commit = String::from_utf8(output.stdout)\n        .expect(\"Output should be UTF-8\")\n        .trim()\n        .into();\n\n    Ok(commit)\n}\n\n/// Provide a package from a git repository\nfn provide_git_package(\n    package_name: EcoString,\n    repo: &str,\n    // A git ref, such as a branch name, commit hash or tag name\n    ref_: &str,\n    project_paths: &ProjectPaths,\n    provided: &mut HashMap<EcoString, ProvidedPackage>,\n    parents: &mut Vec<EcoString>,\n) -> Result<hexpm::version::Range> {\n    let commit = download_git_package(&package_name, repo, ref_, project_paths)?;\n\n    let package_source = ProvidedPackageSource::Git {\n        repo: repo.into(),\n        commit,\n    };\n\n    let package_path = fs::canonicalise(&project_paths.build_packages_package(&package_name))?;\n\n    provide_package(\n        package_name,\n        package_path,\n        package_source,\n        project_paths,\n        provided,\n        parents,\n    )\n}\n\n/// Adds a gleam project located at a specific path to the list of \"provided packages\"\nfn provide_package(\n    package_name: EcoString,\n    package_path: Utf8PathBuf,\n    package_source: ProvidedPackageSource,\n    project_paths: &ProjectPaths,\n    provided: &mut HashMap<EcoString, ProvidedPackage>,\n    parents: &mut Vec<EcoString>,\n) -> Result<hexpm::version::Range> {\n    // Return early if a package cycle is detected\n    if parents.contains(&package_name) {\n        let mut last_cycle = parents\n            .split(|p| p == &package_name)\n            .next_back()\n            .unwrap_or_default()\n            .to_vec();\n        last_cycle.push(package_name);\n        return Err(Error::PackageCycle {\n            packages: last_cycle,\n        });\n    }\n    // Check that we do not have a cached version of this package already\n    match provided.get(&package_name) {\n        Some(package) if package.source == package_source => {\n            // This package has already been provided from this source, return the version\n            let version = hexpm::version::Range::new(format!(\"== {}\", &package.version))\n                .expect(\"== {version} should be a valid range\");\n            return Ok(version);\n        }\n        Some(package) => {\n            // This package has already been provided from a different source which conflicts\n            return Err(Error::ProvidedDependencyConflict {\n                package: package_name.into(),\n                source_1: package_source.to_toml(),\n                source_2: package.source.to_toml(),\n            });\n        }\n        None => (),\n    }\n    // Load the package\n    let config = crate::config::read(package_path.join(\"gleam.toml\"))?;\n    // Check that we are loading the correct project\n    if config.name != package_name {\n        return Err(Error::WrongDependencyProvided {\n            expected: package_name.into(),\n            path: package_path.to_path_buf(),\n            found: config.name.into(),\n        });\n    };\n    // Walk the requirements of the package\n    let mut requirements = HashMap::new();\n    parents.push(package_name);\n    for (name, requirement) in config.dependencies.into_iter() {\n        let version = match requirement {\n            Requirement::Hex { version } => version,\n            Requirement::Path { path } => {\n                // Recursively walk local packages\n                provide_local_package(\n                    name.clone(),\n                    &path,\n                    &package_path,\n                    project_paths,\n                    provided,\n                    parents,\n                )?\n            }\n            Requirement::Git { git, ref_ } => {\n                provide_git_package(name.clone(), &git, &ref_, project_paths, provided, parents)?\n            }\n        };\n        let _ = requirements.insert(name, version);\n    }\n    let _ = parents.pop();\n    // Add the package to the provided packages dictionary\n    let version = hexpm::version::Range::new(format!(\"== {}\", &config.version))\n        .expect(\"== {version} should be a valid range\");\n    let _ = provided.insert(\n        config.name,\n        ProvidedPackage {\n            version: config.version,\n            source: package_source,\n            requirements,\n        },\n    );\n    // Return the version\n    Ok(version)\n}\n\n/// Unlocks specified packages and their unique dependencies.\n///\n/// If a manifest is provided, it also unlocks indirect dependencies that are\n/// not required by any other package or the root project.\npub fn unlock_packages(\n    locked: &mut HashMap<EcoString, Version>,\n    packages_to_unlock: &[EcoString],\n    manifest: Option<&Manifest>,\n) -> Result<()> {\n    if let Some(manifest) = manifest {\n        let mut packages_to_unlock: Vec<EcoString> = packages_to_unlock.to_vec();\n\n        while let Some(package_name) = packages_to_unlock.pop() {\n            if locked.remove(&package_name).is_some()\n                && let Some(package) = manifest.packages.iter().find(|p| p.name == package_name)\n            {\n                let deps_to_unlock = find_deps_to_unlock(package, locked, manifest);\n                packages_to_unlock.extend(deps_to_unlock);\n            }\n        }\n    } else {\n        for package_name in packages_to_unlock {\n            let _ = locked.remove(package_name);\n        }\n    }\n\n    Ok(())\n}\n\n/// Identifies which dependencies of a package should be unlocked.\n///\n/// A dependency is eligible for unlocking if it is currently locked,\n/// is not a root dependency, and is not required by any locked package.\nfn find_deps_to_unlock(\n    package: &ManifestPackage,\n    locked: &HashMap<EcoString, Version>,\n    manifest: &Manifest,\n) -> Vec<EcoString> {\n    package\n        .requirements\n        .iter()\n        .filter(|&dep| {\n            locked.contains_key(dep)\n                && !manifest.requirements.contains_key(dep)\n                && manifest\n                    .packages\n                    .iter()\n                    .all(|p| !locked.contains_key(&p.name) || !p.requirements.contains(dep))\n        })\n        .cloned()\n        .collect()\n}\n\n/// Determine the information to add to the manifest for a specific package\nasync fn lookup_package(\n    name: String,\n    version: Version,\n    provided: &HashMap<EcoString, ProvidedPackage>,\n) -> Result<ManifestPackage> {\n    match provided.get(name.as_str()) {\n        Some(provided_package) => Ok(provided_package.to_manifest_package(name.as_str())),\n        None => {\n            let config = hexpm::Config::new();\n            let release =\n                hex::get_package_release(&name, &version, &config, &HttpClient::new()).await?;\n            let build_tools = release\n                .meta\n                .build_tools\n                .iter()\n                .map(|s| EcoString::from(s.as_str()))\n                .collect_vec();\n            let requirements = release\n                .requirements\n                .keys()\n                .map(|s| EcoString::from(s.as_str()))\n                .collect_vec();\n            Ok(ManifestPackage {\n                name: name.into(),\n                version,\n                otp_app: Some(release.meta.app.into()),\n                build_tools,\n                requirements,\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(release.outer_checksum),\n                },\n            })\n        }\n    }\n}\n\nstruct PackageFetcher {\n    runtime_cache: RefCell<HashMap<String, Rc<hexpm::Package>>>,\n    runtime: tokio::runtime::Handle,\n    http: HttpClient,\n}\n\nimpl PackageFetcher {\n    pub fn new(runtime: tokio::runtime::Handle) -> Self {\n        Self {\n            runtime_cache: RefCell::new(HashMap::new()),\n            runtime,\n            http: HttpClient::new(),\n        }\n    }\n\n    /// Caches the result of `get_dependencies` so that we don't need to make a network request.\n    /// Currently dependencies are fetched during initial version resolution, and then during check\n    /// for major version availability.\n    fn cache_package(&self, package: &str, result: Rc<hexpm::Package>) {\n        let mut runtime_cache = self.runtime_cache.borrow_mut();\n        let _ = runtime_cache.insert(package.to_string(), result);\n    }\n}\n\n#[derive(Debug)]\npub struct Untar;\n\nimpl Untar {\n    pub fn boxed() -> Box<Self> {\n        Box::new(Self)\n    }\n}\n\nimpl TarUnpacker for Untar {\n    fn io_result_entries<'a>(\n        &self,\n        archive: &'a mut tar::Archive<WrappedReader>,\n    ) -> std::io::Result<tar::Entries<'a, WrappedReader>> {\n        archive.entries()\n    }\n\n    fn io_result_unpack(\n        &self,\n        path: &Utf8Path,\n        mut archive: tar::Archive<GzDecoder<tar::Entry<'_, WrappedReader>>>,\n    ) -> std::io::Result<()> {\n        archive.unpack(path)\n    }\n}\n\nimpl dependency::PackageFetcher for PackageFetcher {\n    fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError> {\n        {\n            let runtime_cache = self.runtime_cache.borrow();\n            let result = runtime_cache.get(package);\n\n            if let Some(result) = result {\n                return Ok(result.clone());\n            }\n        }\n\n        tracing::debug!(package = package, \"looking_up_hex_package\");\n        let config = hexpm::Config::new();\n        let request = hexpm::repository_v2_get_package_request(package, None, &config);\n        let response = self\n            .runtime\n            .block_on(self.http.send(request))\n            .map_err(PackageFetchError::fetch_error)?;\n\n        let pkg = hexpm::repository_v2_get_package_response(response, HEXPM_PUBLIC_KEY)\n            .map_err(|e| PackageFetchError::from_api_error(e, package))?;\n        let pkg = Rc::new(pkg);\n        let pkg_ref = Rc::clone(&pkg);\n        self.cache_package(package, pkg);\n        Ok(pkg_ref)\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/docs.rs",
    "content": "use std::{collections::HashMap, time::SystemTime};\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::EcoString;\n\nuse crate::{cli, fs::ProjectIO, http::HttpClient};\nuse gleam_core::{\n    Result,\n    analyse::TargetSupport,\n    build::{Codegen, Compile, Mode, Options, Package, Target},\n    config::{DocsPage, PackageConfig},\n    docs::{Dependency, DependencyKind, DocContext},\n    error::Error,\n    hex,\n    io::HttpClient as _,\n    manifest::ManifestPackageSource,\n    paths::ProjectPaths,\n    type_,\n};\n\npub fn remove(package: String, version: String) -> Result<()> {\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let http = HttpClient::new();\n    let hex_config = hexpm::Config::new();\n    let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone())\n        .get_or_create_api_credentials()?;\n\n    // Remove docs from API\n    let request = hexpm::api_remove_docs_request(\n        &package,\n        &version,\n        &crate::hex::write_credentials(&credentials)?,\n        &hex_config,\n    )\n    .map_err(Error::hex)?;\n    let response = runtime.block_on(http.send(request))?;\n    hexpm::api_remove_docs_response(response).map_err(Error::hex)?;\n\n    // Done!\n    println!(\"The docs for {package} {version} have been removed from HexDocs\");\n    Ok(())\n}\n\n#[derive(Debug)]\npub struct BuildOptions {\n    /// Whether to open the docs after building.\n    pub open: bool,\n    pub target: Option<Target>,\n}\n\npub fn build(paths: &ProjectPaths, options: BuildOptions) -> Result<()> {\n    let config = crate::config::root_config(paths)?;\n\n    // Reset the build directory so we know the state of the project\n    crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?;\n\n    let out = paths.build_documentation_directory(&config.name);\n\n    let manifest = crate::build::download_dependencies(paths, cli::Reporter::new())?;\n    let dependencies = manifest\n        .packages\n        .iter()\n        .map(|package| {\n            (\n                package.name.clone(),\n                Dependency {\n                    version: package.version.clone(),\n                    kind: match &package.source {\n                        ManifestPackageSource::Hex { .. } => DependencyKind::Hex,\n                        ManifestPackageSource::Git { .. } => DependencyKind::Git,\n                        ManifestPackageSource::Local { .. } => DependencyKind::Path,\n                    },\n                },\n            )\n        })\n        .collect();\n\n    let mut built = crate::build::main(\n        paths,\n        Options {\n            mode: Mode::Prod,\n            target: options.target,\n            codegen: Codegen::All,\n            compile: Compile::All,\n            warnings_as_errors: false,\n            root_target_support: TargetSupport::Enforced,\n            no_print_progress: false,\n        },\n        manifest,\n    )?;\n    let outputs = build_documentation(\n        paths,\n        &config,\n        dependencies,\n        &mut built.root_package,\n        DocContext::Build,\n        &built.module_interfaces,\n    )?;\n\n    // Write\n    crate::fs::delete_directory(&out)?;\n    crate::fs::write_outputs_under(&outputs, &out)?;\n\n    let index_html = out.join(\"index.html\");\n\n    println!(\n        \"\\nThe documentation for {package} has been rendered to \\n{index_html}\",\n        package = config.name,\n        index_html = index_html\n    );\n\n    if options.open {\n        open_docs(&index_html)?;\n    }\n\n    // We're done!\n    Ok(())\n}\n\n/// Opens the indicated path in the default program configured by the system.\n///\n/// For the docs this will generally be a browser (unless some other program is\n/// configured as the default for `.html` files).\nfn open_docs(path: &Utf8Path) -> Result<()> {\n    opener::open(path).map_err(|error| Error::FailedToOpenDocs {\n        path: path.to_path_buf(),\n        error: error.to_string(),\n    })?;\n\n    Ok(())\n}\n\npub(crate) fn build_documentation(\n    paths: &ProjectPaths,\n    config: &PackageConfig,\n    dependencies: HashMap<EcoString, Dependency>,\n    compiled: &mut Package,\n    is_hex_publish: DocContext,\n    cached_modules: &im::HashMap<EcoString, type_::ModuleInterface>,\n) -> Result<Vec<gleam_core::io::OutputFile>, Error> {\n    compiled.attach_doc_and_module_comments();\n    cli::print_generating_documentation();\n    let mut pages = vec![DocsPage {\n        title: \"README\".into(),\n        path: \"index.html\".into(),\n        source: paths.readme(), // TODO: support non markdown READMEs. Or a default if there is none.\n    }];\n    pages.extend(config.documentation.pages.iter().cloned());\n    let mut outputs = gleam_core::docs::generate_html(\n        paths,\n        gleam_core::docs::DocumentationConfig {\n            package_config: config,\n            dependencies,\n            analysed: compiled.modules.as_slice(),\n            docs_pages: &pages,\n            rendering_timestamp: SystemTime::now(),\n            context: is_hex_publish,\n        },\n        ProjectIO::new(),\n    );\n\n    outputs.push(gleam_core::docs::generate_json_package_interface(\n        Utf8PathBuf::from(\"package-interface.json\"),\n        compiled,\n        cached_modules,\n    ));\n    Ok(outputs)\n}\n\npub fn publish(paths: &ProjectPaths) -> Result<()> {\n    let config = crate::config::root_config(paths)?;\n    let http = HttpClient::new();\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let hex_config = hexpm::Config::new();\n    let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone())\n        .get_or_create_api_credentials()?;\n\n    // Reset the build directory so we know the state of the project\n    crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?;\n\n    let manifest = crate::build::download_dependencies(paths, cli::Reporter::new())?;\n    let dependencies = manifest\n        .packages\n        .iter()\n        .map(|package| {\n            (\n                package.name.clone(),\n                Dependency {\n                    version: package.version.clone(),\n                    kind: match &package.source {\n                        ManifestPackageSource::Hex { .. } => DependencyKind::Hex,\n                        ManifestPackageSource::Git { .. } => DependencyKind::Git,\n                        ManifestPackageSource::Local { .. } => DependencyKind::Path,\n                    },\n                },\n            )\n        })\n        .collect();\n\n    let mut built = crate::build::main(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors: false,\n            codegen: Codegen::All,\n            compile: Compile::All,\n            mode: Mode::Prod,\n            target: None,\n            no_print_progress: false,\n        },\n        manifest,\n    )?;\n    let outputs = build_documentation(\n        paths,\n        &config,\n        dependencies,\n        &mut built.root_package,\n        DocContext::HexPublish,\n        &built.module_interfaces,\n    )?;\n    let archive = crate::fs::create_tar_archive(outputs)?;\n\n    cli::print_publishing_documentation();\n    runtime.block_on(hex::publish_documentation(\n        &config.name,\n        &config.version,\n        archive,\n        &crate::hex::write_credentials(&credentials)?,\n        &hex_config,\n        &http,\n    ))?;\n    cli::print_published(\"documentation\");\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/export.rs",
    "content": "use camino::Utf8PathBuf;\nuse gleam_core::{\n    Result,\n    analyse::TargetSupport,\n    build::{Codegen, Compile, Mode, Options, Target},\n    paths::ProjectPaths,\n};\n\nstatic ENTRYPOINT_FILENAME_POWERSHELL: &str = \"entrypoint.ps1\";\nstatic ENTRYPOINT_FILENAME_POSIX_SHELL: &str = \"entrypoint.sh\";\n\nstatic ENTRYPOINT_TEMPLATE_POWERSHELL: &str =\n    include_str!(\"../templates/erlang-shipment-entrypoint.ps1\");\nstatic ENTRYPOINT_TEMPLATE_POSIX_SHELL: &str =\n    include_str!(\"../templates/erlang-shipment-entrypoint.sh\");\n\n// TODO: start in embedded mode\n// TODO: test\n\n/// Generate a directory of precompiled Erlang along with a start script.\n/// Suitable for deployment to a server.\n///\n/// For each Erlang application (aka package) directory these directories are\n/// copied across:\n/// - ebin\n/// - include\n/// - priv\npub(crate) fn erlang_shipment(paths: &ProjectPaths) -> Result<()> {\n    let target = Target::Erlang;\n    let mode = Mode::Prod;\n    let build = paths.build_directory_for_target(mode, target);\n    let out = paths.erlang_shipment_directory();\n\n    crate::fs::mkdir(&out)?;\n\n    // Reset the directories to ensure we have a clean slate and no old code\n    crate::fs::delete_directory(&build)?;\n    crate::fs::delete_directory(&out)?;\n\n    // Build project in production mode\n    let built = crate::build::main(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors: false,\n            codegen: Codegen::All,\n            compile: Compile::All,\n            mode,\n            target: Some(target),\n            no_print_progress: false,\n        },\n        crate::build::download_dependencies(paths, crate::cli::Reporter::new())?,\n    )?;\n\n    for entry in crate::fs::read_dir(&build)?.filter_map(Result::ok) {\n        let path = entry.path();\n\n        // We are only interested in package directories\n        if !path.is_dir() {\n            continue;\n        }\n\n        let name = path.file_name().expect(\"Directory name\");\n        let build = build.join(name);\n        let out = out.join(name);\n        crate::fs::mkdir(&out)?;\n\n        // Copy desired package subdirectories\n        for subdirectory in [\"ebin\", \"priv\", \"include\"] {\n            let source = build.join(subdirectory);\n            if source.is_dir() {\n                let source = crate::fs::canonicalise(&source)?;\n                let out = out.join(subdirectory);\n                crate::fs::copy_dir(source, &out)?;\n            }\n        }\n    }\n\n    // PowerShell entry point script.\n    write_entrypoint_script(\n        &out.join(ENTRYPOINT_FILENAME_POWERSHELL),\n        ENTRYPOINT_TEMPLATE_POWERSHELL,\n        &built.root_package.config.name,\n    )?;\n\n    // POSIX Shell entry point script.\n    write_entrypoint_script(\n        &out.join(ENTRYPOINT_FILENAME_POSIX_SHELL),\n        ENTRYPOINT_TEMPLATE_POSIX_SHELL,\n        &built.root_package.config.name,\n    )?;\n\n    crate::cli::print_exported(&built.root_package.config.name);\n\n    println!(\n        \"\nYour Erlang shipment has been generated to {out}.\n\nIt can be copied to a compatible server with Erlang installed and run with\none of the following scripts:\n    - {ENTRYPOINT_FILENAME_POWERSHELL} (PowerShell script)\n    - {ENTRYPOINT_FILENAME_POSIX_SHELL} (POSIX Shell script)\n\",\n    );\n\n    Ok(())\n}\n\nfn write_entrypoint_script(\n    entrypoint_output_path: &Utf8PathBuf,\n    entrypoint_template_path: &str,\n    package_name: &str,\n) -> Result<()> {\n    let text = entrypoint_template_path.replace(\"$PACKAGE_NAME_FROM_GLEAM\", package_name);\n    crate::fs::write(entrypoint_output_path, &text)?;\n    crate::fs::make_executable(entrypoint_output_path)?;\n    Ok(())\n}\n\npub fn hex_tarball(paths: &ProjectPaths) -> Result<()> {\n    let mut config = crate::config::root_config(paths)?;\n    let data: Vec<u8> = crate::publish::build_hex_tarball(paths, &mut config)?;\n\n    let path = paths.build_export_hex_tarball(&config.name, &config.version.to_string());\n    crate::fs::write_bytes(&path, &data)?;\n    println!(\n        \"\nYour hex tarball has been generated in {}.\n\",\n        &path\n    );\n    Ok(())\n}\n\npub fn javascript_prelude() -> Result<()> {\n    print!(\"{}\", gleam_core::javascript::PRELUDE);\n    Ok(())\n}\n\npub fn typescript_prelude() -> Result<()> {\n    print!(\"{}\", gleam_core::javascript::PRELUDE_TS_DEF);\n    Ok(())\n}\n\npub fn package_interface(paths: &ProjectPaths, out: Utf8PathBuf) -> Result<()> {\n    // Build the project\n    let mut built = crate::build::main(\n        paths,\n        Options {\n            mode: Mode::Prod,\n            target: None,\n            codegen: Codegen::None,\n            compile: Compile::All,\n            warnings_as_errors: false,\n            root_target_support: TargetSupport::Enforced,\n            no_print_progress: false,\n        },\n        crate::build::download_dependencies(paths, crate::cli::Reporter::new())?,\n    )?;\n    built.root_package.attach_doc_and_module_comments();\n\n    let out = gleam_core::docs::generate_json_package_interface(\n        out,\n        &built.root_package,\n        &built.module_interfaces,\n    );\n    crate::fs::write_outputs_under(&[out], paths.root())?;\n    Ok(())\n}\n\npub fn package_information(paths: &ProjectPaths, out: Utf8PathBuf) -> Result<()> {\n    let config = crate::config::root_config(paths)?;\n    let out = gleam_core::docs::generate_json_package_information(out, config);\n    crate::fs::write_outputs_under(&[out], paths.root())?;\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/fix.rs",
    "content": "use std::rc::Rc;\n\nuse gleam_core::{\n    Error, Result, Warning,\n    analyse::TargetSupport,\n    build::{Codegen, Compile, Mode, Options},\n    error::{FileIoAction, FileKind},\n    paths::ProjectPaths,\n    type_,\n    warning::VectorWarningEmitterIO,\n};\nuse hexpm::version::Version;\n\nuse crate::{build, cli};\n\npub fn run(paths: &ProjectPaths) -> Result<()> {\n    // When running gleam fix we want all the compilation warnings to be hidden,\n    // at the same time we need to access those to apply the fixes: so we\n    // accumulate those into a vector.\n    let warnings = Rc::new(VectorWarningEmitterIO::new());\n    let _built = build::main_with_warnings(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors: false,\n            codegen: Codegen::DepsOnly,\n            compile: Compile::All,\n            mode: Mode::Dev,\n            target: None,\n            no_print_progress: false,\n        },\n        build::download_dependencies(paths, cli::Reporter::new())?,\n        warnings.clone(),\n    )?;\n    let warnings = warnings.take();\n\n    fix_minimum_required_version(paths, warnings)?;\n\n    println!(\"Done!\");\n    Ok(())\n}\n\nfn fix_minimum_required_version(paths: &ProjectPaths, warnings: Vec<Warning>) -> Result<()> {\n    let Some(minimum_required_version) = minimum_required_version_from_warnings(warnings) else {\n        return Ok(());\n    };\n\n    // Set the version requirement in gleam.toml\n    let root_config = paths.root_config();\n    let mut toml = crate::fs::read(&root_config)?\n        .parse::<toml_edit::DocumentMut>()\n        .map_err(|e| Error::FileIo {\n            kind: FileKind::File,\n            action: FileIoAction::Parse,\n            path: root_config.to_path_buf(),\n            err: Some(e.to_string()),\n        })?;\n\n    #[allow(clippy::indexing_slicing)]\n    {\n        toml[\"gleam\"] = toml_edit::value(format!(\">= {minimum_required_version}\"));\n    }\n\n    // Write the updated config\n    crate::fs::write(root_config.as_path(), &toml.to_string())?;\n\n    println!(\"- Set required Gleam version to \\\">= {minimum_required_version}\\\"\");\n    Ok(())\n}\n\n/// Returns the highest minimum required version among all warnings requiring a\n/// specific Gleam version that is not allowed by the `gleam` version contraint\n/// in the `gleam.toml`.\nfn minimum_required_version_from_warnings(warnings: Vec<Warning>) -> Option<Version> {\n    warnings\n        .iter()\n        .filter_map(|warning| match warning {\n            Warning::Type {\n                warning:\n                    type_::Warning::FeatureRequiresHigherGleamVersion {\n                        minimum_required_version,\n                        ..\n                    },\n                ..\n            } => Some(minimum_required_version),\n            _ => None,\n        })\n        .reduce(std::cmp::max)\n        .cloned()\n}\n"
  },
  {
    "path": "compiler-cli/src/format.rs",
    "content": "use gleam_core::{\n    error::{Error, FileIoAction, FileKind, Result, StandardIoAction, Unformatted},\n    io::Content,\n    io::OutputFile,\n};\nuse std::{io::Read, str::FromStr};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\npub fn run(stdin: bool, check: bool, files: Vec<String>) -> Result<()> {\n    if stdin {\n        process_stdin(check)\n    } else {\n        process_files(check, files)\n    }\n}\n\nfn process_stdin(check: bool) -> Result<()> {\n    let src = read_stdin()?.into();\n    let mut out = String::new();\n    gleam_core::format::pretty(&mut out, &src, Utf8Path::new(\"<stdin>\"))?;\n\n    if !check {\n        print!(\"{out}\");\n        return Ok(());\n    }\n\n    if src != out {\n        return Err(Error::Format {\n            problem_files: vec![Unformatted {\n                source: Utf8PathBuf::from(\"<standard input>\"),\n                destination: Utf8PathBuf::from(\"<standard output>\"),\n                input: src,\n                output: out,\n            }],\n        });\n    }\n\n    Ok(())\n}\n\nfn process_files(check: bool, files: Vec<String>) -> Result<()> {\n    if check {\n        check_files(files)\n    } else {\n        format_files(files)\n    }\n}\n\nfn check_files(files: Vec<String>) -> Result<()> {\n    let problem_files = unformatted_files(files)?;\n\n    if problem_files.is_empty() {\n        Ok(())\n    } else {\n        Err(Error::Format { problem_files })\n    }\n}\n\nfn format_files(files: Vec<String>) -> Result<()> {\n    for file in unformatted_files(files)? {\n        crate::fs::write_output(&OutputFile {\n            path: file.destination,\n            content: Content::Text(file.output),\n        })?;\n    }\n    Ok(())\n}\n\npub fn unformatted_files(files: Vec<String>) -> Result<Vec<Unformatted>> {\n    let mut problem_files = Vec::with_capacity(files.len());\n\n    for file_path in files {\n        let path = Utf8PathBuf::from_str(&file_path).map_err(|e| Error::FileIo {\n            action: FileIoAction::Open,\n            kind: FileKind::File,\n            path: Utf8PathBuf::from(file_path),\n            err: Some(e.to_string()),\n        })?;\n\n        if path.is_dir() {\n            for path in crate::fs::gleam_files(&path) {\n                format_file(&mut problem_files, path)?;\n            }\n        } else {\n            format_file(&mut problem_files, path)?;\n        }\n    }\n\n    Ok(problem_files)\n}\n\nfn format_file(problem_files: &mut Vec<Unformatted>, path: Utf8PathBuf) -> Result<()> {\n    let src = crate::fs::read(&path)?.into();\n    let mut output = String::new();\n    gleam_core::format::pretty(&mut output, &src, &path)?;\n\n    if src != output {\n        problem_files.push(Unformatted {\n            source: path.clone(),\n            destination: path,\n            input: src,\n            output,\n        });\n    }\n    Ok(())\n}\n\npub fn read_stdin() -> Result<String> {\n    let mut src = String::new();\n    let _ = std::io::stdin()\n        .read_to_string(&mut src)\n        .map_err(|e| Error::StandardIo {\n            action: StandardIoAction::Read,\n            err: Some(e.kind()),\n        })?;\n    Ok(src)\n}\n"
  },
  {
    "path": "compiler-cli/src/fs/tests.rs",
    "content": "use camino::Utf8Path;\nuse itertools::Itertools;\n\n#[test]\nfn is_inside_git_work_tree_ok() {\n    let tmp_dir = tempfile::tempdir().unwrap();\n    let path = Utf8Path::from_path(tmp_dir.path()).expect(\"Non Utf-8 Path\");\n\n    assert!(!super::is_inside_git_work_tree(path).unwrap());\n    assert_eq!(super::git_init(path), Ok(()));\n    assert!(super::is_inside_git_work_tree(path).unwrap())\n}\n\n#[test]\nfn git_init_success() {\n    let tmp_dir = tempfile::tempdir().unwrap();\n    let path = Utf8Path::from_path(tmp_dir.path()).expect(\"Non Utf-8 Path\");\n    let git = path.join(\".git\");\n\n    assert!(!git.exists());\n    assert_eq!(super::git_init(path), Ok(()));\n    assert!(git.exists());\n}\n\n#[test]\nfn git_init_already_in_git() {\n    let tmp_dir = tempfile::tempdir().unwrap();\n    let git = Utf8Path::from_path(tmp_dir.path())\n        .expect(\"Non Utf-8 Path\")\n        .join(\".git\");\n    assert!(!git.exists());\n    assert_eq!(\n        super::git_init(Utf8Path::from_path(tmp_dir.path()).expect(\"Non Utf-8 Path\")),\n        Ok(())\n    );\n    assert!(git.exists());\n\n    let sub = Utf8Path::from_path(tmp_dir.path())\n        .expect(\"Non Utf-8 Path\")\n        .join(\"subproject\");\n    let git = sub.join(\".git\");\n    crate::fs::mkdir(&sub).unwrap();\n    assert!(!git.exists());\n    assert_eq!(super::git_init(&sub), Ok(()));\n    assert!(!git.exists());\n}\n\n#[test]\nfn exclude_build_dir() {\n    /*\n    a\n    |-- gleam.toml\n    |-- build\n    |  |-- f.gleam  # do not count as gleam file\n    b\n    |-- build\n    |  |-- f.gleam  # count as gleam file\n     */\n\n    let tmp_dir = tempfile::tempdir().unwrap();\n    let path = Utf8Path::from_path(tmp_dir.path()).expect(\"Non Utf-8 Path\");\n\n    // excluded gleam file\n    {\n        let gleam_toml = path.join(\"a/gleam.toml\").to_path_buf();\n        super::write(&gleam_toml, \"\").unwrap();\n\n        let gleam_file = path.join(\"a/build/f.gleam\").to_path_buf();\n        super::write(&gleam_file, \"\").unwrap();\n    };\n\n    // included gleam file\n    let gleam_file = path.join(\"b/build/f.gleam\").to_path_buf();\n    super::write(&gleam_file, \"\").unwrap();\n\n    let files = super::gleam_files(path).collect::<Vec<_>>();\n\n    assert_eq!(files, vec![gleam_file]);\n}\n\n#[test]\nfn erlang_files_include_gitignored_files() {\n    let tmp_dir = tempfile::tempdir().unwrap();\n    let path = Utf8Path::from_path(tmp_dir.path()).expect(\"Non Utf-8 Path\");\n\n    let included_files = &[\n        \".hidden.erl\",\n        \"abc.erl\",\n        \"abc.hrl\",\n        \"build/include/abc.erl\",\n        \"build/include/abc.hrl\",\n        \"ignored.erl\",\n        \"ignored.hrl\",\n    ];\n\n    let excluded_files = &[\n        \".gitignore\",\n        \"abc.gleam\",\n        \"abc.js\",\n        \"build/abc.gleam\",\n        \"build/abc.js\",\n    ];\n\n    let gitignore = \"build/\nignored.*\";\n\n    for &file in included_files.iter().chain(excluded_files) {\n        let contents = match file {\n            \".gitignore\" => gitignore,\n            _ => \"\",\n        };\n\n        super::write(&path.join(file), contents).unwrap();\n    }\n\n    let mut chosen_files = super::erlang_files(path).collect_vec();\n    chosen_files.sort_unstable();\n\n    let expected_files = included_files.iter().map(|s| path.join(s)).collect_vec();\n\n    assert_eq!(expected_files, chosen_files);\n}\n\n#[test]\nfn is_gleam_path_test() {\n    assert!(super::is_gleam_path(\n        Utf8Path::new(\"/some-prefix/a.gleam\"),\n        Utf8Path::new(\"/some-prefix/\")\n    ));\n\n    assert!(super::is_gleam_path(\n        Utf8Path::new(\"/some-prefix/one_two/a.gleam\"),\n        Utf8Path::new(\"/some-prefix/\")\n    ));\n\n    assert!(super::is_gleam_path(\n        Utf8Path::new(\"/some-prefix/one_two/a123.gleam\"),\n        Utf8Path::new(\"/some-prefix/\")\n    ));\n\n    assert!(super::is_gleam_path(\n        Utf8Path::new(\"/some-prefix/one_2/a123.gleam\"),\n        Utf8Path::new(\"/some-prefix/\")\n    ));\n}\n\n#[test]\nfn extract_distro_id_test() {\n    let os_release = \"\nPRETTY_NAME=\\\"Debian GNU/Linux 12 (bookworm)\\\"\nNAME=\\\"Debian GNU/Linux\\\"\nVERSION_ID=\\\"12\\\"\nVERSION=\\\"12 (bookworm)\\\"\nVERSION_CODENAME=bookworm\nID=debian\nHOME_URL=\\\"https://www.debian.org/\\\"\n\";\n    assert_eq!(super::extract_distro_id(os_release.to_string()), \"debian\");\n\n    let os_release = \"\nVERSION_CODENAME=jammy\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\\\"https://www.ubuntu.com/\\\"\n\";\n    assert_eq!(super::extract_distro_id(os_release.to_string()), \"ubuntu\");\n\n    assert_eq!(super::extract_distro_id(\"\".to_string()), \"\");\n    assert_eq!(super::extract_distro_id(\"\\n\".to_string()), \"\");\n    assert_eq!(super::extract_distro_id(\"ID=\".to_string()), \"\");\n    assert_eq!(super::extract_distro_id(\"ID= \".to_string()), \" \");\n    assert_eq!(\n        super::extract_distro_id(\"ID= space test \".to_string()),\n        \" space test \"\n    );\n    assert_eq!(super::extract_distro_id(\"id=ubuntu\".to_string()), \"\");\n    assert_eq!(\n        super::extract_distro_id(\"NAME=\\\"Debian\\\"\\nID=debian\".to_string()),\n        \"debian\"\n    );\n    assert_eq!(\n        super::extract_distro_id(\"\\n\\nNAME=\\n\\n\\nID=test123\\n\".to_string()),\n        \"test123\"\n    );\n    assert_eq!(\n        super::extract_distro_id(\"\\nID=\\\"id first\\\"\\nID=another_id\".to_string()),\n        \"id first\"\n    );\n}\n"
  },
  {
    "path": "compiler-cli/src/fs.rs",
    "content": "use gleam_core::{\n    Result, Warning,\n    build::{NullTelemetry, Target},\n    error::{Error, FileIoAction, FileKind, OS, ShellCommandFailureReason, parse_os},\n    io::{\n        BeamCompiler, Command, CommandExecutor, Content, DirEntry, FileSystemReader,\n        FileSystemWriter, OutputFile, ReadDir, Stdio, WrappedReader, is_native_file_extension,\n    },\n    manifest::Manifest,\n    paths::ProjectPaths,\n    warning::WarningEmitterIO,\n};\nuse gleam_language_server::{DownloadDependencies, Locker, MakeLocker};\nuse std::{\n    collections::HashSet,\n    fmt::Debug,\n    fs::{File, exists},\n    io::{self, BufRead, BufReader, Write},\n    sync::{Arc, Mutex, OnceLock},\n    time::SystemTime,\n};\n\nuse camino::{ReadDirUtf8, Utf8Path, Utf8PathBuf};\n\nuse crate::{dependencies, lsp::LspLocker};\n\n#[cfg(test)]\nmod tests;\n\n/// Return the current directory as a UTF-8 Path\npub fn get_current_directory() -> Result<Utf8PathBuf, Error> {\n    let curr_dir = std::env::current_dir().map_err(|e| Error::FileIo {\n        kind: FileKind::Directory,\n        action: FileIoAction::Open,\n        path: \".\".into(),\n        err: Some(e.to_string()),\n    })?;\n    Utf8PathBuf::from_path_buf(curr_dir.clone()).map_err(|_| Error::NonUtf8Path { path: curr_dir })\n}\n\n// Return the first directory with a gleam.toml as a UTF-8 Path\npub fn get_project_root(path: Utf8PathBuf) -> Result<Utf8PathBuf, Error> {\n    fn walk(dir: Utf8PathBuf) -> Option<Utf8PathBuf> {\n        match dir.join(\"gleam.toml\").is_file() {\n            true => Some(dir),\n            false => match dir.parent() {\n                Some(p) => walk(p.into()),\n                None => None,\n            },\n        }\n    }\n    walk(path.clone()).ok_or(Error::UnableToFindProjectRoot {\n        path: path.to_string(),\n    })\n}\n\npub fn get_os() -> OS {\n    parse_os(std::env::consts::OS, get_distro_str().as_str())\n}\n\n// try to extract the distro id from /etc/os-release\npub fn extract_distro_id(os_release: String) -> String {\n    let distro = os_release.lines().find(|line| line.starts_with(\"ID=\"));\n    if let Some(distro) = distro {\n        let id = distro.split('=').nth(1).unwrap_or(\"\").replace(\"\\\"\", \"\");\n        return id;\n    }\n    \"\".to_string()\n}\n\npub fn get_distro_str() -> String {\n    let path = Utf8Path::new(\"/etc/os-release\");\n    if std::env::consts::OS != \"linux\" || !path.exists() {\n        return \"other\".to_string();\n    }\n    let os_release = read(path);\n    match os_release {\n        Ok(os_release) => extract_distro_id(os_release),\n        Err(_) => \"other\".to_string(),\n    }\n}\n\n/// A `FileWriter` implementation that writes to the file system.\n#[derive(Debug, Clone, Default)]\npub struct ProjectIO {\n    beam_compiler: Arc<Mutex<crate::beam_compiler::BeamCompiler>>,\n}\n\nimpl ProjectIO {\n    pub fn new() -> Self {\n        Self {\n            beam_compiler: Default::default(),\n        }\n    }\n\n    pub fn boxed() -> Box<Self> {\n        Box::new(Self::new())\n    }\n}\n\nimpl FileSystemReader for ProjectIO {\n    fn read(&self, path: &Utf8Path) -> Result<String, Error> {\n        read(path)\n    }\n\n    fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>, Error> {\n        read_bytes(path)\n    }\n\n    fn is_file(&self, path: &Utf8Path) -> bool {\n        path.is_file()\n    }\n\n    fn is_directory(&self, path: &Utf8Path) -> bool {\n        path.is_dir()\n    }\n\n    fn reader(&self, path: &Utf8Path) -> Result<WrappedReader, Error> {\n        reader(path)\n    }\n\n    fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir> {\n        read_dir(path).map(|entries| {\n            entries\n                .map(|result| result.map(|entry| DirEntry::from_path(entry.path())))\n                .collect()\n        })\n    }\n\n    fn modification_time(&self, path: &Utf8Path) -> Result<SystemTime, Error> {\n        modification_time(path)\n    }\n\n    fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, Error> {\n        canonicalise(path)\n    }\n}\n\npub fn modification_time(path: &Utf8Path) -> std::result::Result<SystemTime, Error> {\n    path.metadata()\n        .map(|m| m.modified().unwrap_or_else(|_| SystemTime::now()))\n        .map_err(|e| Error::FileIo {\n            action: FileIoAction::ReadMetadata,\n            kind: FileKind::File,\n            path: path.to_path_buf(),\n            err: Some(e.to_string()),\n        })\n}\n\nimpl FileSystemWriter for ProjectIO {\n    fn delete_directory(&self, path: &Utf8Path) -> Result<()> {\n        delete_directory(path)\n    }\n\n    fn copy(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        copy(from, to)\n    }\n\n    fn copy_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        copy_dir(from, to)\n    }\n\n    fn mkdir(&self, path: &Utf8Path) -> Result<(), Error> {\n        mkdir(path)\n    }\n\n    fn hardlink(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error> {\n        hardlink(from, to)\n    }\n\n    fn symlink_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error> {\n        symlink_dir(from, to)\n    }\n\n    fn delete_file(&self, path: &Utf8Path) -> Result<()> {\n        delete_file(path)\n    }\n\n    fn write(&self, path: &Utf8Path, content: &str) -> Result<(), Error> {\n        write(path, content)\n    }\n\n    fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<(), Error> {\n        write_bytes(path, content)\n    }\n\n    fn exists(&self, path: &Utf8Path) -> bool {\n        path.exists()\n    }\n}\n\nimpl CommandExecutor for ProjectIO {\n    fn exec(&self, command: Command) -> Result<i32, Error> {\n        let Command {\n            program,\n            args,\n            env,\n            cwd,\n            stdio,\n        } = command;\n        tracing::debug!(program=program, args=?args.join(\" \"), env=?env, cwd=?cwd, \"command_exec\");\n        let result = std::process::Command::new(&program)\n            .args(args)\n            .stdin(stdio.get_process_stdio())\n            .stdout(stdio.get_process_stdio())\n            .envs(env.iter().map(|pair| (&pair.0, &pair.1)))\n            .current_dir(cwd.unwrap_or_else(|| Utf8Path::new(\"./\").to_path_buf()))\n            .status();\n\n        match result {\n            Ok(status) => Ok(status.code().unwrap_or_default()),\n\n            Err(error) => Err(match error.kind() {\n                io::ErrorKind::NotFound => Error::ShellProgramNotFound {\n                    program,\n                    os: get_os(),\n                },\n\n                other => Error::ShellCommand {\n                    program,\n                    reason: ShellCommandFailureReason::IoError(other),\n                },\n            }),\n        }\n    }\n}\n\nimpl BeamCompiler for ProjectIO {\n    fn compile_beam(\n        &self,\n        out: &Utf8Path,\n        lib: &Utf8Path,\n        modules: &HashSet<Utf8PathBuf>,\n        stdio: Stdio,\n    ) -> Result<Vec<String>, Error> {\n        self.beam_compiler\n            .lock()\n            .as_mut()\n            .expect(\"could not get beam_compiler\")\n            .compile(self, out, lib, modules, stdio)\n    }\n}\n\nimpl MakeLocker for ProjectIO {\n    fn make_locker(&self, paths: &ProjectPaths, target: Target) -> Result<Box<dyn Locker>> {\n        let locker = LspLocker::new(paths, target)?;\n        Ok(Box::new(locker))\n    }\n}\n\nimpl DownloadDependencies for ProjectIO {\n    fn download_dependencies(&self, paths: &ProjectPaths) -> Result<Manifest> {\n        dependencies::resolve_and_download(\n            paths,\n            NullTelemetry,\n            None,\n            Vec::new(),\n            dependencies::DependencyManagerConfig {\n                use_manifest: dependencies::UseManifest::Yes,\n                check_major_versions: dependencies::CheckMajorVersions::No,\n            },\n        )\n    }\n}\n\npub fn delete_directory(dir: &Utf8Path) -> Result<(), Error> {\n    tracing::debug!(path=?dir, \"deleting_directory\");\n    if dir.exists() {\n        std::fs::remove_dir_all(dir).map_err(|e| Error::FileIo {\n            action: FileIoAction::Delete,\n            kind: FileKind::Directory,\n            path: dir.to_path_buf(),\n            err: Some(e.to_string()),\n        })?;\n    } else {\n        tracing::debug!(path=?dir, \"directory_did_not_exist_for_deletion\");\n    }\n    Ok(())\n}\n\npub fn delete_file(file: &Utf8Path) -> Result<(), Error> {\n    tracing::debug!(\"Deleting file {:?}\", file);\n    if file.exists() {\n        std::fs::remove_file(file).map_err(|e| Error::FileIo {\n            action: FileIoAction::Delete,\n            kind: FileKind::File,\n            path: file.to_path_buf(),\n            err: Some(e.to_string()),\n        })?;\n    } else {\n        tracing::debug!(\"Did not exist for deletion: {:?}\", file);\n    }\n    Ok(())\n}\n\npub fn write_outputs_under(outputs: &[OutputFile], base: &Utf8Path) -> Result<(), Error> {\n    for file in outputs {\n        let path = base.join(&file.path);\n        match &file.content {\n            Content::Binary(buffer) => write_bytes(&path, buffer),\n            Content::Text(buffer) => write(&path, buffer),\n        }?;\n    }\n    Ok(())\n}\n\npub fn write_output(file: &OutputFile) -> Result<(), Error> {\n    let OutputFile { path, content } = file;\n    match content {\n        Content::Binary(buffer) => write_bytes(path, buffer),\n        Content::Text(buffer) => write(path, buffer),\n    }\n}\n\npub fn write(path: &Utf8Path, text: &str) -> Result<(), Error> {\n    write_bytes(path, text.as_bytes())\n}\n\n#[cfg(target_family = \"unix\")]\npub fn make_executable(path: impl AsRef<Utf8Path>) -> Result<(), Error> {\n    use std::os::unix::fs::PermissionsExt;\n    tracing::debug!(path = ?path.as_ref(), \"setting_permissions\");\n\n    std::fs::set_permissions(path.as_ref(), std::fs::Permissions::from_mode(0o755)).map_err(\n        |e| Error::FileIo {\n            action: FileIoAction::UpdatePermissions,\n            kind: FileKind::File,\n            path: path.as_ref().to_path_buf(),\n            err: Some(e.to_string()),\n        },\n    )?;\n    Ok(())\n}\n\n#[cfg(not(target_family = \"unix\"))]\npub fn make_executable(_path: impl AsRef<Utf8Path>) -> Result<(), Error> {\n    Ok(())\n}\n\npub fn write_bytes(path: &Utf8Path, bytes: &[u8]) -> Result<(), Error> {\n    tracing::debug!(path=?path, \"writing_file\");\n\n    let dir_path = path.parent().ok_or_else(|| Error::FileIo {\n        action: FileIoAction::FindParent,\n        kind: FileKind::Directory,\n        path: path.to_path_buf(),\n        err: None,\n    })?;\n\n    std::fs::create_dir_all(dir_path).map_err(|e| Error::FileIo {\n        action: FileIoAction::Create,\n        kind: FileKind::Directory,\n        path: dir_path.to_path_buf(),\n        err: Some(e.to_string()),\n    })?;\n\n    let mut f = File::create(path).map_err(|e| Error::FileIo {\n        action: FileIoAction::Create,\n        kind: FileKind::File,\n        path: path.to_path_buf(),\n        err: Some(e.to_string()),\n    })?;\n\n    f.write_all(bytes).map_err(|e| Error::FileIo {\n        action: FileIoAction::WriteTo,\n        kind: FileKind::File,\n        path: path.to_path_buf(),\n        err: Some(e.to_string()),\n    })?;\n    Ok(())\n}\n\nfn is_gleam_path(path: &Utf8Path, dir: impl AsRef<Utf8Path>) -> bool {\n    use regex::Regex;\n\n    static RE: OnceLock<Regex> = OnceLock::new();\n\n    RE.get_or_init(|| {\n        Regex::new(&format!(\n            \"^({module}{slash})*{module}\\\\.gleam$\",\n            module = \"[a-z][_a-z0-9]*\",\n            slash = \"(/|\\\\\\\\)\",\n        ))\n        .expect(\"is_gleam_path() RE regex\")\n    })\n    .is_match(\n        path.strip_prefix(dir.as_ref())\n            .expect(\"is_gleam_path(): strip_prefix\")\n            .as_str(),\n    )\n}\n\nfn is_gleam_build_dir(e: &ignore::DirEntry) -> bool {\n    if !e.path().is_dir() || !e.path().ends_with(\"build\") {\n        return false;\n    }\n\n    let Some(parent_path) = e.path().parent() else {\n        return false;\n    };\n\n    parent_path.join(\"gleam.toml\").exists()\n}\n\n/// Walks through all Gleam module files in the directory, even if ignored,\n/// except for those in the `build/` directory. Excludes any Gleam files within\n/// invalid module paths, for example if they or a folder they're in contain a\n/// dot or a hyphen within their names.\npub fn gleam_files(dir: &Utf8Path) -> impl Iterator<Item = Utf8PathBuf> + '_ {\n    ignore::WalkBuilder::new(dir)\n        .follow_links(true)\n        .standard_filters(false)\n        .filter_entry(|entry| !is_gleam_build_dir(entry))\n        .build()\n        .filter_map(Result::ok)\n        .filter(|entry| {\n            entry\n                .file_type()\n                .map(|type_| type_.is_file())\n                .unwrap_or(false)\n        })\n        .map(ignore::DirEntry::into_path)\n        .map(|path| Utf8PathBuf::from_path_buf(path).expect(\"Non Utf-8 Path\"))\n        .filter(move |d| is_gleam_path(d, dir))\n}\n\n/// Walks through all native files in the directory, such as `.mjs` and `.erl`,\n/// even if ignored.\npub fn native_files(dir: &Utf8Path) -> impl Iterator<Item = Utf8PathBuf> + '_ {\n    ignore::WalkBuilder::new(dir)\n        .follow_links(true)\n        .standard_filters(false)\n        .filter_entry(|entry| !is_gleam_build_dir(entry))\n        .build()\n        .filter_map(Result::ok)\n        .filter(|entry| {\n            entry\n                .file_type()\n                .map(|type_| type_.is_file())\n                .unwrap_or(false)\n        })\n        .map(ignore::DirEntry::into_path)\n        .map(|path| Utf8PathBuf::from_path_buf(path).expect(\"Non Utf-8 Path\"))\n        .filter(|path| {\n            let extension = path.extension().unwrap_or_default();\n            is_native_file_extension(extension)\n        })\n}\n\n/// Walks through all files in the directory, even if ignored.\npub fn private_files(dir: &Utf8Path) -> impl Iterator<Item = Utf8PathBuf> + '_ {\n    ignore::WalkBuilder::new(dir)\n        .follow_links(true)\n        .standard_filters(false)\n        .build()\n        .filter_map(Result::ok)\n        .filter(|entry| {\n            entry\n                .file_type()\n                .map(|type_| type_.is_file())\n                .unwrap_or(false)\n        })\n        .map(ignore::DirEntry::into_path)\n        .map(|path| Utf8PathBuf::from_path_buf(path).expect(\"Non Utf-8 Path\"))\n}\n\n/// Walks through all `.erl` and `.hrl` files in the directory, even if ignored.\npub fn erlang_files(dir: &Utf8Path) -> impl Iterator<Item = Utf8PathBuf> + '_ {\n    ignore::WalkBuilder::new(dir)\n        .follow_links(true)\n        .standard_filters(false)\n        .build()\n        .filter_map(Result::ok)\n        .filter(|entry| {\n            entry\n                .file_type()\n                .map(|type_| type_.is_file())\n                .unwrap_or(false)\n        })\n        .map(ignore::DirEntry::into_path)\n        .map(|path| Utf8PathBuf::from_path_buf(path).expect(\"Non Utf-8 Path\"))\n        .filter(|path| {\n            let extension = path.extension().unwrap_or_default();\n            extension == \"erl\" || extension == \"hrl\"\n        })\n}\n\npub fn create_tar_archive(outputs: Vec<OutputFile>) -> Result<Vec<u8>, Error> {\n    tracing::debug!(\"creating_tar_archive\");\n\n    let encoder = flate2::write::GzEncoder::new(vec![], flate2::Compression::default());\n    let mut builder = tar::Builder::new(encoder);\n\n    for file in outputs {\n        let mut header = tar::Header::new_gnu();\n        header.set_path(&file.path).map_err(|e| Error::AddTar {\n            path: file.path.clone(),\n            err: e.to_string(),\n        })?;\n        header.set_size(file.content.as_bytes().len() as u64);\n        header.set_cksum();\n        builder\n            .append(&header, file.content.as_bytes())\n            .map_err(|e| Error::AddTar {\n                path: file.path.clone(),\n                err: e.to_string(),\n            })?;\n    }\n\n    builder\n        .into_inner()\n        .map_err(|e| Error::TarFinish(e.to_string()))?\n        .finish()\n        .map_err(|e| Error::Gzip(e.to_string()))\n}\n\npub fn mkdir(path: impl AsRef<Utf8Path> + Debug) -> Result<(), Error> {\n    if path.as_ref().exists() {\n        return Ok(());\n    }\n\n    tracing::debug!(path=?path, \"creating_directory\");\n\n    std::fs::create_dir_all(path.as_ref()).map_err(|err| Error::FileIo {\n        kind: FileKind::Directory,\n        path: Utf8PathBuf::from(path.as_ref()),\n        action: FileIoAction::Create,\n        err: Some(err.to_string()),\n    })\n}\n\npub fn read_dir(path: impl AsRef<Utf8Path> + Debug) -> Result<ReadDirUtf8, Error> {\n    tracing::debug!(path=?path,\"reading_directory\");\n\n    Utf8Path::read_dir_utf8(path.as_ref()).map_err(|e| Error::FileIo {\n        action: FileIoAction::Read,\n        kind: FileKind::Directory,\n        path: Utf8PathBuf::from(path.as_ref()),\n        err: Some(e.to_string()),\n    })\n}\n\npub fn module_caches_paths(\n    path: impl AsRef<Utf8Path> + Debug,\n) -> Result<impl Iterator<Item = Utf8PathBuf>, Error> {\n    Ok(read_dir(path)?\n        .filter_map(Result::ok)\n        .map(|f| f.into_path())\n        .filter(|p| p.extension() == Some(\"cache\")))\n}\n\npub fn read(path: impl AsRef<Utf8Path> + Debug) -> Result<String, Error> {\n    tracing::debug!(path=?path,\"reading_file\");\n\n    std::fs::read_to_string(path.as_ref()).map_err(|err| Error::FileIo {\n        action: FileIoAction::Read,\n        kind: FileKind::File,\n        path: Utf8PathBuf::from(path.as_ref()),\n        err: Some(err.to_string()),\n    })\n}\n\npub fn read_bytes(path: impl AsRef<Utf8Path> + Debug) -> Result<Vec<u8>, Error> {\n    tracing::debug!(path=?path,\"reading_file\");\n\n    std::fs::read(path.as_ref()).map_err(|err| Error::FileIo {\n        action: FileIoAction::Read,\n        kind: FileKind::File,\n        path: Utf8PathBuf::from(path.as_ref()),\n        err: Some(err.to_string()),\n    })\n}\n\npub fn reader(path: impl AsRef<Utf8Path> + Debug) -> Result<WrappedReader, Error> {\n    tracing::debug!(path=?path,\"opening_file_reader\");\n\n    let reader = File::open(path.as_ref()).map_err(|err| Error::FileIo {\n        action: FileIoAction::Open,\n        kind: FileKind::File,\n        path: Utf8PathBuf::from(path.as_ref()),\n        err: Some(err.to_string()),\n    })?;\n\n    Ok(WrappedReader::new(path.as_ref(), Box::new(reader)))\n}\n\npub fn buffered_reader<P: AsRef<Utf8Path> + Debug>(path: P) -> Result<impl BufRead, Error> {\n    tracing::debug!(path=?path,\"opening_file_buffered_reader\");\n    let reader = File::open(path.as_ref()).map_err(|err| Error::FileIo {\n        action: FileIoAction::Open,\n        kind: FileKind::File,\n        path: Utf8PathBuf::from(path.as_ref()),\n        err: Some(err.to_string()),\n    })?;\n    Ok(BufReader::new(reader))\n}\n\npub fn copy(\n    path: impl AsRef<Utf8Path> + Debug,\n    to: impl AsRef<Utf8Path> + Debug,\n) -> Result<(), Error> {\n    tracing::debug!(from=?path, to=?to, \"copying_file\");\n\n    // TODO: include the destination in the error message\n    std::fs::copy(path.as_ref(), to.as_ref())\n        .map_err(|err| Error::FileIo {\n            action: FileIoAction::Copy,\n            kind: FileKind::File,\n            path: Utf8PathBuf::from(path.as_ref()),\n            err: Some(err.to_string()),\n        })\n        .map(|_| ())\n}\n\n// pub fn rename(path: impl AsRef<Utf8Path> + Debug, to: impl AsRef<Utf8Path> + Debug) -> Result<(), Error> {\n//     tracing::debug!(from=?path, to=?to, \"renaming_file\");\n\n//     // TODO: include the destination in the error message\n//     std::fs::rename(&path, &to)\n//         .map_err(|err| Error::FileIo {\n//             action: FileIoAction::Rename,\n//             kind: FileKind::File,\n//             path: Utf8PathBuf::from(path.as_ref()),\n//             err: Some(err.to_string()),\n//         })\n//         .map(|_| ())\n// }\n\npub fn copy_dir(\n    path: impl AsRef<Utf8Path> + Debug,\n    to: impl AsRef<Utf8Path> + Debug,\n) -> Result<(), Error> {\n    tracing::debug!(from=?path, to=?to, \"copying_directory\");\n\n    // TODO: include the destination in the error message\n    fs_extra::dir::copy(\n        path.as_ref(),\n        to.as_ref(),\n        &fs_extra::dir::CopyOptions::new()\n            .copy_inside(false)\n            .content_only(true),\n    )\n    .map_err(|err| Error::FileIo {\n        action: FileIoAction::Copy,\n        kind: FileKind::Directory,\n        path: Utf8PathBuf::from(path.as_ref()),\n        err: Some(err.to_string()),\n    })\n    .map(|_| ())\n}\n\npub fn symlink_dir(\n    src: impl AsRef<Utf8Path> + Debug,\n    dest: impl AsRef<Utf8Path> + Debug,\n) -> Result<(), Error> {\n    tracing::debug!(src=?src, dest=?dest, \"symlinking\");\n    let src = canonicalise(src.as_ref())?;\n\n    #[cfg(target_family = \"windows\")]\n    let result = std::os::windows::fs::symlink_dir(src, dest.as_ref());\n    #[cfg(not(target_family = \"windows\"))]\n    let result = std::os::unix::fs::symlink(src, dest.as_ref());\n\n    result.map_err(|err| Error::FileIo {\n        action: FileIoAction::Link,\n        kind: FileKind::File,\n        path: Utf8PathBuf::from(dest.as_ref()),\n        err: Some(err.to_string()),\n    })?;\n    Ok(())\n}\n\npub fn hardlink(\n    from: impl AsRef<Utf8Path> + Debug,\n    to: impl AsRef<Utf8Path> + Debug,\n) -> Result<(), Error> {\n    tracing::debug!(from=?from, to=?to, \"hardlinking\");\n    std::fs::hard_link(from.as_ref(), to.as_ref())\n        .map_err(|err| Error::FileIo {\n            action: FileIoAction::Link,\n            kind: FileKind::File,\n            path: Utf8PathBuf::from(from.as_ref()),\n            err: Some(err.to_string()),\n        })\n        .map(|_| ())\n}\n\n/// Check if the given path is inside a git work tree.\n/// This is done by running `git rev-parse --is-inside-work-tree --quiet` in the\n/// given path. If git is not installed then we assume we're not in a git work\n/// tree.\n///\nfn is_inside_git_work_tree(path: &Utf8Path) -> Result<bool, Error> {\n    tracing::debug!(path=?path, \"checking_for_git_repo\");\n\n    let args: Vec<&str> = vec![\"rev-parse\", \"--is-inside-work-tree\", \"--quiet\"];\n\n    // Ignore all output, rely on the exit code instead.\n    // git will display a fatal error on stderr if rev-parse isn't run inside of a git work tree,\n    // so send stderr to /dev/null\n    let result = std::process::Command::new(\"git\")\n        .args(args)\n        .stdin(std::process::Stdio::null())\n        .stdout(std::process::Stdio::null())\n        .stderr(std::process::Stdio::null())\n        .current_dir(path)\n        .status();\n\n    match result {\n        Ok(status) => Ok(status.success()),\n        Err(error) => match error.kind() {\n            io::ErrorKind::NotFound => Ok(false),\n\n            other => Err(Error::ShellCommand {\n                program: \"git\".into(),\n                reason: ShellCommandFailureReason::IoError(other),\n            }),\n        },\n    }\n}\n\npub(crate) fn is_git_work_tree_root(path: &Utf8Path) -> bool {\n    tracing::debug!(path=?path, \"checking_for_git_repo_root\");\n    exists(path.join(\".git\")).unwrap_or(false)\n}\n\n/// Run `git init` in the given path.\n/// If git is not installed then we do nothing.\npub fn git_init(path: &Utf8Path) -> Result<(), Error> {\n    tracing::debug!(path=?path, \"initializing git\");\n\n    if is_inside_git_work_tree(path)? {\n        tracing::debug!(path=?path, \"git_repo_already_exists\");\n        return Ok(());\n    }\n\n    let args = vec![\"init\".into(), \"--quiet\".into(), path.to_string()];\n\n    let command = Command {\n        program: \"git\".to_string(),\n        args,\n        env: vec![],\n        cwd: None,\n        stdio: Stdio::Inherit,\n    };\n    match ProjectIO::new().exec(command) {\n        Ok(_) => Ok(()),\n        Err(err) => match err {\n            Error::ShellProgramNotFound { .. } => Ok(()),\n            _ => Err(Error::GitInitialization {\n                error: err.to_string(),\n            }),\n        },\n    }\n}\n\npub fn canonicalise(path: &Utf8Path) -> Result<Utf8PathBuf, Error> {\n    std::fs::canonicalize(path)\n        .map_err(|err| Error::FileIo {\n            action: FileIoAction::Canonicalise,\n            kind: FileKind::File,\n            path: Utf8PathBuf::from(path),\n            err: Some(err.to_string()),\n        })\n        .map(|pb| Utf8PathBuf::from_path_buf(pb).expect(\"Non Utf8 Path\"))\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct ConsoleWarningEmitter;\n\nimpl WarningEmitterIO for ConsoleWarningEmitter {\n    fn emit_warning(&self, warning: Warning) {\n        let buffer_writer = crate::cli::stderr_buffer_writer();\n        let mut buffer = buffer_writer.buffer();\n        warning.pretty(&mut buffer);\n        buffer_writer\n            .print(&buffer)\n            .expect(\"Writing warning to stderr\");\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/hex/auth.rs",
    "content": "use crate::{cli, http::HttpClient};\nuse ecow::EcoString;\nuse gleam_core::{\n    Error, Result, encryption,\n    error::{FileIoAction, FileKind},\n    io::HttpClient as _,\n    paths,\n};\nuse hexpm::OAuthTokens;\nuse sha2::Digest as _;\n\npub const HEX_OAUTH_CLIENT_ID: &str = \"877731e8-cb88-45e1-9b84-9214de7da421\";\n\npub const LOCAL_PASS_PROMPT: &str = \"Local password\";\npub const API_ENV_NAME: &str = \"HEXPM_API_KEY\";\n\n#[derive(Debug)]\npub struct EncryptedLegacyApiKey {\n    pub name: String,\n}\n\npub struct HexAuthentication<'runtime> {\n    runtime: &'runtime tokio::runtime::Runtime,\n    http: &'runtime HttpClient,\n    local_password: Option<EcoString>,\n    hex_config: hexpm::Config,\n}\n\nimpl<'runtime> HexAuthentication<'runtime> {\n    /// Reads the stored API key from disc, if it exists.\n    ///\n    pub fn new(\n        runtime: &'runtime tokio::runtime::Runtime,\n        http: &'runtime HttpClient,\n        hex_config: hexpm::Config,\n    ) -> Self {\n        Self {\n            runtime,\n            http,\n            local_password: None,\n            hex_config,\n        }\n    }\n\n    /// Create new OAuth tokens by sending the user through the OAuth flow.\n    ///\n    /// Any already-existing tokens stored on the file system are revoked.\n    ///\n    pub fn create_and_store_new_credentials_via_oauth(&mut self) -> Result<hexpm::Credentials> {\n        let previous_oauth_token = self.read_stored_encrypted_oauth_refresh_token()?;\n        let previous_legacy_key = self.read_stored_legacy_api_key()?;\n\n        // Create a device authorisation with Hex, starting the oauth flow.\n        let mut device_authorisation = self.create_oauth_device_authorisation()?;\n\n        // Show the user their code, and send them to Hex to log in.\n        send_user_to_oauth_verification_url(&device_authorisation);\n\n        // The user has been sent to the Hex website to authenticate.\n        // Poll the Hex API until they accept or reject the request, or it times out.\n        let tokens = loop {\n            let next = self.poll_for_oauth_next_step(&mut device_authorisation)?;\n            match next {\n                hexpm::PollStep::Done(tokens) => break tokens,\n                hexpm::PollStep::SleepThenPollAgain(duration) => std::thread::sleep(duration),\n            }\n        };\n\n        // We are creating a new API key, so we need a new local password\n        // to encrypt it with.\n        self.ask_for_new_local_password()?;\n        self.encrypt_and_store_oauth_refresh_token(&tokens)?;\n\n        let credentials = tokens.as_credentials();\n\n        // Dispose of old tokens, if there was any.\n        self.revoke_old_tokens(&credentials, previous_oauth_token, previous_legacy_key)?;\n        self.delete_legacy_api_key_from_filesystem()?;\n\n        Ok(credentials)\n    }\n\n    fn poll_for_oauth_next_step(\n        &mut self,\n        device_authorisation: &mut hexpm::OAuthDeviceAuthorisation,\n    ) -> Result<hexpm::PollStep, Error> {\n        let request = device_authorisation.poll_token_request(&self.hex_config);\n        let response = self.runtime.block_on(self.http.send(request))?;\n        let next = device_authorisation\n            .poll_token_response(response)\n            .map_err(Error::hex)?;\n        Ok(next)\n    }\n\n    fn create_oauth_device_authorisation(\n        &mut self,\n    ) -> Result<hexpm::OAuthDeviceAuthorisation, Error> {\n        // Create a recognisable name for the client, so folks can more easily understand which\n        // session is which in the Hex console.\n        // It is expected that we can always get the hostname.\n        let hostname = hostname::get().expect(\"hostname\");\n        let client_name = format!(\"Gleam ({})\", hostname.to_string_lossy());\n\n        let request = hexpm::oauth_device_authorisation_request(\n            HEX_OAUTH_CLIENT_ID,\n            &client_name,\n            &self.hex_config,\n        );\n        let response = self.runtime.block_on(self.http.send(request))?;\n        hexpm::oauth_device_authorisation_response(HEX_OAUTH_CLIENT_ID.to_string(), response)\n            .map_err(Error::hex)\n    }\n\n    fn encrypt_and_store_oauth_refresh_token(&mut self, tokens: &OAuthTokens) -> Result<(), Error> {\n        let path = paths::global_hexpm_oauth_credentials_path();\n        let local_password = self.get_local_password()?;\n        let encrypted_refresh_token =\n            encryption::encrypt_with_passphrase(tokens.refresh_token.as_bytes(), &local_password)\n                .map_err(|e| Error::FailedToEncryptLocalHexApiKey {\n                detail: e.to_string(),\n            })?;\n\n        let credentials = StoredOAuthCredentials {\n            hexpm: StoredOAuthRepoCredentials {\n                api: self.hex_config.api_base.clone(),\n                repository: self.hex_config.repository_base.clone(),\n                refresh_token: encrypted_refresh_token,\n                refresh_token_hash: {\n                    let mut hasher = sha2::Sha256::new();\n                    hasher.update(tokens.refresh_token.as_bytes());\n                    base16::encode_lower(&hasher.finalize())\n                },\n            },\n        };\n        let toml = toml::to_string(&credentials).expect(\"OAuth credentials TOML encoding\");\n        crate::fs::write(&path, &toml)?;\n        Ok(())\n    }\n\n    /// Create a new local password.\n    ///\n    /// The password must be long enough.\n    ///\n    /// The old password will be discarded, and the new one will be both\n    /// returned and stored in `self.local_password`\n    ///\n    fn ask_for_new_local_password(&mut self) -> Result<()> {\n        let required_length = 8;\n        self.local_password = None;\n        println!(\n            \"Please enter a new unique password, at least {required_length} characters long.\nIt will be used to locally encrypt your Hex API tokens.\n\"\n        );\n\n        loop {\n            let password = cli::ask_password(LOCAL_PASS_PROMPT)?;\n            if password.chars().count() < required_length {\n                println!(\"\\nPlease use a password at least {required_length} characters long.\\n\")\n            } else {\n                self.local_password = Some(password.clone());\n                return Ok(());\n            }\n        }\n    }\n\n    fn get_local_password(&mut self) -> Result<EcoString> {\n        if let Some(password) = self.local_password.as_ref() {\n            return Ok(password.clone());\n        }\n\n        let password = cli::ask_password(LOCAL_PASS_PROMPT)?;\n        self.local_password = Some(password.clone());\n        Ok(password)\n    }\n\n    /// Get a token that can be used to authenticate with the Hex API.\n    /// In order, it will try these sources:\n    ///\n    /// 1. An API key from the HEXPM_API_KEY environment variable.\n    /// 2. An OAuth refresh token from the file system, which is then exchanged for\n    ///    an access token.\n    /// 3. The OAuth flow.\n    pub fn get_or_create_api_credentials(&mut self) -> Result<hexpm::Credentials> {\n        if let Some(key) = Self::read_env_api_key()? {\n            return Ok(key);\n        }\n\n        if let Some(tokens) = self.read_and_decrypt_and_refresh_stored_tokens()? {\n            return Ok(tokens.as_credentials());\n        }\n\n        self.create_and_store_new_credentials_via_oauth()\n    }\n\n    fn read_env_api_key() -> Result<Option<hexpm::Credentials>> {\n        let api_key = std::env::var(API_ENV_NAME).unwrap_or_default();\n        if api_key.trim().is_empty() {\n            Ok(None)\n        } else {\n            Ok(Some(hexpm::Credentials::ApiKey(EcoString::from(api_key))))\n        }\n    }\n\n    /// Read, decrypt, and refresh OAuth keys stored on the filesystem.\n    ///\n    /// The new refresh is encrypted and stored on the file system for next use.\n    ///\n    /// If there is no stored key then this return `Ok(None)`, and you'll\n    /// need to create a new one.\n    ///\n    fn read_and_decrypt_and_refresh_stored_tokens(&mut self) -> Result<Option<OAuthTokens>> {\n        let Some(encrypted_credentials) = self.read_stored_encrypted_oauth_refresh_token()? else {\n            return Ok(None);\n        };\n\n        let local_password = self.get_local_password()?;\n        let refresh_token = encryption::decrypt_with_passphrase(\n            encrypted_credentials.refresh_token.as_bytes(),\n            &local_password,\n        )\n        .map_err(|e| Error::FailedToDecryptLocalHexApiKey {\n            detail: e.to_string(),\n        })?;\n\n        // Use a refresh token, consuming it to get a new set of tokens.\n        let request = hexpm::oauth_refresh_token_request(\n            HEX_OAUTH_CLIENT_ID,\n            &refresh_token,\n            &self.hex_config,\n        );\n        let response = self.runtime.block_on(self.http.send(request))?;\n        let tokens = hexpm::oauth_refresh_token_response(response).map_err(Error::hex)?;\n\n        // Store the refresh token for future use.\n        self.encrypt_and_store_oauth_refresh_token(&tokens)?;\n\n        Ok(Some(tokens))\n    }\n\n    fn read_stored_encrypted_oauth_refresh_token(\n        &self,\n    ) -> Result<Option<StoredOAuthRepoCredentials>> {\n        let path = paths::global_hexpm_oauth_credentials_path();\n        if !path.exists() {\n            return Ok(None);\n        }\n        let toml = crate::fs::read(&path)?;\n        let credentials: StoredOAuthCredentials =\n            toml::from_str(&toml).map_err(|e| Error::FileIo {\n                action: FileIoAction::Parse,\n                kind: FileKind::File,\n                path,\n                err: Some(e.to_string()),\n            })?;\n        Ok(Some(credentials.hexpm))\n    }\n\n    fn delete_legacy_api_key_from_filesystem(&self) -> Result<()> {\n        let path = paths::global_hexpm_legacy_credentials_path();\n        if !path.exists() {\n            return Ok(());\n        }\n        crate::fs::delete_file(&path)\n    }\n\n    fn read_stored_legacy_api_key(&self) -> Result<Option<EncryptedLegacyApiKey>> {\n        let path = paths::global_hexpm_legacy_credentials_path();\n        if !path.exists() {\n            return Ok(None);\n        }\n        let text = crate::fs::read(&path)?;\n        let mut chunks = text.splitn(2, '\\n');\n        let Some(name) = chunks.next() else {\n            return Ok(None);\n        };\n        // We no longer use this encrypted key, but we still parse it to ensure that\n        // the file is the correct format. If it is not then we cannot safely use it.\n        let Some(_encrypted) = chunks.next() else {\n            return Ok(None);\n        };\n        Ok(Some(EncryptedLegacyApiKey {\n            name: name.to_string(),\n        }))\n    }\n\n    fn revoke_old_tokens(\n        &self,\n        credentials: &hexpm::Credentials,\n        previous_oauth_token: Option<StoredOAuthRepoCredentials>,\n        previous_legacy_key: Option<EncryptedLegacyApiKey>,\n    ) -> Result<()> {\n        if previous_oauth_token.is_none() && previous_legacy_key.is_none() {\n            return Ok(());\n        }\n\n        println!(\"\\nRevoking old authentication credentials\");\n        let credentials = crate::hex::write_credentials(credentials)?;\n\n        if let Some(token) = previous_oauth_token {\n            let hash = token.refresh_token_hash;\n            let request =\n                hexpm::revoke_oauth_token_by_hash_request(&hash, &credentials, &self.hex_config);\n            let response = self.runtime.block_on(self.http.send(request))?;\n            hexpm::revoke_oauth_token_by_hash_response(response).map_err(Error::hex)?;\n        }\n\n        if let Some(key) = previous_legacy_key {\n            let request =\n                hexpm::api_remove_api_key_request(&key.name, &credentials, &self.hex_config);\n            let response = self.runtime.block_on(self.http.send(request))?;\n            hexpm::api_remove_api_key_response(response).map_err(Error::hex)?;\n        }\n\n        Ok(())\n    }\n}\n\nfn send_user_to_oauth_verification_url(device_authorisation: &hexpm::OAuthDeviceAuthorisation) {\n    // We make them press Enter to open the browser instead of going there immediately,\n    // to make sure they see the code before the browser window potentially hides the\n    // terminal window.\n    let uri = &device_authorisation.verification_uri;\n    println!(\n        \"Your Hex verification code:\n\n    {code}\n\nVerify this code matches what is shown in your browser.\n\nPress Enter to open {uri}\",\n        code = device_authorisation.user_code,\n    );\n\n    let _ = std::io::stdin()\n        .read_line(&mut String::new())\n        .expect(\"stdin read_line\");\n    if opener::open_browser(uri).is_err() {\n        println!(\"\\nFailed to open the browser, please navigate to {uri}\");\n    }\n}\n\n#[derive(Debug, serde::Serialize, serde::Deserialize)]\nstruct StoredOAuthRepoCredentials {\n    #[serde(with = \"http_serde::uri\")]\n    api: http::Uri,\n    #[serde(with = \"http_serde::uri\")]\n    repository: http::Uri,\n    /// An encrypted refresh token.\n    refresh_token: String,\n    /// The hash of the token, so it can be revoked even if it cannot be encrypted.\n    refresh_token_hash: String,\n}\n\n#[derive(Debug, serde::Serialize, serde::Deserialize)]\nstruct StoredOAuthCredentials {\n    hexpm: StoredOAuthRepoCredentials,\n}\n"
  },
  {
    "path": "compiler-cli/src/hex.rs",
    "content": "mod auth;\n\nuse crate::{cli, http::HttpClient};\nuse gleam_core::{\n    Error, Result,\n    hex::{self, RetirementReason},\n    io::HttpClient as _,\n    paths::ProjectPaths,\n};\n\npub use auth::HexAuthentication;\n\n/// Prepare credentials for user for write actions.\n/// This will prompt for a one-time-password if needed.\npub fn write_credentials(\n    credentials: &hexpm::Credentials,\n) -> Result<hexpm::WriteActionCredentials> {\n    match credentials {\n        hexpm::Credentials::ApiKey(key) => Ok(hexpm::WriteActionCredentials::ApiKey(key.clone())),\n        hexpm::Credentials::OAuthAccessToken(token) => {\n            let one_time_password = cli::ask(\"Enter your two-factor authentication code\")?.into();\n            Ok(hexpm::WriteActionCredentials::OAuthAccessToken {\n                access_token: token.clone(),\n                one_time_password,\n            })\n        }\n    }\n}\n\npub fn retire(\n    package: String,\n    version: String,\n    reason: RetirementReason,\n    message: Option<String>,\n) -> Result<()> {\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let config = hexpm::Config::new();\n    let http = HttpClient::new();\n    let credentials =\n        HexAuthentication::new(&runtime, &http, config.clone()).get_or_create_api_credentials()?;\n\n    runtime.block_on(hex::retire_release(\n        &package,\n        &version,\n        reason,\n        message.as_deref(),\n        &write_credentials(&credentials)?,\n        &config,\n        &http,\n    ))?;\n    cli::print_retired(&package, &version);\n    Ok(())\n}\n\npub fn unretire(package: String, version: String) -> Result<()> {\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let http = HttpClient::new();\n    let config = hexpm::Config::new();\n    let credentials =\n        HexAuthentication::new(&runtime, &http, config.clone()).get_or_create_api_credentials()?;\n\n    runtime.block_on(hex::unretire_release(\n        &package,\n        &version,\n        &write_credentials(&credentials)?,\n        &config,\n        &http,\n    ))?;\n    cli::print_unretired(&package, &version);\n    Ok(())\n}\n\npub fn revert(\n    paths: &ProjectPaths,\n    package: Option<String>,\n    version: Option<String>,\n) -> Result<()> {\n    let (package, version) = match (package, version) {\n        (Some(pkg), Some(ver)) => (pkg, ver),\n        (None, Some(ver)) => (crate::config::root_config(paths)?.name.to_string(), ver),\n        (Some(pkg), None) => {\n            let query = format!(\"Which version of package {pkg} do you want to revert?\");\n            let ver = cli::ask(&query)?;\n            (pkg, ver)\n        }\n        (None, None) => {\n            // Only want to access root_config once rather than twice\n            let config = crate::config::root_config(paths)?;\n            (config.name.to_string(), config.version.to_string())\n        }\n    };\n\n    let question = format!(\"Do you wish to revert {package} version {version}?\");\n    if !cli::confirm(&question)? {\n        println!(\"Not reverting.\");\n        return Ok(());\n    }\n\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let hex_config = hexpm::Config::new();\n    let http = HttpClient::new();\n    let credentials = HexAuthentication::new(&runtime, &http, hex_config.clone())\n        .get_or_create_api_credentials()?;\n\n    // Revert release from API\n    let request = hexpm::api_revert_release_request(\n        &package,\n        &version,\n        &write_credentials(&credentials)?,\n        &hex_config,\n    )\n    .map_err(Error::hex)?;\n    let response = runtime.block_on(http.send(request))?;\n    hexpm::api_revert_release_response(response).map_err(Error::hex)?;\n\n    // Done!\n    println!(\"{package} {version} has been removed from Hex\");\n    Ok(())\n}\n\npub(crate) fn authenticate() -> Result<()> {\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let http = HttpClient::new();\n    let config = hexpm::Config::new();\n    let credentials = HexAuthentication::new(&runtime, &http, config.clone())\n        .create_and_store_new_credentials_via_oauth()?;\n\n    let request = hexpm::get_me_request(&credentials, &config);\n    let response = runtime.block_on(http.send(request))?;\n    let me = hexpm::get_me_response(response).map_err(Error::hex)?;\n    println!(\"\\nSuccessfully logged in as {}\", me.username);\n\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/http.rs",
    "content": "use std::convert::TryInto;\nuse std::sync::OnceLock;\n\nuse async_trait::async_trait;\nuse camino::Utf8PathBuf;\nuse gleam_core::{\n    Error, Result,\n    error::{FileIoAction, FileKind},\n};\nuse http::{Request, Response};\nuse reqwest::{Certificate, Client};\n\nuse crate::fs;\n\nstatic REQWEST_CLIENT: OnceLock<Client> = OnceLock::new();\n\n#[derive(Debug)]\npub struct HttpClient;\n\nimpl HttpClient {\n    pub fn new() -> Self {\n        Self\n    }\n\n    pub fn boxed() -> Box<Self> {\n        Box::new(Self::new())\n    }\n}\n\n#[async_trait]\nimpl gleam_core::io::HttpClient for HttpClient {\n    async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Vec<u8>>> {\n        tracing::debug!(\n            method = request.method().as_str(),\n            url = request.uri().to_string(),\n            \"http-send\",\n        );\n        let request = request\n            .try_into()\n            .expect(\"Unable to convert HTTP request for use by reqwest library\");\n        let client = init_client().map_err(Error::http)?;\n        let mut response = client.execute(request).await.map_err(Error::http)?;\n        let mut builder = Response::builder()\n            .status(response.status())\n            .version(response.version());\n        if let Some(headers) = builder.headers_mut() {\n            std::mem::swap(headers, response.headers_mut());\n        }\n        builder\n            .body(response.bytes().await.map_err(Error::http)?.to_vec())\n            .map_err(Error::http)\n    }\n}\n\nfn init_client() -> Result<&'static Client, Error> {\n    if let Some(client) = REQWEST_CLIENT.get() {\n        return Ok(client);\n    }\n\n    let certificate_path = match std::env::var(\"GLEAM_CACERTS_PATH\") {\n        Ok(path) => {\n            tracing::trace!(\"Using GLEAM_CACERTS_PATH environment variable\");\n            path\n        }\n        Err(_) => {\n            return Ok(REQWEST_CLIENT.get_or_init(|| {\n                Client::builder()\n                    .build()\n                    .expect(\"Failed to create reqwest client\")\n            }));\n        }\n    };\n\n    let certificate_bytes = fs::read_bytes(&certificate_path)?;\n    let certificate = Certificate::from_pem(&certificate_bytes).map_err(|error| Error::FileIo {\n        kind: FileKind::File,\n        action: FileIoAction::Parse,\n        path: Utf8PathBuf::from(&certificate_path),\n        err: Some(error.to_string()),\n    })?;\n\n    Ok(REQWEST_CLIENT.get_or_init(|| {\n        Client::builder()\n            .add_root_certificate(certificate)\n            .build()\n            .expect(\"Failed to create reqwest client\")\n    }))\n}\n"
  },
  {
    "path": "compiler-cli/src/lib.rs",
    "content": "#![warn(\n    clippy::all,\n    clippy::dbg_macro,\n    clippy::todo,\n    clippy::mem_forget,\n    clippy::use_self,\n    clippy::filter_map_next,\n    clippy::needless_continue,\n    clippy::needless_borrow,\n    clippy::match_wildcard_for_single_variants,\n    clippy::imprecise_flops,\n    clippy::suboptimal_flops,\n    clippy::lossy_float_literal,\n    clippy::rest_pat_in_fully_bound_structs,\n    clippy::fn_params_excessive_bools,\n    clippy::inefficient_to_string,\n    clippy::linkedlist,\n    clippy::macro_use_imports,\n    clippy::option_option,\n    clippy::verbose_file_reads,\n    clippy::unnested_or_patterns,\n    rust_2018_idioms,\n    missing_debug_implementations,\n    missing_copy_implementations,\n    trivial_casts,\n    trivial_numeric_casts,\n    nonstandard_style,\n    unexpected_cfgs,\n    unused_import_braces,\n    unused_qualifications\n)]\n#![deny(\n    clippy::await_holding_lock,\n    clippy::if_let_mutex,\n    clippy::indexing_slicing,\n    clippy::mem_forget,\n    clippy::ok_expect,\n    clippy::unimplemented,\n    clippy::unwrap_used,\n    unsafe_code,\n    unstable_features,\n    unused_results\n)]\n#![allow(\n    clippy::match_single_binding,\n    clippy::inconsistent_struct_constructor,\n    clippy::assign_op_pattern,\n    clippy::len_without_is_empty\n)]\n\n#[cfg(test)]\n#[macro_use]\nextern crate pretty_assertions;\n\nmod add;\nmod beam_compiler;\nmod build;\nmod build_lock;\nmod cli;\nmod compile_package;\nmod config;\nmod dependencies;\nmod docs;\nmod export;\nmod fix;\nmod format;\npub mod fs;\nmod hex;\nmod http;\nmod lsp;\nmod new;\nmod owner;\nmod panic;\nmod publish;\nmod remove;\npub mod run;\nmod shell;\nmod text_layout;\n\nuse config::root_config;\nuse fs::{get_current_directory, get_project_root};\npub use gleam_core::error::{Error, Result};\n\nuse gleam_core::{\n    analyse::TargetSupport,\n    build::{Codegen, Compile, Mode, NullTelemetry, Options, Runtime, Target},\n    hex::RetirementReason,\n    paths::ProjectPaths,\n    version::COMPILER_VERSION,\n};\nuse std::str::FromStr;\n\nuse camino::Utf8PathBuf;\n\nuse clap::{\n    Args, Parser, Subcommand,\n    builder::{PossibleValuesParser, Styles, TypedValueParser, styling},\n};\nuse strum::VariantNames;\n\n#[derive(Args, Debug, Clone)]\nstruct UpdateOptions {\n    /// (optional) Names of the packages to update\n    /// If omitted, all dependencies will be updated\n    #[arg(verbatim_doc_comment)]\n    packages: Vec<String>,\n}\n\n#[derive(Args, Debug, Clone)]\nstruct TreeOptions {\n    /// Name of the package to get the dependency tree for\n    #[arg(\n        short,\n        long,\n        ignore_case = true,\n        conflicts_with = \"invert\",\n        help = \"Package to be used as the root of the tree\"\n    )]\n    package: Option<String>,\n    /// Name of the package to get the inverted dependency tree for\n    #[arg(\n        short,\n        long,\n        ignore_case = true,\n        conflicts_with = \"package\",\n        help = \"Invert the tree direction and focus on the given package\",\n        value_name = \"PACKAGE\"\n    )]\n    invert: Option<String>,\n}\n\n#[derive(Parser, Debug)]\n#[command(\n    version,\n    name = \"gleam\",\n    next_display_order = None,\n    help_template = \"\\\n{before-help}{name} {version}\n\n{usage-heading} {usage}\n\n{all-args}{after-help}\",\n    styles = Styles::styled()\n        .header(styling::AnsiColor::Yellow.on_default())\n        .usage(styling::AnsiColor::Yellow.on_default())\n        .literal(styling::AnsiColor::Green.on_default())\n)]\nenum Command {\n    /// Build the project\n    Build {\n        /// Consider the build failed if the package contains any warnings\n        #[arg(long)]\n        warnings_as_errors: bool,\n\n        /// Which compilation target to use\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        target: Option<Target>,\n\n        /// Don't print progress information\n        #[clap(long)]\n        no_print_progress: bool,\n    },\n\n    /// Type check the project\n    Check {\n        /// Which compilation target to use\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        target: Option<Target>,\n    },\n\n    /// Publish the project to the Hex package repository\n    ///\n    /// Please ensure your package is suitable for production use before\n    /// publishing. If you have a prototype package that you wish to use\n    /// in another project then use git dependencies instead of publishing\n    /// to the package repository.\n    ///\n    /// This command optionally accepts the environment variable\n    /// `HEXPM_API_KEY`, which can hold a Hex API key to authenticate\n    /// with Hex.\n    ///\n    #[command(verbatim_doc_comment)]\n    Publish {\n        #[arg(long)]\n        replace: bool,\n        #[arg(short, long)]\n        yes: bool,\n    },\n\n    /// Render HTML documentation for the package\n    ///\n    /// There are several options in `gleam.toml` that can be used to\n    /// configure the output.\n    ///\n    ///    repository = { type = \"github\", user = \"lpil\", repo = \"wibble\" }\n    ///\n    /// Specify the location of the source code repository for the package.\n    /// This will add a link to the side bar, and add \"view code\" links for\n    /// the documented types and values.\n    ///\n    ///    links = [\n    ///      { title = \"Home page\", href = \"https://example.com\" },\n    ///      { title = \"Other site\", href = \"https://another.example.com\" },\n    ///    ]\n    ///\n    /// Specify some additional links to include in the sidebar.\n    ///\n    ///    [documentation]\n    ///    pages = [\n    ///      { title = \"My Page\", path = \"my-page.html\", source = \"./path/to/my-page.md\" },\n    ///    ]\n    ///\n    /// Specify additional markdown pages to include in the documentation,\n    /// with links for each added to the sidebar.\n    ///\n    #[command(subcommand, verbatim_doc_comment)]\n    Docs(Docs),\n\n    /// Work with dependency packages\n    ///\n    /// The packages and the acceptable version ranges are specified in\n    /// `gleam.toml`. You can edit this file manually, or use the `gleam add`\n    /// and `gleam remove` commands.\n    ///\n    /// Package versions follow semantic versioning: MAJOR.MINOR.PATCH.\n    /// - Major updates include breaking changes, either type changes or\n    ///   semantic changes.\n    /// - Minor updates include new functionality, but no breaking changes.\n    /// - Patch updates include only bug fixes.\n    ///\n    /// Dependency resolution will be performed automatically by any command\n    /// that builds your project. Once versions have been selected they are\n    /// written to `manifest.toml`, which locks the package to those versions,\n    /// making your build deterministic. You should not edit this file manually.\n    ///\n    /// To upgrade the dependencies you can use the `gleam update` command,\n    /// which will select the newest versions compatible with the requirements\n    /// in `gleam.toml`.\n    ///\n    /// The `[dependencies]` section of `gleam.toml` holds the production\n    /// dependencies. These are included in your production application, or\n    /// are used as the dependencies when published as a library. The\n    /// `[dev_dependencies]` section holds dependencies that are only used\n    /// during development, e.g. code used for testing the package.\n    ///\n    /// ## Syntax examples:\n    ///\n    ///    [dependencies]\n    ///    wibble = \">= 1.2.0 and < 2.0.0\"\n    ///\n    /// Require the package `wibble`, permitting versions greater than or\n    /// equal to 1.2.0, but lower than 2.0.0.\n    ///\n    ///    [dependencies]\n    ///    wibble = \">= 1.2.0 and < 2.0.0 and != 1.4.1\"\n    ///\n    /// Permit a range, but deny a specific version within that range. This\n    /// could be useful if there is a version known to have a bug.\n    ///\n    ///    [dependencies]\n    ///    wibble = { git = \"https://example.com/wibble.git\", ref = \"a8b3c5d82\" }\n    ///\n    /// A dependency fetched from Git instead of from Hex. This is useful\n    /// for using packages of yours that are not-yet production-ready, or\n    /// for bug fixes that have not yet been published to Hex.\n    ///\n    ///    [dependencies]\n    ///    wibble = { path = \"../wibble\" }\n    ///\n    /// A local dependency, on your computer. This is useful for testing and\n    /// and for applications made of multiple packages in a single version\n    /// control repository.\n    ///\n    #[command(subcommand, verbatim_doc_comment)]\n    Deps(Dependencies),\n\n    /// Update dependency packages to their latest versions\n    Update(UpdateOptions),\n\n    /// Work with the Hex package manager\n    #[command(subcommand)]\n    Hex(Hex),\n\n    /// Create a new project\n    New(NewOptions),\n\n    /// Format source code\n    Format {\n        /// The files or directories to format\n        #[arg(default_value = \".\")]\n        files: Vec<String>,\n\n        /// Read source from standard-input\n        #[arg(long)]\n        stdin: bool,\n\n        /// Only check if inputs are formatted correctly, erroring if they are not\n        #[arg(long)]\n        check: bool,\n    },\n\n    /// Rewrite deprecated Gleam code\n    Fix,\n\n    /// Start an Erlang REPL with the Gleam code loaded\n    Shell,\n\n    /// Run the project\n    ///\n    /// This command runs the `main` function from the `<PROJECT_NAME>` module.\n    #[command(trailing_var_arg = true)]\n    Run {\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        /// Which compilation target to use\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        target: Option<Target>,\n\n        #[arg(long, ignore_case = true, help = runtime_doc())]\n        runtime: Option<Runtime>,\n\n        /// The module to run\n        #[arg(short, long)]\n        module: Option<String>,\n\n        /// Don't print progress information\n        #[clap(long)]\n        no_print_progress: bool,\n\n        arguments: Vec<String>,\n    },\n\n    /// Run the project tests\n    ///\n    /// This command runs the `main` function from the `<PROJECT_NAME>_test` module.\n    #[command(trailing_var_arg = true)]\n    Test {\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        /// Which compilation target to use\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        target: Option<Target>,\n\n        #[arg(long, ignore_case = true, help = runtime_doc())]\n        runtime: Option<Runtime>,\n\n        arguments: Vec<String>,\n    },\n\n    /// Run the project development entrypoint\n    ///\n    /// This command runs the `main` function from the `<PROJECT_NAME>_dev` module.\n    #[command(trailing_var_arg = true)]\n    Dev {\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        /// Which compilation target to use\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        target: Option<Target>,\n\n        #[arg(long, ignore_case = true, help = runtime_doc())]\n        runtime: Option<Runtime>,\n\n        arguments: Vec<String>,\n    },\n\n    /// A low-level API for compiling a single Gleam package\n    ///\n    /// This is to be used by other build tools to implement support for Gleam\n    /// code. It is not used directly by humans.\n    ///\n    #[command(verbatim_doc_comment)]\n    CompilePackage(CompilePackage),\n\n    /// Read and print gleam.toml for debugging\n    #[command(hide = true)]\n    PrintConfig,\n\n    /// Add new dependencies\n    ///\n    /// The newest compatible version of the package is determined, and then\n    /// `gleam.toml` is updated to require at least that version, with a range\n    /// permitting future patch and minor updates.\n    ///\n    /// Add the package \"wibble\":\n    ///     gleam add wibble\n    ///\n    /// Add the package \"wibble\", requiring version >= v2.0.0 and < v3.0.0:\n    ///     gleam add wibble@2\n    ///\n    /// Add the package \"wibble\", requiring version >= v2.5.1 and < v3.0.0:\n    ///     gleam add wibble@2.5.1\n    ///\n    /// Add multiple packages:\n    ///     gleam add wibble@2 warble@1\n    ///\n    /// Add a package as a non-production dependency:\n    ///     gleam add --dev wibble\n    ///\n    /// You can also edit `gleam.toml` directly, for further control over your\n    /// package dependencies. Run `gleam help deps` for documentation on the\n    /// format.\n    ///\n    #[command(verbatim_doc_comment)]\n    Add {\n        /// The names of Hex packages to add\n        #[arg(required = true)]\n        packages: Vec<String>,\n\n        /// Add the packages as dev-only dependencies\n        #[arg(long)]\n        dev: bool,\n    },\n\n    /// Remove project dependencies\n    Remove {\n        /// The names of packages to remove\n        #[arg(required = true)]\n        packages: Vec<String>,\n    },\n\n    /// Delete any build artifacts for this project\n    Clean,\n\n    /// Run the language server, to be used by editors\n    #[command(name = \"lsp\")]\n    LanguageServer,\n\n    /// Export something useful from the Gleam project\n    #[command(subcommand)]\n    Export(ExportTarget),\n}\n\nfn template_doc() -> &'static str {\n    \"The template to use\"\n}\n\nfn target_doc() -> String {\n    format!(\"The platform to target ({})\", Target::VARIANTS.join(\"|\"))\n}\n\nfn runtime_doc() -> String {\n    format!(\"The runtime to target ({})\", Runtime::VARIANTS.join(\"|\"))\n}\n\n#[derive(Subcommand, Debug, Clone)]\npub enum ExportTarget {\n    /// Precompiled Erlang, suitable for deployment\n    ErlangShipment,\n    /// The package bundled into a tarball, suitable for publishing to Hex\n    HexTarball,\n    /// The JavaScript prelude module\n    JavascriptPrelude,\n    /// The TypeScript prelude module\n    TypescriptPrelude,\n    /// Information on the modules, functions, and types in the project in JSON format\n    PackageInterface {\n        #[arg(long = \"out\", required = true)]\n        /// The path to write the JSON file to\n        output: Utf8PathBuf,\n    },\n    /// Package information (gleam.toml) in JSON format\n    PackageInformation {\n        #[arg(long = \"out\", required = true)]\n        /// The path to write the JSON file to\n        output: Utf8PathBuf,\n    },\n}\n\n#[derive(Args, Debug, Clone)]\npub struct NewOptions {\n    /// Location of the project root\n    pub project_root: String,\n\n    /// Name of the project\n    #[arg(long)]\n    pub name: Option<String>,\n\n    #[arg(long, ignore_case = true, default_value = \"erlang\", help = template_doc())]\n    pub template: new::Template,\n\n    /// Skip git initialization and creation of .gitignore, .git/* and .github/* files\n    #[arg(long)]\n    pub skip_git: bool,\n\n    /// Skip creation of .github/* files\n    #[arg(long)]\n    pub skip_github: bool,\n}\n\n#[derive(Args, Debug)]\npub struct CompilePackage {\n    /// The compilation target for the generated project\n    #[arg(long, ignore_case = true)]\n    target: Target,\n\n    /// The directory of the Gleam package\n    #[arg(long = \"package\")]\n    package_directory: Utf8PathBuf,\n\n    /// A directory to write compiled package to\n    #[arg(long = \"out\")]\n    output_directory: Utf8PathBuf,\n\n    /// A directories of precompiled Gleam projects\n    #[arg(long = \"lib\")]\n    libraries_directory: Utf8PathBuf,\n\n    /// The location of the JavaScript prelude module, relative to the `out`\n    /// directory.\n    ///\n    /// Required when compiling to JavaScript.\n    ///\n    /// This likely wants to be a `.mjs` file as NodeJS does not permit\n    /// importing of other JavaScript file extensions.\n    ///\n    #[arg(verbatim_doc_comment, long = \"javascript-prelude\")]\n    javascript_prelude: Option<Utf8PathBuf>,\n\n    /// Skip Erlang to BEAM bytecode compilation\n    #[arg(long = \"no-beam\")]\n    skip_beam_compilation: bool,\n}\n\n#[derive(Subcommand, Debug)]\nenum Dependencies {\n    /// List all dependency packages\n    List,\n\n    /// Download all dependency packages\n    Download,\n\n    /// List all outdated dependencies\n    Outdated,\n\n    /// Update dependency packages to their latest versions\n    Update(UpdateOptions),\n\n    /// Tree of all the dependency packages\n    Tree(TreeOptions),\n}\n\n#[derive(Subcommand, Debug)]\nenum Hex {\n    /// Retire a release from Hex\n    ///\n    /// This command uses the environment variable:\n    ///\n    /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager.\n    ///\n    #[command(verbatim_doc_comment)]\n    Retire {\n        package: String,\n\n        version: String,\n\n        #[arg(value_parser = PossibleValuesParser::new(RetirementReason::VARIANTS).map(|s| RetirementReason::from_str(&s).unwrap()))]\n        reason: RetirementReason,\n\n        message: Option<String>,\n    },\n\n    /// Un-retire a release from Hex\n    ///\n    /// This command uses this environment variable:\n    ///\n    /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager.\n    ///\n    #[command(verbatim_doc_comment)]\n    Unretire { package: String, version: String },\n\n    /// Revert a release from Hex\n    ///\n    /// This command uses this environment variable:\n    ///\n    /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager.\n    ///\n    #[command(verbatim_doc_comment)]\n    Revert {\n        #[arg(long)]\n        package: Option<String>,\n\n        #[arg(long)]\n        version: Option<String>,\n    },\n\n    /// Deal with package ownership\n    #[command(subcommand)]\n    Owner(Owner),\n\n    /// Log in to Hex. Replaces the credentials with new ones if already logged in.\n    Authenticate,\n}\n\n#[derive(Subcommand, Debug)]\nenum Owner {\n    /// Transfers ownership of the given package to a new Hex user\n    ///\n    /// This command uses this environment variable:\n    ///\n    /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate against the Hex package manager.\n    ///\n    #[command(verbatim_doc_comment)]\n    Transfer {\n        package: String,\n\n        /// The username or email of the new owner\n        #[arg(long = \"to\")]\n        username_or_email: String,\n    },\n}\n\n#[derive(Subcommand, Debug)]\nenum Docs {\n    /// Render HTML docs locally\n    Build {\n        /// Opens the docs in a browser after rendering\n        #[arg(long)]\n        open: bool,\n\n        #[arg(short, long, ignore_case = true, help = target_doc())]\n        target: Option<Target>,\n    },\n\n    /// Publish HTML docs to HexDocs\n    ///\n    /// This command uses this environment variable:\n    ///\n    /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager.\n    ///\n    #[command(verbatim_doc_comment)]\n    Publish,\n\n    /// Remove HTML docs from HexDocs\n    ///\n    /// This command uses this environment variable:\n    ///\n    /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager.\n    ///\n    #[command(verbatim_doc_comment)]\n    Remove {\n        /// The name of the package\n        #[arg(long)]\n        package: String,\n\n        /// The version of the docs to remove\n        #[arg(long)]\n        version: String,\n    },\n}\n\npub fn main() {\n    initialise_logger();\n    panic::add_handler();\n    let stderr = cli::stderr_buffer_writer();\n    let result = parse_and_run_command();\n    match result {\n        Ok(_) => {\n            tracing::info!(\"Successfully completed\");\n        }\n        Err(error) => {\n            tracing::error!(error = ?error, \"Failed\");\n            let mut buffer = stderr.buffer();\n            error.pretty(&mut buffer);\n            stderr.print(&buffer).expect(\"Final result error writing\");\n            std::process::exit(1);\n        }\n    }\n}\n\nfn parse_and_run_command() -> Result<(), Error> {\n    match Command::parse() {\n        Command::Build {\n            target,\n            warnings_as_errors,\n            no_print_progress,\n        } => {\n            let paths = find_project_paths()?;\n            command_build(&paths, target, warnings_as_errors, no_print_progress)\n        }\n\n        Command::Check { target } => {\n            let paths = find_project_paths()?;\n            command_check(&paths, target)\n        }\n\n        Command::Docs(Docs::Build { open, target }) => {\n            let paths = find_project_paths()?;\n            docs::build(&paths, docs::BuildOptions { open, target })\n        }\n\n        Command::Docs(Docs::Publish) => {\n            let paths = find_project_paths()?;\n            docs::publish(&paths)\n        }\n\n        Command::Docs(Docs::Remove { package, version }) => docs::remove(package, version),\n\n        Command::Format {\n            stdin,\n            files,\n            check,\n        } => format::run(stdin, check, files),\n\n        Command::Fix => {\n            let paths = find_project_paths()?;\n            fix::run(&paths)\n        }\n\n        Command::Deps(Dependencies::List) => {\n            let paths = find_project_paths()?;\n            dependencies::list(&paths)\n        }\n\n        Command::Deps(Dependencies::Download) => {\n            let paths = find_project_paths()?;\n            download_dependencies(&paths)\n        }\n\n        Command::Deps(Dependencies::Outdated) => {\n            let paths = find_project_paths()?;\n            dependencies::outdated(&paths)\n        }\n\n        Command::Deps(Dependencies::Update(options)) => {\n            let paths = find_project_paths()?;\n            dependencies::update(&paths, options.packages)\n        }\n\n        Command::Deps(Dependencies::Tree(options)) => {\n            let paths = find_project_paths()?;\n            dependencies::tree(&paths, options)\n        }\n\n        Command::Hex(Hex::Authenticate) => hex::authenticate(),\n\n        Command::New(options) => new::create(options, COMPILER_VERSION),\n\n        Command::Shell => {\n            let paths = find_project_paths()?;\n            shell::command(&paths)\n        }\n\n        Command::Run {\n            target,\n            arguments,\n            runtime,\n            module,\n            no_print_progress,\n        } => {\n            let paths = find_project_paths()?;\n            run::command(\n                &paths,\n                arguments,\n                target,\n                runtime,\n                module,\n                run::Which::Src,\n                no_print_progress,\n            )\n        }\n\n        Command::Test {\n            target,\n            arguments,\n            runtime,\n        } => {\n            let paths = find_project_paths()?;\n            run::command(\n                &paths,\n                arguments,\n                target,\n                runtime,\n                None,\n                run::Which::Test,\n                false,\n            )\n        }\n\n        Command::Dev {\n            target,\n            arguments,\n            runtime,\n        } => {\n            let paths = find_project_paths()?;\n            run::command(\n                &paths,\n                arguments,\n                target,\n                runtime,\n                None,\n                run::Which::Dev,\n                false,\n            )\n        }\n\n        Command::CompilePackage(opts) => compile_package::command(opts),\n\n        Command::Publish { replace, yes } => {\n            let paths = find_project_paths()?;\n            publish::command(&paths, replace, yes)\n        }\n\n        Command::PrintConfig => {\n            let paths = find_project_paths()?;\n            print_config(&paths)\n        }\n\n        Command::Hex(Hex::Retire {\n            package,\n            version,\n            reason,\n            message,\n        }) => hex::retire(package, version, reason, message),\n\n        Command::Hex(Hex::Unretire { package, version }) => hex::unretire(package, version),\n\n        Command::Hex(Hex::Revert { package, version }) => {\n            let paths = find_project_paths()?;\n            hex::revert(&paths, package, version)\n        }\n\n        Command::Hex(Hex::Owner(Owner::Transfer {\n            package,\n            username_or_email,\n        })) => owner::transfer(package, username_or_email),\n\n        Command::Add { packages, dev } => {\n            let paths = find_project_paths()?;\n            add::command(&paths, packages, dev)\n        }\n\n        Command::Remove { packages } => {\n            let paths = find_project_paths()?;\n            remove::command(&paths, packages)\n        }\n\n        Command::Update(options) => {\n            let paths = find_project_paths()?;\n            dependencies::update(&paths, options.packages)\n        }\n\n        Command::Clean => {\n            let paths = find_project_paths()?;\n            clean(&paths)\n        }\n\n        Command::LanguageServer => lsp::main(),\n\n        Command::Export(ExportTarget::ErlangShipment) => {\n            let paths = find_project_paths()?;\n            export::erlang_shipment(&paths)\n        }\n        Command::Export(ExportTarget::HexTarball) => {\n            let paths = find_project_paths()?;\n            export::hex_tarball(&paths)\n        }\n        Command::Export(ExportTarget::JavascriptPrelude) => export::javascript_prelude(),\n        Command::Export(ExportTarget::TypescriptPrelude) => export::typescript_prelude(),\n        Command::Export(ExportTarget::PackageInterface { output }) => {\n            let paths = find_project_paths()?;\n            export::package_interface(&paths, output)\n        }\n        Command::Export(ExportTarget::PackageInformation { output }) => {\n            let paths = find_project_paths()?;\n            export::package_information(&paths, output)\n        }\n    }\n}\n\nfn command_check(paths: &ProjectPaths, target: Option<Target>) -> Result<()> {\n    let _ = build::main(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors: false,\n            codegen: Codegen::DepsOnly,\n            compile: Compile::All,\n            mode: Mode::Dev,\n            target,\n            no_print_progress: false,\n        },\n        build::download_dependencies(paths, cli::Reporter::new())?,\n    )?;\n    Ok(())\n}\n\nfn command_build(\n    paths: &ProjectPaths,\n    target: Option<Target>,\n    warnings_as_errors: bool,\n    no_print_progress: bool,\n) -> Result<()> {\n    let manifest = if no_print_progress {\n        build::download_dependencies(paths, NullTelemetry)?\n    } else {\n        build::download_dependencies(paths, cli::Reporter::new())?\n    };\n    let _ = build::main(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors,\n            codegen: Codegen::All,\n            compile: Compile::All,\n            mode: Mode::Dev,\n            target,\n            no_print_progress,\n        },\n        manifest,\n    )?;\n    Ok(())\n}\n\nfn print_config(paths: &ProjectPaths) -> Result<()> {\n    let config = root_config(paths)?;\n    println!(\"{config:#?}\");\n    Ok(())\n}\n\nfn clean(paths: &ProjectPaths) -> Result<()> {\n    fs::delete_directory(&paths.build_directory())\n}\n\nfn initialise_logger() {\n    let enable_colours = std::env::var(\"GLEAM_LOG_NOCOLOUR\").is_err();\n    tracing_subscriber::fmt()\n        .with_writer(std::io::stderr)\n        .with_env_filter(std::env::var(\"GLEAM_LOG\").unwrap_or_else(|_| \"off\".into()))\n        .with_target(false)\n        .with_ansi(enable_colours)\n        .without_time()\n        .init();\n}\n\nfn find_project_paths() -> Result<ProjectPaths> {\n    let current_dir = get_current_directory()?;\n    get_project_root(current_dir).map(ProjectPaths::new)\n}\n\n#[cfg(test)]\nfn project_paths_at_current_directory_without_toml() -> ProjectPaths {\n    let current_dir = get_current_directory().expect(\"Failed to get current directory\");\n    ProjectPaths::new(current_dir)\n}\n\nfn download_dependencies(paths: &ProjectPaths) -> Result<()> {\n    _ = dependencies::resolve_and_download(\n        paths,\n        cli::Reporter::new(),\n        None,\n        Vec::new(),\n        dependencies::DependencyManagerConfig {\n            use_manifest: dependencies::UseManifest::Yes,\n            check_major_versions: dependencies::CheckMajorVersions::No,\n        },\n    )?;\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/lsp.rs",
    "content": "use crate::{\n    build_lock::{BuildLock, Guard},\n    fs::ProjectIO,\n};\nuse gleam_core::{\n    Result,\n    build::{Mode, NullTelemetry, Target},\n    paths::ProjectPaths,\n};\nuse gleam_language_server::{LanguageServer, LockGuard, Locker};\n\npub fn main() -> Result<()> {\n    tracing::info!(\"language_server_starting\");\n\n    if std::io::IsTerminal::is_terminal(&std::io::stdin()) {\n        eprintln!(\n            \"Hello human!\n\nThis command is intended to be run by language server clients such\nas a text editor rather than being run directly in the console.\n\nMany editors will automatically start the language server for you\nwhen you open a Gleam project. If yours does not you may need to\nlook up how to configure your editor to use a language server.\n\nIf you are seeing this in the logs of your editor you can safely\nignore this message.\n\nIf you have run `gleam lsp` yourself in your terminal then exit\nthis program by pressing ctrl+c.\n\"\n        );\n    }\n\n    // Create the transport. Includes the stdio (stdin and stdout) versions but this could\n    // also be implemented to use sockets or HTTP.\n    let (connection, io_threads) = lsp_server::Connection::stdio();\n\n    // Run the server and wait for the two threads to end, typically by trigger\n    // LSP Exit event.\n    LanguageServer::new(&connection, ProjectIO::new())?.run()?;\n\n    // Shut down gracefully.\n    drop(connection);\n    io_threads.join().expect(\"joining_lsp_threads\");\n\n    tracing::info!(\"language_server_stopped\");\n    Ok(())\n}\n\n#[derive(Debug)]\npub struct LspLocker(BuildLock);\n\nimpl LspLocker {\n    pub fn new(paths: &ProjectPaths, target: Target) -> Result<Self> {\n        let build_lock = BuildLock::new_target(paths, Mode::Lsp, target)?;\n        Ok(Self(build_lock))\n    }\n}\n\nimpl Locker for LspLocker {\n    fn lock_for_build(&self) -> Result<LockGuard> {\n        let guard: Guard = self.0.lock(&NullTelemetry)?;\n        Ok(LockGuard(Box::new(guard)))\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/new/snapshots/gleam_cli__new__tests__new_with_default_template@src__my_project.gleam.snap",
    "content": "---\nsource: compiler-cli/src/new/tests.rs\nexpression: \"crate::fs::read(Utf8PathBuf::from_path_buf(file_path.to_path_buf()).expect(\\\"Non Utf8 Path\\\"),).unwrap()\"\n---\nimport gleam/io\n\npub fn main() -> Nil {\n  io.println(\"Hello from my_project!\")\n}\n"
  },
  {
    "path": "compiler-cli/src/new/snapshots/gleam_cli__new__tests__new_with_default_template@test__my_project_test.gleam.snap",
    "content": "---\nsource: compiler-cli/src/new/tests.rs\nassertion_line: 56\nexpression: \"crate::fs::read(Utf8PathBuf::from_path_buf(file_path.to_path_buf()).expect(\\\"Non Utf8 Path\\\"),).unwrap()\"\nsnapshot_kind: text\n---\nimport gleeunit\n\npub fn main() -> Nil {\n  gleeunit.main()\n}\n\n// gleeunit test functions end in `_test`\npub fn hello_world_test() {\n  let name = \"Joe\"\n  let greeting = \"Hello, \" <> name <> \"!\"\n\n  assert greeting == \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "compiler-cli/src/new/snapshots/gleam_cli__new__tests__new_with_javascript_template@src__my_project.gleam.snap",
    "content": "---\nsource: compiler-cli/src/new/tests.rs\nexpression: \"crate::fs::read(Utf8PathBuf::from_path_buf(file_path.to_path_buf()).expect(\\\"Non Utf8 Path\\\"),).unwrap()\"\n---\nimport gleam/io\n\npub fn main() -> Nil {\n  io.println(\"Hello from my_project!\")\n}\n"
  },
  {
    "path": "compiler-cli/src/new/snapshots/gleam_cli__new__tests__new_with_javascript_template@test__my_project_test.gleam.snap",
    "content": "---\nsource: compiler-cli/src/new/tests.rs\nassertion_line: 86\nexpression: \"crate::fs::read(Utf8PathBuf::from_path_buf(file_path.to_path_buf()).expect(\\\"Non Utf8 Path\\\"),).unwrap()\"\nsnapshot_kind: text\n---\nimport gleeunit\n\npub fn main() -> Nil {\n  gleeunit.main()\n}\n\n// gleeunit test functions end in `_test`\npub fn hello_world_test() {\n  let name = \"Joe\"\n  let greeting = \"Hello, \" <> name <> \"!\"\n\n  assert greeting == \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "compiler-cli/src/new/tests.rs",
    "content": "use std::path::PathBuf;\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse gleam_core::Error;\n\n#[test]\nfn new() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: false,\n            skip_github: false,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n\n    creator.run().unwrap();\n\n    assert!(path.join(\".git\").exists());\n    assert!(path.join(\"README.md\").exists());\n    assert!(path.join(\"gleam.toml\").exists());\n    assert!(path.join(\"src/my_project.gleam\").exists());\n    assert!(path.join(\"test/my_project_test.gleam\").exists());\n    assert!(path.join(\".github/workflows/test.yml\").exists());\n\n    let toml = crate::fs::read(path.join(\"gleam.toml\")).unwrap();\n    assert!(toml.contains(\"name = \\\"my_project\\\"\"));\n}\n\n#[test]\nfn new_with_default_template() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.into_path()).expect(\"Non Utf8 Path\");\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.join(\"my_project\").to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: false,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n    creator.run().unwrap();\n\n    insta::glob!(&path, \"my_project/[^.]**/*.*\", |file_path| {\n        if !file_path.is_dir() {\n            insta::assert_snapshot!(\n                crate::fs::read(\n                    Utf8PathBuf::from_path_buf(file_path.to_path_buf()).expect(\"Non Utf8 Path\"),\n                )\n                .unwrap()\n            );\n        }\n    });\n}\n\n#[test]\nfn new_with_javascript_template() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.into_path()).expect(\"Non Utf8 Path\");\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.join(\"my_project\").to_string(),\n            template: super::Template::JavaScript,\n            name: None,\n            skip_git: false,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n    creator.run().unwrap();\n\n    insta::glob!(&path, \"my_project/[^.]**/*.*\", |file_path| {\n        if !file_path.is_dir() {\n            insta::assert_snapshot!(\n                crate::fs::read(\n                    Utf8PathBuf::from_path_buf(file_path.to_path_buf()).expect(\"Non Utf8 Path\"),\n                )\n                .unwrap()\n            );\n        }\n    });\n}\n\n#[test]\nfn new_with_skip_git() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: true,\n            skip_github: false,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n    creator.run().unwrap();\n    assert!(!path.join(\".git\").exists());\n    assert!(!path.join(\".github\").exists());\n}\n\n#[test]\nfn new_with_skip_github() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: false,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n    creator.run().unwrap();\n\n    assert!(path.join(\".git\").exists());\n\n    assert!(!path.join(\".github\").exists());\n    assert!(!path.join(\".github/workflows/test.yml\").exists());\n}\n\n#[test]\nfn new_with_skip_git_and_github() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: true,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n    creator.run().unwrap();\n\n    assert!(!path.join(\".git\").exists());\n\n    assert!(!path.join(\".github\").exists());\n    assert!(!path.join(\".github/workflows/test.yml\").exists());\n}\n\n#[test]\nfn invalid_path() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"-------\")).expect(\"Non Utf8 Path\");\n\n    assert!(\n        super::Creator::new(\n            super::NewOptions {\n                project_root: path.to_string(),\n                template: super::Template::Erlang,\n                name: None,\n                skip_git: false,\n                skip_github: false,\n            },\n            \"1.0.0-gleam\",\n        )\n        .is_err()\n    );\n}\n\n#[test]\nfn invalid_name() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"projec\")).expect(\"Non Utf8 Path\");\n\n    assert!(\n        super::Creator::new(\n            super::NewOptions {\n                project_root: path.to_string(),\n                template: super::Template::Erlang,\n                name: Some(\"-\".into()),\n                skip_git: false,\n                skip_github: false,\n            },\n            \"1.0.0-gleam\",\n        )\n        .is_err()\n    );\n}\n\n#[test]\nfn existing_directory_no_files() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    crate::fs::mkdir(&path).unwrap();\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: true,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n\n    creator.run().unwrap();\n\n    assert!(path.join(\"README.md\").exists());\n}\n\n#[test]\nfn existing_directory_with_one_existing_file() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    crate::fs::mkdir(&path).unwrap();\n\n    let _ = std::fs::File::create(PathBuf::from(&path).join(\"README.md\")).unwrap();\n    let _ = std::fs::File::create(PathBuf::from(&path).join(\"my_project.gleam\")).unwrap();\n\n    assert!(\n        super::Creator::new(\n            super::NewOptions {\n                project_root: path.to_string(),\n                template: super::Template::Erlang,\n                name: None,\n                skip_git: true,\n                skip_github: true,\n            },\n            \"1.0.0-gleam\",\n        )\n        .is_err()\n    );\n}\n\n#[test]\nfn existing_directory_with_non_generated_file() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    crate::fs::mkdir(&path).unwrap();\n    let file_path = PathBuf::from(&path).join(\"some_fake_thing_that_is_not_generated.md\");\n\n    let _ = std::fs::File::create(file_path).unwrap();\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: true,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n\n    creator.run().unwrap();\n\n    assert!(path.join(\"README.md\").exists());\n    assert!(\n        path.join(\"some_fake_thing_that_is_not_generated.md\")\n            .exists()\n    );\n}\n\n#[test]\nfn conflict_with_existing_files() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    crate::fs::mkdir(&path).unwrap();\n\n    let _ = std::fs::File::create(PathBuf::from(&path).join(\"README.md\")).unwrap();\n\n    assert_eq!(\n        super::Creator::new(\n            super::NewOptions {\n                project_root: path.to_string(),\n                template: super::Template::Erlang,\n                name: None,\n                skip_git: true,\n                skip_github: true,\n            },\n            \"1.0.0-gleam\",\n        )\n        .err(),\n        Some(Error::OutputFilesAlreadyExist {\n            file_names: vec![path.join(\"README.md\")]\n        })\n    );\n}\n\n#[test]\nfn skip_existing_git_files_when_skip_git_is_true() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    crate::fs::mkdir(&path).unwrap();\n    let file_path = PathBuf::from(&path).join(\".gitignore\");\n\n    let _ = std::fs::File::create(file_path).unwrap();\n\n    let creator = super::Creator::new(\n        super::NewOptions {\n            project_root: path.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: true,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n    )\n    .unwrap();\n\n    creator.run().unwrap();\n\n    assert!(path.join(\"README.md\").exists());\n    assert!(path.join(\".gitignore\").exists());\n}\n\n#[test]\nfn suggested_project_name_updates_directory() {\n    let tmp = tempfile::tempdir().unwrap();\n    let base = Utf8PathBuf::from_path_buf(tmp.path().to_path_buf()).expect(\"Non Utf8 Path\");\n    let original_root = base.join(\"gleam_testproject\");\n\n    let creator = super::Creator::new_with_confirmation(\n        super::NewOptions {\n            project_root: original_root.to_string(),\n            template: super::Template::Erlang,\n            name: None,\n            skip_git: true,\n            skip_github: true,\n        },\n        \"1.0.0-gleam\",\n        |_| Ok::<bool, Error>(true),\n    )\n    .unwrap();\n\n    let expected_root = base.join(\"testproject\");\n    assert_eq!(creator.project_name, \"testproject\");\n    assert_eq!(\n        Utf8Path::new(&creator.options.project_root),\n        expected_root.as_path()\n    );\n\n    creator.run().unwrap();\n\n    assert!(expected_root.exists());\n    assert!(!original_root.exists());\n}\n\n#[test]\nfn validate_name_format() {\n    assert!(crate::new::validate_name(\"project\").is_ok());\n    assert!(crate::new::validate_name(\"project_name\").is_ok());\n    assert!(crate::new::validate_name(\"project2\").is_ok());\n\n    let invalid = [\"Project\", \"PROJECT\", \"Project_Name\"];\n    for name in invalid {\n        assert!(matches!(\n            crate::new::validate_name(name),\n            Err(Error::InvalidProjectName {\n                name: _,\n                reason: crate::new::InvalidProjectNameReason::FormatNotLowercase\n            })\n        ));\n    }\n\n    let invalid = [\"0project\", \"_project\", \"project-name\"];\n    for name in invalid {\n        assert!(matches!(\n            crate::new::validate_name(name),\n            Err(Error::InvalidProjectName {\n                name: _,\n                reason: crate::new::InvalidProjectNameReason::Format\n            })\n        ));\n    }\n}\n\n#[test]\nfn suggest_valid_names() {\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"gleam_\",\n            &crate::new::InvalidProjectNameReason::GleamPrefix\n        ),\n        None\n    );\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"gleam_project\",\n            &crate::new::InvalidProjectNameReason::GleamPrefix\n        ),\n        Some(\"project\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"try\",\n            &crate::new::InvalidProjectNameReason::ErlangReservedWord\n        ),\n        Some(\"try_app\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"erl_eval\",\n            &crate::new::InvalidProjectNameReason::ErlangStandardLibraryModule\n        ),\n        Some(\"erl_eval_app\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"assert\",\n            &crate::new::InvalidProjectNameReason::GleamReservedWord\n        ),\n        Some(\"assert_app\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"gleam\",\n            &crate::new::InvalidProjectNameReason::GleamReservedModule\n        ),\n        Some(\"app_gleam\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"Project_Name\",\n            &crate::new::InvalidProjectNameReason::FormatNotLowercase\n        ),\n        Some(\"project_name\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"Pr0ject-n4me!\",\n            &crate::new::InvalidProjectNameReason::Format\n        ),\n        Some(\"pr0ject_n4me_\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"Pr0ject--n4me!\",\n            &crate::new::InvalidProjectNameReason::Format\n        ),\n        Some(\"pr0ject_n4me_\".to_string())\n    );\n\n    assert_eq!(\n        crate::new::suggest_valid_name(\n            \"_pr0ject-name\",\n            &crate::new::InvalidProjectNameReason::Format\n        ),\n        None\n    );\n}\n"
  },
  {
    "path": "compiler-cli/src/new.rs",
    "content": "use camino::{Utf8Path, Utf8PathBuf};\nuse clap::ValueEnum;\nuse gleam_core::{\n    Result, erlang, error,\n    error::{Error, FileIoAction, FileKind, InvalidProjectNameReason},\n    parse,\n};\nuse serde::{Deserialize, Serialize};\nuse std::fs::File;\nuse std::{env, io::Write};\nuse strum::{Display, EnumIter, EnumString, IntoEnumIterator, VariantNames};\n\n#[cfg(test)]\nmod tests;\n\nuse crate::{NewOptions, fs::get_current_directory};\n\nconst GLEAM_STDLIB_REQUIREMENT: &str = \">= 0.44.0 and < 2.0.0\";\nconst GLEEUNIT_REQUIREMENT: &str = \">= 1.0.0 and < 2.0.0\";\nconst ERLANG_OTP_VERSION: &str = \"28\";\nconst REBAR3_VERSION: &str = \"3\";\nconst ELIXIR_VERSION: &str = \"1\";\n\n#[derive(\n    Debug, Serialize, Deserialize, Display, EnumString, VariantNames, ValueEnum, Clone, Copy,\n)]\n#[strum(serialize_all = \"lowercase\")]\n#[clap(rename_all = \"lower\")]\npub enum Template {\n    #[clap(skip)]\n    Lib,\n    Erlang,\n    JavaScript,\n}\n\n#[derive(Debug)]\npub struct Creator {\n    root: Utf8PathBuf,\n    src: Utf8PathBuf,\n    test: Utf8PathBuf,\n    github: Utf8PathBuf,\n    workflows: Utf8PathBuf,\n    gleam_version: &'static str,\n    options: NewOptions,\n    project_name: String,\n}\n\n#[derive(EnumIter, PartialEq, Eq, Debug, Hash)]\nenum FileToCreate {\n    Readme,\n    Gitignore,\n    SrcModule,\n    TestModule,\n    GleamToml,\n    GithubCi,\n}\n\nimpl FileToCreate {\n    pub fn location(&self, creator: &Creator) -> Utf8PathBuf {\n        let project_name = &creator.project_name;\n\n        match self {\n            Self::Readme => creator.root.join(Utf8PathBuf::from(\"README.md\")),\n            Self::Gitignore => creator.root.join(Utf8PathBuf::from(\".gitignore\")),\n            Self::SrcModule => creator\n                .src\n                .join(Utf8PathBuf::from(format!(\"{project_name}.gleam\"))),\n            Self::TestModule => creator\n                .test\n                .join(Utf8PathBuf::from(format!(\"{project_name}_test.gleam\"))),\n            Self::GleamToml => creator.root.join(Utf8PathBuf::from(\"gleam.toml\")),\n            Self::GithubCi => creator.workflows.join(Utf8PathBuf::from(\"test.yml\")),\n        }\n    }\n\n    pub fn contents(&self, creator: &Creator) -> Option<String> {\n        let project_name = &creator.project_name;\n        let skip_git = creator.options.skip_git;\n        let skip_github = creator.options.skip_github;\n        let gleam_version = creator.gleam_version;\n        let target = match creator.options.template {\n            Template::JavaScript => \"target = \\\"javascript\\\"\\n\",\n            Template::Lib | Template::Erlang => \"\",\n        };\n\n        match self {\n            Self::Readme => Some(default_readme(project_name)),\n            Self::Gitignore if !skip_git => Some(\n                \"*.beam\n*.ez\n/build\nerl_crash.dump\n\"\n                .into(),\n            ),\n\n            Self::SrcModule => Some(format!(\n                r#\"import gleam/io\n\npub fn main() -> Nil {{\n  io.println(\"Hello from {project_name}!\")\n}}\n\"#,\n            )),\n\n            Self::TestModule => Some(\n                r#\"import gleeunit\n\npub fn main() -> Nil {\n  gleeunit.main()\n}\n\n// gleeunit test functions end in `_test`\npub fn hello_world_test() {\n  let name = \"Joe\"\n  let greeting = \"Hello, \" <> name <> \"!\"\n\n  assert greeting == \"Hello, Joe!\"\n}\n\"#\n                .into(),\n            ),\n\n            Self::GleamToml => Some(format!(\n                r#\"name = \"{project_name}\"\nversion = \"1.0.0\"\n{target}\n# Fill out these fields if you intend to generate HTML documentation or publish\n# your project to the Hex package manager.\n#\n# description = \"\"\n# licences = [\"Apache-2.0\"]\n# repository = {{ type = \"github\", user = \"\", repo = \"\" }}\n# links = [{{ title = \"Website\", href = \"\" }}]\n#\n# For a full reference of all the available options, you can have a look at\n# https://gleam.run/writing-gleam/gleam-toml/.\n\n[dependencies]\ngleam_stdlib = \"{GLEAM_STDLIB_REQUIREMENT}\"\n\n[dev_dependencies]\ngleeunit = \"{GLEEUNIT_REQUIREMENT}\"\n\"#,\n            )),\n\n            Self::GithubCi if !skip_git && !skip_github => Some(format!(\n                r#\"name: test\n\non:\n  push:\n    branches:\n      - master\n      - main\n  pull_request:\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: erlef/setup-beam@v1\n        with:\n          otp-version: \"{ERLANG_OTP_VERSION}\"\n          gleam-version: \"{gleam_version}\"\n          rebar3-version: \"{REBAR3_VERSION}\"\n          # elixir-version: \"{ELIXIR_VERSION}\"\n      - run: gleam deps download\n      - run: gleam test\n      - run: gleam format --check src test\n\"#,\n            )),\n            Self::GithubCi | Self::Gitignore => None,\n        }\n    }\n}\n\npub fn default_readme(project_name: &str) -> String {\n    format!(\n        r#\"# {project_name}\n\n[![Package Version](https://img.shields.io/hexpm/v/{project_name})](https://hex.pm/packages/{project_name})\n[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/{project_name}/)\n\n```sh\ngleam add {project_name}@1\n```\n```gleam\nimport {project_name}\n\npub fn main() -> Nil {{\n  // TODO: An example of the project in use\n}}\n```\n\nFurther documentation can be found at <https://hexdocs.pm/{project_name}>.\n\n## Development\n\n```sh\ngleam run   # Run the project\ngleam test  # Run the tests\n```\n\"#,\n    )\n}\n\nimpl Creator {\n    fn new(options: NewOptions, gleam_version: &'static str) -> Result<Self, Error> {\n        Self::new_with_confirmation(options, gleam_version, crate::cli::confirm)\n    }\n\n    fn new_with_confirmation(\n        mut options: NewOptions,\n        gleam_version: &'static str,\n        confirm: impl Fn(&str) -> Result<bool, Error>,\n    ) -> Result<Self, Error> {\n        let name =\n            get_valid_project_name(options.name.as_deref(), &options.project_root, &confirm)?;\n        options.project_root = name.project_root(&options.project_root);\n\n        let root = get_current_directory()?.join(&options.project_root);\n        let src = root.join(\"src\");\n        let test = root.join(\"test\");\n        let github = root.join(\".github\");\n        let workflows = github.join(\"workflows\");\n        let me = Self {\n            root: root.clone(),\n            src,\n            test,\n            github,\n            workflows,\n            gleam_version,\n            options,\n            project_name: name.decided().to_string(),\n        };\n\n        validate_root_folder(&me)?;\n\n        Ok(me)\n    }\n\n    fn run(&self) -> Result<()> {\n        crate::fs::mkdir(&self.root)?;\n        crate::fs::mkdir(&self.src)?;\n        crate::fs::mkdir(&self.test)?;\n\n        if !self.options.skip_git && !self.options.skip_github {\n            crate::fs::mkdir(&self.github)?;\n            crate::fs::mkdir(&self.workflows)?;\n        }\n\n        if !self.options.skip_git {\n            crate::fs::git_init(&self.root)?;\n        }\n\n        match self.options.template {\n            Template::Lib | Template::Erlang | Template::JavaScript => {\n                for file in FileToCreate::iter() {\n                    let path = file.location(self);\n                    if let Some(contents) = file.contents(self) {\n                        write(path, &contents)?;\n                    }\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\npub fn create(options: NewOptions, version: &'static str) -> Result<()> {\n    let creator = Creator::new(options.clone(), version)?;\n\n    creator.run()?;\n\n    let cd_folder = if options.project_root == \".\" {\n        \"\".into()\n    } else {\n        format!(\"\\tcd {}\\n\", creator.options.project_root)\n    };\n\n    println!(\n        \"Your Gleam project {} has been successfully created.\nThe project can be compiled and tested by running these commands:\n\n{}\\tgleam test\n\",\n        creator.project_name, cd_folder,\n    );\n    Ok(())\n}\n\nfn write(path: Utf8PathBuf, contents: &str) -> Result<()> {\n    let mut f = File::create(&path).map_err(|err| Error::FileIo {\n        kind: FileKind::File,\n        path: path.clone(),\n        action: FileIoAction::Create,\n        err: Some(err.to_string()),\n    })?;\n\n    f.write_all(contents.as_bytes())\n        .map_err(|err| Error::FileIo {\n            kind: FileKind::File,\n            path,\n            action: FileIoAction::WriteTo,\n            err: Some(err.to_string()),\n        })?;\n    Ok(())\n}\n\nfn validate_root_folder(creator: &Creator) -> Result<(), Error> {\n    let mut duplicate_files: Vec<Utf8PathBuf> = Vec::new();\n\n    for t in FileToCreate::iter() {\n        let full_path = t.location(creator);\n        let content = t.contents(creator);\n        if full_path.exists() && content.is_some() {\n            duplicate_files.push(full_path);\n        }\n    }\n\n    if !duplicate_files.is_empty() {\n        return Err(Error::OutputFilesAlreadyExist {\n            file_names: duplicate_files,\n        });\n    }\n\n    Ok(())\n}\n\nfn validate_name(name: &str) -> Result<(), Error> {\n    if name.starts_with(\"gleam_\") {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::GleamPrefix,\n        })\n    } else if erlang::is_erlang_reserved_word(name) {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::ErlangReservedWord,\n        })\n    } else if erlang::is_erlang_standard_library_module(name) {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::ErlangStandardLibraryModule,\n        })\n    } else if parse::lexer::str_to_keyword(name).is_some() {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::GleamReservedWord,\n        })\n    } else if name == \"gleam\" {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::GleamReservedModule,\n        })\n    } else if regex::Regex::new(\"^[a-z][a-z0-9_]*$\")\n        .expect(\"failed regex to match valid name format\")\n        .is_match(name)\n    {\n        Ok(())\n    } else if regex::Regex::new(\"^[a-zA-Z][a-zA-Z0-9_]*$\")\n        .expect(\"failed regex to match valid but non-lowercase name format\")\n        .is_match(name)\n    {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::FormatNotLowercase,\n        })\n    } else {\n        Err(Error::InvalidProjectName {\n            name: name.to_string(),\n            reason: InvalidProjectNameReason::Format,\n        })\n    }\n}\n\nfn suggest_valid_name(invalid_name: &str, reason: &InvalidProjectNameReason) -> Option<String> {\n    match reason {\n        InvalidProjectNameReason::GleamPrefix => match invalid_name.strip_prefix(\"gleam_\") {\n            Some(stripped) if invalid_name != \"gleam_\" => {\n                let suggestion = stripped.to_string();\n                match validate_name(&suggestion) {\n                    Ok(_) => Some(suggestion),\n                    Err(_) => None,\n                }\n            }\n            _ => None,\n        },\n        InvalidProjectNameReason::ErlangReservedWord => Some(format!(\"{invalid_name}_app\")),\n        InvalidProjectNameReason::ErlangStandardLibraryModule => {\n            Some(format!(\"{invalid_name}_app\"))\n        }\n        InvalidProjectNameReason::GleamReservedWord => Some(format!(\"{invalid_name}_app\")),\n        InvalidProjectNameReason::GleamReservedModule => {\n            if invalid_name == \"gleam\" {\n                Some(\"app_gleam\".into())\n            } else {\n                Some(format!(\"{invalid_name}_app\"))\n            }\n        }\n        InvalidProjectNameReason::FormatNotLowercase => Some(invalid_name.to_lowercase()),\n        InvalidProjectNameReason::Format => {\n            let suggestion = regex::Regex::new(r\"[^a-z0-9]\")\n                .expect(\"failed regex to match any non-lowercase and non-alphanumeric characters\")\n                .replace_all(&invalid_name.to_lowercase(), \"_\")\n                .to_string();\n\n            let suggestion = regex::Regex::new(r\"_+\")\n                .expect(\"failed regex to match consecutive underscores\")\n                .replace_all(&suggestion, \"_\")\n                .to_string();\n\n            match validate_name(&suggestion) {\n                Ok(_) => Some(suggestion),\n                Err(_) => None,\n            }\n        }\n    }\n}\n\nfn get_valid_project_name(\n    provided_name: Option<&str>,\n    project_root: &str,\n    confirm: impl Fn(&str) -> Result<bool, Error>,\n) -> Result<ProjectName, Error> {\n    let initial_name = match provided_name {\n        Some(name) => name.trim().to_string(),\n        None => get_foldername(project_root)?.trim().to_string(),\n    };\n\n    let invalid_reason = match validate_name(&initial_name) {\n        Ok(_) => {\n            return Ok(match provided_name {\n                Some(_) => ProjectName::Provided {\n                    decided: initial_name,\n                },\n                None => ProjectName::Derived {\n                    folder: initial_name.clone(),\n                    decided: initial_name,\n                },\n            });\n        }\n        Err(Error::InvalidProjectName { reason, .. }) => reason,\n        Err(error) => return Err(error),\n    };\n\n    let suggested_name = match suggest_valid_name(&initial_name, &invalid_reason) {\n        Some(suggested_name) => suggested_name,\n        None => {\n            return Err(Error::InvalidProjectName {\n                name: initial_name,\n                reason: invalid_reason,\n            });\n        }\n    };\n\n    let prompt_for_suggested_name = error::format_invalid_project_name_error(\n        &initial_name,\n        &invalid_reason,\n        &Some(suggested_name.clone()),\n    );\n\n    if confirm(&prompt_for_suggested_name)? {\n        return Ok(match provided_name {\n            Some(_) => ProjectName::Provided {\n                decided: suggested_name,\n            },\n            None => ProjectName::Derived {\n                folder: initial_name,\n                decided: suggested_name,\n            },\n        });\n    }\n\n    Err(Error::InvalidProjectName {\n        name: initial_name,\n        reason: invalid_reason,\n    })\n}\n\nfn get_foldername(path: &str) -> Result<String, Error> {\n    match path {\n        \".\" => env::current_dir()\n            .expect(\"invalid folder\")\n            .file_name()\n            .and_then(|x| x.to_str())\n            .map(ToString::to_string)\n            .ok_or(Error::UnableToFindProjectRoot {\n                path: path.to_string(),\n            }),\n        _ => Utf8Path::new(path)\n            .file_name()\n            .map(ToString::to_string)\n            .ok_or(Error::UnableToFindProjectRoot {\n                path: path.to_string(),\n            }),\n    }\n}\n\n#[derive(Debug, Clone)]\nenum ProjectName {\n    Provided { decided: String },\n    Derived { folder: String, decided: String },\n}\n\nimpl ProjectName {\n    fn decided(&self) -> &str {\n        match self {\n            Self::Provided { decided } | Self::Derived { decided, .. } => decided,\n        }\n    }\n\n    fn project_root(&self, current_root: &str) -> String {\n        match self {\n            Self::Provided { .. } => current_root.to_string(),\n            Self::Derived { folder, decided } => {\n                if current_root == \".\" || folder == decided {\n                    return current_root.to_string();\n                }\n\n                // If the name was invalid and generated suggestion was accepted,\n                // align the directory path with the new name.\n                let original_root = Utf8Path::new(current_root);\n                let new_root = match original_root.parent() {\n                    Some(parent) if !parent.as_str().is_empty() => parent.join(decided),\n                    Some(_) | None => Utf8PathBuf::from(decided),\n                };\n                new_root.to_string()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/owner.rs",
    "content": "use crate::{cli, http::HttpClient};\nuse gleam_core::{Result, hex};\n\npub fn transfer(package: String, new_owner_username_or_email: String) -> Result<()> {\n    println!(\n        \"Transferring ownership of this package will remove all current owners and make\n{new_owner_username_or_email} its new owner.\nDo you wish to transfer ownership of `{package}` to {new_owner_username_or_email}?\",\n    );\n\n    let should_transfer_ownership = cli::confirm_with_text(&package)?;\n    if !should_transfer_ownership {\n        println!(\"Not transferring ownership.\");\n        return Ok(());\n    }\n\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let http = HttpClient::new();\n    let hex_config = hexpm::Config::new();\n    let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone())\n        .get_or_create_api_credentials()?;\n\n    cli::print_transferring_ownership();\n    runtime.block_on(hex::transfer_owner(\n        &crate::hex::write_credentials(&credentials)?,\n        package,\n        new_owner_username_or_email,\n        &hex_config,\n        &HttpClient::new(),\n    ))?;\n    cli::print_transferred_ownership();\n\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/panic.rs",
    "content": "#![allow(clippy::unwrap_used)]\nuse std::panic::PanicHookInfo;\n\npub fn add_handler() {\n    std::panic::set_hook(Box::new(move |info: &PanicHookInfo<'_>| {\n        print_compiler_bug_message(info)\n    }));\n}\n\nfn print_compiler_bug_message(info: &PanicHookInfo<'_>) {\n    let message = match (\n        info.payload().downcast_ref::<&str>(),\n        info.payload().downcast_ref::<String>(),\n    ) {\n        (Some(s), _) => (*s).to_string(),\n        (_, Some(s)) => s.to_string(),\n        (None, None) => \"unknown error\".into(),\n    };\n    let location = match info.location() {\n        None => \"\".into(),\n        Some(location) => format!(\"{}:{}\\n\\t\", location.file(), location.line()),\n    };\n\n    let buffer_writer = crate::cli::stderr_buffer_writer();\n    let mut buffer = buffer_writer.buffer();\n    use std::io::Write;\n    use termcolor::{Color, ColorSpec, WriteColor};\n    buffer\n        .set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Red)))\n        .unwrap();\n    write!(buffer, \"error\").unwrap();\n    buffer.set_color(ColorSpec::new().set_bold(true)).unwrap();\n    write!(buffer, \": Fatal compiler bug!\\n\\n\").unwrap();\n    buffer.set_color(&ColorSpec::new()).unwrap();\n    writeln!(\n        buffer,\n        \"This is a bug in the Gleam compiler, sorry!\n\nPlease report this crash to https://github.com/gleam-lang/gleam/issues/new\nand include this error message with your report.\n\nPanic: {location}{message}\nGleam version: {version}\nOperating system: {os}\n\nIf you can also share your code and say what file you were editing or any\nsteps to reproduce the crash that would be a great help.\n\nYou may also want to try again with the `GLEAM_LOG=trace` environment\nvariable set.\n\",\n        location = location,\n        message = message,\n        version = env!(\"CARGO_PKG_VERSION\"),\n        os = std::env::consts::OS,\n    )\n    .unwrap();\n    buffer_writer.print(&buffer).unwrap();\n}\n"
  },
  {
    "path": "compiler-cli/src/publish.rs",
    "content": "use camino::{Utf8Path, Utf8PathBuf};\nuse ecow::EcoString;\nuse flate2::{Compression, write::GzEncoder};\nuse gleam_core::{\n    Error, Result,\n    analyse::TargetSupport,\n    ast::{CallArg, Statement, TypedExpr, TypedFunction},\n    build::{Codegen, Compile, Mode, Options, Package, Target},\n    config::{GleamVersion, PackageConfig, SpdxLicense},\n    docs::{Dependency, DependencyKind, DocContext},\n    error::{InvalidReadmeReason, SmallVersion, wrap},\n    hex,\n    manifest::ManifestPackageSource,\n    paths::{self, ProjectPaths},\n    requirement::Requirement,\n    type_,\n};\nuse hexpm::version::{Range, Version};\nuse itertools::Itertools;\nuse sha2::Digest;\nuse std::{collections::HashMap, io::Write, path::PathBuf};\n\nuse crate::{build, cli, docs, fs, http::HttpClient, new::default_readme};\n\nconst CORE_TEAM_PUBLISH_PASSWORD: &str = \"Trans rights are human rights\";\n\npub fn command(paths: &ProjectPaths, replace: bool, i_am_sure: bool) -> Result<()> {\n    let mut config = crate::config::root_config(paths)?;\n\n    let should_publish = check_for_gleam_prefix(&config)?\n        && check_for_version_zero(&config)?\n        && check_repo_url(&config, i_am_sure)?;\n\n    check_for_invalid_readme(&config, paths)?;\n\n    if !should_publish {\n        println!(\"Not publishing.\");\n        return Ok(());\n    }\n\n    let Tarball {\n        mut compile_result,\n        cached_modules,\n        data: package_tarball,\n        src_files_added,\n        generated_files_added,\n        dependencies,\n    } = do_build_hex_tarball(paths, &mut config)?;\n\n    check_for_name_squatting(&compile_result)?;\n    check_for_multiple_top_level_modules(&compile_result, i_am_sure)?;\n    check_for_default_main(&compile_result)?;\n\n    // Build HTML documentation\n    let docs_tarball = fs::create_tar_archive(docs::build_documentation(\n        paths,\n        &config,\n        dependencies,\n        &mut compile_result,\n        DocContext::HexPublish,\n        &cached_modules,\n    )?)?;\n\n    // Ask user if this is correct\n    if !generated_files_added.is_empty() {\n        println!(\"\\nGenerated files:\");\n        for file in generated_files_added.iter().sorted() {\n            println!(\"  - {}\", file.0);\n        }\n    }\n    println!(\"\\nSource files:\");\n    for file in src_files_added.iter().sorted() {\n        println!(\"  - {file}\");\n    }\n    println!(\"\\nName: {}\", config.name);\n    println!(\"Version: {}\", config.version);\n\n    let should_publish = i_am_sure || cli::confirm(\"\\nDo you wish to publish this package?\")?;\n    if !should_publish {\n        println!(\"Not publishing.\");\n        return Ok(());\n    }\n\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let http = HttpClient::new();\n    let hex_config = hexpm::Config::new();\n    let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone())\n        .get_or_create_api_credentials()?;\n    let credentials = crate::hex::write_credentials(&credentials)?;\n    cli::print_publishing(&config.name, &config.version);\n\n    runtime.block_on(hex::publish_package(\n        package_tarball,\n        config.version.to_string(),\n        &config.name,\n        &credentials,\n        &hex_config,\n        replace,\n        &http,\n    ))?;\n\n    cli::print_publishing_documentation();\n    runtime.block_on(hex::publish_documentation(\n        &config.name,\n        &config.version,\n        docs_tarball,\n        &credentials,\n        &hex_config,\n        &http,\n    ))?;\n    cli::print_published(\"package and documentation\");\n    println!(\n        \"\\nView your package at https://hex.pm/packages/{}\",\n        &config.name\n    );\n\n    // Prompt the user to make a git tag if they have not.\n    let has_repo = config.repository.is_some();\n    let git = PathBuf::from(\".git\");\n    let tag_name = config.tag_for_version(&config.version);\n    let git_tag = git.join(\"refs\").join(\"tags\").join(&tag_name);\n    if has_repo && git.exists() && !git_tag.exists() {\n        println!(\n            \"\nPlease push a git tag for this release so source code links in the\nHTML documentation will work:\n\n    git tag {tag_name}\n    git push origin {tag_name}\n\"\n        )\n    }\n    Ok(())\n}\n\nfn check_for_invalid_readme(config: &PackageConfig, paths: &ProjectPaths) -> Result<(), Error> {\n    let normalise = |string: String| {\n        string\n            .trim()\n            .replace(\"\\r\\n\", \"\")\n            .replace(\"\\n\", \"\")\n            .replace(\"\\t\", \"\")\n            .replace(\" \", \"\")\n    };\n\n    let project_readme = match fs::read(paths.readme()) {\n        Err(Error::FileIo {\n            err: Some(message), ..\n        }) if message.contains(\"No such file or directory\") => {\n            return Err(Error::CannotPublishWithInvalidReadme {\n                reason: InvalidReadmeReason::Missing,\n            });\n        }\n        Err(error) => return Err(error),\n        Ok(project_readme) => project_readme,\n    };\n\n    let normalised_project_readme = normalise(project_readme);\n    if normalised_project_readme.is_empty() {\n        return Err(Error::CannotPublishWithInvalidReadme {\n            reason: InvalidReadmeReason::Empty,\n        });\n    }\n\n    let default_readme = default_readme(config.name.as_str());\n    if normalised_project_readme == normalise(default_readme) {\n        return Err(Error::CannotPublishWithInvalidReadme {\n            reason: InvalidReadmeReason::Default,\n        });\n    }\n\n    Ok(())\n}\n\nfn check_for_name_squatting(package: &Package) -> Result<(), Error> {\n    if package.modules.len() > 1 {\n        return Ok(());\n    }\n\n    let Some(module) = package.modules.first() else {\n        return Err(Error::HexPackageSquatting);\n    };\n\n    if module.dependencies.len() > 1 {\n        return Ok(());\n    }\n\n    if module.ast.definitions_len() > 2 {\n        return Ok(());\n    }\n\n    let Some(main) = module\n        .ast\n        .definitions\n        .functions\n        .iter()\n        .find_map(|function| function.main_function())\n    else {\n        return Ok(());\n    };\n\n    if let Some(first) = &main.body.first()\n        && first.is_println()\n    {\n        return Err(Error::HexPackageSquatting);\n    }\n\n    Ok(())\n}\n\n/// Checks if publishing packages contain default main functions.\n/// Main functions with documentation are considered intentional and allowed.\nfn check_for_default_main(package: &Package) -> Result<(), Error> {\n    let package_name = &package.config.name;\n\n    let has_default_main = package\n        .modules\n        .iter()\n        .flat_map(|module| module.ast.definitions.functions.iter())\n        .filter_map(|function| function.main_function())\n        .any(|main| main.documentation.is_none() && is_default_main(main, package_name));\n\n    if has_default_main {\n        return Err(Error::CannotPublishWithDefaultMain {\n            package_name: package_name.clone(),\n        });\n    }\n\n    Ok(())\n}\n\nfn is_default_main(main: &TypedFunction, package_name: &EcoString) -> bool {\n    if main.body.len() != 1 {\n        return false;\n    }\n\n    let Some(Statement::Expression(expression)) = main.body.first() else {\n        return false;\n    };\n\n    if !expression.is_println() {\n        return false;\n    }\n\n    match expression {\n        TypedExpr::Call { arguments, .. } => {\n            if arguments.len() != 1 {\n                return false;\n            }\n\n            match arguments.first() {\n                Some(CallArg {\n                    value: TypedExpr::String { value, .. },\n                    ..\n                }) => {\n                    let default_argument = format!(\"Hello from {}!\", &package_name);\n                    value == &default_argument\n                }\n                _ => false,\n            }\n        }\n        _ => false,\n    }\n}\n\nfn check_for_multiple_top_level_modules(package: &Package, i_am_sure: bool) -> Result<(), Error> {\n    // Collect top-level module names\n    let mut top_level_module_names = package\n        .modules\n        .iter()\n        .filter_map(|module| {\n            // Top-level modules are those that don't contain any path separators\n            if module.name.contains('/') {\n                None\n            } else {\n                Some(module.name.clone())\n            }\n        })\n        .collect::<Vec<_>>();\n\n    // Remove duplicates\n    top_level_module_names.sort_unstable();\n    top_level_module_names.dedup();\n\n    // If more than one top-level module name is found, prompt for confirmation\n    if top_level_module_names.len() > 1 {\n        let text = wrap(&format!(\n            \"Your package defines multiple top-level modules: {}.\n\nDefining multiple top-level modules can lead to namespace pollution \\\nand potential conflicts for consumers.\n\nTo fix this, move all your modules under a single top-level module of your choice.\n\nFor example:\n  src/{1}.gleam\n  src/{1}/module1.gleam\n  src/{1}/module2.gleam\",\n            top_level_module_names.join(\", \"),\n            package.config.name\n        ));\n        println!(\"{text}\\n\");\n\n        let should_publish =\n            i_am_sure || cli::confirm(\"\\nDo you wish to continue publishing this package?\")?;\n        println!();\n\n        if !should_publish {\n            println!(\"Not publishing.\");\n            std::process::exit(0);\n        }\n    }\n\n    Ok(())\n}\n\nfn check_repo_url(config: &PackageConfig, i_am_sure: bool) -> Result<bool, Error> {\n    let Some(repo) = config.repository.as_ref() else {\n        return Ok(true);\n    };\n    let url = repo.url();\n\n    let runtime = tokio::runtime::Runtime::new().expect(\"Unable to start Tokio async runtime\");\n    let response = runtime.block_on(reqwest::get(&url)).map_err(Error::http)?;\n\n    if response.status().is_success() {\n        return Ok(true);\n    }\n\n    println!(\n        \"The repository configuration in your `gleam.toml` file does not appear to be\nvalid, {} returned status {}\",\n        &url,\n        response.status()\n    );\n    let should_publish = i_am_sure || cli::confirm(\"\\nDo you wish to continue?\")?;\n    println!();\n    Ok(should_publish)\n}\n\n/// Ask for confirmation if the package name if a v0.x.x version\nfn check_for_version_zero(config: &PackageConfig) -> Result<bool, Error> {\n    if config.version.major != 0 {\n        return Ok(true);\n    }\n\n    println!(\n        \"You are about to publish a release that is below version 1.0.0.\n\nSemantic versioning doesn't apply to version 0.x.x releases, so your\nusers will not be protected from breaking changes. This can result\nin a poor user experience where packages can break unexpectedly with\nupdates that would normally be safe.\n\nIf your package is not ready to be used in production it should not\nbe published.\n\\n\"\n    );\n    let should_publish = cli::confirm_with_text(\"I am not using semantic versioning\")?;\n    println!();\n    Ok(should_publish)\n}\n\n/// Ask for confirmation if the package name if `gleam_*`\nfn check_for_gleam_prefix(config: &PackageConfig) -> Result<bool, Error> {\n    if !config.name.starts_with(\"gleam_\") || config.name.starts_with(\"gleam_community_\") {\n        return Ok(true);\n    }\n\n    println!(\n        \"You are about to publish a package with a name that starts with\nthe prefix `gleam_`, which is preferred for packages maintained by the\nGleam core team.\n\nSecurity: do not assume the owner of a package from the name, always check\nthe maintainers listed on https://hex.pm/.\n\\n\",\n    );\n    let password = cli::ask_password(\"Please enter the core team password to continue\")?;\n    println!();\n    Ok(password == CORE_TEAM_PUBLISH_PASSWORD)\n}\n\nstruct Tarball {\n    compile_result: Package,\n    cached_modules: im::HashMap<EcoString, type_::ModuleInterface>,\n    data: Vec<u8>,\n    src_files_added: Vec<Utf8PathBuf>,\n    generated_files_added: Vec<(Utf8PathBuf, String)>,\n    dependencies: HashMap<EcoString, Dependency>,\n}\n\npub fn build_hex_tarball(paths: &ProjectPaths, config: &mut PackageConfig) -> Result<Vec<u8>> {\n    let Tarball { data, .. } = do_build_hex_tarball(paths, config)?;\n    Ok(data)\n}\n\nfn do_build_hex_tarball(paths: &ProjectPaths, config: &mut PackageConfig) -> Result<Tarball> {\n    let target = config.target;\n    check_config_for_publishing(config)?;\n\n    // Reset the build directory so we know the state of the project\n    fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, target))?;\n\n    let manifest = build::download_dependencies(paths, cli::Reporter::new())?;\n    let dependencies = manifest\n        .packages\n        .iter()\n        .map(|package| {\n            (\n                package.name.clone(),\n                Dependency {\n                    version: package.version.clone(),\n                    kind: match &package.source {\n                        ManifestPackageSource::Hex { .. } => DependencyKind::Hex,\n                        ManifestPackageSource::Git { .. } => DependencyKind::Git,\n                        ManifestPackageSource::Local { .. } => DependencyKind::Path,\n                    },\n                },\n            )\n        })\n        .collect();\n\n    // Build the project to check that it is valid\n    let built = build::main(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors: false,\n            mode: Mode::Prod,\n            target: Some(target),\n            codegen: Codegen::All,\n            compile: Compile::All,\n            no_print_progress: false,\n        },\n        manifest,\n    )?;\n\n    let minimum_required_version = built.minimum_required_version();\n    match &config.gleam_version {\n        // If the package has no explicit `gleam` version in its `gleam.toml`\n        // then we want to add the automatically inferred one so we know it's\n        // correct and folks getting the package from Hex won't have unpleasant\n        // surprises if the author forgot to manualy write it down.\n        None => {\n            // If we're automatically adding the minimum required version\n            // constraint we want it to at least be `>= 1.0.0`, even if the\n            // inferred lower bound could be lower.\n            let minimum_required_version =\n                std::cmp::max(minimum_required_version, Version::new(1, 0, 0));\n            let inferred_version_range = pubgrub::Range::higher_than(minimum_required_version);\n            config.gleam_version = Some(GleamVersion::from_pubgrub(inferred_version_range));\n        }\n        // Otherwise we need to check that the annotated version range is\n        // correct and includes the minimum required version.\n        Some(gleam_version) => {\n            if let Some(lowest_allowed_version) = gleam_version.lowest_version()\n                && lowest_allowed_version < minimum_required_version\n            {\n                return Err(Error::CannotPublishWrongVersion {\n                    minimum_required_version: SmallVersion::from_hexpm(minimum_required_version),\n                    wrongfully_allowed_version: SmallVersion::from_hexpm(lowest_allowed_version),\n                });\n            }\n        }\n    }\n\n    // If any of the modules in the package contain a todo or an echo then\n    // refuse to publish as the package is not yet finished.\n    let mut modules_containing_todo = vec![];\n    let mut modules_containing_echo = vec![];\n\n    for module in built.root_package.modules.iter() {\n        if module.ast.type_info.contains_todo() {\n            modules_containing_todo.push(module.name.clone());\n        } else if module.ast.type_info.contains_echo {\n            modules_containing_echo.push(module.name.clone());\n        }\n    }\n\n    if !modules_containing_todo.is_empty() {\n        return Err(Error::CannotPublishTodo {\n            unfinished: modules_containing_todo,\n        });\n    }\n\n    if !modules_containing_echo.is_empty() {\n        return Err(Error::CannotPublishEcho {\n            unfinished: modules_containing_echo,\n        });\n    }\n\n    // empty_modules is a list of modules that do not export any values or types.\n    // We do not allow publishing packages that contain empty modules.\n    let empty_modules: Vec<_> = built\n        .root_package\n        .modules\n        .iter()\n        .filter(|module| {\n            built\n                .module_interfaces\n                .get(&module.name)\n                .map(|interface| {\n                    // Check if the module exports any values or types\n                    interface.values.is_empty() && interface.types.is_empty()\n                })\n                .unwrap_or(false)\n        })\n        .map(|module| module.name.clone())\n        .collect();\n\n    if !empty_modules.is_empty() {\n        return Err(Error::CannotPublishEmptyModules {\n            unfinished: empty_modules,\n        });\n    }\n\n    // TODO: If any of the modules in the package contain a leaked internal type then\n    // refuse to publish as the package is not yet finished.\n    // We need to move aliases in to the type system first.\n    // context: https://discord.com/channels/768594524158427167/768594524158427170/1227250677734969386\n\n    // Collect all the files we want to include in the tarball\n    let generated_files = match target {\n        Target::Erlang => generated_erlang_files(paths, &built.root_package)?,\n        Target::JavaScript => vec![],\n    };\n    let src_files = project_files(Utf8Path::new(\"\"))?;\n    let contents_tar_gz = contents_tarball(&src_files, &generated_files)?;\n    let version = \"3\";\n    let metadata = metadata_config(&built.root_package.config, &src_files, &generated_files)?;\n\n    // Calculate checksum\n    let mut hasher = sha2::Sha256::new();\n    hasher.update(version.as_bytes());\n    hasher.update(metadata.as_bytes());\n    hasher.update(contents_tar_gz.as_slice());\n    let checksum = base16::encode_upper(&hasher.finalize());\n    tracing::info!(checksum = %checksum, \"Generated Hex package inner checksum\");\n\n    // Build tarball\n    let mut tarball = Vec::new();\n    {\n        let mut tarball = tar::Builder::new(&mut tarball);\n        add_to_tar(&mut tarball, \"VERSION\", version.as_bytes())?;\n        add_to_tar(&mut tarball, \"metadata.config\", metadata.as_bytes())?;\n        add_to_tar(&mut tarball, \"contents.tar.gz\", contents_tar_gz.as_slice())?;\n        add_to_tar(&mut tarball, \"CHECKSUM\", checksum.as_bytes())?;\n        tarball.finish().map_err(Error::finish_tar)?;\n    }\n    tracing::info!(\"Generated package Hex release tarball\");\n    Ok(Tarball {\n        compile_result: built.root_package,\n        cached_modules: built.module_interfaces,\n        data: tarball,\n        src_files_added: src_files,\n        generated_files_added: generated_files,\n        dependencies,\n    })\n}\n\nfn check_config_for_publishing(config: &PackageConfig) -> Result<()> {\n    // These fields are required to publish a Hex package. Hex will reject\n    // packages without them.\n    if config.description.is_empty() || config.licences.is_empty() {\n        Err(Error::MissingHexPublishFields {\n            description_missing: config.description.is_empty(),\n            licence_missing: config.licences.is_empty(),\n        })\n    } else {\n        Ok(())\n    }\n}\n\nfn metadata_config<'a>(\n    config: &'a PackageConfig,\n    source_files: &[Utf8PathBuf],\n    generated_files: &[(Utf8PathBuf, String)],\n) -> Result<String> {\n    let repo_url = http::Uri::try_from(\n        config\n            .repository\n            .as_ref()\n            .map(|r| r.url())\n            .unwrap_or_default(),\n    )\n    .ok();\n    let requirements: Result<Vec<ReleaseRequirement<'a>>> = config\n        .dependencies\n        .iter()\n        .map(|(name, requirement)| match requirement {\n            Requirement::Hex { version } => Ok(ReleaseRequirement {\n                name,\n                requirement: version,\n            }),\n            _ => Err(Error::PublishNonHexDependencies {\n                package: name.to_string(),\n            }),\n        })\n        .collect();\n    let metadata = ReleaseMetadata {\n        name: &config.name,\n        version: &config.version,\n        description: &config.description,\n        source_files,\n        generated_files,\n        licenses: &config.licences,\n        links: config\n            .links\n            .iter()\n            .map(|l| (l.title.as_str(), l.href.clone()))\n            .chain(repo_url.into_iter().map(|u| (\"Repository\", u)))\n            .collect(),\n        requirements: requirements?,\n        build_tools: vec![\"gleam\"],\n    }\n    .as_erlang();\n    tracing::info!(contents = ?metadata, \"Generated Hex metadata.config\");\n    Ok(metadata)\n}\n\nfn contents_tarball(\n    files: &[Utf8PathBuf],\n    data_files: &[(Utf8PathBuf, String)],\n) -> Result<Vec<u8>, Error> {\n    let mut contents_tar_gz = Vec::new();\n    {\n        let mut tarball =\n            tar::Builder::new(GzEncoder::new(&mut contents_tar_gz, Compression::default()));\n        for path in files {\n            add_path_to_tar(&mut tarball, path)?;\n        }\n        for (path, contents) in data_files {\n            add_to_tar(&mut tarball, path, contents.as_bytes())?;\n        }\n        tarball.finish().map_err(Error::finish_tar)?;\n    }\n    tracing::info!(\"Generated contents.tar.gz\");\n    Ok(contents_tar_gz)\n}\n\nfn project_files(base_path: &Utf8Path) -> Result<Vec<Utf8PathBuf>> {\n    let src = base_path.join(Utf8Path::new(\"src\"));\n    let mut files: Vec<Utf8PathBuf> = fs::gleam_files(&src)\n        .chain(fs::native_files(&src))\n        .collect();\n    let private = base_path.join(Utf8Path::new(\"priv\"));\n    let mut private_files: Vec<Utf8PathBuf> = fs::private_files(&private).collect();\n    files.append(&mut private_files);\n    let mut add = |path| {\n        let path = base_path.join(path);\n        if path.exists() {\n            files.push(path);\n        }\n    };\n    add(\"README\");\n    add(\"README.md\");\n    add(\"README.txt\");\n    add(\"gleam.toml\");\n    add(\"LICENSE\");\n    add(\"LICENCE\");\n    add(\"LICENSE.md\");\n    add(\"LICENCE.md\");\n    add(\"LICENSE.txt\");\n    add(\"LICENCE.txt\");\n    add(\"NOTICE\");\n    add(\"NOTICE.md\");\n    add(\"NOTICE.txt\");\n    Ok(files)\n}\n\n// TODO: test\nfn generated_erlang_files(\n    paths: &ProjectPaths,\n    package: &Package,\n) -> Result<Vec<(Utf8PathBuf, String)>> {\n    let mut files = vec![];\n\n    let dir = paths.build_directory_for_package(Mode::Prod, Target::Erlang, &package.config.name);\n    let ebin = dir.join(\"ebin\");\n    let build = dir.join(paths::ARTEFACT_DIRECTORY_NAME);\n    let include = dir.join(\"include\");\n\n    let tar_src = Utf8Path::new(\"src\");\n    let tar_include = Utf8Path::new(\"include\");\n\n    // Erlang modules\n    for module in &package.modules {\n        // Do not publish test/ and dev/ code\n        if !module.origin.is_src() {\n            continue;\n        }\n\n        let name = module.compiled_erlang_path();\n        files.push((tar_src.join(&name), fs::read(build.join(name))?));\n    }\n\n    // Erlang headers\n    if include.is_dir() {\n        for file in fs::erlang_files(&include) {\n            let name = file.file_name().expect(\"generated_files include file name\");\n            files.push((tar_include.join(name), fs::read(file)?));\n        }\n    }\n\n    // src/package.app.src file\n    let app = format!(\"{}.app\", &package.config.name);\n    let appsrc = format!(\"{}.src\", &app);\n    files.push((tar_src.join(appsrc), fs::read(ebin.join(app))?));\n\n    Ok(files)\n}\n\nfn add_to_tar<P, W>(tarball: &mut tar::Builder<W>, path: P, data: &[u8]) -> Result<()>\nwhere\n    P: AsRef<Utf8Path>,\n    W: Write,\n{\n    let path = path.as_ref();\n    tracing::info!(file=?path, \"Adding file to tarball\");\n    let mut header = tar::Header::new_gnu();\n    header.set_mode(0o600);\n    header.set_size(data.len() as u64);\n    header.set_cksum();\n    tarball\n        .append_data(&mut header, path, data)\n        .map_err(|e| Error::add_tar(path, e))\n}\n\nfn add_path_to_tar<P, W>(tarball: &mut tar::Builder<W>, path: P) -> Result<()>\nwhere\n    P: AsRef<Utf8Path>,\n    W: Write,\n{\n    let path = path.as_ref();\n    tracing::info!(file=?path, \"Adding file to tarball\");\n    tarball\n        .append_path(path)\n        .map_err(|e| Error::add_tar(path, e))\n}\n\n#[derive(Debug, Clone)]\npub struct ReleaseMetadata<'a> {\n    name: &'a str,\n    version: &'a Version,\n    description: &'a str,\n    source_files: &'a [Utf8PathBuf],\n    generated_files: &'a [(Utf8PathBuf, String)],\n    licenses: &'a Vec<SpdxLicense>,\n    links: Vec<(&'a str, http::Uri)>,\n    requirements: Vec<ReleaseRequirement<'a>>,\n    build_tools: Vec<&'a str>,\n    // What should this be? I can't find it in the API anywhere.\n    // extra: (kvlist(string => kvlist(...))) (optional)\n}\n\nimpl ReleaseMetadata<'_> {\n    pub fn as_erlang(&self) -> String {\n        fn link(link: &(&str, http::Uri)) -> String {\n            format!(\n                \"\\n  {{<<\\\"{name}\\\">>, <<\\\"{url}\\\">>}}\",\n                name = link.0,\n                url = link.1\n            )\n        }\n        fn file(name: impl AsRef<Utf8Path>) -> String {\n            format!(\"\\n  <<\\\"{name}\\\">>\", name = name.as_ref())\n        }\n\n        format!(\n            r#\"{{<<\"name\">>, <<\"{name}\">>}}.\n{{<<\"app\">>, <<\"{name}\">>}}.\n{{<<\"version\">>, <<\"{version}\">>}}.\n{{<<\"description\">>, <<\"{description}\"/utf8>>}}.\n{{<<\"licenses\">>, [{licenses}]}}.\n{{<<\"build_tools\">>, [{build_tools}]}}.\n{{<<\"links\">>, [{links}\n]}}.\n{{<<\"requirements\">>, [{requirements}\n]}}.\n{{<<\"files\">>, [{files}\n]}}.\n\"#,\n            name = self.name,\n            version = self.version,\n            description = self.description,\n            files = self\n                .source_files\n                .iter()\n                .chain(self.generated_files.iter().map(|(p, _)| p))\n                .map(file)\n                .sorted()\n                .join(\",\"),\n            links = self.links.iter().map(link).join(\",\"),\n            licenses = self.licenses.iter().map(|l| quotes(l.as_ref())).join(\", \"),\n            build_tools = self.build_tools.iter().map(|l| quotes(l)).join(\", \"),\n            requirements = self\n                .requirements\n                .iter()\n                .map(ReleaseRequirement::as_erlang)\n                .join(\",\")\n        )\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct ReleaseRequirement<'a> {\n    name: &'a str,\n    // optional: bool,\n    requirement: &'a Range,\n    // Support alternate repositories at a later date.\n    // repository: String,\n}\nimpl ReleaseRequirement<'_> {\n    pub fn as_erlang(&self) -> String {\n        format!(\n            r#\"\n  {{<<\"{app}\">>, [\n    {{<<\"app\">>, <<\"{app}\">>}},\n    {{<<\"optional\">>, false}},\n    {{<<\"requirement\">>, <<\"{requirement}\">>}}\n  ]}}\"#,\n            app = self.name,\n            requirement = self.requirement,\n        )\n    }\n}\n\n#[test]\nfn release_metadata_as_erlang() {\n    let licences = vec![\n        SpdxLicense {\n            licence: \"MIT\".into(),\n        },\n        SpdxLicense {\n            licence: \"MPL-2.0\".into(),\n        },\n    ];\n    let version = \"1.2.3\".try_into().unwrap();\n    let homepage = \"https://gleam.run\".parse().unwrap();\n    let github = \"https://github.com/lpil/myapp\".parse().unwrap();\n    let req1 = Range::new(\"~> 1.2.3 or >= 5.0.0\".into()).unwrap();\n    let req2 = Range::new(\"~> 1.2\".into()).unwrap();\n    let meta = ReleaseMetadata {\n        name: \"myapp\",\n        version: &version,\n        description: \"description goes here 🌈\",\n        source_files: &[\n            Utf8PathBuf::from(\"gleam.toml\"),\n            Utf8PathBuf::from(\"src/thingy.gleam\"),\n            Utf8PathBuf::from(\"src/whatever.gleam\"),\n        ],\n        generated_files: &[\n            (Utf8PathBuf::from(\"src/myapp.app\"), \"\".into()),\n            (Utf8PathBuf::from(\"src/thingy.erl\"), \"\".into()),\n            (Utf8PathBuf::from(\"src/whatever.erl\"), \"\".into()),\n        ],\n        licenses: &licences,\n        links: vec![(\"homepage\", homepage), (\"github\", github)],\n        requirements: vec![\n            ReleaseRequirement {\n                name: \"wibble\",\n                requirement: &req1,\n            },\n            ReleaseRequirement {\n                name: \"wobble\",\n                requirement: &req2,\n            },\n        ],\n        build_tools: vec![\"gleam\", \"rebar3\"],\n    };\n    assert_eq!(\n        meta.as_erlang(),\n        r#\"{<<\"name\">>, <<\"myapp\">>}.\n{<<\"app\">>, <<\"myapp\">>}.\n{<<\"version\">>, <<\"1.2.3\">>}.\n{<<\"description\">>, <<\"description goes here 🌈\"/utf8>>}.\n{<<\"licenses\">>, [<<\"MIT\">>, <<\"MPL-2.0\">>]}.\n{<<\"build_tools\">>, [<<\"gleam\">>, <<\"rebar3\">>]}.\n{<<\"links\">>, [\n  {<<\"homepage\">>, <<\"https://gleam.run/\">>},\n  {<<\"github\">>, <<\"https://github.com/lpil/myapp\">>}\n]}.\n{<<\"requirements\">>, [\n  {<<\"wibble\">>, [\n    {<<\"app\">>, <<\"wibble\">>},\n    {<<\"optional\">>, false},\n    {<<\"requirement\">>, <<\"~> 1.2.3 or >= 5.0.0\">>}\n  ]},\n  {<<\"wobble\">>, [\n    {<<\"app\">>, <<\"wobble\">>},\n    {<<\"optional\">>, false},\n    {<<\"requirement\">>, <<\"~> 1.2\">>}\n  ]}\n]}.\n{<<\"files\">>, [\n  <<\"gleam.toml\">>,\n  <<\"src/myapp.app\">>,\n  <<\"src/thingy.erl\">>,\n  <<\"src/thingy.gleam\">>,\n  <<\"src/whatever.erl\">>,\n  <<\"src/whatever.gleam\">>\n]}.\n\"#\n        .to_string()\n    );\n}\n\n#[test]\nfn prevent_publish_local_dependency() {\n    let config = PackageConfig {\n        dependencies: [(\"provided\".into(), Requirement::path(\"./path/to/package\"))].into(),\n        ..Default::default()\n    };\n    assert_eq!(\n        metadata_config(&config, &[], &[]),\n        Err(Error::PublishNonHexDependencies {\n            package: \"provided\".into()\n        })\n    );\n}\n\n#[test]\nfn prevent_publish_git_dependency() {\n    let config = PackageConfig {\n        dependencies: [(\n            \"provided\".into(),\n            Requirement::git(\"https://github.com/gleam-lang/gleam.git\", \"da6e917\"),\n        )]\n        .into(),\n        ..Default::default()\n    };\n    assert_eq!(\n        metadata_config(&config, &[], &[]),\n        Err(Error::PublishNonHexDependencies {\n            package: \"provided\".into()\n        })\n    );\n}\n\nfn quotes(x: &str) -> String {\n    format!(r#\"<<\"{x}\">>\"#)\n}\n\n#[test]\nfn exported_project_files_test() {\n    let tmp = tempfile::tempdir().unwrap();\n    let path = Utf8PathBuf::from_path_buf(tmp.path().join(\"my_project\")).expect(\"Non Utf8 Path\");\n\n    let exported_project_files = &[\n        \"LICENCE\",\n        \"LICENCE.md\",\n        \"LICENCE.txt\",\n        \"LICENSE\",\n        \"LICENSE.md\",\n        \"LICENSE.txt\",\n        \"NOTICE\",\n        \"NOTICE.md\",\n        \"NOTICE.txt\",\n        \"README\",\n        \"README.md\",\n        \"README.txt\",\n        \"gleam.toml\",\n        \"priv/ignored\",\n        \"priv/wibble\",\n        \"priv/wobble.js\",\n        \"src/.hidden/hidden_ffi.erl\",\n        \"src/.hidden/hidden_ffi.mjs\",\n        \"src/.hidden_ffi.erl\",\n        \"src/.hidden_ffi.mjs\",\n        \"src/exported.gleam\",\n        \"src/exported_ffi.erl\",\n        \"src/exported_ffi.ex\",\n        \"src/exported_ffi.hrl\",\n        \"src/exported_ffi.js\",\n        \"src/exported_ffi.mjs\",\n        \"src/exported_ffi.ts\",\n        \"src/ignored.gleam\",\n        \"src/ignored_ffi.erl\",\n        \"src/ignored_ffi.mjs\",\n        \"src/nested/exported.gleam\",\n        \"src/nested/exported_ffi.erl\",\n        \"src/nested/exported_ffi.ex\",\n        \"src/nested/exported_ffi.hrl\",\n        \"src/nested/exported_ffi.js\",\n        \"src/nested/exported_ffi.mjs\",\n        \"src/nested/exported_ffi.ts\",\n        \"src/nested/ignored.gleam\",\n        \"src/nested/ignored_ffi.erl\",\n        \"src/nested/ignored_ffi.mjs\",\n    ];\n\n    let unexported_project_files = &[\n        \".git/\",\n        \".github/workflows/test.yml\",\n        \".gitignore\",\n        \"build/\",\n        \"ignored.txt\",\n        \"src/.hidden/hidden.gleam\", // Not a valid Gleam module path\n        \"src/.hidden.gleam\",        // Not a valid Gleam module name\n        \"src/also-ignored.gleam\",   // Not a valid Gleam module name\n        \"test/exported_test.gleam\",\n        \"test/exported_test_ffi.erl\",\n        \"test/exported_test_ffi.ex\",\n        \"test/exported_test_ffi.hrl\",\n        \"test/exported_test_ffi.js\",\n        \"test/exported_test_ffi.mjs\",\n        \"test/exported_test_ffi.ts\",\n        \"test/ignored_test.gleam\",\n        \"test/ignored_test_ffi.erl\",\n        \"test/ignored_test_ffi.mjs\",\n        \"test/nested/exported_test.gleam\",\n        \"test/nested/exported_test_ffi.erl\",\n        \"test/nested/exported_test_ffi.ex\",\n        \"test/nested/exported_test_ffi.hrl\",\n        \"test/nested/exported_test_ffi.js\",\n        \"test/nested/exported_test_ffi.mjs\",\n        \"test/nested/exported_test_ffi.ts\",\n        \"test/nested/ignored.gleam\",\n        \"test/nested/ignored_test_ffi.erl\",\n        \"test/nested/ignored_test_ffi.mjs\",\n        \"dev/exported_test_ffi.erl\",\n        \"dev/exported_test_ffi.ex\",\n        \"dev/exported_test_ffi.hrl\",\n        \"dev/exported_test_ffi.js\",\n        \"dev/exported_test_ffi.mjs\",\n        \"dev/exported_test_ffi.ts\",\n        \"dev/ignored_test.gleam\",\n        \"dev/ignored_test_ffi.erl\",\n        \"dev/ignored_test_ffi.mjs\",\n        \"dev/nested/exported_test.gleam\",\n        \"dev/nested/exported_test_ffi.erl\",\n        \"dev/nested/exported_test_ffi.ex\",\n        \"dev/nested/exported_test_ffi.hrl\",\n        \"dev/nested/exported_test_ffi.js\",\n        \"dev/nested/exported_test_ffi.mjs\",\n        \"dev/nested/exported_test_ffi.ts\",\n        \"dev/nested/ignored.gleam\",\n        \"dev/nested/ignored_test_ffi.erl\",\n        \"dev/nested/ignored_test_ffi.mjs\",\n        \"unrelated-file.txt\",\n    ];\n\n    let gitignore = \"ignored*\nsrc/also-ignored.gleam\";\n\n    for &file in exported_project_files\n        .iter()\n        .chain(unexported_project_files)\n    {\n        if file.ends_with(\"/\") {\n            fs::mkdir(path.join(file)).unwrap();\n            continue;\n        }\n\n        let contents = match file {\n            \".gitignore\" => gitignore,\n            _ => \"\",\n        };\n\n        fs::write(&path.join(file), contents).unwrap();\n    }\n\n    let mut chosen_exported_files = project_files(&path).unwrap();\n    chosen_exported_files.sort_unstable();\n\n    let expected_exported_files = exported_project_files\n        .iter()\n        .map(|s| path.join(s))\n        .collect_vec();\n\n    assert_eq!(expected_exported_files, chosen_exported_files);\n}\n"
  },
  {
    "path": "compiler-cli/src/remove.rs",
    "content": "use gleam_core::{\n    Error, Result,\n    error::{FileIoAction, FileKind},\n    paths::ProjectPaths,\n};\n\nuse crate::{cli, fs};\n\npub fn command(paths: &ProjectPaths, packages: Vec<String>) -> Result<()> {\n    // Read gleam.toml so we can remove deps from it\n    let root_config = paths.root_config();\n    let mut toml = fs::read(&root_config)?\n        .parse::<toml_edit::DocumentMut>()\n        .map_err(|e| Error::FileIo {\n            kind: FileKind::File,\n            action: FileIoAction::Parse,\n            path: root_config.to_path_buf(),\n            err: Some(e.to_string()),\n        })?;\n\n    // Remove the specified dependencies\n    let mut packages_not_exist = vec![];\n    for package_to_remove in packages.iter() {\n        let remove = |toml: &mut toml_edit::DocumentMut, name| {\n            #[allow(clippy::indexing_slicing)]\n            toml[name]\n                .as_table_like_mut()\n                .and_then(|deps| deps.remove(package_to_remove))\n        };\n\n        // dev-dependencies is the old deprecated name for dev_dependencies\n        let removed = remove(&mut toml, \"dependencies\")\n            .or_else(|| remove(&mut toml, \"dev_dependencies\"))\n            .or_else(|| remove(&mut toml, \"dev-dependencies\"));\n\n        if removed.is_none() {\n            packages_not_exist.push(package_to_remove.into());\n        }\n    }\n\n    if !packages_not_exist.is_empty() {\n        return Err(Error::RemovedPackagesNotExist {\n            packages: packages_not_exist,\n        });\n    }\n\n    // Write the updated config\n    fs::write(root_config.as_path(), &toml.to_string())?;\n    _ = crate::dependencies::cleanup(paths, cli::Reporter::new())?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/run.rs",
    "content": "use std::sync::OnceLock;\n\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\nuse gleam_core::{\n    analyse::TargetSupport,\n    build::{Built, Codegen, Compile, Mode, NullTelemetry, Options, Runtime, Target, Telemetry},\n    config::{DenoFlag, PackageConfig},\n    error::Error,\n    io::{Command, CommandExecutor, Stdio},\n    paths::ProjectPaths,\n    type_::ModuleFunction,\n    version::COMPILER_VERSION,\n};\n\nuse crate::{config::PackageKind, fs::ProjectIO};\n\n#[derive(Debug, Clone, Copy)]\npub enum Which {\n    Src,\n    Test,\n    Dev,\n}\n\n// TODO: test\npub fn command(\n    paths: &ProjectPaths,\n    arguments: Vec<String>,\n    target: Option<Target>,\n    runtime: Option<Runtime>,\n    module: Option<String>,\n    which: Which,\n    no_print_progress: bool,\n) -> Result<(), Error> {\n    // Don't exit on ctrl+c as it is used by child erlang shell\n    ctrlc::set_handler(move || {}).expect(\"Error setting Ctrl-C handler\");\n    let command = setup(\n        paths,\n        arguments,\n        target,\n        runtime,\n        module,\n        which,\n        no_print_progress,\n    )?;\n    let status = ProjectIO::new().exec(command)?;\n    std::process::exit(status);\n}\n\npub fn setup(\n    paths: &ProjectPaths,\n    arguments: Vec<String>,\n    target: Option<Target>,\n    runtime: Option<Runtime>,\n    module: Option<String>,\n    which: Which,\n    no_print_progress: bool,\n) -> Result<Command, Error> {\n    // Validate the module path\n    if let Some(mod_path) = &module\n        && !is_gleam_module(mod_path)\n    {\n        return Err(Error::InvalidModuleName {\n            module: mod_path.to_owned(),\n        });\n    };\n\n    let telemetry: &'static dyn Telemetry = if no_print_progress {\n        &NullTelemetry\n    } else {\n        &crate::cli::Reporter\n    };\n\n    // Download dependencies\n    let manifest = if no_print_progress {\n        crate::build::download_dependencies(paths, NullTelemetry)?\n    } else {\n        crate::build::download_dependencies(paths, crate::cli::Reporter::new())?\n    };\n\n    // Get the config for the module that is being run to check the target.\n    // Also get the kind of the package the module belongs to: wether the module\n    // belongs to a dependency or to the root package.\n    let (mod_config, package_kind) = match &module {\n        Some(mod_path) => {\n            crate::config::find_package_config_for_module(mod_path, &manifest, paths)?\n        }\n        _ => (crate::config::root_config(paths)?, PackageKind::Root),\n    };\n\n    // The root config is required to run the project.\n    let root_config = crate::config::root_config(paths)?;\n\n    // Determine which module to run\n    let module = module.unwrap_or(match which {\n        Which::Src => root_config.name.to_string(),\n        Which::Test => format!(\"{}_test\", &root_config.name),\n        Which::Dev => format!(\"{}_dev\", &root_config.name),\n    });\n\n    let target = target.unwrap_or(mod_config.target);\n\n    let options = Options {\n        warnings_as_errors: false,\n        compile: match package_kind {\n            // If we're trying to run a dependecy module we do not compile and\n            // check the root package. So we can run the main function from a\n            // dependency's module even if the root package doesn't compile.\n            PackageKind::Dependency => Compile::DepsOnly,\n            PackageKind::Root => Compile::All,\n        },\n        codegen: Codegen::All,\n        mode: Mode::Dev,\n        target: Some(target),\n        root_target_support: match package_kind {\n            // The module we want to run is in the root package, so we make sure that the package\n            // can compile successfully for the current target.\n            PackageKind::Root => TargetSupport::Enforced,\n            // On the other hand, if we're trying to run a module that belongs to a dependency, we\n            // only care if the dependency can compile for the current target.\n            PackageKind::Dependency => TargetSupport::NotEnforced,\n        },\n        no_print_progress,\n    };\n\n    let built = crate::build::main(paths, options, manifest)?;\n\n    // A module can not be run if it does not exist or does not have a public main function.\n    let main_function = get_or_suggest_main_function(built, &module, target)?;\n\n    telemetry.running(&format!(\"{module}.main\"));\n\n    // Get the command to run the project.\n    match target {\n        Target::Erlang => match runtime {\n            Some(r) => Err(Error::InvalidRuntime {\n                target: Target::Erlang,\n                invalid_runtime: r,\n            }),\n            _ => run_erlang_command(paths, &root_config.name, &module, arguments),\n        },\n        Target::JavaScript => match runtime.unwrap_or(mod_config.javascript.runtime) {\n            Runtime::Deno => run_javascript_deno_command(\n                paths,\n                &root_config,\n                &main_function.package,\n                &module,\n                arguments,\n            ),\n            Runtime::NodeJs => {\n                run_javascript_node_command(paths, &main_function.package, &module, arguments)\n            }\n            Runtime::Bun => {\n                run_javascript_bun_command(paths, &main_function.package, &module, arguments)\n            }\n        },\n    }\n}\n\nfn run_erlang_command(\n    paths: &ProjectPaths,\n    package: &str,\n    module: &str,\n    arguments: Vec<String>,\n) -> Result<Command, Error> {\n    let mut args = vec![];\n\n    // Specify locations of Erlang applications\n    let packages = paths.build_directory_for_target(Mode::Dev, Target::Erlang);\n\n    for entry in crate::fs::read_dir(packages)?.filter_map(Result::ok) {\n        args.push(\"-pa\".into());\n        args.push(entry.path().join(\"ebin\").into());\n    }\n\n    // gleam modules are separated by `/`. Erlang modules are separated by `@`.\n    let module = module.replace('/', \"@\");\n\n    args.push(\"-eval\".into());\n    args.push(format!(\"{package}@@main:run({module})\"));\n\n    // Don't run the Erlang shell\n    args.push(\"-noshell\".into());\n\n    // Tell the BEAM that any following argument are for the program\n    args.push(\"-extra\".into());\n    for argument in arguments.into_iter() {\n        args.push(argument);\n    }\n\n    Ok(Command {\n        program: \"erl\".to_string(),\n        args,\n        env: vec![],\n        cwd: None,\n        stdio: Stdio::Inherit,\n    })\n}\n\nfn run_javascript_bun_command(\n    paths: &ProjectPaths,\n    package: &str,\n    module: &str,\n    arguments: Vec<String>,\n) -> Result<Command, Error> {\n    let mut args = vec![\"run\".to_string()];\n    let entry = write_javascript_entrypoint(paths, package, module)?;\n\n    args.push(entry.to_string());\n\n    for arg in arguments.into_iter() {\n        args.push(arg);\n    }\n\n    Ok(Command {\n        program: \"bun\".to_string(),\n        args,\n        env: vec![],\n        cwd: None,\n        stdio: Stdio::Inherit,\n    })\n}\n\nfn run_javascript_node_command(\n    paths: &ProjectPaths,\n    package: &str,\n    module: &str,\n    arguments: Vec<String>,\n) -> Result<Command, Error> {\n    let mut args = vec![];\n    let entry = write_javascript_entrypoint(paths, package, module)?;\n\n    args.push(entry.to_string());\n\n    for argument in arguments.into_iter() {\n        args.push(argument);\n    }\n\n    Ok(Command {\n        program: \"node\".to_string(),\n        args,\n        env: vec![],\n        cwd: None,\n        stdio: Stdio::Inherit,\n    })\n}\n\nfn write_javascript_entrypoint(\n    paths: &ProjectPaths,\n    package: &str,\n    module: &str,\n) -> Result<Utf8PathBuf, Error> {\n    let path = paths\n        .build_directory_for_package(Mode::Dev, Target::JavaScript, package)\n        .to_path_buf()\n        .join(format!(\"gleam@@private_main_v{}.mjs\", COMPILER_VERSION));\n    let module = format!(\n        r#\"import {{ main }} from \"./{module}.mjs\";\nmain();\n\"#,\n    );\n    crate::fs::write(&path, &module)?;\n    Ok(path)\n}\n\nfn run_javascript_deno_command(\n    paths: &ProjectPaths,\n    config: &PackageConfig,\n    package: &str,\n    module: &str,\n    arguments: Vec<String>,\n) -> Result<Command, Error> {\n    let mut args = vec![];\n\n    // Run the main function.\n    args.push(\"run\".into());\n\n    // Enable unstable features and APIs\n    if config.javascript.deno.unstable {\n        args.push(\"--unstable\".into())\n    }\n\n    // Enable location API\n    if let Some(location) = &config.javascript.deno.location {\n        args.push(format!(\"--location={location}\"));\n    }\n\n    // Set deno permissions\n    if config.javascript.deno.allow_all {\n        // Allow all\n        args.push(\"--allow-all\".into())\n    } else {\n        // Allow env\n        add_deno_flag(&mut args, \"--allow-env\", &config.javascript.deno.allow_env);\n\n        // Allow sys\n        if config.javascript.deno.allow_sys {\n            args.push(\"--allow-sys\".into())\n        }\n\n        // Allow hrtime\n        if config.javascript.deno.allow_hrtime {\n            args.push(\"--allow-hrtime\".into())\n        }\n\n        // Allow net\n        add_deno_flag(&mut args, \"--allow-net\", &config.javascript.deno.allow_net);\n\n        // Allow ffi\n        if config.javascript.deno.allow_ffi {\n            args.push(\"--allow-ffi\".into())\n        }\n\n        // Allow read\n        add_deno_flag(\n            &mut args,\n            \"--allow-read\",\n            &config.javascript.deno.allow_read,\n        );\n\n        // Allow run\n        add_deno_flag(&mut args, \"--allow-run\", &config.javascript.deno.allow_run);\n\n        // Allow write\n        add_deno_flag(\n            &mut args,\n            \"--allow-write\",\n            &config.javascript.deno.allow_write,\n        );\n    }\n\n    let entrypoint = write_javascript_entrypoint(paths, package, module)?;\n    args.push(entrypoint.to_string());\n\n    for argument in arguments.into_iter() {\n        args.push(argument);\n    }\n\n    Ok(Command {\n        program: \"deno\".to_string(),\n        args,\n        env: vec![],\n        cwd: None,\n        stdio: Stdio::Inherit,\n    })\n}\n\nfn add_deno_flag(args: &mut Vec<String>, flag: &str, flags: &DenoFlag) {\n    match flags {\n        DenoFlag::AllowAll => args.push(flag.to_owned()),\n        DenoFlag::Allow(allow) => {\n            if !allow.is_empty() {\n                args.push(format!(\"{}={}\", flag.to_owned(), allow.join(\",\")));\n            }\n        }\n    }\n}\n\n/// Check if a module name is a valid gleam module name.\nfn is_gleam_module(module: &str) -> bool {\n    use regex::Regex;\n    static RE: OnceLock<Regex> = OnceLock::new();\n\n    RE.get_or_init(|| {\n        Regex::new(&format!(\n            \"^({module}{slash})*{module}$\",\n            module = \"[a-z][_a-z0-9]*\",\n            slash = \"/\",\n        ))\n        .expect(\"is_gleam_module() RE regex\")\n    })\n    .is_match(module)\n}\n\n/// If provided module is not executable, suggest a possible valid module.\nfn get_or_suggest_main_function(\n    built: Built,\n    module: &str,\n    target: Target,\n) -> Result<ModuleFunction, Error> {\n    // Check if the module exists\n    let error = match built.get_main_function(&module.into(), target) {\n        Ok(main_fn) => return Ok(main_fn),\n        Err(error) => error,\n    };\n\n    // Otherwise see if the module has been prefixed with \"src/\", \"test/\" or \"dev/\".\n    for prefix in [\"src/\", \"test/\", \"dev/\"] {\n        let other = match module.strip_prefix(prefix) {\n            Some(other) => other.into(),\n            None => continue,\n        };\n        if built.get_main_function(&other, target).is_ok() {\n            return Err(Error::ModuleDoesNotExist {\n                module: EcoString::from(module),\n                suggestion: Some(other),\n            });\n        }\n    }\n\n    Err(error)\n}\n\n#[test]\nfn invalid_module_names() {\n    for mod_name in [\n        \"\",\n        \"/mod/name\",\n        \"/mod/name/\",\n        \"mod/name/\",\n        \"/mod/\",\n        \"mod/\",\n        \"common-invalid-character\",\n    ] {\n        assert!(!is_gleam_module(mod_name));\n    }\n}\n\n#[test]\nfn valid_module_names() {\n    for mod_name in [\"valid\", \"valid/name\", \"valid/mod/name\"] {\n        assert!(is_gleam_module(mod_name));\n    }\n}\n"
  },
  {
    "path": "compiler-cli/src/shell.rs",
    "content": "use gleam_core::{\n    analyse::TargetSupport,\n    build::{Codegen, Compile, Mode, Options, Target},\n    error::{Error, ShellCommandFailureReason},\n    paths::ProjectPaths,\n};\nuse std::process::Command;\n\npub fn command(paths: &ProjectPaths) -> Result<(), Error> {\n    // Build project\n    let _ = crate::build::main(\n        paths,\n        Options {\n            root_target_support: TargetSupport::Enforced,\n            warnings_as_errors: false,\n            codegen: Codegen::All,\n            compile: Compile::All,\n            mode: Mode::Dev,\n            target: Some(Target::Erlang),\n            no_print_progress: false,\n        },\n        crate::build::download_dependencies(paths, crate::cli::Reporter::new())?,\n    )?;\n\n    // Don't exit on ctrl+c as it is used by child erlang shell\n    ctrlc::set_handler(move || {}).expect(\"Error setting Ctrl-C handler\");\n\n    // Prepare the Erlang shell command\n    let mut command = Command::new(\"erl\");\n\n    // Print character lists as lists\n    let _ = command.arg(\"-stdlib\").arg(\"shell_strings\").arg(\"false\");\n\n    // Specify locations of .beam files\n    let packages = paths.build_directory_for_target(Mode::Dev, Target::Erlang);\n    for entry in crate::fs::read_dir(packages)?.filter_map(Result::ok) {\n        let _ = command.arg(\"-pa\").arg(entry.path().join(\"ebin\"));\n    }\n\n    crate::cli::print_running(\"Erlang shell\");\n\n    // Run the shell\n    tracing::info!(\"Running OS process {:?}\", command);\n    let _ = command.status().map_err(|e| Error::ShellCommand {\n        program: \"erl\".into(),\n        reason: ShellCommandFailureReason::IoError(e.kind()),\n    })?;\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-cli/src/text_layout.rs",
    "content": "use ecow::EcoString;\n\n/// Generates a string delimeted table with 2 spaces between each column, columns padded with\n/// enough spaces to be aligned, and hyphens under the headers (excluding the final column of each\n/// row). Rows should have the right number of columns.\n///\n/// ## Example\n///\n/// ```txt\n/// Package  Current  Latest\n/// -------  -------  ------\n/// wibble   1.4.0    1.4.1\n/// wobble   1.0.1    2.3.0\n/// ```\n///\npub fn space_table<Grid, Row, Cell>(headers: &[impl AsRef<str>], data: Grid) -> EcoString\nwhere\n    Grid: AsRef<[Row]>,\n    Row: AsRef<[Cell]>,\n    Cell: AsRef<str>,\n{\n    let mut output = EcoString::new();\n\n    let mut column_widths: Vec<usize> =\n        headers.iter().map(|header| header.as_ref().len()).collect();\n\n    for row in data.as_ref() {\n        for (index, cell) in row.as_ref().iter().enumerate() {\n            if let Some(width) = column_widths.get_mut(index) {\n                let cell = cell.as_ref();\n                *width = (*width).max(cell.len());\n            }\n        }\n    }\n\n    for (index, (header, width)) in headers.iter().zip(column_widths.iter()).enumerate() {\n        if index > 0 {\n            output.push_str(\"  \");\n        }\n        let header = header.as_ref();\n        output.push_str(header);\n        if index < headers.len() - 1 {\n            let padding = width - header.len();\n            if padding > 0 {\n                output.push_str(&\" \".repeat(padding));\n            }\n        }\n    }\n    output.push('\\n');\n\n    for (index, (header, width)) in headers.iter().zip(column_widths.iter()).enumerate() {\n        if index > 0 {\n            output.push_str(\"  \");\n        }\n        let header = header.as_ref();\n        output.push_str(&\"-\".repeat(header.len()));\n        if index < headers.len() - 1 {\n            let padding = width - header.len();\n            if padding > 0 {\n                output.push_str(&\" \".repeat(padding));\n            }\n        }\n    }\n    output.push('\\n');\n\n    for row in data.as_ref() {\n        for (index, (cell, width)) in row.as_ref().iter().zip(column_widths.iter()).enumerate() {\n            if index > 0 {\n                output.push_str(\"  \");\n            }\n            let cell = cell.as_ref();\n            output.push_str(cell);\n            if index < headers.len() - 1 {\n                let padding = width - cell.len();\n                if padding > 0 {\n                    output.push_str(&\" \".repeat(padding));\n                }\n            }\n        }\n        output.push('\\n');\n    }\n\n    output\n}\n"
  },
  {
    "path": "compiler-cli/templates/erlang-shipment-entrypoint.ps1",
    "content": "$ErrorActionPreference = \"Stop\"\n\n$PackageName = \"$PACKAGE_NAME_FROM_GLEAM\"\n$BaseDirectory = $PSScriptRoot\n$ScriptCommand = $args[0]\n\n$CodePath = Join-Path -Path $BaseDirectory -ChildPath \"\\*\\ebin\" -Resolve\n\nfunction Run {\n  erl `\n    -pa $CodePath `\n    -eval \"$PackageName@@main:run($PackageName)\" `\n    -noshell `\n    -extra $args\n}\n\nfunction Shell {\n  erl -pa $CodePath\n}\n\nswitch ($ScriptCommand) {\n  \"run\" {\n    Run $args[1..($args.Length - 1)]\n  }\n  \"shell\" {\n    Shell\n  }\n  default {\n    Write-Host \"usage:\"\n    Write-Host \"  entrypoint.ps1 `$COMMAND\"\n    Write-Host \"\"\n    Write-Host \"commands:\"\n    Write-Host \"  run    Run the project main function\"\n    Write-Host \"  shell  Run an Erlang shell\"\n    exit 1\n  }\n}\n"
  },
  {
    "path": "compiler-cli/templates/erlang-shipment-entrypoint.sh",
    "content": "#!/bin/sh\nset -eu\n\nPACKAGE=$PACKAGE_NAME_FROM_GLEAM\nBASE=$(dirname \"$0\")\nCOMMAND=\"${1-default}\"\n\nrun() {\n  exec erl \\\n    -pa \"$BASE\"/*/ebin \\\n    -eval \"$PACKAGE@@main:run($PACKAGE)\" \\\n    -noshell \\\n    -extra \"$@\"\n}\n\nshell() {\n  erl -pa \"$BASE\"/*/ebin\n}\n\ncase \"$COMMAND\" in\nrun)\n  shift\n  run \"$@\"\n  ;;\n\nshell)\n  shell\n  ;;\n\n*)\n  echo \"usage:\" >&2\n  echo \"  entrypoint.sh \\$COMMAND\" >&2\n  echo \"\" >&2\n  echo \"commands:\" >&2\n  echo \"  run    Run the project main function\" >&2\n  echo \"  shell  Run an Erlang shell\" >&2\n  exit 1\n  ;;\nesac\n"
  },
  {
    "path": "compiler-cli/templates/gleam@@compile.erl",
    "content": "#!/usr/bin/env escript\n-mode(compile).\n\n% TODO: Don't concurrently print warnings and errors\n% TODO: Some tests\n\nmain(_) ->\n    ok = io:setopts([binary, {encoding, utf8}]),\n    ok = configure_logging(),\n    compile_package_loop().\n\ncompile_package_loop() ->\n    case io:get_line(\"\") of\n        eof -> ok;\n        Line ->\n            Chars = unicode:characters_to_list(Line),\n            {ok, Tokens, _} = erl_scan:string(Chars),\n            {ok, {Lib, Out, Modules}} = erl_parse:parse_term(Tokens),\n            case compile_package(Lib, Out, Modules) of\n                {ok, ModuleNames} ->\n                    PrintModuleName = fun(ModuleName) ->\n                        io:put_chars(\"gleam-compile-module:\" ++ atom_to_list(ModuleName) ++ \"\\n\")\n                    end,\n                    lists:map(PrintModuleName, ModuleNames),\n                    io:put_chars(\"gleam-compile-result-ok\\n\");\n                err ->\n                    io:put_chars(\"gleam-compile-result-error\\n\")\n            end,\n            compile_package_loop()\n    end.\n\ncompile_package(Lib, Out, Modules) ->\n    IsElixirModule = fun(Module) ->\n        filename:extension(Module) =:= \".ex\"\n    end,\n    {ElixirModules, ErlangModules} = lists:partition(IsElixirModule, Modules),\n    ok = filelib:ensure_dir([Out, $/]),\n    ok = add_lib_to_erlang_path(Lib),\n    {ErlangOk, ErlangBeams} = compile_erlang(ErlangModules, Out),\n    {ElixirOk, ElixirBeams} = case ErlangOk of\n        true -> compile_elixir(ElixirModules, Out);\n        false -> {false, []}\n    end,\n    ok = del_lib_from_erlang_path(Lib),\n    case ErlangOk andalso ElixirOk of\n        true ->\n            ModuleNames = proplists:get_keys(ErlangBeams ++ ElixirBeams),\n            {ok, ModuleNames};\n        false ->\n            err\n    end.\n\ncompile_erlang(Modules, Out) ->\n    Workers = start_compiler_workers(Out),\n    ok = producer_loop(Modules, Workers),\n    collect_results({true, []}).\n\ncollect_results(Acc = {Result, Beams}) ->\n    receive\n        {compiled, ModuleName, Beam} -> collect_results({Result, [{ModuleName, Beam} | Beams]});\n        failed -> collect_results({false, Beams})\n        after 0 -> Acc\n    end.\n\nproducer_loop([], 0) ->\n    ok;\nproducer_loop([], Workers) ->\n    receive\n        {work_please, _} -> producer_loop([], Workers - 1)\n    end;\nproducer_loop([Module | Modules], Workers) ->\n    receive\n        {work_please, Worker} ->\n            erlang:send(Worker, {module, Module}),\n            producer_loop(Modules, Workers)\n    end.\n\nstart_compiler_workers(Out) ->\n    Parent = self(),\n    NumSchedulers = erlang:system_info(schedulers),\n    SpawnWorker = fun(_) ->\n        erlang:spawn_link(fun() -> worker_loop(Parent, Out) end)\n    end,\n    lists:foreach(SpawnWorker, lists:seq(1, NumSchedulers)),\n    NumSchedulers.\n\nworker_loop(Parent, Out) ->\n    Options = [report_errors, report_warnings, debug_info, {outdir, Out}],\n    erlang:send(Parent, {work_please, self()}),\n    receive\n        {module, Module} ->\n            log({compiling, Module}),\n            case compile:file(Module, Options) of\n                {ok, ModuleName} ->\n                    Beam = filename:join(Out, ModuleName) ++ \".beam\",\n                    Message = {compiled, ModuleName, Beam},\n                    log(Message),\n                    erlang:send(Parent, Message);\n                error ->\n                    log({failed, Module}),\n                    erlang:send(Parent, failed)\n            end,\n            worker_loop(Parent, Out)\n    end.\n\ncompile_elixir(Modules, Out) ->\n    Error = [\n        \"The program elixir was not found. Is it installed?\",\n        $\\n,\n        \"Documentation for installing Elixir can be viewed here:\",\n        $\\n,\n        \"https://elixir-lang.org/install.html\"\n    ],\n    case Modules of\n        [] -> {true, []};\n        _ ->\n            log({starting, \"compiler.app,elixir.app\"}),\n            case application:ensure_all_started([compiler, elixir]) of\n                {ok, _} -> do_compile_elixir(Modules, Out);\n                _ ->\n                    io:put_chars(standard_error, [Error, $\\n]),\n                    {false, []}\n            end\n    end.\n\ndo_compile_elixir(Modules, Out) ->\n    ModuleBins = lists:map(fun(Module) ->\n        log({compiling, Module}),\n        list_to_binary(Module)\n    end, Modules),\n    OutBin = list_to_binary(Out),\n    Options = [{dest, OutBin}, {return_diagnostics, true}],\n    % Silence \"redefining module\" warnings.\n    % Compiled modules in the build directory are added to the code path.\n    % These warnings result from recompiling loaded modules.\n    % TODO: This line can likely be removed if/when the build directory is cleaned before every compilation.\n    'Elixir.Code':compiler_options([{ignore_module_conflict, true}]),\n    case 'Elixir.Kernel.ParallelCompiler':compile_to_path(ModuleBins, OutBin, Options) of\n        {ok, ModuleAtoms, _} ->\n            ToBeam = fun(ModuleAtom) ->\n                Beam = filename:join(Out, atom_to_list(ModuleAtom)) ++ \".beam\",\n                log({compiled, Beam}),\n                {ModuleAtom, Beam}\n            end,\n            {true, lists:map(ToBeam, ModuleAtoms)};\n        {error, Errors, _} ->\n            % Log all filenames associated with modules that failed to compile.\n            % Note: The compiler prints compilation errors upon encountering them.\n            ErrorFiles = lists:usort([File || {File, _, _} <- Errors]),\n            Log = fun(File) ->\n                log({failed, binary_to_list(File)})\n            end,\n            lists:foreach(Log, ErrorFiles),\n            {false, []};\n        _ -> {false, []}\n    end.\n\nadd_lib_to_erlang_path(Lib) ->\n    code:add_paths(expand_lib_paths(Lib)).\n\n-if(?OTP_RELEASE >= 26).\ndel_lib_from_erlang_path(Lib) ->\n    code:del_paths(expand_lib_paths(Lib)).\n-else.\ndel_lib_from_erlang_path(Lib) ->\n    lists:foreach(fun code:del_path/1, expand_lib_paths(Lib)).\n-endif.\n\nexpand_lib_paths(Lib) ->\n    filelib:wildcard([Lib, \"/*/ebin\"]).\n\nconfigure_logging() ->\n    Enabled = os:getenv(\"GLEAM_LOG\") /= false,\n    persistent_term:put(gleam_logging_enabled, Enabled).\n\nlog(Term) ->\n    case persistent_term:get(gleam_logging_enabled) of\n        true -> io:fwrite(\"~p~n\", [Term]), ok;\n        false -> ok\n    end.\n"
  },
  {
    "path": "compiler-cli/test/hello_world/.gitignore",
    "content": "build\n"
  },
  {
    "path": "compiler-cli/test/hello_world/gleam.toml",
    "content": "name = \"hello_world\"\nversion = \"0.1.0\"\n\n[dependencies]\ngleam_stdlib = \"~> 0.28\"\n\n[dev_dependencies]\ngleeunit = \"~> 0.10\"\n"
  },
  {
    "path": "compiler-cli/test/hello_world/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n  { name = \"gleeunit\", version = \"0.11.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"1397E5C4AC4108769EE979939AC39BF7870659C5AFB714630DEEEE16B8272AD5\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \"~> 0.28\" }\ngleeunit = { version = \"~> 0.10\" }\n"
  },
  {
    "path": "compiler-core/Cargo.toml",
    "content": "[package]\nname = \"gleam-core\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\n# Error message and warning formatting\ncodespan-reporting = \"0\"\n# Graph data structures\npetgraph = \"0.8\"\n# Template rendering\naskama = \"0\"\n# Markdown parsing\npulldown-cmark = { version = \"0\", default-features = false, features = [\n  \"html\",\n] }\n# XDG directory locations\ndirs-next = \"2\"\n# SPDX license parsing\nspdx = \"0\"\n# Binary format de-serialization\nbincode = { version = \"2\", features = [\"alloc\", \"serde\"] }\n# cross platform single glob and glob set matching\nglobset = { version = \"0\", features = [\"serde1\"] }\n# Checksums\nxxhash-rust = { version = \"0\", features = [\"xxh3\"] }\n# Pubgrub dependency resolution algorithm\npubgrub = \"0.3\"\n# Used for converting absolute path to relative path\npathdiff = { version = \"0\", features = [\"camino\"] }\n# Memory arena using ids rather than references\nid-arena = \"2\"\n# Unicode grapheme traversal\nunicode-segmentation = \"1.12.0\"\n# Bijective (bi-directional) hashmap\nbimap = \"0.6.3\"\n# Parsing of arbitrary width int values\nnum-bigint = { version = \"0.4.6\", features = [\"serde\"] }\nnum-traits = \"0.2.19\"\n# Encryption\nage = { version = \"0.11\", features = [\"armor\"] }\nradix_trie = \"0.3\"\n# Ensuring recursive type-checking doesn't stack overflow\nstacker = \"0.1.21\"\n# Manipulating bit arrays\nbitvec = { version = \"1\", features = [\"serde\"] }\n\nasync-trait.workspace = true\nbase16.workspace = true\ncamino = { workspace = true, features = [\"serde1\"] }\ndebug-ignore.workspace = true\necow = { workspace = true, features = [\"serde\"] }\nflate2.workspace = true\nfutures.workspace = true\nhexpm = { path = \"../hexpm\" }\nhttp.workspace = true\nim.workspace = true\nitertools.workspace = true\nlsp-server.workspace = true\nlsp-types.workspace = true\nregex.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nstrum.workspace = true\ntar.workspace = true\ntermcolor.workspace = true\nthiserror.workspace = true\ntoml.workspace = true\ntracing.workspace = true\nindexmap = \"2.12.1\"\nvec1.workspace = true\n\n[build-dependencies]\n# Data (de)serialisation\nserde_derive = \"1\"\n\n[dev-dependencies]\npretty_assertions.workspace = true\ninsta.workspace = true\n# Random value generation\nrand = \"0.9\"\n"
  },
  {
    "path": "compiler-core/clippy.toml",
    "content": "disallowed-methods = [\n  { path = \"std::env::current_dir\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::canonicalize\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::exists\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::is_dir\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::is_file\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::is_symlink\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::read_dir\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::read_link\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::symlink_metadata\", reason = \"IO is not permitted in core\" },\n  { path = \"std::path::Path::try_exists\", reason = \"IO is not permitted in core\" },\n  \n  { path = \"camino::Utf8Path::canonicalize\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::exists\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::is_dir\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::is_file\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::is_symlink\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::read_dir\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::read_link\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::symlink_metadata\", reason = \"IO is not permitted in core\" },\n  { path = \"camino::Utf8Path::try_exists\", reason = \"IO is not permitted in core\" },\n\n\n  { path = \"std::path::Path::new\", reason = \"Manually constructed paths should use camino::Utf8Path\" },\n  { path = \"std::path::PathBuf::new\", reason = \"Manually constructed pathbufs should use camino::Utf8Path\" },\n]\n"
  },
  {
    "path": "compiler-core/src/analyse/imports.rs",
    "content": "use ecow::EcoString;\n\nuse crate::{\n    ast::{Publicity, SrcSpan, UnqualifiedImport, UntypedImport},\n    build::Origin,\n    reference::{EntityKind, ReferenceKind},\n    type_::{\n        Environment, Error, ModuleInterface, Problems, ValueConstructorVariant, Warning,\n        error::InvalidImportKind,\n    },\n};\n\nuse super::Imported;\n\n#[derive(Debug)]\npub struct Importer<'context, 'problems> {\n    origin: Origin,\n    environment: Environment<'context>,\n    problems: &'problems mut Problems,\n}\n\nimpl<'context, 'problems> Importer<'context, 'problems> {\n    pub fn new(\n        origin: Origin,\n        environment: Environment<'context>,\n        problems: &'problems mut Problems,\n    ) -> Self {\n        Self {\n            origin,\n            environment,\n            problems,\n        }\n    }\n\n    pub fn run<'code>(\n        origin: Origin,\n        env: Environment<'context>,\n        imports: &'code [UntypedImport],\n        problems: &'problems mut Problems,\n    ) -> Environment<'context> {\n        let mut importer = Self::new(origin, env, problems);\n        for import in imports {\n            importer.register_import(import)\n        }\n        importer.environment\n    }\n\n    fn register_import(&mut self, import: &UntypedImport) {\n        let location = import.location;\n        let name = import.module.clone();\n\n        // Find imported module\n        let Some(module_info) = self.environment.importable_modules.get(&name) else {\n            self.problems.error(Error::UnknownModule {\n                location,\n                name: name.clone(),\n                suggestions: self.environment.suggest_modules(&name, Imported::Module),\n            });\n            return;\n        };\n\n        if let Err(e) = self.check_for_invalid_imports(module_info, location) {\n            self.problems.error(e);\n        }\n\n        if let Err(e) = self.register_module(import, module_info) {\n            self.problems.error(e);\n            return;\n        }\n\n        // Insert unqualified imports into scope\n        let module_name = &module_info.name;\n        for type_ in &import.unqualified_types {\n            self.register_unqualified_type(type_, module_name.clone(), module_info);\n        }\n        for value in &import.unqualified_values {\n            self.register_unqualified_value(value, module_name.clone(), module_info);\n        }\n    }\n\n    fn register_unqualified_type(\n        &mut self,\n        import: &UnqualifiedImport,\n        module_name: EcoString,\n        module: &ModuleInterface,\n    ) {\n        let imported_name = import.as_name.as_ref().unwrap_or(&import.name);\n\n        // Register the unqualified import if it is a type constructor\n        let Some(type_info) = module.get_public_type(&import.name) else {\n            // TODO: refine to a type specific error\n            self.problems.error(Error::UnknownModuleType {\n                location: import.location,\n                name: import.name.clone(),\n                module_name: module.name.clone(),\n                type_constructors: module.public_type_names(),\n                value_with_same_name: module.get_public_value(&import.name).is_some(),\n            });\n            return;\n        };\n\n        let type_info = type_info.clone().with_location(import.location);\n\n        self.environment.names.type_in_scope(\n            imported_name.clone(),\n            type_info.type_.as_ref(),\n            &type_info.parameters,\n        );\n\n        self.environment.references.register_type(\n            imported_name.clone(),\n            EntityKind::ImportedType {\n                module: module_name,\n            },\n            import.location,\n            Publicity::Private,\n        );\n\n        self.environment.references.register_type_reference(\n            type_info.module.clone(),\n            import.name.clone(),\n            imported_name,\n            import.imported_name_location,\n            ReferenceKind::Import,\n        );\n\n        if let Err(e) = self\n            .environment\n            .insert_type_constructor(imported_name.clone(), type_info)\n        {\n            self.problems.error(e);\n        }\n    }\n\n    fn register_unqualified_value(\n        &mut self,\n        import: &UnqualifiedImport,\n        module_name: EcoString,\n        module: &ModuleInterface,\n    ) {\n        let import_name = &import.name;\n        let location = import.location;\n        let used_name = import.as_name.as_ref().unwrap_or(&import.name);\n\n        // Register the unqualified import if it is a value\n        let variant = match module.get_public_value(import_name) {\n            Some(value) => {\n                let implementations = value.variant.implementations();\n                // Check the target support of the imported value\n                if self.environment.target_support.is_enforced()\n                    && !implementations.supports(self.environment.target)\n                {\n                    self.problems.error(Error::UnsupportedExpressionTarget {\n                        target: self.environment.target,\n                        location,\n                    })\n                }\n\n                self.environment.insert_variable(\n                    used_name.clone(),\n                    value.variant.clone(),\n                    value.type_.clone(),\n                    value.publicity,\n                    value.deprecation.clone(),\n                );\n                &value.variant\n            }\n            None => {\n                self.problems.error(Error::UnknownModuleValue {\n                    location,\n                    name: import_name.clone(),\n                    module_name: module.name.clone(),\n                    value_constructors: module.public_value_names(),\n                    type_with_same_name: module.get_public_type(import_name).is_some(),\n                    context: crate::type_::error::ModuleValueUsageContext::UnqualifiedImport,\n                });\n                return;\n            }\n        };\n\n        match variant {\n            ValueConstructorVariant::Record { name, module, .. } => {\n                self.environment.names.named_constructor_in_scope(\n                    module.clone(),\n                    name.clone(),\n                    used_name.clone(),\n                );\n                self.environment.references.register_value(\n                    used_name.clone(),\n                    EntityKind::ImportedConstructor {\n                        module: module_name,\n                    },\n                    location,\n                    Publicity::Private,\n                );\n\n                self.environment.references.register_value_reference(\n                    module.clone(),\n                    import_name.clone(),\n                    used_name,\n                    import.imported_name_location,\n                    ReferenceKind::Import,\n                );\n            }\n            ValueConstructorVariant::ModuleConstant { module, .. }\n            | ValueConstructorVariant::ModuleFn { module, .. } => {\n                self.environment.references.register_value(\n                    used_name.clone(),\n                    EntityKind::ImportedValue {\n                        module: module_name,\n                    },\n                    location,\n                    Publicity::Private,\n                );\n                self.environment.references.register_value_reference(\n                    module.clone(),\n                    import_name.clone(),\n                    used_name,\n                    import.imported_name_location,\n                    ReferenceKind::Import,\n                );\n            }\n            ValueConstructorVariant::LocalVariable { .. } => {}\n        };\n\n        // Check if value already was imported\n        if let Some(previous) = self.environment.unqualified_imported_names.get(used_name) {\n            self.problems.error(Error::DuplicateImport {\n                location,\n                previous_location: *previous,\n                name: import_name.clone(),\n            });\n            return;\n        }\n\n        // Register the name as imported so it can't be imported a\n        // second time in future\n        let _ = self\n            .environment\n            .unqualified_imported_names\n            .insert(used_name.clone(), location);\n    }\n\n    /// Check for invalid imports, such as `src` importing `test` or `dev`.\n    fn check_for_invalid_imports(\n        &mut self,\n        module_info: &ModuleInterface,\n        location: SrcSpan,\n    ) -> Result<(), Error> {\n        if self.origin.is_src()\n            && self\n                .environment\n                .dev_dependencies\n                .contains(&module_info.package)\n        {\n            return Err(Error::SrcImportingDevDependency {\n                importing_module: self.environment.current_module.clone(),\n                imported_module: module_info.name.clone(),\n                package: module_info.package.clone(),\n                location,\n            });\n        }\n\n        let kind = match (self.origin, module_info.origin) {\n            // `src` cannot import `test` or `dev`\n            (Origin::Src, Origin::Test) => InvalidImportKind::SrcImportingTest,\n            (Origin::Src, Origin::Dev) => InvalidImportKind::SrcImportingDev,\n            // `dev` cannot import `test`\n            (Origin::Dev, Origin::Test) => InvalidImportKind::DevImportingTest,\n            _ => return Ok(()),\n        };\n\n        Err(Error::InvalidImport {\n            location,\n            importing_module: self.environment.current_module.clone(),\n            imported_module: module_info.name.clone(),\n            kind,\n        })\n    }\n\n    fn register_module(\n        &mut self,\n        import: &UntypedImport,\n        import_info: &'context ModuleInterface,\n    ) -> Result<(), Error> {\n        let Some(used_name) = import.used_name() else {\n            return Ok(());\n        };\n\n        self.check_not_a_duplicate_import(&used_name, import.location)?;\n\n        if let Some(alias_location) = import.alias_location() {\n            self.environment.references.register_aliased_module(\n                used_name.clone(),\n                import.module.clone(),\n                alias_location,\n                import.location,\n            );\n        } else {\n            self.environment.references.register_module(\n                used_name.clone(),\n                import.module.clone(),\n                import.location,\n            );\n        }\n\n        // Insert imported module into scope\n        let _ = self\n            .environment\n            .imported_modules\n            .insert(used_name.clone(), (import.location, import_info));\n\n        // Register this module as being imported\n        //\n        // Emit a warning if the module had already been imported.\n        // This isn't an error so long as the modules have different local aliases. In Gleam v2\n        // this will likely become an error.\n        if let Some(previous) = self.environment.names.imported_module(\n            import.module.clone(),\n            used_name,\n            import.location,\n        ) {\n            self.problems.warning(Warning::ModuleImportedTwice {\n                name: import.module.clone(),\n                first: previous,\n                second: import.location,\n            });\n        }\n\n        Ok(())\n    }\n\n    fn check_not_a_duplicate_import(\n        &self,\n        used_name: &EcoString,\n        location: SrcSpan,\n    ) -> Result<(), Error> {\n        // Check if a module was already imported with this name\n        if let Some((previous_location, _)) = self.environment.imported_modules.get(used_name) {\n            return Err(Error::DuplicateImport {\n                location,\n                previous_location: *previous_location,\n                name: used_name.clone(),\n            });\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/analyse/name.rs",
    "content": "use std::sync::OnceLock;\n\nuse ecow::{EcoString, eco_format};\nuse regex::Regex;\n\nuse crate::{\n    ast::{ArgNames, SrcSpan},\n    strings::{to_snake_case, to_upper_camel_case},\n    type_::Problems,\n};\n\nuse super::{Error, Named};\n\nstatic VALID_NAME_PATTERN: OnceLock<Regex> = OnceLock::new();\n\nfn valid_name(name: &EcoString) -> bool {\n    // Some of the internally generated variables (such as `_capture` and `_use0`)\n    // start with underscores, so we allow underscores here.\n    let valid_name_pattern = VALID_NAME_PATTERN\n        .get_or_init(|| Regex::new(\"^_?[a-z][a-z0-9_]*$\").expect(\"Regex is correct\"));\n    valid_name_pattern.is_match(name)\n}\n\nstatic VALID_DISCARD_PATTERN: OnceLock<Regex> = OnceLock::new();\n\nfn valid_discard_name(name: &EcoString) -> bool {\n    let valid_discard_pattern = VALID_DISCARD_PATTERN\n        .get_or_init(|| Regex::new(\"^_[a-z0-9_]*$\").expect(\"Regex is correct\"));\n    valid_discard_pattern.is_match(name)\n}\n\nstatic VALID_UPNAME_PATTERN: OnceLock<Regex> = OnceLock::new();\n\nfn valid_upname(name: &EcoString) -> bool {\n    let valid_upname_pattern = VALID_UPNAME_PATTERN\n        .get_or_init(|| Regex::new(\"^[A-Z][A-Za-z0-9]*$\").expect(\"Regex is correct\"));\n    valid_upname_pattern.is_match(name)\n}\n\npub fn check_name_case(location: SrcSpan, name: &EcoString, kind: Named) -> Result<(), Error> {\n    let valid = match kind {\n        Named::Type | Named::TypeAlias | Named::CustomTypeVariant => valid_upname(name),\n        Named::Variable\n        | Named::TypeVariable\n        | Named::Argument\n        | Named::Label\n        | Named::Constant\n        | Named::Function => valid_name(name),\n        Named::Discard => valid_discard_name(name),\n    };\n\n    if valid {\n        return Ok(());\n    }\n\n    Err(Error::BadName {\n        location,\n        kind,\n        name: name.clone(),\n    })\n}\n\npub fn correct_name_case(name: &EcoString, kind: Named) -> EcoString {\n    match kind {\n        Named::Type | Named::TypeAlias | Named::CustomTypeVariant => to_upper_camel_case(name),\n        Named::Variable\n        | Named::TypeVariable\n        | Named::Argument\n        | Named::Label\n        | Named::Constant\n        | Named::Function => to_snake_case(name),\n        Named::Discard => eco_format!(\"_{}\", to_snake_case(name)),\n    }\n}\n\npub fn check_argument_names(names: &ArgNames, problems: &mut Problems) {\n    match names {\n        ArgNames::Discard { name, location } => {\n            if let Err(error) = check_name_case(*location, name, Named::Discard) {\n                problems.error(error);\n            }\n        }\n        ArgNames::LabelledDiscard {\n            label,\n            label_location,\n            name,\n            name_location,\n        } => {\n            if let Err(error) = check_name_case(*label_location, label, Named::Label) {\n                problems.error(error);\n            }\n            if let Err(error) = check_name_case(*name_location, name, Named::Discard) {\n                problems.error(error);\n            }\n        }\n        ArgNames::Named { name, location } => {\n            if let Err(error) = check_name_case(*location, name, Named::Argument) {\n                problems.error(error);\n            }\n        }\n        ArgNames::NamedLabelled {\n            name,\n            name_location,\n            label,\n            label_location,\n        } => {\n            if let Err(error) = check_name_case(*label_location, label, Named::Label) {\n                problems.error(error);\n            }\n            if let Err(error) = check_name_case(*name_location, name, Named::Argument) {\n                problems.error(error);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/analyse/tests.rs",
    "content": "use super::*;\n\n#[test]\nfn module_name_validation() {\n    assert!(validate_module_name(&\"dream\".into()).is_ok());\n\n    assert!(validate_module_name(&\"gleam\".into()).is_err());\n\n    assert!(validate_module_name(&\"gleam/ok\".into()).is_ok());\n\n    assert!(validate_module_name(&\"ok/gleam\".into()).is_ok());\n\n    assert!(validate_module_name(&\"type\".into()).is_err());\n\n    assert!(validate_module_name(&\"pub\".into()).is_err());\n\n    assert!(validate_module_name(&\"ok/type\".into()).is_err());\n\n    assert!(validate_module_name(&\"ok/pub\".into()).is_err());\n}\n"
  },
  {
    "path": "compiler-core/src/analyse.rs",
    "content": "mod imports;\npub mod name;\n\n#[cfg(test)]\nmod tests;\n\nuse crate::{\n    GLEAM_CORE_PACKAGE_NAME, STDLIB_PACKAGE_NAME,\n    ast::{\n        self, Arg, BitArrayOption, CustomType, DefinitionLocation, Function, GroupedDefinitions,\n        Import, ModuleConstant, Publicity, RecordConstructor, RecordConstructorArg, SrcSpan,\n        Statement, TypeAlias, TypeAst, TypeAstConstructor, TypeAstFn, TypeAstHole, TypeAstTuple,\n        TypeAstVar, TypedCustomType, TypedDefinitions, TypedExpr, TypedFunction, TypedImport,\n        TypedModule, TypedModuleConstant, TypedTypeAlias, UntypedArg, UntypedCustomType,\n        UntypedFunction, UntypedImport, UntypedModule, UntypedModuleConstant, UntypedStatement,\n        UntypedTypeAlias,\n    },\n    build::{Origin, Outcome, Target},\n    call_graph::{CallGraphNode, into_dependency_order},\n    config::PackageConfig,\n    dep_tree,\n    inline::{self, InlinableFunction},\n    line_numbers::LineNumbers,\n    parse::SpannedString,\n    reference::{EntityKind, ReferenceKind},\n    type_::{\n        self, AccessorsMap, Deprecation, FieldMap, ModuleInterface, Opaque, PatternConstructor,\n        RecordAccessor, References, Type, TypeAliasConstructor, TypeConstructor,\n        TypeValueConstructor, TypeValueConstructorField, TypeVariantConstructors, ValueConstructor,\n        ValueConstructorVariant, Warning,\n        environment::*,\n        error::{Error, FeatureKind, MissingAnnotation, Named, Problems, convert_unify_error},\n        expression::{ExprTyper, FunctionDefinition, Implementations, Purity},\n        fields::FieldMapBuilder,\n        hydrator::Hydrator,\n        prelude::*,\n    },\n    uid::UniqueIdGenerator,\n    warning::TypeWarningEmitter,\n};\nuse camino::Utf8PathBuf;\nuse ecow::{EcoString, eco_format};\nuse hexpm::version::Version;\nuse itertools::Itertools;\nuse name::{check_argument_names, check_name_case};\nuse std::{\n    collections::{HashMap, HashSet},\n    ops::Deref,\n    sync::{Arc, OnceLock},\n};\nuse vec1::Vec1;\n\nuse self::imports::Importer;\n\n#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]\npub enum Inferred<T> {\n    Known(T),\n    #[default]\n    Unknown,\n}\n\nimpl<T> Inferred<T> {\n    pub fn expect(self, message: &str) -> T {\n        match self {\n            Inferred::Known(value) => Some(value),\n            Inferred::Unknown => None,\n        }\n        .expect(message)\n    }\n\n    pub fn expect_ref(&self, message: &str) -> &T {\n        match self {\n            Inferred::Known(value) => Some(value),\n            Inferred::Unknown => None,\n        }\n        .expect(message)\n    }\n}\n\nimpl Inferred<PatternConstructor> {\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        match self {\n            Inferred::Known(value) => value.definition_location(),\n            Inferred::Unknown => None,\n        }\n    }\n\n    pub fn get_documentation(&self) -> Option<&str> {\n        match self {\n            Inferred::Known(value) => value.get_documentation(),\n            Inferred::Unknown => None,\n        }\n    }\n\n    pub fn field_map(&self) -> Option<&FieldMap> {\n        match self {\n            Inferred::Known(value) => value.field_map.as_ref(),\n            Inferred::Unknown => None,\n        }\n    }\n}\n\n/// How the compiler should treat target support.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum TargetSupport {\n    /// Target support is enfored, meaning if a function is found to not have an implementation for\n    /// the current target then an error is emitted and compilation halts.\n    ///\n    /// This is used when compiling the root package, with the exception of when using\n    /// `gleam run --module $module` to run a module from a dependency package, in which case we do\n    /// not want to error as the root package code isn't going to be run.\n    Enforced,\n    /// Target support is enfored, meaning if a function is found to not have an implementation for\n    /// the current target it will continue onwards and not generate any code for this function.\n    ///\n    /// This is used when compiling dependencies.\n    NotEnforced,\n}\n\nimpl TargetSupport {\n    /// Returns `true` if the target support is [`Enforced`].\n    ///\n    /// [`Enforced`]: TargetSupport::Enforced\n    #[must_use]\n    pub fn is_enforced(&self) -> bool {\n        match self {\n            Self::Enforced => true,\n            Self::NotEnforced => false,\n        }\n    }\n}\n\nimpl<T> From<Error> for Outcome<T, Vec1<Error>> {\n    fn from(error: Error) -> Self {\n        Outcome::TotalFailure(Vec1::new(error))\n    }\n}\n\n/// This struct is used to take the data required for analysis. It is used to\n/// construct the private ModuleAnalyzer which has this data plus any\n/// internal state.\n///\n#[derive(Debug)]\npub struct ModuleAnalyzerConstructor<'a, A> {\n    pub target: Target,\n    pub ids: &'a UniqueIdGenerator,\n    pub origin: Origin,\n    pub importable_modules: &'a im::HashMap<EcoString, ModuleInterface>,\n    pub warnings: &'a TypeWarningEmitter,\n    pub direct_dependencies: &'a HashMap<EcoString, A>,\n    pub dev_dependencies: &'a HashSet<EcoString>,\n    pub target_support: TargetSupport,\n    pub package_config: &'a PackageConfig,\n}\n\nimpl<A> ModuleAnalyzerConstructor<'_, A> {\n    /// Crawl the AST, annotating each node with the inferred type or\n    /// returning an error.\n    ///\n    pub fn infer_module(\n        self,\n        module: UntypedModule,\n        line_numbers: LineNumbers,\n        src_path: Utf8PathBuf,\n    ) -> Outcome<TypedModule, Vec1<Error>> {\n        ModuleAnalyzer {\n            target: self.target,\n            ids: self.ids,\n            origin: self.origin,\n            importable_modules: self.importable_modules,\n            warnings: self.warnings,\n            direct_dependencies: self.direct_dependencies,\n            dev_dependencies: self.dev_dependencies,\n            target_support: self.target_support,\n            package_config: self.package_config,\n            line_numbers,\n            src_path,\n            problems: Problems::new(),\n            value_names: HashMap::with_capacity(module.definitions.len()),\n            hydrators: HashMap::with_capacity(module.definitions.len()),\n            module_name: module.name.clone(),\n            inline_functions: HashMap::new(),\n            minimum_required_version: Version::new(0, 1, 0),\n        }\n        .infer_module(module)\n    }\n}\n\nstruct ModuleAnalyzer<'a, A> {\n    target: Target,\n    ids: &'a UniqueIdGenerator,\n    origin: Origin,\n    importable_modules: &'a im::HashMap<EcoString, ModuleInterface>,\n    warnings: &'a TypeWarningEmitter,\n    direct_dependencies: &'a HashMap<EcoString, A>,\n    dev_dependencies: &'a HashSet<EcoString>,\n    target_support: TargetSupport,\n    package_config: &'a PackageConfig,\n    line_numbers: LineNumbers,\n    src_path: Utf8PathBuf,\n    problems: Problems,\n    value_names: HashMap<EcoString, SrcSpan>,\n    hydrators: HashMap<EcoString, Hydrator>,\n    module_name: EcoString,\n\n    inline_functions: HashMap<EcoString, InlinableFunction>,\n\n    /// The minimum Gleam version required to compile the analysed module.\n    minimum_required_version: Version,\n}\n\nimpl<'a, A> ModuleAnalyzer<'a, A> {\n    pub fn infer_module(mut self, mut module: UntypedModule) -> Outcome<TypedModule, Vec1<Error>> {\n        if let Err(error) = validate_module_name(&self.module_name) {\n            return self.all_errors(error);\n        }\n\n        let documentation = std::mem::take(&mut module.documentation);\n        let env = EnvironmentArguments {\n            ids: self.ids.clone(),\n            current_package: self.package_config.name.clone(),\n            gleam_version: self\n                .package_config\n                .gleam_version\n                .clone()\n                .map(|version| version.into()),\n            current_module: self.module_name.clone(),\n            target: self.target,\n            importable_modules: self.importable_modules,\n            target_support: self.target_support,\n            current_origin: self.origin,\n            dev_dependencies: self.dev_dependencies,\n        }\n        .build();\n\n        let definitions = GroupedDefinitions::new(module.into_iter_definitions(self.target));\n\n        // Register any modules, types, and values being imported\n        // We process imports first so that anything imported can be referenced\n        // anywhere in the module.\n        let mut env = Importer::run(self.origin, env, &definitions.imports, &mut self.problems);\n\n        // Register types so they can be used in constructors and functions\n        // earlier in the module.\n        for type_ in &definitions.custom_types {\n            if let Err(error) = self.register_types_from_custom_type(type_, &mut env) {\n                return self.all_errors(error);\n            }\n        }\n\n        let sorted_aliases = match sorted_type_aliases(&definitions.type_aliases) {\n            Ok(sorted_aliases) => sorted_aliases,\n            Err(error) => return self.all_errors(error),\n        };\n        for type_alias in sorted_aliases {\n            self.register_type_alias(type_alias, &mut env);\n        }\n\n        for function in &definitions.functions {\n            self.register_value_from_function(function, &mut env);\n        }\n\n        // Infer the types of each statement in the module\n        let typed_imports = definitions\n            .imports\n            .into_iter()\n            .filter_map(|import| self.analyse_import(import, &env))\n            .collect_vec();\n\n        let typed_custom_types = definitions\n            .custom_types\n            .into_iter()\n            .filter_map(|custom_type| self.analyse_custom_type(custom_type, &mut env))\n            .collect_vec();\n\n        let typed_type_aliases = definitions\n            .type_aliases\n            .into_iter()\n            .map(|type_alias| analyse_type_alias(type_alias, &mut env))\n            .collect_vec();\n\n        // Sort functions and constants into dependency order for inference.\n        // Definitions that do not depend on other definitions are inferred\n        // first, then ones that depend on those, etc.\n        let mut typed_functions = Vec::with_capacity(definitions.functions.len());\n        let mut typed_constants = Vec::with_capacity(definitions.constants.len());\n        let definition_groups =\n            match into_dependency_order(definitions.functions, definitions.constants) {\n                Ok(definition_groups) => definition_groups,\n                Err(error) => return self.all_errors(error),\n            };\n\n        let mut working_constants = vec![];\n        let mut working_functions = vec![];\n        for group in definition_groups {\n            // A group may have multiple functions and constants that depend on\n            // each other by mutual reference.\n            for definition in group {\n                match definition {\n                    CallGraphNode::Function(function) => {\n                        working_functions.push(self.infer_function(function, &mut env))\n                    }\n                    CallGraphNode::ModuleConstant(constant) => {\n                        working_constants.push(self.infer_module_constant(constant, &mut env))\n                    }\n                };\n            }\n\n            // Now that the entire group has been inferred, generalise their types.\n            for inferred_constant in working_constants.drain(..) {\n                typed_constants.push(generalise_module_constant(\n                    inferred_constant,\n                    &mut env,\n                    &self.module_name,\n                ))\n            }\n            for inferred_function in working_functions.drain(..) {\n                typed_functions.push(generalise_function(\n                    inferred_function,\n                    &mut env,\n                    &self.module_name,\n                ));\n            }\n        }\n\n        let typed_definitions = TypedDefinitions {\n            imports: typed_imports,\n            constants: typed_constants,\n            custom_types: typed_custom_types,\n            type_aliases: typed_type_aliases,\n            functions: typed_functions,\n        };\n\n        // Generate warnings for unused items\n        let unused_definition_positions = env.handle_unused(&mut self.problems);\n\n        // Remove imported types and values to create the public interface\n        // Private types and values are retained so they can be used in the language\n        // server, but are filtered out when type checking to prevent using private\n        // items.\n        env.module_types\n            .retain(|_, info| info.module == self.module_name);\n\n        // Ensure no exported values have private types in their type signature\n        for value in env.module_values.values() {\n            self.check_for_type_leaks(value)\n        }\n\n        // Resolve deferred type variable aliases now that all unification is\n        // done and link chains are stable.\n        env.resolve_deferred_type_variable_aliases();\n\n        let Environment {\n            module_types: types,\n            module_types_constructors: types_constructors,\n            module_values: values,\n            accessors,\n            names: type_names,\n            module_type_aliases: type_aliases,\n            echo_found,\n            ..\n        } = env;\n\n        let is_internal = self\n            .package_config\n            .is_internal_module(self.module_name.as_str());\n\n        // We sort warnings and errors to ensure they are emitted in a\n        // deterministic order, making them easier to test and debug, and to\n        // make the output predictable.\n        self.problems.sort();\n\n        let warnings = self.problems.take_warnings();\n        for warning in &warnings {\n            // TODO: remove this clone\n            self.warnings.emit(warning.clone());\n        }\n\n        let module = ast::Module {\n            documentation: documentation.clone(),\n            name: self.module_name.clone(),\n            definitions: typed_definitions,\n            names: type_names,\n            unused_definition_positions,\n            type_info: ModuleInterface {\n                name: self.module_name,\n                types,\n                types_value_constructors: types_constructors,\n                values,\n                accessors,\n                origin: self.origin,\n                package: self.package_config.name.clone(),\n                is_internal,\n                line_numbers: self.line_numbers,\n                src_path: self.src_path,\n                warnings,\n                minimum_required_version: self.minimum_required_version,\n                type_aliases,\n                documentation,\n                contains_echo: echo_found,\n                references: References {\n                    imported_modules: env\n                        .imported_modules\n                        .values()\n                        .map(|(_location, module)| module.name.clone())\n                        .collect(),\n                    value_references: env.references.value_references,\n                    type_references: env.references.type_references,\n                },\n                inline_functions: self.inline_functions,\n            },\n        };\n\n        match Vec1::try_from_vec(self.problems.take_errors()) {\n            Err(_) => Outcome::Ok(module),\n            Ok(errors) => Outcome::PartialFailure(module, errors),\n        }\n    }\n\n    fn all_errors<T>(&mut self, error: Error) -> Outcome<T, Vec1<Error>> {\n        Outcome::TotalFailure(Vec1::from_vec_push(self.problems.take_errors(), error))\n    }\n\n    fn infer_module_constant(\n        &mut self,\n        c: UntypedModuleConstant,\n        environment: &mut Environment<'_>,\n    ) -> TypedModuleConstant {\n        let ModuleConstant {\n            documentation: doc,\n            location,\n            name,\n            name_location,\n            annotation,\n            publicity,\n            value,\n            deprecation,\n            ..\n        } = c;\n        self.check_name_case(name_location, &name, Named::Constant);\n        // If the constant's name matches an unqualified import, emit a warning:\n        self.check_shadow_import(&name, c.location, environment);\n\n        environment.references.begin_constant();\n\n        let definition = FunctionDefinition {\n            has_body: true,\n            has_erlang_external: false,\n            has_javascript_external: false,\n        };\n        let mut expr_typer = ExprTyper::new(environment, definition, &mut self.problems);\n        let typed_expr = expr_typer.infer_const(&annotation, *value);\n        let type_ = typed_expr.type_();\n        let implementations = expr_typer.implementations;\n\n        let minimum_required_version = expr_typer.minimum_required_version;\n        if minimum_required_version > self.minimum_required_version {\n            self.minimum_required_version = minimum_required_version;\n        }\n\n        match publicity {\n            Publicity::Private\n            | Publicity::Public\n            | Publicity::Internal {\n                attribute_location: None,\n            } => (),\n\n            Publicity::Internal {\n                attribute_location: Some(location),\n            } => self.track_feature_usage(FeatureKind::InternalAnnotation, location),\n        }\n\n        let variant = ValueConstructor {\n            publicity,\n            deprecation: deprecation.clone(),\n            variant: ValueConstructorVariant::ModuleConstant {\n                documentation: doc.as_ref().map(|(_, doc)| doc.clone()),\n                location,\n                literal: typed_expr.clone(),\n                module: self.module_name.clone(),\n                name: name.clone(),\n                implementations,\n            },\n            type_: type_.clone(),\n        };\n\n        environment.insert_variable(\n            name.clone(),\n            variant.variant.clone(),\n            type_.clone(),\n            publicity,\n            Deprecation::NotDeprecated,\n        );\n        environment.insert_module_value(name.clone(), variant);\n\n        environment\n            .references\n            .register_constant(name.clone(), location, publicity);\n\n        environment.references.register_value_reference(\n            environment.current_module.clone(),\n            name.clone(),\n            &name,\n            name_location,\n            ReferenceKind::Definition,\n        );\n\n        ModuleConstant {\n            documentation: doc,\n            location,\n            name,\n            name_location,\n            annotation,\n            publicity,\n            value: Box::new(typed_expr),\n            type_,\n            deprecation,\n            implementations,\n        }\n    }\n\n    // TODO: Extract this into a class of its own! Or perhaps it just wants some\n    // helper methods extracted. There's a whole bunch of state in this one\n    // function, and it does a handful of things.\n    fn infer_function(\n        &mut self,\n        f: UntypedFunction,\n        environment: &mut Environment<'_>,\n    ) -> TypedFunction {\n        let Function {\n            documentation: doc,\n            location,\n            name,\n            publicity,\n            arguments,\n            body,\n            body_start,\n            return_annotation,\n            end_position: end_location,\n            deprecation,\n            external_erlang,\n            external_javascript,\n            return_type: (),\n            implementations: _,\n            purity: _,\n        } = f;\n        let (name_location, name) = name.expect(\"Function in a definition must be named\");\n        let target = environment.target;\n        let body_location = body\n            .last()\n            .map(|statement| statement.location())\n            .unwrap_or(location);\n        let preregistered_fn = environment\n            .get_variable(&name)\n            .expect(\"Could not find preregistered type for function\");\n        let field_map = preregistered_fn.field_map().cloned();\n        let preregistered_type = preregistered_fn.type_.clone();\n        let (prereg_arguments_types, prereg_return_type) = preregistered_type\n            .fn_types()\n            .expect(\"Preregistered type for fn was not a fn\");\n\n        // Ensure that folks are not writing inline JavaScript expressions as\n        // the implementation for JS externals.\n        self.assert_valid_javascript_external(&name, external_javascript.as_ref(), location);\n\n        // Find the external implementation for the current target, if one has been given.\n        let external =\n            target_function_implementation(target, &external_erlang, &external_javascript);\n\n        // The function must have at least one implementation somewhere.\n        let has_implementation = self.ensure_function_has_an_implementation(\n            &body,\n            &external_erlang,\n            &external_javascript,\n            location,\n        );\n\n        if external.is_some() {\n            // There was an external implementation, so type annotations are\n            // mandatory as the Gleam implementation may be absent, and because we\n            // think you should always specify types for external functions for\n            // clarity + to avoid accidental mistakes.\n            self.ensure_annotations_present(&arguments, return_annotation.as_ref(), location);\n        }\n\n        let has_body = !body.is_empty();\n        let definition = FunctionDefinition {\n            has_body,\n            has_erlang_external: external_erlang.is_some(),\n            has_javascript_external: external_javascript.is_some(),\n        };\n\n        // We have already registered the function in the `register_value_from_function`\n        // method, but here we must set this as the current function again, so that anything\n        // we reference in the body of it can be tracked properly in the call graph.\n        environment.references.set_current_node(name.clone());\n\n        let mut typed_arguments = Vec::with_capacity(arguments.len());\n\n        // Infer the type using the preregistered args + return types as a starting point\n        let result = environment.in_new_scope(&mut self.problems, |environment, problems| {\n            for (argument, type_) in arguments.into_iter().zip(&prereg_arguments_types) {\n                let argument = argument.set_type(type_.clone());\n\n                // We track which arguments are discarded so we can provide nice\n                // error messages when someone\n                match &argument.names {\n                    ast::ArgNames::Named { .. } | ast::ArgNames::NamedLabelled { .. } => (),\n                    ast::ArgNames::Discard { name, location }\n                    | ast::ArgNames::LabelledDiscard {\n                        name,\n                        name_location: location,\n                        ..\n                    } => {\n                        let _ = environment.discarded_names.insert(name.clone(), *location);\n                    }\n                }\n\n                typed_arguments.push(argument);\n            }\n\n            let mut expr_typer = ExprTyper::new(environment, definition, problems);\n            expr_typer.hydrator = self\n                .hydrators\n                .remove(&name)\n                .expect(\"Could not find hydrator for fn\");\n\n            let (arguments, body) = expr_typer.infer_fn_with_known_types(\n                Some(name.clone()),\n                typed_arguments.clone(),\n                body,\n                Some(prereg_return_type.clone()),\n            )?;\n            let arguments_types = arguments.iter().map(|a| a.type_.clone()).collect();\n            let return_type = body\n                .last()\n                .map_or(prereg_return_type.clone(), |last| last.type_());\n\n            // `dict.do_fold` is a bit special: since it belongs to the stdlib\n            // it is considered pure by default.\n            // However, since it ends up calling its function argument its\n            // purity should actually be `Impure`. We need to special case it\n            // and set the value ourselves.\n            //\n            // You might wonder why `do_fold` needs this but other similar\n            // functions like `list.each` don't need this special handling.\n            // The key difference is `list.each` calls the higher order function\n            // in its gleam body:\n            //\n            // ```gleam\n            // fn each(list, fun) {\n            //   case list {\n            //     [] -> Nil\n            //     [first, ..rest] -> {\n            //       fun(first)\n            //       // ^^^ Here we're calling `fun`. It's happening in Gleam so\n            //       //     the compiler can see this and understand that `each`\n            //       //     is impure.\n            //       //     You might argue the purity actually depends on the\n            //       //     purity of `fun` itself. That's true! But it's a\n            //       //     separate known problem. For the time being we always\n            //       //     assume a function argument is impure.\n            //       each(rest, fun)\n            //     }\n            //   }\n            // }\n            // ```\n            //\n            // But since `do_fold` is an external the compiler can't know what\n            // is going on with its function argument and keeps thinking it must\n            // be pure\n            //\n            // ```gleam\n            // @external(erlang, \"\", \"\")\n            // fn do_fold(dict: Dict(k, v), fun: fn(k, v) -> a) -> Nil\n            // ```\n            //\n            let purity = if expr_typer.environment.current_package == STDLIB_PACKAGE_NAME\n                && expr_typer.environment.current_module == \"gleam/dict\"\n                && name == \"do_fold\"\n            {\n                Purity::Impure\n            } else {\n                expr_typer.purity\n            };\n\n            let type_ = fn_(arguments_types, return_type);\n            Ok((\n                type_,\n                body,\n                expr_typer.implementations,\n                expr_typer.minimum_required_version,\n                purity,\n            ))\n        });\n\n        // If we could not successfully infer the type etc information of the\n        // function then register the error and continue anaylsis using the best\n        // information that we have, so we can still learn about the rest of the\n        // module.\n        let (type_, body, implementations, required_version, purity) = match result {\n            Ok((type_, body, implementations, required_version, purity)) => {\n                (type_, body, implementations, required_version, purity)\n            }\n            Err(error) => {\n                self.problems.error(error);\n                let type_ = preregistered_type.clone();\n                let body = vec![Statement::Expression(TypedExpr::Invalid {\n                    type_: prereg_return_type.clone(),\n                    location: SrcSpan {\n                        start: body_location.end,\n                        end: body_location.end,\n                    },\n                    extra_information: None,\n                })];\n                let implementations = Implementations::supporting_all();\n                (\n                    type_,\n                    body,\n                    implementations,\n                    Version::new(1, 0, 0),\n                    Purity::Impure,\n                )\n            }\n        };\n\n        if required_version > self.minimum_required_version {\n            self.minimum_required_version = required_version;\n        }\n\n        match publicity {\n            Publicity::Private\n            | Publicity::Public\n            | Publicity::Internal {\n                attribute_location: None,\n            } => (),\n\n            Publicity::Internal {\n                attribute_location: Some(location),\n            } => self.track_feature_usage(FeatureKind::InternalAnnotation, location),\n        }\n\n        if let Some((module, _, location)) = &external_javascript\n            && module.contains('@')\n        {\n            self.track_feature_usage(FeatureKind::AtInJavascriptModules, *location)\n        }\n\n        // Assert that the inferred type matches the type of any recursive call\n        if let Err(error) = unify(preregistered_type.clone(), type_) {\n            self.problems.error(convert_unify_error(error, location));\n        }\n\n        // Ensure that the current target has an implementation for the function.\n        // This is done at the expression level while inferring the function body, but we do it again\n        // here as externally implemented functions may not have a Gleam body.\n        //\n        // We don't emit this error if there is no implementation, as this would\n        // have already emitted an error above.\n        if has_implementation\n            && publicity.is_importable()\n            && environment.target_support.is_enforced()\n            && !implementations.supports(target)\n            // We don't emit this error if there is a body\n            // since this would be caught at the statement level\n            && !has_body\n        {\n            self.problems.error(Error::UnsupportedPublicFunctionTarget {\n                name: name.clone(),\n                target,\n                location,\n            });\n        }\n\n        let variant = ValueConstructorVariant::ModuleFn {\n            documentation: doc.as_ref().map(|(_, doc)| doc.clone()),\n            name: name.clone(),\n            external_erlang: external_erlang\n                .as_ref()\n                .map(|(m, f, _)| (m.clone(), f.clone())),\n            external_javascript: external_javascript\n                .as_ref()\n                .map(|(m, f, _)| (m.clone(), f.clone())),\n            field_map,\n            module: environment.current_module.clone(),\n            arity: typed_arguments.len(),\n            location,\n            implementations,\n            purity,\n        };\n\n        environment.insert_variable(\n            name.clone(),\n            variant,\n            preregistered_type.clone(),\n            publicity,\n            deprecation.clone(),\n        );\n\n        environment.references.register_value_reference(\n            environment.current_module.clone(),\n            name.clone(),\n            &name,\n            name_location,\n            ReferenceKind::Definition,\n        );\n\n        let function = Function {\n            documentation: doc,\n            location,\n            name: Some((name_location, name.clone())),\n            publicity,\n            deprecation,\n            arguments: typed_arguments,\n            body_start,\n            end_position: end_location,\n            return_annotation,\n            return_type: preregistered_type\n                .return_type()\n                .expect(\"Could not find return type for fn\"),\n            body,\n            external_erlang,\n            external_javascript,\n            implementations,\n            purity,\n        };\n\n        if let Some(inline_function) = inline::function_to_inlinable(\n            &environment.current_package,\n            &environment.current_module,\n            &function,\n        ) {\n            _ = self.inline_functions.insert(name, inline_function);\n        }\n\n        function\n    }\n\n    fn assert_valid_javascript_external(\n        &mut self,\n        function_name: &EcoString,\n        external_javascript: Option<&(EcoString, EcoString, SrcSpan)>,\n        location: SrcSpan,\n    ) {\n        use regex::Regex;\n\n        static MODULE: OnceLock<Regex> = OnceLock::new();\n        static FUNCTION: OnceLock<Regex> = OnceLock::new();\n\n        let (module, function) = match external_javascript {\n            None => return,\n            Some((module, function, _location)) => (module, function),\n        };\n        if !MODULE\n            .get_or_init(|| Regex::new(\"^[@a-zA-Z0-9\\\\./:_-]+$\").expect(\"regex\"))\n            .is_match(module)\n        {\n            self.problems.error(Error::InvalidExternalJavascriptModule {\n                location,\n                module: module.clone(),\n                name: function_name.clone(),\n            });\n        }\n        if !FUNCTION\n            .get_or_init(|| Regex::new(\"^[a-zA-Z_][a-zA-Z0-9_]*$\").expect(\"regex\"))\n            .is_match(function)\n        {\n            self.problems\n                .error(Error::InvalidExternalJavascriptFunction {\n                    location,\n                    function: function.clone(),\n                    name: function_name.clone(),\n                });\n        }\n    }\n\n    fn ensure_annotations_present(\n        &mut self,\n        arguments: &[UntypedArg],\n        return_annotation: Option<&TypeAst>,\n        location: SrcSpan,\n    ) {\n        for arg in arguments {\n            if arg.annotation.is_none() {\n                self.problems.error(Error::ExternalMissingAnnotation {\n                    location: arg.location,\n                    kind: MissingAnnotation::Parameter,\n                });\n            }\n        }\n        if return_annotation.is_none() {\n            self.problems.error(Error::ExternalMissingAnnotation {\n                location,\n                kind: MissingAnnotation::Return,\n            });\n        }\n    }\n\n    fn ensure_function_has_an_implementation(\n        &mut self,\n        body: &[UntypedStatement],\n        external_erlang: &Option<(EcoString, EcoString, SrcSpan)>,\n        external_javascript: &Option<(EcoString, EcoString, SrcSpan)>,\n        location: SrcSpan,\n    ) -> bool {\n        match (external_erlang, external_javascript) {\n            (None, None) if body.is_empty() => {\n                self.problems.error(Error::NoImplementation { location });\n                false\n            }\n            _ => true,\n        }\n    }\n\n    fn analyse_import(\n        &mut self,\n        i: UntypedImport,\n        environment: &Environment<'_>,\n    ) -> Option<TypedImport> {\n        let Import {\n            documentation,\n            location,\n            module_location,\n            module,\n            as_name,\n            unqualified_values,\n            unqualified_types,\n            ..\n        } = i;\n        // Find imported module\n        let Some(module_info) = environment.importable_modules.get(&module) else {\n            // Here the module being imported doesn't exist. We don't emit an\n            // error here as the `Importer` that was run earlier will have\n            // already emitted an error for this.\n            return None;\n        };\n\n        // Modules should belong to a package that is a direct dependency of the\n        // current package to be imported.\n        // Upgrade this to an error in future.\n        if module_info.package != GLEAM_CORE_PACKAGE_NAME\n            && module_info.package != self.package_config.name\n            && !self.direct_dependencies.contains_key(&module_info.package)\n        {\n            self.warnings.emit(Warning::TransitiveDependencyImported {\n                location,\n                module: module_info.name.clone(),\n                package: module_info.package.clone(),\n            })\n        }\n\n        Some(Import {\n            documentation,\n            location,\n            module_location,\n            module,\n            as_name,\n            unqualified_values,\n            unqualified_types,\n            package: module_info.package.clone(),\n        })\n    }\n\n    fn analyse_custom_type(\n        &mut self,\n        t: UntypedCustomType,\n        environment: &mut Environment<'_>,\n    ) -> Option<TypedCustomType> {\n        match self.do_analyse_custom_type(t, environment) {\n            Ok(custom_type) => Some(custom_type),\n            Err(error) => {\n                self.problems.error(error);\n                None\n            }\n        }\n    }\n\n    // TODO: split this into a new class.\n    fn do_analyse_custom_type(\n        &mut self,\n        t: UntypedCustomType,\n        environment: &mut Environment<'_>,\n    ) -> Result<TypedCustomType, Error> {\n        self.register_values_from_custom_type(\n            &t,\n            environment,\n            &t.parameters.iter().map(|(_, name)| name).collect_vec(),\n        )?;\n\n        let CustomType {\n            documentation: doc,\n            location,\n            end_position,\n            publicity,\n            opaque,\n            name,\n            name_location,\n            parameters,\n            constructors,\n            deprecation,\n            external_erlang,\n            external_javascript,\n            ..\n        } = t;\n\n        match publicity {\n            Publicity::Private\n            | Publicity::Public\n            | Publicity::Internal {\n                attribute_location: None,\n            } => (),\n\n            Publicity::Internal {\n                attribute_location: Some(location),\n            } => self.track_feature_usage(FeatureKind::InternalAnnotation, location),\n        }\n\n        let constructors: Vec<RecordConstructor<Arc<Type>>> = constructors\n            .into_iter()\n            .map(\n                |RecordConstructor {\n                     location,\n                     name_location,\n                     name,\n                     arguments,\n                     documentation,\n                     deprecation: constructor_deprecation,\n                 }| {\n                    self.check_name_case(name_location, &name, Named::CustomTypeVariant);\n                    if constructor_deprecation.is_deprecated() {\n                        self.track_feature_usage(\n                            FeatureKind::VariantWithDeprecatedAnnotation,\n                            location,\n                        );\n                    }\n\n                    let preregistered_fn = environment\n                        .get_variable(&name)\n                        .expect(\"Could not find preregistered type for function\");\n                    let preregistered_type = preregistered_fn.type_.clone();\n\n                    let arguments = match preregistered_type.fn_types() {\n                        Some((arguments_types, _return_type)) => arguments\n                            .into_iter()\n                            .zip(&arguments_types)\n                            .map(|(argument, type_)| {\n                                if let Some((location, label)) = &argument.label {\n                                    self.check_name_case(*location, label, Named::Label);\n                                }\n\n                                RecordConstructorArg {\n                                    label: argument.label,\n                                    ast: argument.ast,\n                                    location: argument.location,\n                                    type_: type_.clone(),\n                                    doc: argument.doc,\n                                }\n                            })\n                            .collect(),\n                        _ => {\n                            vec![]\n                        }\n                    };\n\n                    RecordConstructor {\n                        location,\n                        name_location,\n                        name,\n                        arguments,\n                        documentation,\n                        deprecation: constructor_deprecation,\n                    }\n                },\n            )\n            .collect();\n        let typed_parameters = environment\n            .get_type_constructor(&None, &name)\n            .expect(\"Could not find preregistered type constructor\")\n            .parameters\n            .clone();\n\n        // Check if all constructors are deprecated if so error.\n        if !constructors.is_empty()\n            && constructors\n                .iter()\n                .all(|record| record.deprecation.is_deprecated())\n        {\n            self.problems\n                .error(Error::AllVariantsDeprecated { location });\n        }\n\n        // If any constructor record/varient is deprecated while\n        // the type is deprecated as a whole that is considered an error.\n        if deprecation.is_deprecated()\n            && !constructors.is_empty()\n            && constructors\n                .iter()\n                .any(|record| record.deprecation.is_deprecated())\n        {\n            // Report error on all variants attibuted with deprecated\n            constructors\n                .iter()\n                .filter(|record| record.deprecation.is_deprecated())\n                .for_each(|record| {\n                    self.problems\n                        .error(Error::DeprecatedVariantOnDeprecatedType {\n                            location: record.location,\n                        });\n                });\n        }\n\n        if external_erlang.is_some() || external_javascript.is_some() {\n            self.track_feature_usage(FeatureKind::ExternalCustomType, location);\n\n            if !constructors.is_empty() {\n                self.problems\n                    .error(Error::ExternalTypeWithConstructors { location });\n            }\n        }\n\n        Ok(CustomType {\n            documentation: doc,\n            location,\n            end_position,\n            publicity,\n            opaque,\n            name,\n            name_location,\n            parameters,\n            constructors,\n            typed_parameters,\n            deprecation,\n            external_erlang,\n            external_javascript,\n        })\n    }\n\n    fn register_values_from_custom_type(\n        &mut self,\n        t: &UntypedCustomType,\n        environment: &mut Environment<'_>,\n        type_parameters: &[&EcoString],\n    ) -> Result<(), Error> {\n        let CustomType {\n            publicity,\n            opaque,\n            name,\n            constructors,\n            deprecation,\n            ..\n        } = t;\n\n        let mut hydrator = self\n            .hydrators\n            .remove(name)\n            .expect(\"Could not find hydrator for register_values custom type\");\n        hydrator.disallow_new_type_variables();\n        let type_ = environment\n            .module_types\n            .get(name)\n            .expect(\"Type for custom type not found in register_values\")\n            .type_\n            .clone();\n\n        let mut constructors_data = vec![];\n\n        let mut index = 0;\n        for constructor in constructors.iter() {\n            if let Err(error) = assert_unique_name(\n                &mut self.value_names,\n                &constructor.name,\n                constructor.location,\n            ) {\n                self.problems.error(error);\n                continue;\n            }\n\n            // If the constructor belongs to an opaque type then it's going to be\n            // considered as private.\n            let value_constructor_publicity = if *opaque {\n                Publicity::Private\n            } else {\n                *publicity\n            };\n\n            environment.references.register_value(\n                constructor.name.clone(),\n                EntityKind::Constructor,\n                constructor.location,\n                value_constructor_publicity,\n            );\n\n            environment\n                .references\n                .register_type_reference_in_call_graph(name.clone());\n\n            let mut field_map_builder = FieldMapBuilder::new(constructor.arguments.len() as u32);\n            let mut arguments_types = Vec::with_capacity(constructor.arguments.len());\n            let mut fields = Vec::with_capacity(constructor.arguments.len());\n\n            for RecordConstructorArg {\n                label,\n                ast,\n                location,\n                doc,\n                ..\n            } in constructor.arguments.iter()\n            {\n                // Build a type from the annotation AST\n                let t = match hydrator.type_from_ast(ast, environment, &mut self.problems) {\n                    Ok(t) => t,\n                    Err(e) => {\n                        self.problems.error(e);\n                        environment.new_unbound_var()\n                    }\n                };\n\n                fields.push(TypeValueConstructorField {\n                    type_: t.clone(),\n                    label: label.as_ref().map(|(_location, label)| label.clone()),\n                    documentation: doc.as_ref().map(|(_, documentation)| documentation.clone()),\n                });\n\n                // Register the type for this parameter\n                arguments_types.push(t);\n\n                let (label_location, label) = match label {\n                    Some((location, label)) => (*location, Some(label)),\n                    None => (*location, None),\n                };\n\n                // Register the label for this parameter\n                if let Err(error) = field_map_builder.add(label, label_location) {\n                    self.problems.error(error);\n                }\n            }\n            let field_map = field_map_builder.finish();\n            // Insert constructor function into module scope\n            let mut type_ = type_.deref().clone();\n            type_.set_custom_type_variant(index as u16);\n            let type_ = match constructor.arguments.len() {\n                0 => Arc::new(type_),\n                _ => fn_(arguments_types.clone(), Arc::new(type_)),\n            };\n            let constructor_info = ValueConstructorVariant::Record {\n                documentation: constructor\n                    .documentation\n                    .as_ref()\n                    .map(|(_, doc)| doc.clone()),\n                variants_count: constructors.len() as u16,\n                name: constructor.name.clone(),\n                arity: constructor.arguments.len() as u16,\n                field_map: field_map.clone(),\n                location: constructor.location,\n                module: self.module_name.clone(),\n                variant_index: index as u16,\n            };\n            index += 1;\n\n            // If the whole custom type is deprecated all of its varints are too.\n            // Otherwise just the varint(s) attributed as deprecated are.\n            let deprecate_constructor = if deprecation.is_deprecated() {\n                deprecation\n            } else {\n                &constructor.deprecation\n            };\n\n            environment.insert_module_value(\n                constructor.name.clone(),\n                ValueConstructor {\n                    publicity: value_constructor_publicity,\n                    deprecation: deprecate_constructor.clone(),\n                    type_: type_.clone(),\n                    variant: constructor_info.clone(),\n                },\n            );\n\n            environment.references.register_value_reference(\n                environment.current_module.clone(),\n                constructor.name.clone(),\n                &constructor.name,\n                constructor.name_location,\n                ReferenceKind::Definition,\n            );\n\n            constructors_data.push(TypeValueConstructor {\n                name: constructor.name.clone(),\n                parameters: fields,\n                documentation: constructor\n                    .documentation\n                    .as_ref()\n                    .map(|(_, documentation)| documentation.clone()),\n            });\n            environment.insert_variable(\n                constructor.name.clone(),\n                constructor_info,\n                type_,\n                value_constructor_publicity,\n                deprecate_constructor.clone(),\n            );\n\n            environment.names.named_constructor_in_scope(\n                environment.current_module.clone(),\n                constructor.name.clone(),\n                constructor.name.clone(),\n            );\n        }\n\n        let Accessors {\n            shared_accessors,\n            variant_specific_accessors,\n            positional_accessors,\n        } = custom_type_accessors(&constructors_data)?;\n\n        let map = AccessorsMap {\n            publicity: if *opaque {\n                Publicity::Private\n            } else {\n                *publicity\n            },\n            shared_accessors,\n            // TODO: improve the ownership here so that we can use the\n            // `return_type_constructor` below rather than looking it up twice.\n            type_: type_.clone(),\n            variant_specific_accessors,\n            variant_positional_accessors: positional_accessors,\n        };\n        environment.insert_accessors(name.clone(), map);\n\n        let opaque = if *opaque {\n            Opaque::Opaque\n        } else {\n            Opaque::NotOpaque\n        };\n        // Now record the constructors for the type.\n        environment.insert_type_to_constructors(\n            name.clone(),\n            TypeVariantConstructors::new(constructors_data, type_parameters, opaque, hydrator),\n        );\n\n        Ok(())\n    }\n\n    fn register_types_from_custom_type(\n        &mut self,\n        t: &UntypedCustomType,\n        environment: &mut Environment<'a>,\n    ) -> Result<(), Error> {\n        let CustomType {\n            name,\n            name_location,\n            publicity,\n            parameters,\n            location,\n            deprecation,\n            opaque,\n            constructors,\n            documentation,\n            ..\n        } = t;\n        // We exit early here as we don't yet have a good way to handle the two\n        // duplicate definitions in the later pass of the analyser which\n        // register the constructor values for the types. The latter would end up\n        // overwriting the former, but here in type registering we keep the\n        // former. I think we want to really keep the former both times.\n        // The fact we can't straightforwardly do this indicated to me that we\n        // could improve our approach here somewhat.\n        environment.assert_unique_type_name(name, *location)?;\n\n        self.check_name_case(*name_location, name, Named::Type);\n\n        let mut hydrator = Hydrator::new();\n        let parameters = self.make_type_vars(parameters, &mut hydrator, environment);\n\n        hydrator.clear_ridgid_type_names();\n\n        // We check is the type comes from an internal module and restrict its\n        // publicity.\n        let publicity = match publicity {\n            // It's important we only restrict the publicity of public types.\n            Publicity::Public if self.package_config.is_internal_module(&self.module_name) => {\n                Publicity::Internal {\n                    attribute_location: None,\n                }\n            }\n            // If a type is private we don't want to make it internal just because\n            // it comes from an internal module, so in that case the publicity is\n            // left unchanged.\n            Publicity::Public | Publicity::Private | Publicity::Internal { .. } => *publicity,\n        };\n\n        let type_ = Arc::new(Type::Named {\n            publicity,\n            package: environment.current_package.clone(),\n            module: self.module_name.to_owned(),\n            name: name.clone(),\n            arguments: parameters.clone(),\n            inferred_variant: None,\n        });\n        let _ = self.hydrators.insert(name.clone(), hydrator);\n        environment\n            .insert_type_constructor(\n                name.clone(),\n                TypeConstructor {\n                    origin: *location,\n                    module: self.module_name.clone(),\n                    deprecation: deprecation.clone(),\n                    parameters,\n                    publicity,\n                    type_,\n                    documentation: documentation.as_ref().map(|(_, doc)| doc.clone()),\n                },\n            )\n            .expect(\"name uniqueness checked above\");\n\n        environment.names.named_type_in_scope(\n            environment.current_module.clone(),\n            name.clone(),\n            name.clone(),\n        );\n\n        environment\n            .references\n            .register_type(name.clone(), EntityKind::Type, *location, publicity);\n\n        environment.references.register_type_reference(\n            environment.current_module.clone(),\n            name.clone(),\n            name,\n            *name_location,\n            ReferenceKind::Definition,\n        );\n\n        if *opaque && constructors.is_empty() {\n            self.problems.warning(Warning::OpaqueExternalType {\n                location: *location,\n            });\n        }\n\n        if *opaque && publicity.is_private() {\n            self.problems.error(Error::PrivateOpaqueType {\n                location: SrcSpan {\n                    start: location.start,\n                    end: location.start + 6,\n                },\n            });\n        }\n\n        Ok(())\n    }\n\n    fn register_type_alias(&mut self, t: &UntypedTypeAlias, environment: &mut Environment<'_>) {\n        let TypeAlias {\n            location,\n            publicity,\n            parameters: arguments,\n            alias: name,\n            name_location,\n            type_ast: resolved_type,\n            deprecation,\n            type_: _,\n            documentation,\n        } = t;\n\n        // A type alias must not have the same name as any other type in the module.\n        if let Err(error) = environment.assert_unique_type_name(name, *location) {\n            self.problems.error(error);\n            // A type already exists with the name so we cannot continue and\n            // register this new type with the same name.\n            return;\n        }\n\n        self.check_name_case(*name_location, name, Named::TypeAlias);\n\n        environment\n            .references\n            .register_type(name.clone(), EntityKind::Type, *location, *publicity);\n\n        // Use the hydrator to convert the AST into a type, erroring if the AST was invalid\n        // in some fashion.\n        let mut hydrator = Hydrator::new();\n        let parameters = self.make_type_vars(arguments, &mut hydrator, environment);\n        let arity = parameters.len();\n        let tryblock = || {\n            hydrator.disallow_new_type_variables();\n            let type_ = hydrator.type_from_ast(resolved_type, environment, &mut self.problems)?;\n\n            environment\n                .names\n                .type_in_scope(name.clone(), type_.as_ref(), &parameters);\n\n            // Insert the alias so that it can be used by other code.\n            environment.insert_type_constructor(\n                name.clone(),\n                TypeConstructor {\n                    origin: *location,\n                    module: self.module_name.clone(),\n                    parameters: parameters.clone(),\n                    type_: type_.clone(),\n                    deprecation: deprecation.clone(),\n                    publicity: *publicity,\n                    documentation: documentation.as_ref().map(|(_, doc)| doc.clone()),\n                },\n            )?;\n\n            let alias = TypeAliasConstructor {\n                origin: *location,\n                module: self.module_name.clone(),\n                type_,\n                publicity: *publicity,\n                deprecation: deprecation.clone(),\n                documentation: documentation.as_ref().map(|(_, doc)| doc.clone()),\n                arity,\n                parameters,\n            };\n\n            environment.names.maybe_register_reexport_alias(\n                &environment.current_package,\n                name,\n                &alias,\n            );\n\n            environment.insert_type_alias(name.clone(), alias)?;\n\n            if let Some(name) = hydrator.unused_type_variables().next() {\n                return Err(Error::UnusedTypeAliasParameter {\n                    location: *location,\n                    name: name.clone(),\n                });\n            }\n\n            Ok(())\n        };\n        let result = tryblock();\n        self.record_if_error(result);\n    }\n\n    fn make_type_vars(\n        &mut self,\n        arguments: &[SpannedString],\n        hydrator: &mut Hydrator,\n        environment: &mut Environment<'_>,\n    ) -> Vec<Arc<Type>> {\n        arguments\n            .iter()\n            .map(|(location, name)| {\n                self.check_name_case(*location, name, Named::TypeVariable);\n                match hydrator.add_type_variable(name, environment) {\n                    Ok(t) => t,\n                    Err(t) => {\n                        self.problems.error(Error::DuplicateTypeParameter {\n                            location: *location,\n                            name: name.clone(),\n                        });\n                        t\n                    }\n                }\n            })\n            .collect()\n    }\n\n    fn record_if_error(&mut self, result: Result<(), Error>) {\n        if let Err(error) = result {\n            self.problems.error(error);\n        }\n    }\n\n    fn register_value_from_function(\n        &mut self,\n        f: &UntypedFunction,\n        environment: &mut Environment<'_>,\n    ) {\n        let Function {\n            name,\n            arguments,\n            location,\n            return_annotation,\n            publicity,\n            documentation,\n            external_erlang,\n            external_javascript,\n            deprecation,\n            end_position: _,\n            body: _,\n            body_start: _,\n            return_type: _,\n            implementations,\n            purity,\n        } = f;\n        let (name_location, name) = name.as_ref().expect(\"A module's function must be named\");\n\n        self.check_name_case(*name_location, name, Named::Function);\n        // If the function's name matches an unqualified import, emit a warning:\n        self.check_shadow_import(name, f.location, environment);\n\n        environment.references.register_value(\n            name.clone(),\n            EntityKind::Function,\n            *location,\n            *publicity,\n        );\n\n        let mut builder = FieldMapBuilder::new(arguments.len() as u32);\n        for Arg {\n            names, location, ..\n        } in arguments.iter()\n        {\n            check_argument_names(names, &mut self.problems);\n\n            if let Err(error) = builder.add(names.get_label(), *location) {\n                self.problems.error(error);\n            }\n        }\n        let field_map = builder.finish();\n        let mut hydrator = Hydrator::new();\n\n        // When external implementations are present then the type annotations\n        // must be given in full, so we disallow holes in the annotations.\n        hydrator.permit_holes(external_erlang.is_none() && external_javascript.is_none());\n\n        let arguments_types = arguments\n            .iter()\n            .map(|argument| {\n                match hydrator.type_from_option_ast(\n                    &argument.annotation,\n                    environment,\n                    &mut self.problems,\n                ) {\n                    Ok(type_) => type_,\n                    Err(error) => {\n                        self.problems.error(error);\n                        environment.new_unbound_var()\n                    }\n                }\n            })\n            .collect();\n\n        let return_type =\n            match hydrator.type_from_option_ast(return_annotation, environment, &mut self.problems)\n            {\n                Ok(type_) => type_,\n                Err(error) => {\n                    self.problems.error(error);\n                    environment.new_unbound_var()\n                }\n            };\n\n        let type_ = fn_(arguments_types, return_type);\n        let _ = self.hydrators.insert(name.clone(), hydrator);\n\n        let variant = ValueConstructorVariant::ModuleFn {\n            documentation: documentation.as_ref().map(|(_, doc)| doc.clone()),\n            name: name.clone(),\n            field_map,\n            external_erlang: external_erlang\n                .as_ref()\n                .map(|(m, f, _)| (m.clone(), f.clone())),\n            external_javascript: external_javascript\n                .as_ref()\n                .map(|(m, f, _)| (m.clone(), f.clone())),\n            module: environment.current_module.clone(),\n            arity: arguments.len(),\n            location: *location,\n            implementations: *implementations,\n            purity: *purity,\n        };\n        environment.insert_variable(\n            name.clone(),\n            variant,\n            type_,\n            *publicity,\n            deprecation.clone(),\n        );\n    }\n\n    fn check_for_type_leaks(&mut self, value: &ValueConstructor) {\n        // A private value doesn't export anything so it can't leak anything.\n        if value.publicity.is_private() {\n            return;\n        }\n\n        // If a private or internal value references a private type\n        if let Some(leaked) = value.type_.find_private_type() {\n            self.problems.error(Error::PrivateTypeLeak {\n                location: value.variant.definition_location(),\n                leaked,\n            });\n        }\n    }\n\n    fn check_name_case(&mut self, location: SrcSpan, name: &EcoString, kind: Named) {\n        if let Err(error) = check_name_case(location, name, kind) {\n            self.problems.error(error);\n        }\n    }\n\n    fn track_feature_usage(&mut self, feature_kind: FeatureKind, location: SrcSpan) {\n        let minimum_required_version = feature_kind.required_version();\n\n        // Then if the required version is not in the specified version for the\n        // range we emit a warning highlighting the usage of the feature.\n        if let Some(gleam_version) = &self.package_config.gleam_version\n            && let Some(lowest_allowed_version) = gleam_version.lowest_version()\n        {\n            // There is a version in the specified range that is lower than\n            // the one required by this feature! This means that the\n            // specified range is wrong and would allow someone to run a\n            // compiler that is too old to know of this feature.\n            if minimum_required_version > lowest_allowed_version {\n                self.problems\n                    .warning(Warning::FeatureRequiresHigherGleamVersion {\n                        location,\n                        feature_kind,\n                        minimum_required_version: minimum_required_version.clone(),\n                        wrongfully_allowed_version: lowest_allowed_version,\n                    })\n            }\n        }\n\n        if minimum_required_version > self.minimum_required_version {\n            self.minimum_required_version = minimum_required_version;\n        }\n    }\n\n    fn check_shadow_import(\n        &mut self,\n        name: &EcoString,\n        location: SrcSpan,\n        environment: &mut Environment<'_>,\n    ) {\n        if environment.unqualified_imported_names.contains_key(name) {\n            self.problems\n                .warning(Warning::TopLevelDefinitionShadowsImport {\n                    location,\n                    name: name.clone(),\n                });\n        }\n    }\n}\n\nfn validate_module_name(name: &EcoString) -> Result<(), Error> {\n    if is_prelude_module(name) {\n        return Err(Error::ReservedModuleName { name: name.clone() });\n    };\n    for segment in name.split('/') {\n        if crate::parse::lexer::str_to_keyword(segment).is_some() {\n            return Err(Error::KeywordInModuleName {\n                name: name.clone(),\n                keyword: segment.into(),\n            });\n        }\n    }\n    Ok(())\n}\n\nfn target_function_implementation<'a>(\n    target: Target,\n    external_erlang: &'a Option<(EcoString, EcoString, SrcSpan)>,\n    external_javascript: &'a Option<(EcoString, EcoString, SrcSpan)>,\n) -> &'a Option<(EcoString, EcoString, SrcSpan)> {\n    match target {\n        Target::Erlang => external_erlang,\n        Target::JavaScript => external_javascript,\n    }\n}\n\nfn analyse_type_alias(t: UntypedTypeAlias, environment: &mut Environment<'_>) -> TypedTypeAlias {\n    let TypeAlias {\n        documentation: doc,\n        location,\n        publicity,\n        alias,\n        name_location,\n        parameters: arguments,\n        type_ast: resolved_type,\n        deprecation,\n        ..\n    } = t;\n\n    // There could be no type alias registered if it was invalid in some way.\n    // analysis aims to be fault tolerant to get the best possible feedback for\n    // the programmer in the language server, so the analyser gets here even\n    // though there was previously errors.\n    let type_ = match environment.get_type_constructor(&None, &alias) {\n        Ok(constructor) => constructor.type_.clone(),\n        Err(_) => environment.new_generic_var(),\n    };\n\n    TypeAlias {\n        documentation: doc,\n        location,\n        publicity,\n        alias,\n        name_location,\n        parameters: arguments,\n        type_ast: resolved_type,\n        type_,\n        deprecation,\n    }\n}\n\npub fn infer_bit_array_option<UntypedValue, TypedValue, Typer>(\n    segment_option: BitArrayOption<UntypedValue>,\n    mut type_check: Typer,\n) -> Result<BitArrayOption<TypedValue>, Error>\nwhere\n    Typer: FnMut(UntypedValue, Arc<Type>) -> Result<TypedValue, Error>,\n{\n    match segment_option {\n        BitArrayOption::Size {\n            value,\n            location,\n            short_form,\n            ..\n        } => {\n            let value = type_check(*value, int())?;\n            Ok(BitArrayOption::Size {\n                location,\n                short_form,\n                value: Box::new(value),\n            })\n        }\n\n        BitArrayOption::Unit { location, value } => Ok(BitArrayOption::Unit { location, value }),\n\n        BitArrayOption::Bytes { location } => Ok(BitArrayOption::Bytes { location }),\n        BitArrayOption::Int { location } => Ok(BitArrayOption::Int { location }),\n        BitArrayOption::Float { location } => Ok(BitArrayOption::Float { location }),\n        BitArrayOption::Bits { location } => Ok(BitArrayOption::Bits { location }),\n        BitArrayOption::Utf8 { location } => Ok(BitArrayOption::Utf8 { location }),\n        BitArrayOption::Utf16 { location } => Ok(BitArrayOption::Utf16 { location }),\n        BitArrayOption::Utf32 { location } => Ok(BitArrayOption::Utf32 { location }),\n        BitArrayOption::Utf8Codepoint { location } => {\n            Ok(BitArrayOption::Utf8Codepoint { location })\n        }\n        BitArrayOption::Utf16Codepoint { location } => {\n            Ok(BitArrayOption::Utf16Codepoint { location })\n        }\n        BitArrayOption::Utf32Codepoint { location } => {\n            Ok(BitArrayOption::Utf32Codepoint { location })\n        }\n        BitArrayOption::Signed { location } => Ok(BitArrayOption::Signed { location }),\n        BitArrayOption::Unsigned { location } => Ok(BitArrayOption::Unsigned { location }),\n        BitArrayOption::Big { location } => Ok(BitArrayOption::Big { location }),\n        BitArrayOption::Little { location } => Ok(BitArrayOption::Little { location }),\n        BitArrayOption::Native { location } => Ok(BitArrayOption::Native { location }),\n    }\n}\n\nfn generalise_module_constant(\n    constant: ModuleConstant<Arc<Type>, EcoString>,\n    environment: &mut Environment<'_>,\n    module_name: &EcoString,\n) -> TypedModuleConstant {\n    let ModuleConstant {\n        documentation: doc,\n        location,\n        name,\n        name_location,\n        annotation,\n        publicity,\n        value,\n        type_,\n        deprecation,\n        implementations,\n    } = constant;\n    let type_ = type_.clone();\n    let type_ = type_::generalise(type_);\n    let variant = ValueConstructorVariant::ModuleConstant {\n        documentation: doc.as_ref().map(|(_, doc)| doc.clone()),\n        location,\n        literal: *value.clone(),\n        module: module_name.clone(),\n        implementations,\n        name: name.clone(),\n    };\n    environment.insert_variable(\n        name.clone(),\n        variant.clone(),\n        type_.clone(),\n        publicity,\n        deprecation.clone(),\n    );\n\n    environment.insert_module_value(\n        name.clone(),\n        ValueConstructor {\n            publicity,\n            variant,\n            deprecation: deprecation.clone(),\n            type_: type_.clone(),\n        },\n    );\n\n    ModuleConstant {\n        documentation: doc,\n        location,\n        name,\n        name_location,\n        annotation,\n        publicity,\n        value,\n        type_,\n        deprecation,\n        implementations,\n    }\n}\n\nfn generalise_function(\n    function: TypedFunction,\n    environment: &mut Environment<'_>,\n    module_name: &EcoString,\n) -> TypedFunction {\n    let Function {\n        documentation: doc,\n        location,\n        name,\n        publicity,\n        deprecation,\n        arguments,\n        body,\n        return_annotation,\n        end_position: end_location,\n        body_start,\n        return_type,\n        external_erlang,\n        external_javascript,\n        implementations,\n        purity,\n    } = function;\n\n    let (name_location, name) = name.expect(\"Function in a definition must be named\");\n\n    // Lookup the inferred function information\n    let function = environment\n        .get_variable(&name)\n        .expect(\"Could not find preregistered type for function\");\n    let field_map = function.field_map().cloned();\n    let type_ = function.type_.clone();\n\n    let type_ = type_::generalise(type_);\n\n    // Insert the function into the module's interface\n    let variant = ValueConstructorVariant::ModuleFn {\n        documentation: doc.as_ref().map(|(_, doc)| doc.clone()),\n        name: name.clone(),\n        field_map,\n        external_erlang: external_erlang\n            .as_ref()\n            .map(|(m, f, _)| (m.clone(), f.clone())),\n        external_javascript: external_javascript\n            .as_ref()\n            .map(|(m, f, _)| (m.clone(), f.clone())),\n        module: module_name.clone(),\n        arity: arguments.len(),\n        location,\n        implementations,\n        purity,\n    };\n    environment.insert_variable(\n        name.clone(),\n        variant.clone(),\n        type_.clone(),\n        publicity,\n        deprecation.clone(),\n    );\n    environment.insert_module_value(\n        name.clone(),\n        ValueConstructor {\n            publicity,\n            deprecation: deprecation.clone(),\n            type_,\n            variant,\n        },\n    );\n\n    Function {\n        documentation: doc,\n        location,\n        name: Some((name_location, name)),\n        publicity,\n        deprecation,\n        arguments,\n        end_position: end_location,\n        body_start,\n        return_annotation,\n        return_type,\n        body,\n        external_erlang,\n        external_javascript,\n        implementations,\n        purity,\n    }\n}\n\nfn assert_unique_name(\n    names: &mut HashMap<EcoString, SrcSpan>,\n    name: &EcoString,\n    location: SrcSpan,\n) -> Result<(), Error> {\n    match names.insert(name.clone(), location) {\n        Some(previous_location) => Err(Error::DuplicateName {\n            location_a: location,\n            location_b: previous_location,\n            name: name.clone(),\n        }),\n        None => Ok(()),\n    }\n}\n\nstruct Accessors {\n    shared_accessors: HashMap<EcoString, RecordAccessor>,\n    variant_specific_accessors: Vec<HashMap<EcoString, RecordAccessor>>,\n    positional_accessors: Vec<Vec<Arc<Type>>>,\n}\n\nfn custom_type_accessors(constructors: &[TypeValueConstructor]) -> Result<Accessors, Error> {\n    let accessors = get_compatible_record_fields(constructors);\n\n    let mut shared_accessors = HashMap::with_capacity(accessors.len());\n\n    for accessor in accessors {\n        let _ = shared_accessors.insert(accessor.label.clone(), accessor);\n    }\n\n    let mut variant_specific_accessors = Vec::with_capacity(constructors.len());\n    let mut positional_accessors = Vec::with_capacity(constructors.len());\n\n    for constructor in constructors {\n        let mut fields = HashMap::with_capacity(constructor.parameters.len());\n        let mut positional_fields = Vec::new();\n\n        for (index, parameter) in constructor.parameters.iter().enumerate() {\n            if let Some(label) = &parameter.label {\n                _ = fields.insert(\n                    label.clone(),\n                    RecordAccessor {\n                        index: index as u64,\n                        label: label.clone(),\n                        type_: parameter.type_.clone(),\n                        documentation: parameter.documentation.clone(),\n                    },\n                );\n            } else {\n                positional_fields.push(parameter.type_.clone());\n            }\n        }\n        variant_specific_accessors.push(fields);\n        positional_accessors.push(positional_fields);\n    }\n\n    Ok(Accessors {\n        shared_accessors,\n        variant_specific_accessors,\n        positional_accessors,\n    })\n}\n\n/// Returns the fields that have the same label and type across all variants of\n/// the given type.\nfn get_compatible_record_fields(constructors: &[TypeValueConstructor]) -> Vec<RecordAccessor> {\n    let mut compatible = vec![];\n\n    let first = match constructors.first() {\n        Some(first) => first,\n        None => return compatible,\n    };\n\n    'next_argument: for (index, first_parameter) in first.parameters.iter().enumerate() {\n        // Fields without labels do not have accessors\n        let first_label = match first_parameter.label.as_ref() {\n            Some(label) => label,\n            None => continue 'next_argument,\n        };\n\n        let mut documentation = if constructors.len() == 1 {\n            // If there is only one constructor, we simply show the documentation\n            // for the field.\n            first_parameter.documentation.clone()\n        } else {\n            // If there are multiple constructors, we show the documentation of\n            // this field for each of the variants.\n            first_parameter\n                .documentation\n                .as_ref()\n                .map(|field_documentation| {\n                    eco_format!(\"## {}\\n\\n{}\", first.name, field_documentation)\n                })\n        };\n\n        // Check each variant to see if they have an field in the same position\n        // with the same label and the same type\n        for constructor in constructors.iter().skip(1) {\n            // The field must exist in all variants\n            let parameter = match constructor.parameters.get(index) {\n                Some(argument) => argument,\n                None => continue 'next_argument,\n            };\n\n            // The labels must be the same\n            if parameter\n                .label\n                .as_ref()\n                .is_none_or(|arg_label| arg_label != first_label)\n            {\n                continue 'next_argument;\n            }\n\n            // The types must be the same\n            if !parameter.type_.same_as(&first_parameter.type_) {\n                continue 'next_argument;\n            }\n\n            if let Some(field_documentation) = &parameter.documentation {\n                let field_documentation =\n                    eco_format!(\"## {}\\n\\n{}\", constructor.name, field_documentation);\n\n                match &mut documentation {\n                    None => {\n                        documentation = Some(field_documentation);\n                    }\n                    Some(documentation) => {\n                        documentation.push('\\n');\n                        documentation.push_str(&field_documentation);\n                    }\n                }\n            }\n        }\n\n        // The previous loop did not find any incompatible fields in the other\n        // variants so this field is compatible across variants and we should\n        // generate an accessor for it.\n\n        compatible.push(RecordAccessor {\n            index: index as u64,\n            label: first_label.clone(),\n            type_: first_parameter.type_.clone(),\n            documentation,\n        })\n    }\n\n    compatible\n}\n\n/// Given a type, return a list of all the types it depends on\nfn get_type_dependencies(type_: &TypeAst) -> Vec<EcoString> {\n    let mut deps = Vec::with_capacity(1);\n\n    match type_ {\n        TypeAst::Var(TypeAstVar { .. }) => (),\n        TypeAst::Hole(TypeAstHole { .. }) => (),\n        TypeAst::Constructor(TypeAstConstructor {\n            name,\n            arguments,\n            module,\n            ..\n        }) => {\n            deps.push(match module {\n                Some((module, _)) => format!(\"{name}.{module}\").into(),\n                None => name.clone(),\n            });\n\n            for arg in arguments {\n                deps.extend(get_type_dependencies(arg))\n            }\n        }\n        TypeAst::Fn(TypeAstFn {\n            arguments, return_, ..\n        }) => {\n            for arg in arguments {\n                deps.extend(get_type_dependencies(arg))\n            }\n            deps.extend(get_type_dependencies(return_))\n        }\n        TypeAst::Tuple(TypeAstTuple { elements, .. }) => {\n            for element in elements {\n                deps.extend(get_type_dependencies(element))\n            }\n        }\n    }\n\n    deps\n}\n\nfn sorted_type_aliases(aliases: &Vec<UntypedTypeAlias>) -> Result<Vec<&UntypedTypeAlias>, Error> {\n    let mut deps: Vec<(EcoString, Vec<EcoString>)> = Vec::with_capacity(aliases.len());\n\n    for alias in aliases {\n        deps.push((alias.alias.clone(), get_type_dependencies(&alias.type_ast)))\n    }\n\n    let sorted_deps = dep_tree::toposort_deps(deps).map_err(|err| {\n        let dep_tree::Error::Cycle(cycle) = err;\n\n        let last = cycle.last().expect(\"Cycle should not be empty\");\n        let alias = aliases\n            .iter()\n            .find(|alias| alias.alias == *last)\n            .expect(\"Could not find alias for cycle\");\n\n        Error::RecursiveTypeAlias {\n            cycle,\n            location: alias.location,\n        }\n    })?;\n\n    Ok(aliases\n        .iter()\n        .sorted_by_key(|alias| sorted_deps.iter().position(|x| x == &alias.alias))\n        .collect())\n}\n"
  },
  {
    "path": "compiler-core/src/ast/constant.rs",
    "content": "use super::*;\nuse crate::analyse::Inferred;\nuse crate::type_::{FieldMap, HasType};\n\npub type TypedConstant = Constant<Arc<Type>, EcoString>;\npub type UntypedConstant = Constant<(), ()>;\n\n// TODO: remove RecordTag paramter\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Constant<T, RecordTag> {\n    Int {\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    },\n\n    Float {\n        location: SrcSpan,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    },\n\n    String {\n        location: SrcSpan,\n        value: EcoString,\n    },\n\n    Tuple {\n        location: SrcSpan,\n        elements: Vec<Self>,\n        type_: T,\n    },\n\n    List {\n        location: SrcSpan,\n        elements: Vec<Self>,\n        type_: T,\n        tail: Option<Box<Self>>,\n    },\n\n    Record {\n        location: SrcSpan,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        arguments: Vec<CallArg<Self>>,\n        tag: RecordTag,\n        type_: T,\n        field_map: Inferred<FieldMap>,\n        record_constructor: Option<Box<ValueConstructor>>,\n    },\n\n    RecordUpdate {\n        location: SrcSpan,\n        constructor_location: SrcSpan,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        record: RecordBeingUpdated<Self>,\n        arguments: Vec<RecordUpdateArg<Self>>,\n        tag: RecordTag,\n        type_: T,\n        field_map: Inferred<FieldMap>,\n    },\n\n    BitArray {\n        location: SrcSpan,\n        segments: Vec<BitArraySegment<Self, T>>,\n    },\n\n    Var {\n        location: SrcSpan,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        constructor: Option<Box<ValueConstructor>>,\n        type_: T,\n    },\n\n    StringConcatenation {\n        location: SrcSpan,\n        left: Box<Self>,\n        right: Box<Self>,\n    },\n\n    /// A placeholder constant used to allow module analysis to continue\n    /// even when there are type errors. Should never end up in generated code.\n    Invalid {\n        location: SrcSpan,\n        type_: T,\n        /// Extra information about the invalid expression, useful for providing\n        /// addition help or information, such as code actions to fix invalid\n        /// states.\n        extra_information: Option<InvalidExpression>,\n    },\n}\n\nimpl TypedConstant {\n    pub fn type_(&self) -> Arc<Type> {\n        match self {\n            Constant::Int { .. } => type_::int(),\n            Constant::Float { .. } => type_::float(),\n            Constant::String { .. } | Constant::StringConcatenation { .. } => type_::string(),\n            Constant::BitArray { .. } => type_::bit_array(),\n\n            Constant::List { type_, .. }\n            | Constant::Tuple { type_, .. }\n            | Constant::Record { type_, .. }\n            | Constant::RecordUpdate { type_, .. }\n            | Constant::Var { type_, .. }\n            | Constant::Invalid { type_, .. } => type_.clone(),\n        }\n    }\n\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if !self.location().contains(byte_index) {\n            return None;\n        }\n        Some(match self {\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Invalid { .. } => Located::Constant(self),\n            Constant::Var {\n                module: Some((module_alias, location)),\n                constructor: Some(constructor),\n                ..\n            }\n            | Constant::Record {\n                module: Some((module_alias, location)),\n                record_constructor: Some(constructor),\n                ..\n            } if location.contains(byte_index) => match &constructor.variant {\n                ValueConstructorVariant::ModuleConstant { module, .. }\n                | ValueConstructorVariant::ModuleFn { module, .. }\n                | ValueConstructorVariant::Record { module, .. } => Located::ModuleName {\n                    location: *location,\n                    module_name: module.clone(),\n                    module_alias: module_alias.clone(),\n                    layer: Layer::Value,\n                },\n                ValueConstructorVariant::LocalVariable { .. } => Located::Constant(self),\n            },\n            Constant::Var { .. } => Located::Constant(self),\n            Constant::Tuple { elements, .. } => elements\n                .iter()\n                .find_map(|element| element.find_node(byte_index))\n                .unwrap_or(Located::Constant(self)),\n            Constant::List { elements, tail, .. } => elements\n                .iter()\n                .find_map(|element| element.find_node(byte_index))\n                .or_else(|| tail.as_deref().and_then(|tail| tail.find_node(byte_index)))\n                .unwrap_or(Located::Constant(self)),\n            Constant::Record { arguments, .. } => arguments\n                .iter()\n                .find_map(|argument| argument.find_node(byte_index))\n                .unwrap_or(Located::Constant(self)),\n            Constant::RecordUpdate {\n                record, arguments, ..\n            } => record\n                .base\n                .find_node(byte_index)\n                .or_else(|| {\n                    arguments\n                        .iter()\n                        .find_map(|arg| arg.value.find_node(byte_index))\n                })\n                .unwrap_or(Located::Constant(self)),\n            Constant::BitArray { segments, .. } => segments\n                .iter()\n                .find_map(|segment| segment.find_node(byte_index))\n                .unwrap_or(Located::Constant(self)),\n            Constant::StringConcatenation { left, right, .. } => left\n                .find_node(byte_index)\n                .or_else(|| right.find_node(byte_index))\n                .unwrap_or(Located::Constant(self)),\n        })\n    }\n\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        match self {\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Tuple { .. }\n            | Constant::List { .. }\n            | Constant::BitArray { .. }\n            | Constant::StringConcatenation { .. }\n            | Constant::Invalid { .. } => None,\n            Constant::Record {\n                record_constructor: value_constructor,\n                ..\n            }\n            | Constant::Var {\n                constructor: value_constructor,\n                ..\n            } => value_constructor\n                .as_ref()\n                .map(|constructor| constructor.definition_location()),\n            Constant::RecordUpdate { .. } => None,\n        }\n    }\n\n    pub(crate) fn referenced_variables(&self) -> im::HashSet<&EcoString> {\n        match self {\n            Constant::Var { name, .. } => im::hashset![name],\n\n            Constant::Invalid { .. }\n            | Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. } => im::hashset![],\n\n            Constant::List { elements, .. } | Constant::Tuple { elements, .. } => elements\n                .iter()\n                .map(|element| element.referenced_variables())\n                .fold(im::hashset![], im::HashSet::union),\n\n            Constant::Record { arguments, .. } => arguments\n                .iter()\n                .map(|argument| argument.value.referenced_variables())\n                .fold(im::hashset![], im::HashSet::union),\n\n            Constant::RecordUpdate {\n                record, arguments, ..\n            } => record.base.referenced_variables().union(\n                arguments\n                    .iter()\n                    .map(|arg| arg.value.referenced_variables())\n                    .fold(im::hashset![], im::HashSet::union),\n            ),\n\n            Constant::BitArray { segments, .. } => segments\n                .iter()\n                .map(|segment| {\n                    segment\n                        .options\n                        .iter()\n                        .map(|option| option.referenced_variables())\n                        .fold(segment.value.referenced_variables(), im::HashSet::union)\n                })\n                .fold(im::hashset![], im::HashSet::union),\n\n            Constant::StringConcatenation { left, right, .. } => left\n                .referenced_variables()\n                .union(right.referenced_variables()),\n        }\n    }\n\n    pub(crate) fn syntactically_eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Constant::Int { int_value: n, .. }, Constant::Int { int_value: m, .. }) => n == m,\n            (Constant::Int { .. }, _) => false,\n\n            (Constant::Float { float_value: n, .. }, Constant::Float { float_value: m, .. }) => {\n                n == m\n            }\n            (Constant::Float { .. }, _) => false,\n\n            (\n                Constant::String { value, .. },\n                Constant::String {\n                    value: other_value, ..\n                },\n            ) => value == other_value,\n            (Constant::String { .. }, _) => false,\n\n            (\n                Constant::Tuple { elements, .. },\n                Constant::Tuple {\n                    elements: other_elements,\n                    ..\n                },\n            ) => pairwise_all(elements, other_elements, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (Constant::Tuple { .. }, _) => false,\n\n            (\n                Constant::List { elements, .. },\n                Constant::List {\n                    elements: other_elements,\n                    ..\n                },\n            ) => pairwise_all(elements, other_elements, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (Constant::List { .. }, _) => false,\n\n            (\n                Constant::Record {\n                    module,\n                    name,\n                    arguments,\n                    ..\n                },\n                Constant::Record {\n                    module: other_module,\n                    name: other_name,\n                    arguments: other_arguments,\n                    ..\n                },\n            ) => {\n                let modules_are_equal = match (module, other_module) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some((one, _)), Some((other, _))) => one == other,\n                };\n\n                modules_are_equal\n                    && name == other_name\n                    && pairwise_all(arguments, other_arguments, |(one, other)| {\n                        one.label == other.label && one.value.syntactically_eq(&other.value)\n                    })\n            }\n            (Constant::Record { .. }, _) => false,\n\n            (\n                Constant::RecordUpdate {\n                    module,\n                    name,\n                    record,\n                    arguments,\n                    ..\n                },\n                Constant::RecordUpdate {\n                    module: other_module,\n                    name: other_name,\n                    record: other_record,\n                    arguments: other_arguments,\n                    ..\n                },\n            ) => {\n                let modules_are_equal = match (module, other_module) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some((one, _)), Some((other, _))) => one == other,\n                };\n\n                modules_are_equal\n                    && name == other_name\n                    && record.base.syntactically_eq(&other_record.base)\n                    && pairwise_all(arguments, other_arguments, |(one, other)| {\n                        one.label == other.label && one.value.syntactically_eq(&other.value)\n                    })\n            }\n            (Constant::RecordUpdate { .. }, _) => false,\n\n            (\n                Constant::BitArray { segments, .. },\n                Constant::BitArray {\n                    segments: other_segments,\n                    ..\n                },\n            ) => pairwise_all(segments, other_segments, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (Constant::BitArray { .. }, _) => false,\n\n            (\n                Constant::Var { module, name, .. },\n                Constant::Var {\n                    module: other_module,\n                    name: other_name,\n                    ..\n                },\n            ) => {\n                let modules_are_equal = match (module, other_module) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some((one, _)), Some((other, _))) => one == other,\n                };\n\n                modules_are_equal && name == other_name\n            }\n            (Constant::Var { .. }, _) => false,\n\n            (\n                Constant::StringConcatenation { left, right, .. },\n                Constant::StringConcatenation {\n                    left: other_left,\n                    right: other_right,\n                    ..\n                },\n            ) => left.syntactically_eq(other_left) && right.syntactically_eq(other_right),\n            (Constant::StringConcatenation { .. }, _) => false,\n\n            (Constant::Invalid { .. }, _) => false,\n        }\n    }\n\n    pub fn list_elements(&self) -> Option<Vec<&Self>> {\n        match self {\n            Constant::List { elements, tail, .. } => Some(\n                elements\n                    .iter()\n                    .chain(\n                        tail.as_deref()\n                            .and_then(|tail| tail.list_elements())\n                            .unwrap_or_default(),\n                    )\n                    .collect(),\n            ),\n            Constant::Var {\n                constructor: Some(constructor),\n                ..\n            } => match &constructor.variant {\n                ValueConstructorVariant::ModuleConstant { literal, .. } => literal.list_elements(),\n                ValueConstructorVariant::LocalVariable { .. }\n                | ValueConstructorVariant::ModuleFn { .. }\n                | ValueConstructorVariant::Record { .. } => None,\n            },\n\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Tuple { .. }\n            | Constant::Record { .. }\n            | Constant::RecordUpdate { .. }\n            | Constant::BitArray { .. }\n            | Constant::StringConcatenation { .. }\n            | Constant::Var { .. }\n            | Constant::Invalid { .. } => None,\n        }\n    }\n}\n\nimpl HasType for TypedConstant {\n    fn type_(&self) -> Arc<Type> {\n        self.type_()\n    }\n}\n\nimpl<A, B> Constant<A, B> {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Constant::Int { location, .. }\n            | Constant::List { location, .. }\n            | Constant::Float { location, .. }\n            | Constant::Tuple { location, .. }\n            | Constant::String { location, .. }\n            | Constant::Record { location, .. }\n            | Constant::RecordUpdate { location, .. }\n            | Constant::BitArray { location, .. }\n            | Constant::Var { location, .. }\n            | Constant::Invalid { location, .. }\n            | Constant::StringConcatenation { location, .. } => *location,\n        }\n    }\n\n    #[must_use]\n    pub fn can_have_multiple_per_line(&self) -> bool {\n        match self {\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Var { .. } => true,\n\n            Constant::Tuple { .. }\n            | Constant::List { .. }\n            | Constant::Record { .. }\n            | Constant::RecordUpdate { .. }\n            | Constant::BitArray { .. }\n            | Constant::StringConcatenation { .. }\n            | Constant::Invalid { .. } => false,\n        }\n    }\n}\n\nimpl<A, B> HasLocation for Constant<A, B> {\n    fn location(&self) -> SrcSpan {\n        self.location()\n    }\n}\n\nimpl<A, B> bit_array::GetLiteralValue for Constant<A, B> {\n    fn as_int_literal(&self) -> Option<BigInt> {\n        if let Constant::Int { int_value, .. } = self {\n            Some(int_value.clone())\n        } else {\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/ast/tests.rs",
    "content": "use std::sync::Arc;\n\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\n\nuse crate::analyse::TargetSupport;\nuse crate::build::{ExpressionPosition, Origin, Target};\nuse crate::config::PackageConfig;\nuse crate::line_numbers::LineNumbers;\nuse crate::type_::error::{VariableDeclaration, VariableOrigin, VariableSyntax};\nuse crate::type_::expression::{FunctionDefinition, Purity};\nuse crate::type_::{Deprecation, PRELUDE_MODULE_NAME, Problems};\nuse crate::warning::WarningEmitter;\nuse crate::{\n    ast::{SrcSpan, TypedExpr},\n    build::Located,\n    type_::{\n        self, AccessorsMap, EnvironmentArguments, ExprTyper, FieldMap, ModuleValueConstructor,\n        RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,\n    },\n    uid::UniqueIdGenerator,\n    warning::TypeWarningEmitter,\n};\n\nuse super::{Publicity, Statement, TypedModule, TypedStatement};\n\nfn compile_module(src: &str) -> TypedModule {\n    use crate::type_::build_prelude;\n    let parsed =\n        crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &WarningEmitter::null())\n            .expect(\"syntax error\");\n    let ast = parsed.module;\n    let ids = UniqueIdGenerator::new();\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n    let mut modules = im::HashMap::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids));\n    let line_numbers = LineNumbers::new(src);\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n\n    crate::analyse::ModuleAnalyzerConstructor::<()> {\n        target: Target::Erlang,\n        ids: &ids,\n        origin: Origin::Src,\n        importable_modules: &modules,\n        warnings: &TypeWarningEmitter::null(),\n        direct_dependencies: &std::collections::HashMap::new(),\n        dev_dependencies: &std::collections::HashSet::new(),\n        target_support: TargetSupport::Enforced,\n        package_config: &config,\n    }\n    .infer_module(ast, line_numbers, \"\".into())\n    .expect(\"should successfully infer\")\n}\n\nfn get_bare_expression(statement: &TypedStatement) -> &TypedExpr {\n    match statement {\n        Statement::Expression(expression) => expression,\n        Statement::Use(_) | Statement::Assignment(_) | Statement::Assert(_) => {\n            panic!(\"Expected expression, got {statement:?}\")\n        }\n    }\n}\n\nfn compile_expression(src: &str) -> TypedStatement {\n    let ast = crate::parse::parse_statement_sequence(src).expect(\"syntax error\");\n\n    let mut modules = im::HashMap::new();\n    let ids = UniqueIdGenerator::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(PRELUDE_MODULE_NAME.into(), type_::build_prelude(&ids));\n    let dev_dependencies = std::collections::HashSet::new();\n\n    let mut environment = EnvironmentArguments {\n        ids,\n        current_package: \"thepackage\".into(),\n        gleam_version: None,\n        current_module: \"mymod\".into(),\n        target: Target::Erlang,\n        importable_modules: &modules,\n        target_support: TargetSupport::Enforced,\n        current_origin: Origin::Src,\n        dev_dependencies: &dev_dependencies,\n    }\n    .build();\n\n    // Insert a cat record to use in the tests\n    let cat_type = Arc::new(Type::Named {\n        publicity: Publicity::Public,\n        package: \"mypackage\".into(),\n        module: \"mymod\".into(),\n        name: \"Cat\".into(),\n        arguments: vec![],\n        inferred_variant: None,\n    });\n    let variant = ValueConstructorVariant::Record {\n        documentation: Some(\"wibble\".into()),\n        variants_count: 1,\n        name: \"Cat\".into(),\n        arity: 2,\n        location: SrcSpan { start: 12, end: 15 },\n        field_map: Some(FieldMap {\n            arity: 2,\n            fields: [(\"name\".into(), 0), (\"age\".into(), 1)].into(),\n        }),\n        module: \"mymod\".into(),\n        variant_index: 0,\n    };\n    environment.insert_variable(\n        \"Cat\".into(),\n        variant,\n        type_::fn_(vec![type_::string(), type_::int()], cat_type.clone()),\n        Publicity::Public,\n        Deprecation::NotDeprecated,\n    );\n\n    let accessors = [\n        (\n            \"name\".into(),\n            RecordAccessor {\n                index: 0,\n                label: \"name\".into(),\n                type_: type_::string(),\n                documentation: None,\n            },\n        ),\n        (\n            \"age\".into(),\n            RecordAccessor {\n                index: 1,\n                label: \"age\".into(),\n                type_: type_::int(),\n                documentation: None,\n            },\n        ),\n    ];\n\n    environment.insert_accessors(\n        \"Cat\".into(),\n        AccessorsMap {\n            publicity: Publicity::Public,\n            type_: cat_type,\n            shared_accessors: accessors.clone().into(),\n            variant_specific_accessors: vec![accessors.into()],\n            variant_positional_accessors: vec![vec![]],\n        },\n    );\n    let mut problems = Problems::new();\n    ExprTyper::new(\n        &mut environment,\n        FunctionDefinition {\n            has_body: true,\n            has_erlang_external: false,\n            has_javascript_external: false,\n        },\n        &mut problems,\n    )\n    .infer_statements(ast)\n    .first()\n    .clone()\n}\n\n#[test]\nfn find_node_todo() {\n    let statement = compile_expression(r#\" todo \"#);\n    let expr = get_bare_expression(&statement);\n    assert_eq!(expr.find_node(0), None);\n    assert_eq!(\n        expr.find_node(1),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(4),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(5),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(expr.find_node(6), None);\n}\n\n#[test]\nfn find_node_todo_with_string() {\n    let statement = compile_expression(r#\" todo as \"ok\" \"#);\n    let expr = get_bare_expression(&statement);\n    let message = TypedExpr::String {\n        location: SrcSpan { start: 9, end: 13 },\n        type_: type_::string(),\n        value: \"ok\".into(),\n    };\n\n    assert_eq!(expr.find_node(0), None);\n    assert_eq!(\n        expr.find_node(1),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(12),\n        Some(Located::Expression {\n            expression: &message,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(13),\n        Some(Located::Expression {\n            expression: &message,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(expr.find_node(14), None);\n}\n\n#[test]\nfn find_node_string() {\n    let statement = compile_expression(r#\" \"ok\" \"#);\n    let expr = get_bare_expression(&statement);\n    assert_eq!(expr.find_node(0), None);\n    assert_eq!(\n        expr.find_node(1),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(4),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(5),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(expr.find_node(6), None);\n}\n\n#[test]\nfn find_node_float() {\n    let statement = compile_expression(r#\" 1.02 \"#);\n    let expr = get_bare_expression(&statement);\n    assert_eq!(expr.find_node(0), None);\n    assert_eq!(\n        expr.find_node(1),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(4),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(5),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(expr.find_node(6), None);\n}\n\n#[test]\nfn find_node_int() {\n    let statement = compile_expression(r#\" 1302 \"#);\n    let expr = get_bare_expression(&statement);\n    assert_eq!(expr.find_node(0), None);\n    assert_eq!(\n        expr.find_node(1),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(4),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(5),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(expr.find_node(6), None);\n}\n\n#[test]\nfn find_node_var() {\n    let statement = compile_expression(\n        r#\"{let wibble = 1\nwibble}\"#,\n    );\n    let expr = get_bare_expression(&statement);\n\n    let int1 = TypedExpr::Int {\n        location: SrcSpan { start: 14, end: 15 },\n        value: \"1\".into(),\n        int_value: 1.into(),\n        type_: type_::int(),\n    };\n\n    let var = TypedExpr::Var {\n        location: SrcSpan { start: 16, end: 22 },\n        constructor: ValueConstructor {\n            deprecation: Deprecation::NotDeprecated,\n            publicity: Publicity::Private,\n            variant: ValueConstructorVariant::LocalVariable {\n                location: SrcSpan { start: 5, end: 11 },\n                origin: VariableOrigin {\n                    syntax: VariableSyntax::Variable(\"wibble\".into()),\n                    declaration: VariableDeclaration::LetPattern,\n                },\n            },\n            type_: type_::int(),\n        },\n        name: \"wibble\".into(),\n    };\n\n    assert_eq!(\n        expr.find_node(15),\n        Some(Located::Expression {\n            expression: &int1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(16),\n        Some(Located::Expression {\n            expression: &var,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(21),\n        Some(Located::Expression {\n            expression: &var,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(22),\n        Some(Located::Expression {\n            expression: &var,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_sequence() {\n    let block = compile_expression(r#\"{ 1 2 3 }\"#);\n    assert!(block.find_node(0).is_none());\n    assert!(block.find_node(1).is_none());\n    assert!(block.find_node(2).is_some());\n    assert!(block.find_node(3).is_some());\n    assert!(block.find_node(4).is_some());\n    assert!(block.find_node(5).is_some());\n    assert!(block.find_node(6).is_some());\n    assert!(block.find_node(7).is_some());\n}\n\n#[test]\nfn find_node_list() {\n    let statement = compile_expression(r#\"[1, 2, 3]\"#);\n    let list = get_bare_expression(&statement);\n\n    let int1 = TypedExpr::Int {\n        location: SrcSpan { start: 1, end: 2 },\n        type_: type_::int(),\n        value: \"1\".into(),\n        int_value: 1.into(),\n    };\n    let int2 = TypedExpr::Int {\n        location: SrcSpan { start: 4, end: 5 },\n        type_: type_::int(),\n        value: \"2\".into(),\n        int_value: 2.into(),\n    };\n    let int3 = TypedExpr::Int {\n        location: SrcSpan { start: 7, end: 8 },\n        type_: type_::int(),\n        value: \"3\".into(),\n        int_value: 3.into(),\n    };\n\n    assert_eq!(\n        list.find_node(0),\n        Some(Located::Expression {\n            expression: list,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(1),\n        Some(Located::Expression {\n            expression: &int1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(2),\n        Some(Located::Expression {\n            expression: &int1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(3),\n        Some(Located::Expression {\n            expression: list,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(4),\n        Some(Located::Expression {\n            expression: &int2,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(5),\n        Some(Located::Expression {\n            expression: &int2,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(6),\n        Some(Located::Expression {\n            expression: list,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(7),\n        Some(Located::Expression {\n            expression: &int3,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(8),\n        Some(Located::Expression {\n            expression: &int3,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        list.find_node(9),\n        Some(Located::Expression {\n            expression: list,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_tuple() {\n    let statement = compile_expression(r#\"#(1, 2, 3)\"#);\n    let tuple = get_bare_expression(&statement);\n\n    let int1 = TypedExpr::Int {\n        location: SrcSpan { start: 2, end: 3 },\n        type_: type_::int(),\n        value: \"1\".into(),\n        int_value: 1.into(),\n    };\n    let int2 = TypedExpr::Int {\n        location: SrcSpan { start: 5, end: 6 },\n        type_: type_::int(),\n        value: \"2\".into(),\n        int_value: 2.into(),\n    };\n    let int3 = TypedExpr::Int {\n        location: SrcSpan { start: 8, end: 9 },\n        type_: type_::int(),\n        value: \"3\".into(),\n        int_value: 3.into(),\n    };\n\n    assert_eq!(\n        tuple.find_node(0),\n        Some(Located::Expression {\n            expression: tuple,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(1),\n        Some(Located::Expression {\n            expression: tuple,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(2),\n        Some(Located::Expression {\n            expression: &int1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(3),\n        Some(Located::Expression {\n            expression: &int1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(4),\n        Some(Located::Expression {\n            expression: tuple,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(5),\n        Some(Located::Expression {\n            expression: &int2,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(6),\n        Some(Located::Expression {\n            expression: &int2,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(7),\n        Some(Located::Expression {\n            expression: tuple,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(8),\n        Some(Located::Expression {\n            expression: &int3,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(9),\n        Some(Located::Expression {\n            expression: &int3,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        tuple.find_node(10),\n        Some(Located::Expression {\n            expression: tuple,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_binop() {\n    let statement = compile_expression(r#\"1 + 2\"#);\n    let expr = get_bare_expression(&statement);\n    assert!(expr.find_node(0).is_some());\n    assert!(expr.find_node(1).is_some());\n    assert!(expr.find_node(2).is_none());\n    assert!(expr.find_node(3).is_none());\n    assert!(expr.find_node(4).is_some());\n    assert!(expr.find_node(5).is_some());\n}\n\n#[test]\nfn find_node_tuple_index() {\n    let statement = compile_expression(r#\"#(1).0\"#);\n    let expr = get_bare_expression(&statement);\n\n    let int = TypedExpr::Int {\n        location: SrcSpan { start: 2, end: 3 },\n        value: \"1\".into(),\n        int_value: 1.into(),\n        type_: type_::int(),\n    };\n\n    assert_eq!(\n        expr.find_node(2),\n        Some(Located::Expression {\n            expression: &int,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(5),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(6),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_module_select() {\n    let expr = TypedExpr::ModuleSelect {\n        location: SrcSpan { start: 1, end: 4 },\n        field_start: 2,\n        type_: type_::int(),\n        label: \"label\".into(),\n        module_name: \"name\".into(),\n        module_alias: \"alias\".into(),\n        constructor: ModuleValueConstructor::Fn {\n            module: \"module\".into(),\n            name: \"function\".into(),\n            external_erlang: None,\n            external_javascript: None,\n            location: SrcSpan { start: 1, end: 55 },\n            documentation: None,\n            field_map: None,\n            purity: Purity::Pure,\n        },\n    };\n\n    assert_eq!(expr.find_node(0), None);\n    assert_eq!(\n        expr.find_node(1),\n        Some(Located::ModuleName {\n            location: SrcSpan::new(1, 6),\n            module_name: \"name\".into(),\n            module_alias: \"alias\".into(),\n            layer: super::Layer::Value\n        })\n    );\n    assert_eq!(\n        expr.find_node(2),\n        Some(Located::Expression {\n            expression: &expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(3),\n        Some(Located::Expression {\n            expression: &expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_fn() {\n    let statement = compile_expression(\"fn() { 1 }\");\n    let expr = get_bare_expression(&statement);\n\n    let int = TypedExpr::Int {\n        location: SrcSpan { start: 7, end: 8 },\n        value: \"1\".into(),\n        int_value: 1.into(),\n        type_: type_::int(),\n    };\n\n    assert_eq!(\n        expr.find_node(0),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(6),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(7),\n        Some(Located::Expression {\n            expression: &int,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(8),\n        Some(Located::Expression {\n            expression: &int,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(9),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(10),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_call() {\n    let statement = compile_expression(\"fn(_, _) { 1 }(1, 2)\");\n    let expr = get_bare_expression(&statement);\n\n    let return_ = TypedExpr::Int {\n        location: SrcSpan { start: 11, end: 12 },\n        value: \"1\".into(),\n        int_value: 1.into(),\n        type_: type_::int(),\n    };\n\n    let arg1 = TypedExpr::Int {\n        location: SrcSpan { start: 15, end: 16 },\n        value: \"1\".into(),\n        int_value: 1.into(),\n        type_: type_::int(),\n    };\n\n    let arg2 = TypedExpr::Int {\n        location: SrcSpan { start: 18, end: 19 },\n        value: \"2\".into(),\n        int_value: 2.into(),\n        type_: type_::int(),\n    };\n\n    let TypedExpr::Call {\n        fun: called_function,\n        arguments: function_arguments,\n        ..\n    } = expr\n    else {\n        panic!(\"Expression was not a function call\");\n    };\n\n    assert_eq!(\n        expr.find_node(11),\n        Some(Located::Expression {\n            expression: &return_,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(15),\n        Some(Located::Expression {\n            expression: &arg1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(16),\n        Some(Located::Expression {\n            expression: &arg1,\n            position: ExpressionPosition::ArgumentOrLabel {\n                called_function,\n                function_arguments\n            }\n        })\n    );\n    assert_eq!(\n        expr.find_node(17),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(18),\n        Some(Located::Expression {\n            expression: &arg2,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        expr.find_node(19),\n        Some(Located::Expression {\n            expression: &arg2,\n            position: ExpressionPosition::ArgumentOrLabel {\n                called_function,\n                function_arguments\n            }\n        })\n    );\n    assert_eq!(\n        expr.find_node(20),\n        Some(Located::Expression {\n            expression: expr,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_record_access() {\n    let statement = compile_expression(r#\"Cat(\"Nubi\", 3).name\"#);\n    let access = get_bare_expression(&statement);\n\n    let string = TypedExpr::String {\n        location: SrcSpan { start: 4, end: 10 },\n        value: \"Nubi\".into(),\n        type_: type_::string(),\n    };\n\n    let int = TypedExpr::Int {\n        location: SrcSpan { start: 12, end: 13 },\n        value: \"3\".into(),\n        int_value: 3.into(),\n        type_: type_::int(),\n    };\n\n    assert_eq!(\n        access.find_node(4),\n        Some(Located::Expression {\n            expression: &string,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        access.find_node(9),\n        Some(Located::Expression {\n            expression: &string,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        access.find_node(12),\n        Some(Located::Expression {\n            expression: &int,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        access.find_node(15),\n        Some(Located::Expression {\n            expression: access,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        access.find_node(18),\n        Some(Located::Expression {\n            expression: access,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        access.find_node(19),\n        Some(Located::Expression {\n            expression: access,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_record_update() {\n    let statement = compile_expression(r#\"Cat(..Cat(\"Nubi\", 3), age: 4)\"#);\n    let update = get_bare_expression(&statement);\n\n    let cat = TypedExpr::Var {\n        location: SrcSpan { start: 0, end: 3 },\n        constructor: ValueConstructor {\n            publicity: Publicity::Public,\n            deprecation: Deprecation::NotDeprecated,\n            variant: ValueConstructorVariant::Record {\n                name: \"Cat\".into(),\n                arity: 2,\n                field_map: Some(FieldMap {\n                    arity: 2,\n                    fields: [(EcoString::from(\"age\"), 1), (EcoString::from(\"name\"), 0)].into(),\n                }),\n                location: SrcSpan { start: 12, end: 15 },\n                module: \"mymod\".into(),\n                variants_count: 1,\n                variant_index: 0,\n                documentation: Some(\"wibble\".into()),\n            },\n            type_: type_::fn_(\n                vec![type_::string(), type_::int()],\n                type_::named(\"mypackage\", \"mymod\", \"Cat\", Publicity::Public, vec![]),\n            ),\n        },\n        name: \"Cat\".into(),\n    };\n\n    let int = TypedExpr::Int {\n        location: SrcSpan { start: 27, end: 28 },\n        value: \"4\".into(),\n        int_value: 4.into(),\n        type_: type_::int(),\n    };\n\n    assert_eq!(\n        update.find_node(0),\n        Some(Located::Expression {\n            expression: &cat,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        update.find_node(3),\n        Some(Located::Expression {\n            expression: &cat,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        update.find_node(27),\n        Some(Located::Expression {\n            expression: &int,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        update.find_node(28),\n        Some(Located::Expression {\n            expression: &int,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        update.find_node(29),\n        Some(Located::Expression {\n            expression: update,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_case() {\n    let statement = compile_expression(\n        r#\"\ncase 1, 2 {\n  _, _ -> 3\n}\n\"#,\n    );\n    let case = get_bare_expression(&statement);\n\n    let int1 = TypedExpr::Int {\n        location: SrcSpan { start: 6, end: 7 },\n        value: \"1\".into(),\n        int_value: 1.into(),\n        type_: type_::int(),\n    };\n\n    let int2 = TypedExpr::Int {\n        location: SrcSpan { start: 9, end: 10 },\n        value: \"2\".into(),\n        int_value: 2.into(),\n        type_: type_::int(),\n    };\n\n    let int3 = TypedExpr::Int {\n        location: SrcSpan { start: 23, end: 24 },\n        value: \"3\".into(),\n        int_value: 3.into(),\n        type_: type_::int(),\n    };\n\n    assert_eq!(\n        case.find_node(1),\n        Some(Located::Expression {\n            expression: case,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        case.find_node(6),\n        Some(Located::Expression {\n            expression: &int1,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        case.find_node(9),\n        Some(Located::Expression {\n            expression: &int2,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        case.find_node(23),\n        Some(Located::Expression {\n            expression: &int3,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        case.find_node(25),\n        Some(Located::Expression {\n            expression: case,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        case.find_node(26),\n        Some(Located::Expression {\n            expression: case,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(case.find_node(27), None);\n}\n\n#[test]\nfn find_node_bool() {\n    let statement = compile_expression(r#\"!True\"#);\n    let negate = get_bare_expression(&statement);\n\n    let bool = TypedExpr::Var {\n        location: SrcSpan { start: 1, end: 5 },\n        constructor: ValueConstructor {\n            deprecation: Deprecation::NotDeprecated,\n            publicity: Publicity::Public,\n            variant: ValueConstructorVariant::Record {\n                documentation: None,\n                variants_count: 2,\n                name: \"True\".into(),\n                arity: 0,\n                field_map: None,\n                location: SrcSpan { start: 0, end: 0 },\n                module: PRELUDE_MODULE_NAME.into(),\n                variant_index: 0,\n            },\n            type_: type_::bool_with_variant(Some(true)),\n        },\n        name: \"True\".into(),\n    };\n\n    assert_eq!(\n        negate.find_node(0),\n        Some(Located::Expression {\n            expression: negate,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        negate.find_node(1),\n        Some(Located::Expression {\n            expression: &bool,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        negate.find_node(2),\n        Some(Located::Expression {\n            expression: &bool,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        negate.find_node(3),\n        Some(Located::Expression {\n            expression: &bool,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        negate.find_node(4),\n        Some(Located::Expression {\n            expression: &bool,\n            position: ExpressionPosition::Expression\n        })\n    );\n    assert_eq!(\n        negate.find_node(5),\n        Some(Located::Expression {\n            expression: &bool,\n            position: ExpressionPosition::Expression\n        })\n    );\n}\n\n#[test]\nfn find_node_statement_fn() {\n    let module = compile_module(\n        r#\"\n\npub fn main() {\n  Nil\n}\n\n\"#,\n    );\n\n    assert!(module.find_node(0).is_none());\n    assert!(module.find_node(1).is_none());\n\n    // The fn\n    assert!(module.find_node(2).is_some());\n    assert!(module.find_node(24).is_some());\n    assert!(module.find_node(25).is_some());\n    assert!(module.find_node(26).is_none());\n}\n\n#[test]\nfn find_node_statement_import() {\n    let module = compile_module(\n        r#\"\nimport gleam\n\"#,\n    );\n\n    assert!(module.find_node(0).is_none());\n\n    // The import\n    assert!(module.find_node(1).is_some());\n    assert!(module.find_node(12).is_some());\n    assert!(module.find_node(13).is_some());\n    assert!(module.find_node(14).is_none());\n}\n\n#[test]\nfn find_node_use() {\n    let use_ = compile_expression(\n        r#\"\nuse x <- fn(f) { f(1) }\n124\n\"#,\n    );\n\n    assert!(use_.find_node(0).is_none());\n    assert!(use_.find_node(1).is_some()); // The use\n    assert!(use_.find_node(23).is_some());\n    assert!(use_.find_node(26).is_some()); // The int\n}\n"
  },
  {
    "path": "compiler-core/src/ast/typed.rs",
    "content": "use type_::{FieldMap, TypedCallArg};\n\nuse super::*;\nuse crate::{\n    build::ExpressionPosition,\n    exhaustiveness::CompiledCase,\n    parse::LiteralFloatValue,\n    type_::{HasType, Type, ValueConstructorVariant, bool},\n};\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum TypedExpr {\n    Int {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        value: EcoString,\n        int_value: BigInt,\n    },\n\n    Float {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    },\n\n    String {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        value: EcoString,\n    },\n\n    Block {\n        location: SrcSpan,\n        statements: Vec1<TypedStatement>,\n    },\n\n    /// A chain of pipe expressions.\n    /// By this point the type checker has expanded it into a series of\n    /// assignments and function calls, but we still have a Pipeline AST node as\n    /// even though it is identical to `Block` we want to use different\n    /// locations when showing it in error messages, etc.\n    Pipeline {\n        location: SrcSpan,\n        first_value: TypedPipelineAssignment,\n        assignments: Vec<(TypedPipelineAssignment, PipelineAssignmentKind)>,\n        finally: Box<Self>,\n        finally_kind: PipelineAssignmentKind,\n    },\n\n    Var {\n        location: SrcSpan,\n        constructor: ValueConstructor,\n        name: EcoString,\n    },\n\n    Fn {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        kind: FunctionLiteralKind,\n        arguments: Vec<TypedArg>,\n        body: Vec1<TypedStatement>,\n        return_annotation: Option<TypeAst>,\n        purity: Purity,\n    },\n\n    List {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        elements: Vec<Self>,\n        tail: Option<Box<Self>>,\n    },\n\n    Call {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        fun: Box<Self>,\n        arguments: Vec<CallArg<Self>>,\n    },\n\n    BinOp {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        name: BinOp,\n        name_location: SrcSpan,\n        left: Box<Self>,\n        right: Box<Self>,\n    },\n\n    Case {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        subjects: Vec<Self>,\n        clauses: Vec<Clause<Self, Arc<Type>, EcoString>>,\n        compiled_case: CompiledCase,\n    },\n\n    RecordAccess {\n        location: SrcSpan,\n        field_start: u32,\n        type_: Arc<Type>,\n        label: EcoString,\n        index: u64,\n        record: Box<Self>,\n        documentation: Option<EcoString>,\n    },\n\n    /// Generated internally for accessing unlabelled fields of a custom type,\n    /// such as for record updates.\n    PositionalAccess {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        index: u64,\n        record: Box<Self>,\n    },\n\n    ModuleSelect {\n        location: SrcSpan,\n        field_start: u32,\n        type_: Arc<Type>,\n        label: EcoString,\n        module_name: EcoString,\n        module_alias: EcoString,\n        constructor: ModuleValueConstructor,\n    },\n\n    Tuple {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        elements: Vec<Self>,\n    },\n\n    TupleIndex {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        index: u64,\n        tuple: Box<Self>,\n    },\n\n    Todo {\n        location: SrcSpan,\n        message: Option<Box<Self>>,\n        kind: TodoKind,\n        type_: Arc<Type>,\n    },\n\n    Panic {\n        location: SrcSpan,\n        message: Option<Box<Self>>,\n        type_: Arc<Type>,\n    },\n\n    Echo {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        expression: Option<Box<Self>>,\n        message: Option<Box<Self>>,\n    },\n\n    BitArray {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        segments: Vec<TypedExprBitArraySegment>,\n    },\n\n    /// A record update gets desugared to a block expression of the form\n    ///\n    /// {\n    ///   let _record = record\n    ///   Constructor(explicit_arg: explicit_value(), implicit_arg: _record.implicit_arg)\n    /// }\n    ///\n    /// We still keep a separate `RecordUpdate` AST node for the same reasons as\n    /// we do for pipelines.\n    RecordUpdate {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        /// If the record is an expression that is not a variable we will need to assign to a\n        /// variable so it can be referred multiple times.\n        record_assignment: Option<Box<TypedAssignment>>,\n        constructor: Box<Self>,\n        arguments: Vec<CallArg<Self>>,\n    },\n\n    NegateBool {\n        location: SrcSpan,\n        value: Box<Self>,\n    },\n\n    NegateInt {\n        location: SrcSpan,\n        value: Box<Self>,\n    },\n\n    /// A placeholder expression used to allow module analysis to continue\n    /// even when there are type errors. Should never end up in generated code.\n    Invalid {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        /// Extra information about the invalid expression, useful for providing\n        /// addition help or information, such as code actions to fix invalid\n        /// states.\n        extra_information: Option<InvalidExpression>,\n    },\n}\n\nimpl TypedExpr {\n    pub fn is_println(&self) -> bool {\n        let fun = if let TypedExpr::Call { fun, arguments, .. } = self\n            && arguments.len() == 1\n        {\n            fun.as_ref()\n        } else {\n            return false;\n        };\n\n        if let TypedExpr::ModuleSelect {\n            label, module_name, ..\n        } = fun\n        {\n            label == \"println\" && module_name == \"gleam/io\"\n        } else {\n            false\n        }\n    }\n\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        match self {\n            Self::Var { .. }\n            | Self::Int { .. }\n            | Self::Float { .. }\n            | Self::String { .. }\n            | Self::Invalid { .. }\n            | Self::PositionalAccess { .. } => self.self_if_contains_location(byte_index),\n\n            Self::ModuleSelect {\n                location,\n                field_start,\n                module_name,\n                module_alias,\n                ..\n            } => {\n                // We want to return the `ModuleSelect` only when we're hovering\n                // over the selected field, not on the module part.\n                let field_span = SrcSpan {\n                    start: *field_start,\n                    end: location.end,\n                };\n\n                let module_span =\n                    SrcSpan::new(location.start, location.start + (module_alias.len() as u32));\n\n                if field_span.contains(byte_index) {\n                    Some(self.into())\n                } else if SrcSpan::new(location.start, field_start - 1).contains(byte_index) {\n                    Some(Located::ModuleName {\n                        location: module_span,\n                        module_name: module_name.clone(),\n                        module_alias: module_alias.clone(),\n                        layer: Layer::Value,\n                    })\n                } else {\n                    None\n                }\n            }\n\n            Self::Echo {\n                expression,\n                message,\n                ..\n            } => expression\n                .as_ref()\n                .and_then(|expression| expression.find_node(byte_index))\n                .or_else(|| {\n                    message\n                        .as_ref()\n                        .and_then(|message| message.find_node(byte_index))\n                })\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::Panic { message, .. } => message\n                .as_ref()\n                .and_then(|message| message.find_node(byte_index))\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::Todo { kind, message, .. } => match kind {\n                TodoKind::Keyword => message\n                    .as_ref()\n                    .and_then(|message| message.find_node(byte_index))\n                    .or_else(|| self.self_if_contains_location(byte_index)),\n                // We don't want to match on todos that were implicitly inserted\n                // by the compiler as it would result in confusing suggestions\n                // from the LSP.\n                TodoKind::EmptyFunction { .. } | TodoKind::EmptyBlock | TodoKind::IncompleteUse => {\n                    None\n                }\n            },\n\n            Self::Pipeline {\n                first_value,\n                assignments,\n                finally,\n                ..\n            } => first_value\n                .find_node(byte_index)\n                .or_else(|| {\n                    assignments\n                        .iter()\n                        .find_map(|(e, _)| e.find_node(byte_index))\n                })\n                .or_else(|| finally.find_node(byte_index)),\n\n            // Exit the search and return None if during iteration a statement\n            // is found with a start index beyond the index under search.\n            Self::Block { statements, .. } => {\n                for statement in statements {\n                    if statement.location().start > byte_index {\n                        break;\n                    }\n\n                    if let Some(located) = statement.find_node(byte_index) {\n                        return Some(located);\n                    }\n                }\n\n                None\n            }\n\n            // Exit the search and return the encompassing type (e.g., list or tuple)\n            // if during iteration, an element is encountered with a start index\n            // beyond the index under search.\n            Self::Tuple {\n                elements: expressions,\n                ..\n            } => {\n                for expression in expressions {\n                    if expression.location().start > byte_index {\n                        break;\n                    }\n\n                    if let Some(located) = expression.find_node(byte_index) {\n                        return Some(located);\n                    }\n                }\n\n                self.self_if_contains_location(byte_index)\n            }\n\n            Self::List {\n                elements: expressions,\n                tail,\n                ..\n            } => {\n                for expression in expressions {\n                    if expression.location().start > byte_index {\n                        break;\n                    }\n\n                    if let Some(located) = expression.find_node(byte_index) {\n                        return Some(located);\n                    }\n                }\n\n                if let Some(tail) = tail\n                    && let Some(node) = tail.find_node(byte_index)\n                {\n                    return Some(node);\n                }\n                self.self_if_contains_location(byte_index)\n            }\n\n            Self::NegateBool { value, .. } | Self::NegateInt { value, .. } => value\n                .find_node(byte_index)\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::Fn {\n                body, arguments, ..\n            } => arguments\n                .iter()\n                .find_map(|arg| arg.find_node(byte_index))\n                .or_else(|| body.iter().find_map(|s| s.find_node(byte_index)))\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::Call { fun, arguments, .. } => arguments\n                .iter()\n                .find_map(|argument| argument.find_node(byte_index, fun, arguments))\n                .or_else(|| fun.find_node(byte_index))\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::BinOp { left, right, .. } => left\n                .find_node(byte_index)\n                .or_else(|| right.find_node(byte_index)),\n\n            Self::Case {\n                subjects, clauses, ..\n            } => subjects\n                .iter()\n                .find_map(|subject| subject.find_node(byte_index))\n                .or_else(|| clauses.iter().find_map(|c| c.find_node(byte_index)))\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::RecordAccess {\n                record: expression, ..\n            }\n            | Self::TupleIndex {\n                tuple: expression, ..\n            } => expression\n                .find_node(byte_index)\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::BitArray { segments, .. } => segments\n                .iter()\n                .find_map(|arg| arg.find_node(byte_index))\n                .or_else(|| self.self_if_contains_location(byte_index)),\n\n            Self::RecordUpdate {\n                record_assignment,\n                constructor,\n                arguments,\n                ..\n            } => arguments\n                .iter()\n                .filter(|argument| argument.implicit.is_none())\n                .find_map(|argument| argument.find_node(byte_index, constructor, arguments))\n                .or_else(|| constructor.find_node(byte_index))\n                .or_else(|| {\n                    record_assignment\n                        .as_ref()\n                        .and_then(|assignment| assignment.find_node(byte_index))\n                })\n                .or_else(|| self.self_if_contains_location(byte_index)),\n        }\n    }\n\n    pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> {\n        match self {\n            Self::Var { .. }\n            | Self::Int { .. }\n            | Self::Float { .. }\n            | Self::String { .. }\n            | Self::ModuleSelect { .. }\n            | Self::Invalid { .. }\n            | Self::PositionalAccess { .. } => None,\n\n            Self::Pipeline {\n                first_value,\n                assignments,\n                finally,\n                ..\n            } => first_value\n                .find_statement(byte_index)\n                .or_else(|| {\n                    assignments\n                        .iter()\n                        .find_map(|(e, _)| e.find_statement(byte_index))\n                })\n                .or_else(|| finally.find_statement(byte_index)),\n\n            // Exit the search and return None if during iteration a statement\n            // is found with a start index beyond the index under search.\n            Self::Block { statements, .. } => {\n                for statement in statements {\n                    if statement.location().start > byte_index {\n                        break;\n                    }\n\n                    if let Some(located) = statement.find_statement(byte_index) {\n                        return Some(located);\n                    }\n                }\n\n                None\n            }\n\n            // Exit the search and return the encompassing type (e.g., list or tuple)\n            // if during iteration, an element is encountered with a start index\n            // beyond the index under search.\n            Self::Tuple {\n                elements: expressions,\n                ..\n            } => {\n                for expression in expressions {\n                    if expression.location().start > byte_index {\n                        break;\n                    }\n\n                    if let Some(located) = expression.find_statement(byte_index) {\n                        return Some(located);\n                    }\n                }\n\n                None\n            }\n\n            Self::List {\n                elements: expressions,\n                tail,\n                ..\n            } => {\n                for expression in expressions {\n                    if expression.location().start > byte_index {\n                        break;\n                    }\n\n                    if let Some(located) = expression.find_statement(byte_index) {\n                        return Some(located);\n                    }\n                }\n\n                if let Some(tail) = tail\n                    && let Some(node) = tail.find_statement(byte_index)\n                {\n                    return Some(node);\n                }\n                None\n            }\n\n            Self::NegateBool { value, .. } | Self::NegateInt { value, .. } => {\n                value.find_statement(byte_index)\n            }\n\n            Self::Fn { body, .. } => body.iter().find_map(|s| s.find_statement(byte_index)),\n\n            Self::Call { fun, arguments, .. } => arguments\n                .iter()\n                .find_map(|argument| argument.find_statement(byte_index))\n                .or_else(|| fun.find_statement(byte_index)),\n\n            Self::BinOp { left, right, .. } => left\n                .find_statement(byte_index)\n                .or_else(|| right.find_statement(byte_index)),\n\n            Self::Case {\n                subjects, clauses, ..\n            } => subjects\n                .iter()\n                .find_map(|subject| subject.find_statement(byte_index))\n                .or_else(|| {\n                    clauses\n                        .iter()\n                        .find_map(|c| c.then.find_statement(byte_index))\n                }),\n\n            Self::RecordAccess {\n                record: expression, ..\n            }\n            | Self::TupleIndex {\n                tuple: expression, ..\n            } => expression.find_statement(byte_index),\n\n            Self::Echo {\n                expression,\n                message,\n                ..\n            } => expression\n                .as_ref()\n                .and_then(|expression| expression.find_statement(byte_index))\n                .or_else(|| {\n                    message\n                        .as_ref()\n                        .and_then(|message| message.find_statement(byte_index))\n                }),\n\n            Self::Todo { message, kind, .. } => match kind {\n                TodoKind::EmptyFunction { .. } | TodoKind::IncompleteUse | TodoKind::EmptyBlock => {\n                    None\n                }\n                TodoKind::Keyword => message\n                    .as_ref()\n                    .and_then(|message| message.find_statement(byte_index)),\n            },\n\n            Self::Panic { message, .. } => message\n                .as_ref()\n                .and_then(|message| message.find_statement(byte_index)),\n\n            Self::BitArray { segments, .. } => segments\n                .iter()\n                .find_map(|arg| arg.value.find_statement(byte_index)),\n\n            Self::RecordUpdate {\n                record_assignment,\n                arguments,\n                ..\n            } => arguments\n                .iter()\n                .filter(|arg| arg.implicit.is_none())\n                .find_map(|arg| arg.find_statement(byte_index))\n                .or_else(|| {\n                    record_assignment\n                        .as_ref()\n                        .and_then(|r| r.value.find_statement(byte_index))\n                }),\n        }\n    }\n\n    fn self_if_contains_location(&self, byte_index: u32) -> Option<Located<'_>> {\n        if self.location().contains(byte_index) {\n            Some(self.into())\n        } else {\n            None\n        }\n    }\n\n    pub fn is_non_zero_compile_time_number(&self) -> bool {\n        match self {\n            Self::Int { int_value, .. } => int_value != &BigInt::ZERO,\n            Self::Float { float_value, .. } => !float_value.value().is_zero(),\n            Self::String { .. }\n            | Self::Block { .. }\n            | Self::Pipeline { .. }\n            | Self::Var { .. }\n            | Self::Fn { .. }\n            | Self::List { .. }\n            | Self::Call { .. }\n            | Self::BinOp { .. }\n            | Self::Case { .. }\n            | Self::RecordAccess { .. }\n            | Self::PositionalAccess { .. }\n            | Self::ModuleSelect { .. }\n            | Self::Tuple { .. }\n            | Self::TupleIndex { .. }\n            | Self::Todo { .. }\n            | Self::Panic { .. }\n            | Self::Echo { .. }\n            | Self::BitArray { .. }\n            | Self::RecordUpdate { .. }\n            | Self::NegateBool { .. }\n            | Self::NegateInt { .. }\n            | Self::Invalid { .. } => false,\n        }\n    }\n\n    pub fn is_zero_compile_time_number(&self) -> bool {\n        match self {\n            Self::Int { int_value, .. } => int_value == &BigInt::ZERO,\n            Self::Float { float_value, .. } => float_value.value().is_zero(),\n            Self::String { .. }\n            | Self::Block { .. }\n            | Self::Pipeline { .. }\n            | Self::Var { .. }\n            | Self::Fn { .. }\n            | Self::List { .. }\n            | Self::Call { .. }\n            | Self::BinOp { .. }\n            | Self::Case { .. }\n            | Self::RecordAccess { .. }\n            | Self::PositionalAccess { .. }\n            | Self::ModuleSelect { .. }\n            | Self::Tuple { .. }\n            | Self::TupleIndex { .. }\n            | Self::Todo { .. }\n            | Self::Panic { .. }\n            | Self::Echo { .. }\n            | Self::BitArray { .. }\n            | Self::RecordUpdate { .. }\n            | Self::NegateBool { .. }\n            | Self::NegateInt { .. }\n            | Self::Invalid { .. } => false,\n        }\n    }\n\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Self::Fn { location, .. }\n            | Self::Int { location, .. }\n            | Self::Var { location, .. }\n            | Self::Todo { location, .. }\n            | Self::Echo { location, .. }\n            | Self::Case { location, .. }\n            | Self::Call { location, .. }\n            | Self::List { location, .. }\n            | Self::Float { location, .. }\n            | Self::BinOp { location, .. }\n            | Self::Tuple { location, .. }\n            | Self::Panic { location, .. }\n            | Self::Block { location, .. }\n            | Self::String { location, .. }\n            | Self::NegateBool { location, .. }\n            | Self::NegateInt { location, .. }\n            | Self::Pipeline { location, .. }\n            | Self::BitArray { location, .. }\n            | Self::TupleIndex { location, .. }\n            | Self::ModuleSelect { location, .. }\n            | Self::RecordAccess { location, .. }\n            | Self::PositionalAccess { location, .. }\n            | Self::RecordUpdate { location, .. }\n            | Self::Invalid { location, .. } => *location,\n        }\n    }\n\n    pub fn type_defining_location(&self) -> SrcSpan {\n        match self {\n            Self::Fn { location, .. }\n            | Self::Int { location, .. }\n            | Self::Var { location, .. }\n            | Self::Todo { location, .. }\n            | Self::Echo { location, .. }\n            | Self::Case { location, .. }\n            | Self::Call { location, .. }\n            | Self::List { location, .. }\n            | Self::Float { location, .. }\n            | Self::BinOp { location, .. }\n            | Self::Tuple { location, .. }\n            | Self::String { location, .. }\n            | Self::Panic { location, .. }\n            | Self::NegateBool { location, .. }\n            | Self::NegateInt { location, .. }\n            | Self::Pipeline { location, .. }\n            | Self::BitArray { location, .. }\n            | Self::TupleIndex { location, .. }\n            | Self::ModuleSelect { location, .. }\n            | Self::RecordAccess { location, .. }\n            | Self::PositionalAccess { location, .. }\n            | Self::RecordUpdate { location, .. }\n            | Self::Invalid { location, .. } => *location,\n            Self::Block { statements, .. } => statements.last().location(),\n        }\n    }\n\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        match self {\n            TypedExpr::Fn { .. }\n            | TypedExpr::Int { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | Self::Invalid { .. } => None,\n\n            // TODO: test\n            // TODO: definition\n            TypedExpr::RecordUpdate { .. } => None,\n\n            // TODO: test\n            TypedExpr::ModuleSelect {\n                module_name,\n                constructor,\n                ..\n            } => Some(DefinitionLocation {\n                module: Some(module_name.clone()),\n                span: constructor.location(),\n            }),\n\n            // TODO: test\n            TypedExpr::Var { constructor, .. } => Some(constructor.definition_location()),\n        }\n    }\n\n    pub fn type_(&self) -> Arc<Type> {\n        match self {\n            Self::NegateBool { .. } => bool(),\n            Self::NegateInt { value, .. } => value.type_(),\n            Self::Var { constructor, .. } => constructor.type_.clone(),\n            Self::Fn { type_, .. }\n            | Self::Int { type_, .. }\n            | Self::Todo { type_, .. }\n            | Self::Echo { type_, .. }\n            | Self::Case { type_, .. }\n            | Self::List { type_, .. }\n            | Self::Call { type_, .. }\n            | Self::Float { type_, .. }\n            | Self::Panic { type_, .. }\n            | Self::BinOp { type_, .. }\n            | Self::Tuple { type_, .. }\n            | Self::String { type_, .. }\n            | Self::BitArray { type_, .. }\n            | Self::TupleIndex { type_, .. }\n            | Self::ModuleSelect { type_, .. }\n            | Self::RecordAccess { type_, .. }\n            | Self::PositionalAccess { type_, .. }\n            | Self::RecordUpdate { type_, .. }\n            | Self::Invalid { type_, .. } => type_.clone(),\n            Self::Pipeline { finally, .. } => finally.type_(),\n            Self::Block { statements, .. } => statements.last().type_(),\n        }\n    }\n\n    pub fn is_literal(&self) -> bool {\n        match self {\n            Self::Int { .. } | Self::Float { .. } | Self::String { .. } => true,\n\n            Self::List { elements, .. } | Self::Tuple { elements, .. } => {\n                elements.iter().all(|value| value.is_literal())\n            }\n\n            Self::BitArray { segments, .. } => {\n                segments.iter().all(|segment| segment.value.is_literal())\n            }\n\n            // Calls are literals if they are records and all the arguemnts are also literals.\n            Self::Call { fun, arguments, .. } => {\n                fun.is_record_literal()\n                    && arguments.iter().all(|argument| argument.value.is_literal())\n            }\n\n            // Variables are literals if they are record constructors that take no arguments.\n            Self::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { arity: 0, .. },\n                        ..\n                    },\n                ..\n            } => true,\n\n            Self::Block { .. }\n            | Self::Pipeline { .. }\n            | Self::Var { .. }\n            | Self::Fn { .. }\n            | Self::BinOp { .. }\n            | Self::Case { .. }\n            | Self::RecordAccess { .. }\n            | Self::PositionalAccess { .. }\n            | Self::ModuleSelect { .. }\n            | Self::TupleIndex { .. }\n            | Self::Todo { .. }\n            | Self::Panic { .. }\n            | Self::Echo { .. }\n            | Self::RecordUpdate { .. }\n            | Self::NegateBool { .. }\n            | Self::NegateInt { .. }\n            | Self::Invalid { .. } => false,\n        }\n    }\n\n    pub fn is_known_bool(&self) -> bool {\n        match self {\n            TypedExpr::BinOp {\n                left, right, name, ..\n            } if name.is_bool_operator() => left.is_known_bool() && right.is_known_bool(),\n            TypedExpr::NegateBool { value, .. } => value.is_known_bool(),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => self.is_literal(),\n        }\n    }\n\n    pub fn is_literal_string(&self) -> bool {\n        matches!(self, Self::String { .. })\n    }\n\n    /// Returns `true` if the typed expr is [`Var`].\n    ///\n    /// [`Var`]: TypedExpr::Var\n    #[must_use]\n    pub fn is_var(&self) -> bool {\n        matches!(self, Self::Var { .. })\n    }\n\n    pub fn get_documentation(&self) -> Option<&str> {\n        match self {\n            TypedExpr::Var { constructor, .. } => constructor.get_documentation(),\n            TypedExpr::ModuleSelect { constructor, .. } => constructor.get_documentation(),\n            TypedExpr::RecordAccess { documentation, .. } => documentation.as_deref(),\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    /// Returns `true` if the typed expr is [`Case`].\n    ///\n    /// [`Case`]: TypedExpr::Case\n    #[must_use]\n    pub fn is_case(&self) -> bool {\n        matches!(self, Self::Case { .. })\n    }\n\n    /// Returns `true` if the typed expr is [`Pipeline`].\n    ///\n    /// [`Pipeline`]: TypedExpr::Pipeline\n    #[must_use]\n    pub fn is_pipeline(&self) -> bool {\n        matches!(self, Self::Pipeline { .. })\n    }\n\n    pub fn is_pure_value_constructor(&self) -> bool {\n        match self {\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::Fn { .. } => true,\n\n            TypedExpr::NegateBool { value, .. } | TypedExpr::NegateInt { value, .. } => {\n                value.is_pure_value_constructor()\n            }\n\n            // Just selecting a value from a module never has any effects. The\n            // selected thing might be a function but it has no side effects as\n            // long as it's not called!\n            TypedExpr::ModuleSelect { .. } => true,\n\n            // A pipeline is a pure value constructor if its last step is a record builder,\n            // or a call to a pure function. For example:\n            //  - `wibble() |> wobble() |> Ok`\n            //  - `\"hello\" |> fn(s) { s <> \" world!\" }`\n            TypedExpr::Pipeline {\n                first_value,\n                assignments,\n                finally,\n                ..\n            } => {\n                first_value.value.is_pure_value_constructor()\n                    && assignments\n                        .iter()\n                        .all(|(assignment, _)| assignment.value.is_pure_value_constructor())\n                    && finally.is_pure_value_constructor()\n            }\n\n            TypedExpr::Call { fun, arguments, .. } => {\n                (fun.is_record_literal() || fun.called_function_purity().is_pure())\n                    && arguments\n                        .iter()\n                        .all(|argument| argument.value.is_pure_value_constructor())\n            }\n\n            // A block is pure if all the statements it's made of are pure.\n            // For example `{ True 1 }`\n            TypedExpr::Block { statements, .. } => {\n                statements.iter().all(|s| s.is_pure_value_constructor())\n            }\n\n            // A case is pure if its subject and all its branches are.\n            // For example:\n            // ```gleam\n            // case 1 + 1 {\n            //   0 -> 1\n            //   _ -> 2\n            // }\n            // ```\n            TypedExpr::Case {\n                subjects, clauses, ..\n            } => {\n                subjects.iter().all(|s| s.is_pure_value_constructor())\n                    && clauses.iter().all(|c| c.then.is_pure_value_constructor())\n            }\n\n            // `panic`, `todo`, and placeholders are never considered pure value constructors,\n            // we don't want to raise a warning for an unused value if it's one\n            // of those.\n            TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::Invalid { .. } => false,\n        }\n    }\n\n    /// Returns the purity of the left hand side of a function call. For example:\n    ///\n    /// ```gleam\n    /// io.println(\"Hello, world!\")\n    /// ```\n    ///\n    /// Here, the left hand side is `io.println`, which is an impure function,\n    /// so we would return `Purity::Impure`.\n    ///\n    /// This does not check whether an expression is pure on its own; for that\n    /// see `is_pure_value_constructor`.\n    ///\n    pub fn called_function_purity(&self) -> Purity {\n        match self {\n            TypedExpr::Var { constructor, .. } => constructor.called_function_purity(),\n            TypedExpr::ModuleSelect { constructor, .. } => constructor.called_function_purity(),\n            TypedExpr::Fn { purity, .. } => *purity,\n\n            // While we can infer the purity of some of these expressions, such\n            // as `Case`, in this example:\n            //  ```gleam\n            // case x {\n            //   True -> io.println\n            //   False -> function.identity\n            // }(\"Hello\")\n            // ```\n            //\n            // This kind of code is rare in real Gleam applications, and as this\n            // system is just used for warnings, it is unlikely that supporting\n            // them will provide any significant benefit to developer experience,\n            // so we just return `Unknown` for simplicity.\n            //\n            TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Echo { .. } => Purity::Unknown,\n\n            // The following expressions are all invalid on the left hand side\n            // of a call expression: `10()` is not valid Gleam. Therefore, we\n            // don't really care about any of these as they shouldn't appear in\n            // well typed Gleam code, and so we can just return `Unknown`.\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Invalid { .. } => Purity::Unknown,\n        }\n    }\n\n    #[must_use]\n    /// Returns true if the value is a literal record builder like\n    /// `Wibble(1, 2)`, `module.Wobble(\"a\")`\n    ///\n    pub fn is_record_literal(&self) -> bool {\n        match self {\n            TypedExpr::Call { fun, .. } => fun.is_record_literal(),\n            TypedExpr::Var { constructor, .. } => constructor.variant.is_record(),\n            TypedExpr::ModuleSelect {\n                constructor: ModuleValueConstructor::Record { .. },\n                ..\n            } => true,\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => false,\n        }\n    }\n\n    /// Returns true if the expression is a record constructor function/record constructor\n    /// with non-zero arity.\n    ///\n    pub fn is_record_constructor_function(&self) -> bool {\n        match self {\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { arity, .. },\n                        ..\n                    },\n                ..\n            } => *arity > 0,\n\n            TypedExpr::ModuleSelect {\n                constructor: ModuleValueConstructor::Record { arity, .. },\n                ..\n            } => *arity > 0,\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => false,\n        }\n    }\n\n    /// If the given expression is a literal record builder, this will return\n    /// index of the variant being built.\n    ///\n    pub fn variant_index(&self) -> Option<u16> {\n        match self {\n            TypedExpr::Call { fun, .. } => fun.variant_index(),\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { variant_index, .. },\n                        ..\n                    },\n                ..\n            }\n            | TypedExpr::ModuleSelect {\n                constructor: ModuleValueConstructor::Record { variant_index, .. },\n                ..\n            } => Some(*variant_index),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    #[must_use]\n    /// If `self` is a record constructor, returns the number of arguments it\n    /// needs to be called. Otherwise, returns `None`.\n    ///\n    pub fn record_constructor_arity(&self) -> Option<u16> {\n        match self {\n            TypedExpr::Call { fun, .. } => fun.record_constructor_arity(),\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { arity, .. },\n                        ..\n                    },\n                ..\n            } => Some(*arity),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    pub fn var_constructor(&self) -> Option<(&ValueConstructor, &EcoString)> {\n        if let TypedExpr::Var {\n            constructor, name, ..\n        } = self\n        {\n            Some((constructor, name))\n        } else {\n            None\n        }\n    }\n\n    #[must_use]\n    pub(crate) fn is_panic(&self) -> bool {\n        matches!(self, TypedExpr::Panic { .. })\n    }\n\n    pub(crate) fn call_arguments(&self) -> Option<&Vec<TypedCallArg>> {\n        if let TypedExpr::Call { arguments, .. } = self {\n            Some(arguments)\n        } else {\n            None\n        }\n    }\n\n    pub(crate) fn fn_expression_body(&self) -> Option<&Vec1<TypedStatement>> {\n        if let TypedExpr::Fn { body, .. } = self {\n            Some(body)\n        } else {\n            None\n        }\n    }\n\n    // If the expression is a fn or a block then returns the location of its\n    // last element, otherwise it returns the location of the whole expression.\n    pub fn last_location(&self) -> SrcSpan {\n        match self {\n            TypedExpr::Int { location, .. }\n            | TypedExpr::Float { location, .. }\n            | TypedExpr::String { location, .. }\n            | TypedExpr::Var { location, .. }\n            | TypedExpr::List { location, .. }\n            | TypedExpr::Call { location, .. }\n            | TypedExpr::BinOp { location, .. }\n            | TypedExpr::Case { location, .. }\n            | TypedExpr::RecordAccess { location, .. }\n            | TypedExpr::PositionalAccess { location, .. }\n            | TypedExpr::ModuleSelect { location, .. }\n            | TypedExpr::Tuple { location, .. }\n            | TypedExpr::TupleIndex { location, .. }\n            | TypedExpr::Todo { location, .. }\n            | TypedExpr::Panic { location, .. }\n            | TypedExpr::BitArray { location, .. }\n            | TypedExpr::RecordUpdate { location, .. }\n            | TypedExpr::NegateBool { location, .. }\n            | TypedExpr::NegateInt { location, .. }\n            | TypedExpr::Invalid { location, .. }\n            | TypedExpr::Echo { location, .. }\n            | TypedExpr::Pipeline { location, .. } => *location,\n\n            TypedExpr::Block { statements, .. } => statements.last().last_location(),\n            TypedExpr::Fn { body, .. } => body.last().last_location(),\n        }\n    }\n\n    pub fn field_map(&self) -> Option<&FieldMap> {\n        match self {\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n\n            TypedExpr::Var { constructor, .. } => constructor.field_map(),\n            TypedExpr::ModuleSelect { constructor, .. } => match constructor {\n                ModuleValueConstructor::Record { field_map, .. }\n                | ModuleValueConstructor::Fn { field_map, .. } => field_map.as_ref(),\n                ModuleValueConstructor::Constant { .. } => None,\n            },\n        }\n    }\n\n    pub fn is_invalid(&self) -> bool {\n        matches!(self, TypedExpr::Invalid { .. })\n    }\n\n    /// Checks that two expressions are written in the same (ignoring\n    /// whitespace).\n    ///\n    /// This is useful for the language server to know when it is possible to\n    /// merge two blocks of code together because they are the same.\n    /// Simply checking for equality of the AST nodes wouldn't work as those\n    /// also contain the source location (meaning that two expression that look\n    /// the same but are in different places would be considered different)!\n    ///\n    pub fn syntactically_eq(&self, other: &TypedExpr) -> bool {\n        match (self, other) {\n            (TypedExpr::Int { int_value: n, .. }, TypedExpr::Int { int_value: m, .. }) => n == m,\n            (TypedExpr::Int { .. }, _) => false,\n\n            (TypedExpr::Float { float_value: n, .. }, TypedExpr::Float { float_value: m, .. }) => {\n                n == m\n            }\n            (TypedExpr::Float { .. }, _) => false,\n\n            (TypedExpr::String { value, .. }, TypedExpr::String { value: other, .. }) => {\n                value == other\n            }\n            (TypedExpr::String { .. }, _) => false,\n\n            (\n                TypedExpr::Block { statements, .. },\n                TypedExpr::Block {\n                    statements: other, ..\n                },\n            ) => pairwise_all(statements, other, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n\n            (TypedExpr::Block { .. }, _) => false,\n\n            (\n                TypedExpr::List { elements, tail, .. },\n                TypedExpr::List {\n                    elements: other_elements,\n                    tail: other_tail,\n                    ..\n                },\n            ) => {\n                let tails_are_equal = match (tail, other_tail) {\n                    (Some(one), Some(other)) => one.syntactically_eq(other),\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (None, None) => true,\n                };\n\n                tails_are_equal\n                    && pairwise_all(elements, other_elements, |(one, other)| {\n                        one.syntactically_eq(other)\n                    })\n            }\n            (TypedExpr::List { .. }, _) => false,\n\n            (TypedExpr::Var { name, .. }, TypedExpr::Var { name: other, .. }) => name == other,\n            (TypedExpr::Var { .. }, _) => false,\n\n            (\n                TypedExpr::Fn {\n                    arguments, body, ..\n                },\n                TypedExpr::Fn {\n                    arguments: other_arguments,\n                    body: other_body,\n                    ..\n                },\n            ) => {\n                let arguments_are_equal =\n                    pairwise_all(arguments, other_arguments, |(one, other)| {\n                        one.get_variable_name() == other.get_variable_name()\n                    });\n\n                let bodies_are_equal =\n                    pairwise_all(body, other_body, |(one, other)| one.syntactically_eq(other));\n\n                arguments_are_equal && bodies_are_equal\n            }\n            (TypedExpr::Fn { .. }, _) => false,\n\n            (\n                TypedExpr::Pipeline {\n                    first_value,\n                    assignments,\n                    finally,\n                    ..\n                },\n                TypedExpr::Pipeline {\n                    first_value: other_first_value,\n                    assignments: other_assignments,\n                    finally: other_finally,\n                    ..\n                },\n            ) => {\n                first_value.value.syntactically_eq(&other_first_value.value)\n                    && pairwise_all(assignments, other_assignments, |(one, other)| {\n                        one.0.value.syntactically_eq(&other.0.value)\n                    })\n                    && finally.syntactically_eq(other_finally)\n            }\n            (TypedExpr::Pipeline { .. }, _) => false,\n\n            (\n                TypedExpr::Call { fun, arguments, .. },\n                TypedExpr::Call {\n                    fun: other_fun,\n                    arguments: other_arguments,\n                    ..\n                },\n            ) => {\n                fun.syntactically_eq(other_fun)\n                    && pairwise_all(arguments, other_arguments, |(one, other)| {\n                        one.label == other.label && one.value.syntactically_eq(&other.value)\n                    })\n            }\n            (TypedExpr::Call { .. }, _) => false,\n\n            (\n                TypedExpr::BinOp {\n                    name, left, right, ..\n                },\n                TypedExpr::BinOp {\n                    name: other_name,\n                    left: other_left,\n                    right: other_right,\n                    ..\n                },\n            ) => {\n                name == other_name\n                    && left.syntactically_eq(other_left)\n                    && right.syntactically_eq(other_right)\n            }\n            (TypedExpr::BinOp { .. }, _) => false,\n\n            (\n                TypedExpr::Case {\n                    subjects, clauses, ..\n                },\n                TypedExpr::Case {\n                    subjects: other_subjects,\n                    clauses: other_clauses,\n                    ..\n                },\n            ) => {\n                pairwise_all(subjects, other_subjects, |(one, other)| {\n                    one.syntactically_eq(other)\n                }) && pairwise_all(clauses, other_clauses, |(one, other)| {\n                    one.syntactically_eq(other)\n                })\n            }\n            (TypedExpr::Case { .. }, _) => false,\n\n            (\n                TypedExpr::RecordAccess { label, record, .. },\n                TypedExpr::RecordAccess {\n                    label: other_label,\n                    record: other_record,\n                    ..\n                },\n            ) => label == other_label && record.syntactically_eq(other_record),\n            (TypedExpr::RecordAccess { .. }, _) => false,\n\n            (\n                TypedExpr::ModuleSelect {\n                    label,\n                    module_alias,\n                    ..\n                },\n                TypedExpr::ModuleSelect {\n                    label: other_label,\n                    module_alias: other_module_alias,\n                    ..\n                },\n            ) => label == other_label && module_alias == other_module_alias,\n            (TypedExpr::ModuleSelect { .. }, _) => false,\n\n            (\n                TypedExpr::Tuple { elements, .. },\n                TypedExpr::Tuple {\n                    elements: other_elements,\n                    ..\n                },\n            ) => pairwise_all(elements, other_elements, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (TypedExpr::Tuple { .. }, _) => false,\n\n            (\n                TypedExpr::TupleIndex { index, tuple, .. },\n                TypedExpr::TupleIndex {\n                    index: other_index,\n                    tuple: other_tuple,\n                    ..\n                },\n            ) => index == other_index && tuple.syntactically_eq(other_tuple),\n            (TypedExpr::TupleIndex { .. }, _) => false,\n\n            (\n                TypedExpr::Todo { message, kind, .. },\n                TypedExpr::Todo {\n                    message: other_message,\n                    kind: other_kind,\n                    ..\n                },\n            ) => {\n                let messages_are_equal = match (message, other_message) {\n                    (Some(one), Some(other)) => one.syntactically_eq(other),\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                };\n                messages_are_equal && kind == other_kind\n            }\n            (TypedExpr::Todo { .. }, _) => false,\n\n            (\n                TypedExpr::Panic { message, .. },\n                TypedExpr::Panic {\n                    message: message_other,\n                    ..\n                },\n            ) => match (message, message_other) {\n                (None, None) => true,\n                (None, Some(_)) | (Some(_), None) => false,\n                (Some(one), Some(other)) => one.syntactically_eq(other),\n            },\n            (TypedExpr::Panic { .. }, _) => false,\n\n            (\n                TypedExpr::Echo {\n                    expression,\n                    message,\n                    ..\n                },\n                TypedExpr::Echo {\n                    expression: other_expression,\n                    message: other_message,\n                    ..\n                },\n            ) => {\n                let messages_are_equal = match (message, other_message) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some(one), Some(other)) => one.syntactically_eq(other),\n                };\n                let expressions_are_equal = match (expression, other_expression) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some(one), Some(other)) => one.syntactically_eq(other),\n                };\n                messages_are_equal && expressions_are_equal\n            }\n            (TypedExpr::Echo { .. }, _) => false,\n\n            (\n                TypedExpr::BitArray { segments, .. },\n                TypedExpr::BitArray {\n                    segments: other_segments,\n                    ..\n                },\n            ) => pairwise_all(segments, other_segments, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (TypedExpr::BitArray { .. }, _) => false,\n\n            (\n                TypedExpr::RecordUpdate {\n                    constructor,\n                    arguments,\n                    ..\n                },\n                TypedExpr::RecordUpdate {\n                    constructor: other_constructor,\n                    arguments: other_arguments,\n                    ..\n                },\n            ) => {\n                constructor.syntactically_eq(other_constructor)\n                    && pairwise_all(arguments, other_arguments, |(one, other)| {\n                        one.label == other.label && one.value.syntactically_eq(&other.value)\n                    })\n            }\n            (TypedExpr::RecordUpdate { .. }, _) => false,\n\n            (\n                TypedExpr::NegateBool { value, .. },\n                TypedExpr::NegateBool {\n                    value: other_value, ..\n                },\n            ) => value.syntactically_eq(other_value),\n            (TypedExpr::NegateBool { .. }, _) => false,\n\n            (TypedExpr::NegateInt { value: n, .. }, TypedExpr::NegateInt { value: m, .. }) => {\n                n.syntactically_eq(m)\n            }\n            (TypedExpr::NegateInt { .. }, _) => false,\n\n            (TypedExpr::PositionalAccess { .. }, _) => false,\n            (TypedExpr::Invalid { .. }, _) => false,\n        }\n    }\n\n    pub fn is_todo_with_no_message(&self) -> bool {\n        matches!(self, TypedExpr::Todo { message: None, .. })\n    }\n}\n\n/// Checks that two slices have the same number of item and that the given\n/// predicate holds for all pairs of items.\n///\npub(crate) fn pairwise_all<A>(one: &[A], other: &[A], function: impl Fn((&A, &A)) -> bool) -> bool {\n    one.len() == other.len() && one.iter().zip(other).all(function)\n}\n\nimpl<'a> From<&'a TypedExpr> for Located<'a> {\n    fn from(expression: &'a TypedExpr) -> Self {\n        Located::Expression {\n            expression,\n            position: ExpressionPosition::Expression,\n        }\n    }\n}\n\nimpl HasLocation for TypedExpr {\n    fn location(&self) -> SrcSpan {\n        self.location()\n    }\n}\n\nimpl HasType for TypedExpr {\n    fn type_(&self) -> Arc<Type> {\n        self.type_()\n    }\n}\n\nimpl bit_array::GetLiteralValue for TypedExpr {\n    fn as_int_literal(&self) -> Option<BigInt> {\n        if let TypedExpr::Int { int_value, .. } = self {\n            Some(int_value.clone())\n        } else {\n            None\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum InvalidExpression {\n    ModuleSelect {\n        module_name: EcoString,\n        label: EcoString,\n    },\n    UnknownVariable {\n        name: EcoString,\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/ast/untyped.rs",
    "content": "use vec1::Vec1;\n\nuse crate::parse::LiteralFloatValue;\n\nuse super::*;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum UntypedExpr {\n    Int {\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    },\n\n    Float {\n        location: SrcSpan,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    },\n\n    String {\n        location: SrcSpan,\n        value: EcoString,\n    },\n\n    Block {\n        location: SrcSpan,\n        statements: Vec1<UntypedStatement>,\n    },\n\n    Var {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    // TODO: create new variant for captures specifically\n    Fn {\n        /// For anonymous functions, this is the location of the entire function including the end of the body.\n        /// For named functions, this is the location of the function head.\n        location: SrcSpan,\n        kind: FunctionLiteralKind,\n        /// The byte location of the end of the function head before the opening bracket\n        end_of_head_byte_index: u32,\n        arguments: Vec<UntypedArg>,\n        body: Vec1<UntypedStatement>,\n        return_annotation: Option<TypeAst>,\n    },\n\n    List {\n        location: SrcSpan,\n        elements: Vec<Self>,\n        tail: Option<Box<Self>>,\n    },\n\n    Call {\n        location: SrcSpan,\n        fun: Box<Self>,\n        arguments: Vec<CallArg<Self>>,\n    },\n\n    BinOp {\n        location: SrcSpan,\n        name: BinOp,\n        name_location: SrcSpan,\n        left: Box<Self>,\n        right: Box<Self>,\n    },\n\n    PipeLine {\n        expressions: Vec1<Self>,\n    },\n\n    Case {\n        location: SrcSpan,\n        subjects: Vec<Self>,\n        // None if the case expression is missing a body.\n        clauses: Option<Vec<Clause<Self, (), ()>>>,\n    },\n\n    FieldAccess {\n        // This is the location of the whole record and field\n        //   user.name\n        //   ^^^^^^^^^\n        location: SrcSpan,\n        // This is the location of just the field access (ignoring the `.`)\n        //   user.name\n        //        ^^^^\n        label_location: SrcSpan,\n        label: EcoString,\n        container: Box<Self>,\n    },\n\n    Tuple {\n        location: SrcSpan,\n        elements: Vec<Self>,\n    },\n\n    TupleIndex {\n        location: SrcSpan,\n        index: u64,\n        tuple: Box<Self>,\n    },\n\n    Todo {\n        kind: TodoKind,\n        location: SrcSpan,\n        message: Option<Box<Self>>,\n    },\n\n    Panic {\n        location: SrcSpan,\n        message: Option<Box<Self>>,\n    },\n\n    Echo {\n        location: SrcSpan,\n        /// This is the position where the echo keyword ends:\n        /// ```gleam\n        /// echo wibble\n        /// // ^ ends here!\n        /// ```\n        keyword_end: u32,\n        expression: Option<Box<Self>>,\n        message: Option<Box<Self>>,\n    },\n\n    BitArray {\n        location: SrcSpan,\n        segments: Vec<UntypedExprBitArraySegment>,\n    },\n\n    RecordUpdate {\n        location: SrcSpan,\n        constructor: Box<Self>,\n        record: RecordBeingUpdated<UntypedExpr>,\n        arguments: Vec<UntypedRecordUpdateArg>,\n    },\n\n    NegateBool {\n        location: SrcSpan,\n        value: Box<Self>,\n    },\n\n    NegateInt {\n        location: SrcSpan,\n        value: Box<Self>,\n    },\n}\n\nimpl UntypedExpr {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Self::PipeLine { expressions, .. } => expressions\n                .first()\n                .location()\n                .merge(&expressions.last().location()),\n\n            Self::Fn { location, .. }\n            | Self::Var { location, .. }\n            | Self::Int { location, .. }\n            | Self::Todo { location, .. }\n            | Self::Echo { location, .. }\n            | Self::Case { location, .. }\n            | Self::Call { location, .. }\n            | Self::List { location, .. }\n            | Self::Float { location, .. }\n            | Self::Block { location, .. }\n            | Self::BinOp { location, .. }\n            | Self::Tuple { location, .. }\n            | Self::Panic { location, .. }\n            | Self::String { location, .. }\n            | Self::BitArray { location, .. }\n            | Self::NegateInt { location, .. }\n            | Self::NegateBool { location, .. }\n            | Self::TupleIndex { location, .. }\n            | Self::FieldAccess { location, .. }\n            | Self::RecordUpdate { location, .. } => *location,\n        }\n    }\n\n    pub fn start_byte_index(&self) -> u32 {\n        match self {\n            Self::Block { location, .. } => location.start,\n            Self::PipeLine { expressions, .. } => expressions.first().start_byte_index(),\n            Self::Int { .. }\n            | Self::Float { .. }\n            | Self::String { .. }\n            | Self::Var { .. }\n            | Self::Fn { .. }\n            | Self::List { .. }\n            | Self::Call { .. }\n            | Self::BinOp { .. }\n            | Self::Case { .. }\n            | Self::FieldAccess { .. }\n            | Self::Tuple { .. }\n            | Self::TupleIndex { .. }\n            | Self::Todo { .. }\n            | Self::Panic { .. }\n            | Self::Echo { .. }\n            | Self::BitArray { .. }\n            | Self::RecordUpdate { .. }\n            | Self::NegateBool { .. }\n            | Self::NegateInt { .. } => self.location().start,\n        }\n    }\n\n    pub fn bin_op_precedence(&self) -> u8 {\n        match self {\n            Self::BinOp { name, .. } => name.precedence(),\n            Self::PipeLine { .. } => 5,\n            Self::Int { .. }\n            | Self::Float { .. }\n            | Self::String { .. }\n            | Self::Block { .. }\n            | Self::Var { .. }\n            | Self::Fn { .. }\n            | Self::List { .. }\n            | Self::Call { .. }\n            | Self::Case { .. }\n            | Self::FieldAccess { .. }\n            | Self::Tuple { .. }\n            | Self::TupleIndex { .. }\n            | Self::Todo { .. }\n            | Self::Panic { .. }\n            | Self::Echo { .. }\n            | Self::BitArray { .. }\n            | Self::RecordUpdate { .. }\n            | Self::NegateBool { .. }\n            | Self::NegateInt { .. } => u8::MAX,\n        }\n    }\n\n    pub fn bin_op_name(&self) -> Option<&BinOp> {\n        if let UntypedExpr::BinOp { name, .. } = self {\n            Some(name)\n        } else {\n            None\n        }\n    }\n\n    pub fn can_have_multiple_per_line(&self) -> bool {\n        match self {\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Var { .. } => true,\n\n            UntypedExpr::NegateBool { value, .. }\n            | UntypedExpr::NegateInt { value, .. }\n            | UntypedExpr::FieldAccess {\n                container: value, ..\n            } => value.can_have_multiple_per_line(),\n\n            UntypedExpr::Block { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::BinOp { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. } => false,\n        }\n    }\n\n    pub fn is_tuple(&self) -> bool {\n        matches!(self, UntypedExpr::Tuple { .. })\n    }\n\n    /// Returns `true` if the untyped expr is [`Call`].\n    ///\n    /// [`Call`]: UntypedExpr::Call\n    #[must_use]\n    pub fn is_call(&self) -> bool {\n        matches!(self, Self::Call { .. })\n    }\n\n    #[must_use]\n    pub fn is_binop(&self) -> bool {\n        matches!(self, Self::BinOp { .. })\n    }\n\n    #[must_use]\n    pub fn is_pipeline(&self) -> bool {\n        matches!(self, Self::PipeLine { .. })\n    }\n\n    #[must_use]\n    pub fn is_todo(&self) -> bool {\n        matches!(self, Self::Todo { .. })\n    }\n\n    #[must_use]\n    pub fn is_panic(&self) -> bool {\n        matches!(self, Self::Panic { .. })\n    }\n}\n\nimpl HasLocation for UntypedExpr {\n    fn location(&self) -> SrcSpan {\n        self.location()\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum FunctionLiteralKind {\n    Capture { hole: SrcSpan },\n    Anonymous { head: SrcSpan },\n    Use { location: SrcSpan },\n}\n\nimpl FunctionLiteralKind {\n    pub fn is_capture(&self) -> bool {\n        match self {\n            FunctionLiteralKind::Capture { .. } => true,\n            FunctionLiteralKind::Anonymous { .. } | FunctionLiteralKind::Use { .. } => false,\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/ast/visit.rs",
    "content": "//! AST traversal routines, referenced from [`syn::visit`](https://docs.rs/syn/latest/syn/visit/index.html)\n//!\n//! Each method of the [`Visit`] trait can be overriden to customize the\n//! behaviour when visiting the corresponding type of AST node. By default,\n//! every method recursively visits the substructure of the node by using the\n//! right visitor method.\n//!\n//! # Example\n//!\n//! Suppose we would like to collect all function names in a module,\n//! we can do the following:\n//!\n//! ```no_run\n//! use gleam_core::ast::{TypedFunction, visit::{self, Visit}};\n//!\n//! struct FnCollector<'ast> {\n//!     functions: Vec<&'ast TypedFunction>\n//! }\n//!\n//! impl<'ast> Visit<'ast> for FnCollector<'ast> {\n//!     fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n//!         self.functions.push(fun);\n//!\n//!         // Use the default behaviour to visit any nested functions\n//!         visit::visit_typed_function(self, fun);\n//!     }\n//! }\n//!\n//! fn print_all_module_functions() {\n//!     let module = todo!(\"module\");\n//!     let mut fn_collector = FnCollector { functions: vec![] };\n//!\n//!     // This will walk the AST and collect all functions\n//!     fn_collector.visit_typed_module(module);\n//!\n//!     // Print the collected functions\n//!     println!(\"{:#?}\", fn_collector.functions);\n//! }\n//! ```\n\nuse crate::{\n    analyse::Inferred,\n    ast::{\n        BitArraySize, RecordBeingUpdated, TypedBitArraySize, TypedConstantBitArraySegment,\n        TypedDefinitions, TypedImport, TypedTailPattern, TypedTypeAlias, typed::InvalidExpression,\n    },\n    exhaustiveness::CompiledCase,\n    parse::LiteralFloatValue,\n    type_::{\n        FieldMap, ModuleValueConstructor, PatternConstructor, TypedCallArg, ValueConstructor,\n        error::VariableOrigin,\n    },\n};\nuse std::sync::Arc;\n\nuse ecow::EcoString;\nuse num_bigint::BigInt;\nuse vec1::Vec1;\n\nuse crate::type_::Type;\n\nuse super::{\n    AssignName, BinOp, BitArrayOption, CallArg, Pattern, PipelineAssignmentKind, RecordUpdateArg,\n    SrcSpan, Statement, TodoKind, TypeAst, TypedArg, TypedAssert, TypedAssignment, TypedClause,\n    TypedClauseGuard, TypedConstant, TypedCustomType, TypedExpr, TypedExprBitArraySegment,\n    TypedFunction, TypedModule, TypedModuleConstant, TypedPattern, TypedPatternBitArraySegment,\n    TypedPipelineAssignment, TypedStatement, TypedUse, untyped::FunctionLiteralKind,\n};\n\npub trait Visit<'ast> {\n    fn visit_typed_module(&mut self, module: &'ast TypedModule) {\n        visit_typed_module(self, module);\n    }\n\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        visit_typed_function(self, fun);\n    }\n\n    fn visit_typed_module_constant(&mut self, constant: &'ast TypedModuleConstant) {\n        visit_typed_module_constant(self, constant);\n    }\n\n    fn visit_typed_custom_type(&mut self, custom_type: &'ast TypedCustomType) {\n        visit_typed_custom_type(self, custom_type);\n    }\n\n    fn visit_typed_type_alias(&mut self, type_alias: &'ast TypedTypeAlias) {\n        visit_typed_type_alias(self, type_alias)\n    }\n\n    fn visit_typed_import(&mut self, import: &'ast TypedImport) {\n        visit_typed_import(self, import)\n    }\n\n    fn visit_typed_expr(&mut self, expr: &'ast TypedExpr) {\n        visit_typed_expr(self, expr);\n    }\n\n    fn visit_typed_expr_echo(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        expression: &'ast Option<Box<TypedExpr>>,\n        message: &'ast Option<Box<TypedExpr>>,\n    ) {\n        visit_typed_expr_echo(self, location, type_, expression, message);\n    }\n\n    fn visit_typed_expr_int(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        value: &'ast EcoString,\n    ) {\n        visit_typed_expr_int(self, location, type_, value);\n    }\n\n    fn visit_typed_expr_float(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        value: &'ast EcoString,\n    ) {\n        visit_typed_expr_float(self, location, type_, value);\n    }\n\n    fn visit_typed_expr_string(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        value: &'ast EcoString,\n    ) {\n        visit_typed_expr_string(self, location, type_, value);\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast SrcSpan,\n        statements: &'ast [TypedStatement],\n    ) {\n        visit_typed_expr_block(self, location, statements);\n    }\n\n    fn visit_typed_expr_pipeline(\n        &mut self,\n        location: &'ast SrcSpan,\n        first_value: &'ast TypedPipelineAssignment,\n        assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)],\n        finally: &'ast TypedExpr,\n        finally_kind: &'ast PipelineAssignmentKind,\n    ) {\n        visit_typed_expr_pipeline(\n            self,\n            location,\n            first_value,\n            assignments,\n            finally,\n            finally_kind,\n        );\n    }\n\n    fn visit_typed_expr_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        visit_typed_expr_var(self, location, constructor, name);\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<TypeAst>,\n    ) {\n        visit_typed_expr_fn(\n            self,\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n        );\n    }\n\n    fn visit_typed_expr_list(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        elements: &'ast [TypedExpr],\n        tail: &'ast Option<Box<TypedExpr>>,\n    ) {\n        visit_typed_expr_list(self, location, type_, elements, tail);\n    }\n\n    fn visit_typed_expr_call(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        fun: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        visit_typed_expr_call(self, location, type_, fun, arguments);\n    }\n\n    fn visit_typed_expr_bin_op(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        name: &'ast BinOp,\n        name_location: &'ast SrcSpan,\n        left: &'ast TypedExpr,\n        right: &'ast TypedExpr,\n    ) {\n        visit_typed_expr_bin_op(self, location, type_, name, name_location, left, right);\n    }\n\n    fn visit_typed_expr_case(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        subjects: &'ast [TypedExpr],\n        clauses: &'ast [TypedClause],\n        compiled_case: &'ast CompiledCase,\n    ) {\n        visit_typed_expr_case(self, location, type_, subjects, clauses, compiled_case);\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn visit_typed_expr_record_access(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        type_: &'ast Arc<Type>,\n        label: &'ast EcoString,\n        index: &'ast u64,\n        record: &'ast TypedExpr,\n        documentation: &'ast Option<EcoString>,\n    ) {\n        visit_typed_expr_record_access(\n            self,\n            location,\n            field_start,\n            type_,\n            label,\n            index,\n            record,\n            documentation,\n        );\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn visit_typed_expr_module_select(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        type_: &'ast Arc<Type>,\n        label: &'ast EcoString,\n        module_name: &'ast EcoString,\n        module_alias: &'ast EcoString,\n        constructor: &'ast ModuleValueConstructor,\n    ) {\n        visit_typed_expr_module_select(\n            self,\n            location,\n            field_start,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            constructor,\n        );\n    }\n\n    fn visit_typed_expr_tuple(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        elements: &'ast [TypedExpr],\n    ) {\n        visit_typed_expr_tuple(self, location, type_, elements);\n    }\n\n    fn visit_typed_expr_tuple_index(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        index: &'ast u64,\n        tuple: &'ast TypedExpr,\n    ) {\n        visit_typed_expr_tuple_index(self, location, type_, index, tuple);\n    }\n\n    fn visit_typed_expr_todo(\n        &mut self,\n        location: &'ast SrcSpan,\n        message: &'ast Option<Box<TypedExpr>>,\n        kind: &'ast TodoKind,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_expr_todo(self, location, message, kind, type_);\n    }\n\n    fn visit_typed_expr_panic(\n        &mut self,\n        location: &'ast SrcSpan,\n        message: &'ast Option<Box<TypedExpr>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_expr_panic(self, location, message, type_);\n    }\n\n    fn visit_typed_expr_bit_array(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        segments: &'ast [TypedExprBitArraySegment],\n    ) {\n        visit_typed_expr_bit_array(self, location, type_, segments);\n    }\n\n    fn visit_typed_expr_record_update(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        record: &'ast Option<Box<TypedAssignment>>,\n        constructor: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        visit_typed_expr_record_update(self, location, type_, record, constructor, arguments);\n    }\n\n    fn visit_typed_expr_negate_bool(&mut self, location: &'ast SrcSpan, value: &'ast TypedExpr) {\n        visit_typed_expr_negate_bool(self, location, value);\n    }\n\n    fn visit_typed_expr_negate_int(&mut self, location: &'ast SrcSpan, value: &'ast TypedExpr) {\n        visit_typed_expr_negate_int(self, location, value)\n    }\n\n    fn visit_typed_expr_invalid(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        extra_information: &'ast Option<InvalidExpression>,\n    ) {\n        visit_typed_expr_invalid(self, location, type_, extra_information);\n    }\n\n    fn visit_typed_statement(&mut self, statement: &'ast TypedStatement) {\n        visit_typed_statement(self, statement);\n    }\n\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        visit_typed_assignment(self, assignment);\n    }\n\n    fn visit_typed_use(&mut self, use_: &'ast TypedUse) {\n        visit_typed_use(self, use_);\n    }\n\n    fn visit_typed_assert(&mut self, assert: &'ast TypedAssert) {\n        visit_typed_assert(self, assert);\n    }\n\n    fn visit_typed_pipeline_assignment(&mut self, assignment: &'ast TypedPipelineAssignment) {\n        visit_typed_pipeline_assignment(self, assignment);\n    }\n\n    fn visit_typed_call_arg(&mut self, arg: &'ast TypedCallArg) {\n        visit_typed_call_arg(self, arg);\n    }\n\n    fn visit_typed_clause(&mut self, clause: &'ast TypedClause) {\n        visit_typed_clause(self, clause);\n    }\n\n    fn visit_typed_clause_guard(&mut self, guard: &'ast TypedClauseGuard) {\n        visit_typed_clause_guard(self, guard);\n    }\n\n    fn visit_typed_clause_guard_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        definition_location: &'ast SrcSpan,\n        origin: &'ast VariableOrigin,\n    ) {\n        visit_typed_clause_guard_var(self, location, name, type_, definition_location, origin);\n    }\n\n    fn visit_typed_clause_guard_tuple_index(\n        &mut self,\n        location: &'ast SrcSpan,\n        index: &'ast u64,\n        type_: &'ast Arc<Type>,\n        tuple: &'ast TypedClauseGuard,\n    ) {\n        visit_typed_clause_guard_tuple_index(self, location, index, type_, tuple)\n    }\n\n    fn visit_typed_clause_guard_field_access(\n        &mut self,\n        label_location: &'ast SrcSpan,\n        index: &'ast Option<u64>,\n        label: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        container: &'ast TypedClauseGuard,\n    ) {\n        visit_typed_clause_guard_field_access(self, label_location, index, label, type_, container)\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn visit_typed_clause_guard_module_select(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        definition_location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        label: &'ast EcoString,\n        module_name: &'ast EcoString,\n        module_alias: &'ast EcoString,\n        literal: &'ast TypedConstant,\n    ) {\n        visit_typed_clause_guard_module_select(\n            self,\n            location,\n            field_start,\n            definition_location,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            literal,\n        )\n    }\n\n    fn visit_typed_expr_bit_array_segment(&mut self, segment: &'ast TypedExprBitArraySegment) {\n        visit_typed_expr_bit_array_segment(self, segment);\n    }\n\n    fn visit_typed_bit_array_option(&mut self, option: &'ast BitArrayOption<TypedExpr>) {\n        visit_typed_bit_array_option(self, option);\n    }\n\n    fn visit_typed_pattern(&mut self, pattern: &'ast TypedPattern) {\n        visit_typed_pattern(self, pattern);\n    }\n\n    fn visit_typed_pattern_int(&mut self, location: &'ast SrcSpan, value: &'ast EcoString) {\n        visit_typed_pattern_int(self, location, value);\n    }\n\n    fn visit_typed_pattern_float(&mut self, location: &'ast SrcSpan, value: &'ast EcoString) {\n        visit_typed_pattern_float(self, location, value);\n    }\n\n    fn visit_typed_pattern_string(&mut self, location: &'ast SrcSpan, value: &'ast EcoString) {\n        visit_typed_pattern_string(self, location, value);\n    }\n\n    fn visit_typed_pattern_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        origin: &'ast VariableOrigin,\n    ) {\n        visit_typed_pattern_variable(self, location, name, type_, origin);\n    }\n\n    fn visit_typed_pattern_bit_array_size(&mut self, size: &'ast TypedBitArraySize) {\n        visit_typed_pattern_bit_array_size(self, size);\n    }\n\n    fn visit_typed_bit_array_size_int(&mut self, location: &'ast SrcSpan, value: &'ast EcoString) {\n        visit_typed_bit_array_size_int(self, location, value)\n    }\n\n    fn visit_typed_bit_array_size_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_bit_array_size_variable(self, location, name, constructor, type_)\n    }\n\n    fn visit_typed_pattern_assign(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        pattern: &'ast TypedPattern,\n    ) {\n        visit_typed_pattern_assign(self, location, name, pattern);\n    }\n\n    fn visit_typed_pattern_discard(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_pattern_discard(self, location, name, type_)\n    }\n\n    fn visit_typed_pattern_list(\n        &mut self,\n        location: &'ast SrcSpan,\n        elements: &'ast Vec<TypedPattern>,\n        tail: &'ast Option<Box<TypedTailPattern>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_pattern_list(self, location, elements, tail, type_);\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n\n    fn visit_typed_pattern_call_arg(&mut self, arg: &'ast CallArg<TypedPattern>) {\n        visit_typed_pattern_call_arg(self, arg);\n    }\n\n    fn visit_typed_pattern_tuple(\n        &mut self,\n        location: &'ast SrcSpan,\n        elements: &'ast Vec<TypedPattern>,\n    ) {\n        visit_typed_pattern_tuple(self, location, elements);\n    }\n\n    fn visit_typed_pattern_bit_array(\n        &mut self,\n        location: &'ast SrcSpan,\n        segments: &'ast [TypedPatternBitArraySegment],\n    ) {\n        visit_typed_pattern_bit_array(self, location, segments);\n    }\n\n    fn visit_typed_pattern_bit_array_option(&mut self, option: &'ast BitArrayOption<TypedPattern>) {\n        visit_typed_pattern_bit_array_option(self, option);\n    }\n\n    fn visit_typed_pattern_string_prefix(\n        &mut self,\n        location: &'ast SrcSpan,\n        left_location: &'ast SrcSpan,\n        left_side_assignment: &'ast Option<(EcoString, SrcSpan)>,\n        right_location: &'ast SrcSpan,\n        left_side_string: &'ast EcoString,\n        right_side_assignment: &'ast AssignName,\n    ) {\n        visit_typed_pattern_string_prefix(\n            self,\n            location,\n            left_location,\n            left_side_assignment,\n            right_location,\n            left_side_string,\n            right_side_assignment,\n        );\n    }\n\n    fn visit_typed_pattern_invalid(&mut self, location: &'ast SrcSpan, type_: &'ast Arc<Type>) {\n        visit_typed_pattern_invalid(self, location, type_);\n    }\n\n    fn visit_type_ast(\n        &mut self,\n        node: &'ast TypeAst,\n        // The type inferred for this annotation.\n        // It might not always be possible to infer one in presence of type\n        // errors, so this is optional!\n        inferred_type: Option<Arc<Type>>,\n    ) {\n        visit_type_ast(self, node, inferred_type);\n    }\n\n    fn visit_type_ast_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast [TypeAst],\n        inferred_arguments_types: Option<Vec<Arc<Type>>>,\n    ) {\n        visit_type_ast_constructor(\n            self,\n            location,\n            name_location,\n            module,\n            name,\n            arguments,\n            inferred_arguments_types,\n        );\n    }\n\n    fn visit_type_ast_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        arguments: &'ast [TypeAst],\n        arguments_types: Option<Vec<Arc<Type>>>,\n        return_: &'ast TypeAst,\n        return_type: Option<Arc<Type>>,\n    ) {\n        visit_type_ast_fn(\n            self,\n            location,\n            arguments,\n            arguments_types,\n            return_,\n            return_type,\n        );\n    }\n\n    fn visit_type_ast_var(&mut self, location: &'ast SrcSpan, name: &'ast EcoString) {\n        visit_type_ast_var(self, location, name);\n    }\n\n    fn visit_type_ast_tuple(\n        &mut self,\n        location: &'ast SrcSpan,\n        elements: &'ast [TypeAst],\n        elements_types: Option<&Vec<Arc<Type>>>,\n    ) {\n        visit_type_ast_tuple(self, location, elements, elements_types);\n    }\n\n    fn visit_type_ast_hole(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: Option<Arc<Type>>,\n    ) {\n        visit_type_ast_hole(self, location, name, type_);\n    }\n\n    fn visit_typed_constant(&mut self, constant: &'ast TypedConstant) {\n        visit_typed_constant(self, constant);\n    }\n\n    fn visit_typed_constant_int(\n        &mut self,\n        location: &'ast SrcSpan,\n        value: &'ast EcoString,\n        int_value: &'ast BigInt,\n    ) {\n        visit_typed_constant_int(self, location, value, int_value);\n    }\n\n    fn visit_typed_constant_float(\n        &mut self,\n        location: &'ast SrcSpan,\n        value: &'ast EcoString,\n        float_value: &'ast LiteralFloatValue,\n    ) {\n        visit_typed_constant_float(self, location, value, float_value);\n    }\n\n    fn visit_typed_constant_string(&mut self, location: &'ast SrcSpan, value: &'ast EcoString) {\n        visit_typed_constant_string(self, location, value);\n    }\n\n    fn visit_typed_constant_tuple(\n        &mut self,\n        location: &'ast SrcSpan,\n        elements: &'ast Vec<TypedConstant>,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_constant_tuple(self, location, elements, type_);\n    }\n\n    fn visit_typed_constant_list(\n        &mut self,\n        location: &'ast SrcSpan,\n        elements: &'ast Vec<TypedConstant>,\n        type_: &'ast Arc<Type>,\n        tail: &'ast Option<Box<TypedConstant>>,\n    ) {\n        visit_typed_constant_list(self, location, elements, type_, tail);\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn visit_typed_constant_record(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedConstant>>,\n        tag: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        field_map: &'ast Inferred<FieldMap>,\n        record_constructor: &'ast Option<Box<ValueConstructor>>,\n    ) {\n        visit_typed_constant_record(\n            self,\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        )\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn visit_typed_constant_record_update(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        record: &'ast RecordBeingUpdated<TypedConstant>,\n        arguments: &'ast [RecordUpdateArg<TypedConstant>],\n        tag: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        field_map: &'ast Inferred<FieldMap>,\n    ) {\n        visit_typed_constant_record_update(\n            self,\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag,\n            type_,\n            field_map,\n        )\n    }\n\n    fn visit_typed_constant_bit_array(\n        &mut self,\n        location: &'ast SrcSpan,\n        segments: &'ast [TypedConstantBitArraySegment],\n    ) {\n        visit_typed_constant_bit_array(self, location, segments);\n    }\n\n    fn visit_typed_constant_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        visit_typed_constant_var(self, location, module, name, constructor, type_);\n    }\n\n    fn visit_typed_constant_string_concatenation(\n        &mut self,\n        location: &'ast SrcSpan,\n        left: &'ast TypedConstant,\n        right: &'ast TypedConstant,\n    ) {\n        visit_typed_constant_string_concatenation(self, location, left, right);\n    }\n\n    fn visit_typed_constant_invalid(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        extra_information: &'ast Option<InvalidExpression>,\n    ) {\n        visit_typed_constant_invalid(self, location, type_, extra_information);\n    }\n}\n\nfn visit_typed_constant_invalid<'a, V: Visit<'a> + ?Sized>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Type,\n    _extra_information: &'a Option<InvalidExpression>,\n) {\n    // No further traversal needed for constant invalid expressions\n}\n\nfn visit_typed_constant_string_concatenation<'a, V: Visit<'a> + ?Sized>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    left: &'a TypedConstant,\n    right: &'a TypedConstant,\n) {\n    v.visit_typed_constant(left);\n    v.visit_typed_constant(right);\n}\n\npub fn visit_typed_constant_var<'a, V: Visit<'a> + ?Sized>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _module: &'a Option<(EcoString, SrcSpan)>,\n    _name: &'a EcoString,\n    _constructor: &'a Option<Box<ValueConstructor>>,\n    _type_: &'a Arc<Type>,\n) {\n    // No further traversal needed for constant vars\n}\n\nfn visit_typed_constant_bit_array<'a, V: Visit<'a> + ?Sized>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _segments: &'a [TypedConstantBitArraySegment],\n) {\n    // TODO\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn visit_typed_constant_record<'a, V: Visit<'a> + ?Sized>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _module: &'a Option<(EcoString, SrcSpan)>,\n    _name: &'a EcoString,\n    arguments: &'a Vec<CallArg<TypedConstant>>,\n    _tag: &'a EcoString,\n    _type_: &'a Arc<Type>,\n    _field_map: &'a Inferred<FieldMap>,\n    _record_constructor: &'a Option<Box<ValueConstructor>>,\n) {\n    for argument in arguments {\n        v.visit_typed_constant(&argument.value)\n    }\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn visit_typed_constant_record_update<'a, V: Visit<'a> + ?Sized>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _constructor_location: &'a SrcSpan,\n    _module: &'a Option<(EcoString, SrcSpan)>,\n    _name: &'a EcoString,\n    record: &'a RecordBeingUpdated<TypedConstant>,\n    arguments: &'a [RecordUpdateArg<TypedConstant>],\n    _tag: &'a EcoString,\n    _type_: &'a Arc<Type>,\n    _field_map: &'a Inferred<FieldMap>,\n) {\n    v.visit_typed_constant(&record.base);\n    for argument in arguments {\n        v.visit_typed_constant(&argument.value);\n    }\n}\n\nfn visit_typed_constant_list<'a, V: Visit<'a> + ?Sized>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    elements: &'a Vec<TypedConstant>,\n    _type_: &'a Arc<Type>,\n    tail: &'a Option<Box<TypedConstant>>,\n) {\n    for element in elements {\n        v.visit_typed_constant(element)\n    }\n    if let Some(tail) = tail {\n        v.visit_typed_constant(tail);\n    }\n}\n\nfn visit_typed_constant_tuple<'a, V: Visit<'a> + ?Sized>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    elements: &'a Vec<TypedConstant>,\n    _type_: &'a Arc<Type>,\n) {\n    for element in elements {\n        v.visit_typed_constant(element)\n    }\n}\n\nfn visit_typed_constant_string<'a, V: Visit<'a> + ?Sized>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _value: &'a EcoString,\n) {\n    // No further traversal needed for constant strings\n}\n\nfn visit_typed_constant_float<'a, V: Visit<'a> + ?Sized>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _value: &'a EcoString,\n    _float_value: &'a LiteralFloatValue,\n) {\n    // No further traversal needed for constant floats\n}\n\nfn visit_typed_constant_int<'a, V: Visit<'a> + ?Sized>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _value: &'a EcoString,\n    _int_value: &'a BigInt,\n) {\n    // No further traversal needed for constant ints\n}\n\npub fn visit_typed_module<'a, V>(v: &mut V, module: &'a TypedModule)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    let TypedDefinitions {\n        imports,\n        constants,\n        custom_types,\n        type_aliases,\n        functions,\n    } = &module.definitions;\n\n    for import in imports {\n        v.visit_typed_import(import);\n    }\n\n    for constant in constants {\n        v.visit_typed_module_constant(constant);\n    }\n\n    for custom_type in custom_types {\n        v.visit_typed_custom_type(custom_type);\n    }\n\n    for type_alias in type_aliases {\n        v.visit_typed_type_alias(type_alias);\n    }\n\n    for function in functions {\n        v.visit_typed_function(function);\n    }\n}\n\npub fn visit_typed_function<'a, V>(v: &mut V, fun: &'a TypedFunction)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    for argument in fun.arguments.iter() {\n        if let Some(annotation) = &argument.annotation {\n            v.visit_type_ast(annotation, Some(argument.type_.clone()));\n        }\n    }\n    if let Some(annotation) = &fun.return_annotation {\n        v.visit_type_ast(annotation, Some(fun.return_type.clone()));\n    }\n\n    for statement in &fun.body {\n        v.visit_typed_statement(statement);\n    }\n}\n\npub fn visit_type_ast<'a, V>(v: &mut V, node: &'a TypeAst, type_: Option<Arc<Type>>)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match node {\n        TypeAst::Constructor(super::TypeAstConstructor {\n            location,\n            name_location,\n            arguments,\n            module,\n            name,\n            start_parentheses: _,\n        }) => {\n            v.visit_type_ast_constructor(\n                location,\n                name_location,\n                module,\n                name,\n                arguments,\n                type_.and_then(|type_| type_.constructor_types()),\n            );\n        }\n        TypeAst::Fn(super::TypeAstFn {\n            location,\n            arguments,\n            return_,\n        }) => {\n            let (arguments_types, return_type) = match type_.and_then(|type_| type_.fn_types()) {\n                Some((arguments_types, return_type)) => (Some(arguments_types), Some(return_type)),\n                None => (None, None),\n            };\n\n            v.visit_type_ast_fn(location, arguments, arguments_types, return_, return_type);\n        }\n        TypeAst::Var(super::TypeAstVar { location, name }) => {\n            v.visit_type_ast_var(location, name);\n        }\n        TypeAst::Tuple(super::TypeAstTuple { location, elements }) => {\n            let elements_types = if let Some(Type::Tuple { elements }) = type_.as_deref() {\n                Some(elements)\n            } else {\n                None\n            };\n            v.visit_type_ast_tuple(location, elements, elements_types);\n        }\n        TypeAst::Hole(super::TypeAstHole { location, name }) => {\n            v.visit_type_ast_hole(location, name, type_);\n        }\n    }\n}\n\npub fn visit_type_ast_constructor<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _name_location: &'a SrcSpan,\n    _module: &'a Option<(EcoString, SrcSpan)>,\n    _name: &'a EcoString,\n    arguments: &'a [TypeAst],\n    inferred_arguments_types: Option<Vec<Arc<Type>>>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for (i, argument) in arguments.iter().enumerate() {\n        let argument_type = inferred_arguments_types\n            .as_ref()\n            .and_then(|types| types.get(i));\n        v.visit_type_ast(argument, argument_type.cloned());\n    }\n}\n\npub fn visit_type_ast_fn<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    arguments: &'a [TypeAst],\n    arguments_types: Option<Vec<Arc<Type>>>,\n    return_: &'a TypeAst,\n    return_type: Option<Arc<Type>>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for (i, argument) in arguments.iter().enumerate() {\n        v.visit_type_ast(\n            argument,\n            arguments_types\n                .as_ref()\n                .and_then(|types| types.get(i))\n                .cloned(),\n        );\n    }\n    v.visit_type_ast(return_, return_type.clone());\n}\n\npub fn visit_type_ast_var<'a, V>(_v: &mut V, _location: &'a SrcSpan, _name: &'a EcoString)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    // No further traversal needed for variables\n}\n\npub fn visit_type_ast_tuple<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    elements: &'a [TypeAst],\n    elements_types: Option<&Vec<Arc<Type>>>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for (i, element) in elements.iter().enumerate() {\n        let element_type = elements_types\n            .as_ref()\n            .and_then(|types| types.get(i))\n            .cloned();\n        v.visit_type_ast(element, element_type);\n    }\n}\n\npub fn visit_type_ast_hole<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _name: &'a EcoString,\n    _type_: Option<Arc<Type>>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    // No further traversal needed for holes\n}\n\npub fn visit_typed_module_constant<'a, V>(v: &mut V, constant: &'a TypedModuleConstant)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    if let Some(annotation) = &constant.annotation {\n        v.visit_type_ast(annotation, Some(constant.type_.clone()));\n    }\n    v.visit_typed_constant(&constant.value);\n}\n\npub fn visit_typed_constant<'a, V: Visit<'a> + ?Sized>(v: &mut V, constant: &'a TypedConstant) {\n    match constant {\n        super::Constant::Int {\n            location,\n            value,\n            int_value,\n        } => v.visit_typed_constant_int(location, value, int_value),\n        super::Constant::Float {\n            location,\n            value,\n            float_value,\n        } => v.visit_typed_constant_float(location, value, float_value),\n        super::Constant::String { location, value } => {\n            v.visit_typed_constant_string(location, value)\n        }\n        super::Constant::Tuple {\n            location,\n            elements,\n            type_,\n        } => v.visit_typed_constant_tuple(location, elements, type_),\n        super::Constant::List {\n            location,\n            elements,\n            type_,\n            tail,\n        } => v.visit_typed_constant_list(location, elements, type_, tail),\n        super::Constant::Record {\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        } => v.visit_typed_constant_record(\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        ),\n        super::Constant::RecordUpdate {\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag,\n            type_,\n            field_map,\n        } => v.visit_typed_constant_record_update(\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag,\n            type_,\n            field_map,\n        ),\n        super::Constant::BitArray { location, segments } => {\n            v.visit_typed_constant_bit_array(location, segments)\n        }\n        super::Constant::Var {\n            location,\n            module,\n            name,\n            constructor,\n            type_,\n        } => v.visit_typed_constant_var(location, module, name, constructor, type_),\n        super::Constant::StringConcatenation {\n            location,\n            left,\n            right,\n        } => v.visit_typed_constant_string_concatenation(location, left, right),\n        super::Constant::Invalid {\n            location,\n            type_,\n            extra_information,\n        } => v.visit_typed_constant_invalid(location, type_, extra_information),\n    }\n}\n\npub fn visit_typed_custom_type<'a, V>(v: &mut V, custom_type: &'a TypedCustomType)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    for record in &custom_type.constructors {\n        for argument in &record.arguments {\n            v.visit_type_ast(&argument.ast, Some(argument.type_.clone()));\n        }\n    }\n}\n\npub fn visit_typed_type_alias<'a, V>(v: &mut V, type_alias: &'a TypedTypeAlias)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_type_ast(&type_alias.type_ast, Some(type_alias.type_.clone()));\n}\n\npub fn visit_typed_import<'a, V>(_v: &mut V, _import: &'a TypedImport)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_expr<'a, V>(v: &mut V, node: &'a TypedExpr)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match node {\n        TypedExpr::Int {\n            location,\n            type_,\n            value,\n            int_value: _,\n        } => v.visit_typed_expr_int(location, type_, value),\n        TypedExpr::Float {\n            location,\n            type_,\n            value,\n            float_value: _,\n        } => v.visit_typed_expr_float(location, type_, value),\n        TypedExpr::String {\n            location,\n            type_,\n            value,\n        } => v.visit_typed_expr_string(location, type_, value),\n        TypedExpr::Block {\n            location,\n            statements,\n        } => v.visit_typed_expr_block(location, statements),\n        TypedExpr::Pipeline {\n            location,\n            first_value,\n            assignments,\n            finally,\n            finally_kind,\n        } => v.visit_typed_expr_pipeline(location, first_value, assignments, finally, finally_kind),\n        TypedExpr::Var {\n            location,\n            constructor,\n            name,\n        } => v.visit_typed_expr_var(location, constructor, name),\n        TypedExpr::Fn {\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n            purity: _,\n        } => v.visit_typed_expr_fn(location, type_, kind, arguments, body, return_annotation),\n        TypedExpr::List {\n            location,\n            type_,\n            elements,\n            tail,\n        } => v.visit_typed_expr_list(location, type_, elements, tail),\n        TypedExpr::Call {\n            location,\n            type_,\n            fun,\n            arguments,\n        } => v.visit_typed_expr_call(location, type_, fun, arguments),\n        TypedExpr::BinOp {\n            location,\n            type_,\n            name,\n            name_location,\n            left,\n            right,\n        } => v.visit_typed_expr_bin_op(location, type_, name, name_location, left, right),\n        TypedExpr::Case {\n            location,\n            type_,\n            subjects,\n            clauses,\n            compiled_case,\n        } => v.visit_typed_expr_case(location, type_, subjects, clauses, compiled_case),\n        TypedExpr::RecordAccess {\n            location,\n            field_start,\n            type_,\n            label,\n            index,\n            record,\n            documentation,\n        } => v.visit_typed_expr_record_access(\n            location,\n            field_start,\n            type_,\n            label,\n            index,\n            record,\n            documentation,\n        ),\n        TypedExpr::ModuleSelect {\n            location,\n            field_start,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            constructor,\n        } => v.visit_typed_expr_module_select(\n            location,\n            field_start,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            constructor,\n        ),\n        TypedExpr::Tuple {\n            location,\n            type_,\n            elements,\n        } => v.visit_typed_expr_tuple(location, type_, elements),\n        TypedExpr::TupleIndex {\n            location,\n            type_,\n            index,\n            tuple,\n        } => v.visit_typed_expr_tuple_index(location, type_, index, tuple),\n        TypedExpr::Todo {\n            location,\n            message,\n            kind,\n            type_,\n        } => v.visit_typed_expr_todo(location, message, kind, type_),\n        TypedExpr::Panic {\n            location,\n            message,\n            type_,\n        } => v.visit_typed_expr_panic(location, message, type_),\n        TypedExpr::BitArray {\n            location,\n            type_,\n            segments,\n        } => v.visit_typed_expr_bit_array(location, type_, segments),\n        TypedExpr::RecordUpdate {\n            location,\n            type_,\n            record_assignment,\n            constructor,\n            arguments,\n        } => v.visit_typed_expr_record_update(\n            location,\n            type_,\n            record_assignment,\n            constructor,\n            arguments,\n        ),\n        TypedExpr::NegateBool { location, value } => {\n            v.visit_typed_expr_negate_bool(location, value)\n        }\n        TypedExpr::NegateInt { location, value } => v.visit_typed_expr_negate_int(location, value),\n        TypedExpr::Invalid {\n            location,\n            type_,\n            extra_information,\n        } => v.visit_typed_expr_invalid(location, type_, extra_information),\n        TypedExpr::Echo {\n            location,\n            expression,\n            message,\n            type_,\n        } => v.visit_typed_expr_echo(location, type_, expression, message),\n        TypedExpr::PositionalAccess { .. } => {}\n    }\n}\n\npub fn visit_typed_expr_int<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _value: &'a EcoString,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_expr_float<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _value: &'a EcoString,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_expr_string<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _value: &'a EcoString,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_expr_block<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    statements: &'a [TypedStatement],\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for statement in statements {\n        v.visit_typed_statement(statement);\n    }\n}\n\npub fn visit_typed_expr_pipeline<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    first_value: &'a TypedPipelineAssignment,\n    assignments: &'a [(TypedPipelineAssignment, PipelineAssignmentKind)],\n    finally: &'a TypedExpr,\n    _finally_kind: &'a PipelineAssignmentKind,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_pipeline_assignment(first_value);\n    for (assignment, _kind) in assignments {\n        v.visit_typed_pipeline_assignment(assignment);\n    }\n\n    v.visit_typed_expr(finally);\n}\n\npub fn visit_typed_pipeline_assignment<'a, V>(v: &mut V, assignment: &'a TypedPipelineAssignment)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(&assignment.value);\n}\n\npub fn visit_typed_expr_var<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _constructor: &'a ValueConstructor,\n    _name: &'a EcoString,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    /* TODO */\n}\n\npub fn visit_typed_expr_fn<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    type_: &'a Arc<Type>,\n    _kind: &'a FunctionLiteralKind,\n    arguments: &'a [TypedArg],\n    body: &'a Vec1<TypedStatement>,\n    return_annotation: &'a Option<TypeAst>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for argument in arguments {\n        if let Some(annotation) = &argument.annotation {\n            v.visit_type_ast(annotation, Some(argument.type_.clone()));\n        }\n    }\n    if let Some(return_) = return_annotation {\n        v.visit_type_ast(\n            return_,\n            type_.fn_types().map(|(_, return_)| return_.clone()),\n        );\n    }\n\n    for statement in body {\n        v.visit_typed_statement(statement);\n    }\n}\n\npub fn visit_typed_expr_list<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    elements: &'a [TypedExpr],\n    tail: &'a Option<Box<TypedExpr>>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for element in elements {\n        v.visit_typed_expr(element);\n    }\n\n    if let Some(tail) = tail {\n        v.visit_typed_expr(tail);\n    }\n}\n\npub fn visit_typed_expr_call<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    fun: &'a TypedExpr,\n    arguments: &'a [TypedCallArg],\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(fun);\n    for argument in arguments {\n        v.visit_typed_call_arg(argument);\n    }\n}\n\npub fn visit_typed_expr_bin_op<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _name: &'a BinOp,\n    _name_location: &'a SrcSpan,\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(left);\n    v.visit_typed_expr(right);\n}\n\npub fn visit_typed_expr_case<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    subjects: &'a [TypedExpr],\n    clauses: &'a [TypedClause],\n    _compiled_case: &'a CompiledCase,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for subject in subjects {\n        v.visit_typed_expr(subject);\n    }\n\n    for clause in clauses {\n        v.visit_typed_clause(clause);\n    }\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn visit_typed_expr_record_access<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _field_start: &'a u32,\n    _type_: &'a Arc<Type>,\n    _label: &'a EcoString,\n    _index: &'a u64,\n    record: &'a TypedExpr,\n    _documentation: &'a Option<EcoString>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(record);\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn visit_typed_expr_module_select<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _field_start: &'a u32,\n    _type_: &'a Arc<Type>,\n    _label: &'a EcoString,\n    _module_name: &'a EcoString,\n    _module_alias: &'a EcoString,\n    _constructor: &'a ModuleValueConstructor,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    /* TODO */\n}\n\npub fn visit_typed_expr_tuple<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    elements: &'a [TypedExpr],\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for element in elements {\n        v.visit_typed_expr(element);\n    }\n}\n\npub fn visit_typed_expr_tuple_index<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _index: &'a u64,\n    tuple: &'a TypedExpr,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(tuple);\n}\n\npub fn visit_typed_expr_todo<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    message: &'a Option<Box<TypedExpr>>,\n    _kind: &'a TodoKind,\n    _type_: &'a Arc<Type>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    if let Some(message) = message {\n        v.visit_typed_expr(message);\n    }\n}\n\npub fn visit_typed_expr_echo<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    expression: &'a Option<Box<TypedExpr>>,\n    message: &'a Option<Box<TypedExpr>>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    if let Some(expression) = expression {\n        v.visit_typed_expr(expression)\n    }\n    if let Some(message) = message {\n        v.visit_typed_expr(message)\n    }\n}\n\npub fn visit_typed_expr_panic<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    message: &'a Option<Box<TypedExpr>>,\n    _type_: &'a Arc<Type>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    if let Some(message) = message {\n        v.visit_typed_expr(message);\n    }\n}\n\npub fn visit_typed_expr_bit_array<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    segments: &'a [TypedExprBitArraySegment],\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for segment in segments {\n        v.visit_typed_expr_bit_array_segment(segment);\n    }\n}\n\npub fn visit_typed_expr_record_update<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    record: &'a Option<Box<TypedAssignment>>,\n    constructor: &'a TypedExpr,\n    arguments: &'a [TypedCallArg],\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(constructor);\n    if let Some(record) = record {\n        v.visit_typed_assignment(record);\n    }\n    for argument in arguments {\n        v.visit_typed_call_arg(argument);\n    }\n}\n\npub fn visit_typed_expr_negate_bool<'a, V>(v: &mut V, _location: &'a SrcSpan, value: &'a TypedExpr)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(value);\n}\n\npub fn visit_typed_expr_negate_int<'a, V>(v: &mut V, _location: &'a SrcSpan, value: &'a TypedExpr)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(value);\n}\n\npub fn visit_typed_statement<'a, V>(v: &mut V, statement: &'a TypedStatement)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match statement {\n        Statement::Expression(expression) => v.visit_typed_expr(expression),\n        Statement::Assignment(assignment) => v.visit_typed_assignment(assignment),\n        Statement::Use(use_) => v.visit_typed_use(use_),\n        Statement::Assert(assert) => v.visit_typed_assert(assert),\n    }\n}\n\npub fn visit_typed_assignment<'a, V>(v: &mut V, assignment: &'a TypedAssignment)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    if let Some(annotation) = &assignment.annotation {\n        v.visit_type_ast(annotation, Some(assignment.type_()));\n    }\n    v.visit_typed_expr(&assignment.value);\n    v.visit_typed_pattern(&assignment.pattern);\n}\n\npub fn visit_typed_use<'a, V>(v: &mut V, use_: &'a TypedUse)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(&use_.call);\n    // TODO: We should also visit the typed patterns!!\n}\n\npub fn visit_typed_assert<'a, V>(v: &mut V, assert: &'a TypedAssert)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(&assert.value);\n    if let Some(message) = &assert.message {\n        v.visit_typed_expr(message);\n    }\n}\n\npub fn visit_typed_call_arg<'a, V>(v: &mut V, arg: &'a TypedCallArg)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(&arg.value);\n}\n\npub fn visit_typed_clause<'a, V>(v: &mut V, clause: &'a TypedClause)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    for pattern in clause.pattern.iter() {\n        v.visit_typed_pattern(pattern);\n    }\n    for patterns in clause.alternative_patterns.iter() {\n        for pattern in patterns {\n            v.visit_typed_pattern(pattern);\n        }\n    }\n    if let Some(guard) = &clause.guard {\n        v.visit_typed_clause_guard(guard);\n    }\n    v.visit_typed_expr(&clause.then);\n}\n\npub fn visit_typed_clause_guard<'a, V>(v: &mut V, guard: &'a TypedClauseGuard)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match guard {\n        super::ClauseGuard::BinaryOperator { left, right, .. } => {\n            v.visit_typed_clause_guard(left);\n            v.visit_typed_clause_guard(right);\n        }\n        super::ClauseGuard::Block { location: _, value } => v.visit_typed_clause_guard(value),\n        super::ClauseGuard::Not {\n            location: _,\n            expression,\n        } => v.visit_typed_clause_guard(expression),\n        super::ClauseGuard::Var {\n            location,\n            type_,\n            name,\n            definition_location,\n            origin,\n        } => v.visit_typed_clause_guard_var(location, name, type_, definition_location, origin),\n        super::ClauseGuard::TupleIndex {\n            location,\n            index,\n            type_,\n            tuple,\n        } => v.visit_typed_clause_guard_tuple_index(location, index, type_, tuple),\n        super::ClauseGuard::FieldAccess {\n            label_location,\n            index,\n            label,\n            type_,\n            container,\n        } => {\n            v.visit_typed_clause_guard_field_access(label_location, index, label, type_, container)\n        }\n        super::ClauseGuard::ModuleSelect {\n            location,\n            field_start,\n            definition_location,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            literal,\n        } => v.visit_typed_clause_guard_module_select(\n            location,\n            field_start,\n            definition_location,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            literal,\n        ),\n        super::ClauseGuard::Constant(constant) => v.visit_typed_constant(constant),\n    }\n}\n\npub fn visit_typed_clause_guard_var<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _name: &'a EcoString,\n    _type_: &'a Arc<Type>,\n    _definition_location: &'a SrcSpan,\n    _origin: &'a VariableOrigin,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_clause_guard_tuple_index<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _index: &'a u64,\n    _type_: &'a Arc<Type>,\n    tuple: &'a TypedClauseGuard,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_clause_guard(tuple);\n}\n\npub fn visit_typed_clause_guard_field_access<'a, V>(\n    v: &mut V,\n    _label_location: &'a SrcSpan,\n    _index: &'a Option<u64>,\n    _label: &'a EcoString,\n    _type_: &'a Arc<Type>,\n    container: &'a TypedClauseGuard,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_clause_guard(container);\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn visit_typed_clause_guard_module_select<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _field_start: &'a u32,\n    _definition_location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _label: &'a EcoString,\n    _module_name: &'a EcoString,\n    _module_alias: &'a EcoString,\n    _literal: &'a TypedConstant,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_expr_bit_array_segment<'a, V>(v: &mut V, segment: &'a TypedExprBitArraySegment)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_expr(&segment.value);\n    for option in &segment.options {\n        v.visit_typed_bit_array_option(option);\n    }\n}\n\npub fn visit_typed_bit_array_option<'a, V>(v: &mut V, option: &'a BitArrayOption<TypedExpr>)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match option {\n        BitArrayOption::Bytes { location: _ } => { /* TODO */ }\n        BitArrayOption::Int { location: _ } => { /* TODO */ }\n        BitArrayOption::Float { location: _ } => { /* TODO */ }\n        BitArrayOption::Bits { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf8 { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf16 { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf32 { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf8Codepoint { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf16Codepoint { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf32Codepoint { location: _ } => { /* TODO */ }\n        BitArrayOption::Signed { location: _ } => { /* TODO */ }\n        BitArrayOption::Unsigned { location: _ } => { /* TODO */ }\n        BitArrayOption::Big { location: _ } => { /* TODO */ }\n        BitArrayOption::Little { location: _ } => { /* TODO */ }\n        BitArrayOption::Native { location: _ } => { /* TODO */ }\n        BitArrayOption::Size {\n            location: _,\n            value,\n            short_form: _,\n        } => {\n            v.visit_typed_expr(value);\n        }\n        BitArrayOption::Unit {\n            location: _,\n            value: _,\n        } => { /* TODO */ }\n    }\n}\n\npub fn visit_typed_pattern<'a, V>(v: &mut V, pattern: &'a TypedPattern)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match pattern {\n        Pattern::Int {\n            location,\n            value,\n            int_value: _,\n        } => v.visit_typed_pattern_int(location, value),\n        Pattern::Float {\n            location,\n            value,\n            float_value: _,\n        } => v.visit_typed_pattern_float(location, value),\n        Pattern::String { location, value } => v.visit_typed_pattern_string(location, value),\n        Pattern::Variable {\n            location,\n            name,\n            type_,\n            origin,\n        } => v.visit_typed_pattern_variable(location, name, type_, origin),\n        Pattern::BitArraySize(size) => v.visit_typed_pattern_bit_array_size(size),\n        Pattern::Assign {\n            location,\n            name,\n            pattern,\n        } => v.visit_typed_pattern_assign(location, name, pattern),\n        Pattern::Discard {\n            location,\n            name,\n            type_,\n        } => v.visit_typed_pattern_discard(location, name, type_),\n        Pattern::List {\n            location,\n            elements,\n            tail,\n            type_,\n        } => v.visit_typed_pattern_list(location, elements, tail, type_),\n        Pattern::Constructor {\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        } => v.visit_typed_pattern_constructor(\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        ),\n        Pattern::Tuple { location, elements } => v.visit_typed_pattern_tuple(location, elements),\n        Pattern::BitArray { location, segments } => {\n            v.visit_typed_pattern_bit_array(location, segments)\n        }\n        Pattern::StringPrefix {\n            location,\n            left_location,\n            left_side_assignment,\n            right_location,\n            left_side_string,\n            right_side_assignment,\n        } => v.visit_typed_pattern_string_prefix(\n            location,\n            left_location,\n            left_side_assignment,\n            right_location,\n            left_side_string,\n            right_side_assignment,\n        ),\n        Pattern::Invalid { location, type_ } => v.visit_typed_pattern_invalid(location, type_),\n    }\n}\n\nfn visit_typed_pattern_int<'a, V>(_v: &mut V, _location: &'a SrcSpan, _value: &'a EcoString)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_float<'a, V>(_v: &mut V, _location: &'a SrcSpan, _value: &'a EcoString)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_string<'a, V>(_v: &mut V, _location: &'a SrcSpan, _value: &'a EcoString)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_variable<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _name: &'a EcoString,\n    _type_: &'a Arc<Type>,\n    _origin: &'a VariableOrigin,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_bit_array_size<'a, V>(v: &mut V, size: &'a TypedBitArraySize)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    match size {\n        BitArraySize::Int {\n            location,\n            value,\n            int_value: _,\n        } => v.visit_typed_bit_array_size_int(location, value),\n        BitArraySize::Variable {\n            location,\n            name,\n            constructor,\n            type_,\n        } => v.visit_typed_bit_array_size_variable(location, name, constructor, type_),\n        BitArraySize::BinaryOperator { left, right, .. } => {\n            v.visit_typed_pattern_bit_array_size(left);\n            v.visit_typed_pattern_bit_array_size(right);\n        }\n        BitArraySize::Block { inner, .. } => v.visit_typed_pattern_bit_array_size(inner),\n    }\n}\n\npub fn visit_typed_bit_array_size_int<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _value: &'a EcoString,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_bit_array_size_variable<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _name: &'a EcoString,\n    _constructor: &'a Option<Box<ValueConstructor>>,\n    _type_: &'a Arc<Type>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_assign<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _name: &'a EcoString,\n    pattern: &'a TypedPattern,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_pattern(pattern);\n}\n\npub fn visit_typed_pattern_discard<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _name: &'a EcoString,\n    _type_: &'a Arc<Type>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_list<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    elements: &'a Vec<TypedPattern>,\n    tail: &'a Option<Box<TypedTailPattern>>,\n    _type_: &'a Arc<Type>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for element in elements {\n        v.visit_typed_pattern(element);\n    }\n    if let Some(tail) = tail {\n        v.visit_typed_pattern(&tail.pattern);\n    }\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn visit_typed_pattern_constructor<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    _name_location: &'a SrcSpan,\n    _name: &'a EcoString,\n    arguments: &'a Vec<CallArg<TypedPattern>>,\n    _module: &'a Option<(EcoString, SrcSpan)>,\n    _constructor: &'a Inferred<PatternConstructor>,\n    _spread: &'a Option<SrcSpan>,\n    _type_: &'a Arc<Type>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for argument in arguments {\n        v.visit_typed_pattern_call_arg(argument);\n    }\n}\n\npub fn visit_typed_pattern_call_arg<'a, V>(v: &mut V, argument: &'a CallArg<TypedPattern>)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n    v.visit_typed_pattern(&argument.value)\n}\n\npub fn visit_typed_pattern_tuple<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    elements: &'a Vec<TypedPattern>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for element in elements {\n        v.visit_typed_pattern(element);\n    }\n}\n\npub fn visit_typed_pattern_bit_array<'a, V>(\n    v: &mut V,\n    _location: &'a SrcSpan,\n    segments: &'a [TypedPatternBitArraySegment],\n) where\n    V: Visit<'a> + ?Sized,\n{\n    for segment in segments {\n        v.visit_typed_pattern(&segment.value);\n        for option in segment.options.iter() {\n            v.visit_typed_pattern_bit_array_option(option);\n        }\n    }\n}\n\npub fn visit_typed_pattern_bit_array_option<'a, V>(\n    v: &mut V,\n    option: &'a BitArrayOption<TypedPattern>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n    match option {\n        BitArrayOption::Bytes { location: _ } => { /* TODO */ }\n        BitArrayOption::Int { location: _ } => { /* TODO */ }\n        BitArrayOption::Float { location: _ } => { /* TODO */ }\n        BitArrayOption::Bits { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf8 { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf16 { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf32 { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf8Codepoint { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf16Codepoint { location: _ } => { /* TODO */ }\n        BitArrayOption::Utf32Codepoint { location: _ } => { /* TODO */ }\n        BitArrayOption::Signed { location: _ } => { /* TODO */ }\n        BitArrayOption::Unsigned { location: _ } => { /* TODO */ }\n        BitArrayOption::Big { location: _ } => { /* TODO */ }\n        BitArrayOption::Little { location: _ } => { /* TODO */ }\n        BitArrayOption::Native { location: _ } => { /* TODO */ }\n        BitArrayOption::Size {\n            location: _,\n            value,\n            short_form: _,\n        } => {\n            v.visit_typed_pattern(value);\n        }\n        BitArrayOption::Unit {\n            location: _,\n            value: _,\n        } => { /* TODO */ }\n    }\n}\n\npub fn visit_typed_pattern_string_prefix<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _left_location: &'a SrcSpan,\n    _left_side_assignment: &'a Option<(EcoString, SrcSpan)>,\n    _right_location: &'a SrcSpan,\n    _left_side_string: &'a EcoString,\n    _right_side_assignment: &'a AssignName,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_pattern_invalid<'a, V>(_v: &mut V, _location: &'a SrcSpan, _type_: &'a Arc<Type>)\nwhere\n    V: Visit<'a> + ?Sized,\n{\n}\n\npub fn visit_typed_expr_invalid<'a, V>(\n    _v: &mut V,\n    _location: &'a SrcSpan,\n    _type_: &'a Arc<Type>,\n    _extra_information: &'a Option<InvalidExpression>,\n) where\n    V: Visit<'a> + ?Sized,\n{\n}\n"
  },
  {
    "path": "compiler-core/src/ast.rs",
    "content": "mod constant;\nmod typed;\nmod untyped;\n\n#[cfg(test)]\nmod tests;\npub mod visit;\n\npub use self::typed::{InvalidExpression, TypedExpr};\npub use self::untyped::{FunctionLiteralKind, UntypedExpr};\n\npub use self::constant::{Constant, TypedConstant, UntypedConstant};\n\nuse crate::analyse::Inferred;\nuse crate::ast::typed::pairwise_all;\nuse crate::bit_array;\nuse crate::build::{ExpressionPosition, Located, Target, module_erlang_name};\nuse crate::exhaustiveness::CompiledCase;\nuse crate::parse::{LiteralFloatValue, SpannedString};\nuse crate::type_::error::VariableOrigin;\nuse crate::type_::expression::{Implementations, Purity};\nuse crate::type_::printer::Names;\nuse crate::type_::{\n    self, Deprecation, HasType, ModuleValueConstructor, PatternConstructor, Type, TypedCallArg,\n    ValueConstructor, ValueConstructorVariant, nil,\n};\nuse itertools::Itertools;\nuse num_traits::Zero;\nuse std::collections::HashSet;\nuse std::sync::Arc;\n\nuse ecow::EcoString;\nuse num_bigint::{BigInt, Sign};\nuse num_traits::{One, ToPrimitive};\n#[cfg(test)]\nuse pretty_assertions::assert_eq;\nuse vec1::Vec1;\n\npub const PIPE_VARIABLE: &str = \"_pipe\";\npub const USE_ASSIGNMENT_VARIABLE: &str = \"_use\";\npub const RECORD_UPDATE_VARIABLE: &str = \"_record\";\npub const ASSERT_FAIL_VARIABLE: &str = \"_assert_fail\";\npub const ASSERT_SUBJECT_VARIABLE: &str = \"_assert_subject\";\npub const CAPTURE_VARIABLE: &str = \"_capture\";\npub const BLOCK_VARIABLE: &str = \"_block\";\n\npub trait HasLocation {\n    fn location(&self) -> SrcSpan;\n}\n\npub type UntypedModule = Module<(), Vec<TargetedDefinition>>;\npub type TypedModule = Module<type_::ModuleInterface, TypedDefinitions>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Module<Info, Definitions> {\n    pub name: EcoString,\n    pub documentation: Vec<EcoString>,\n    pub type_info: Info,\n    pub definitions: Definitions,\n    pub names: Names,\n    /// The source byte locations of definition that are unused.\n    /// This is used in code generation to know when definitions can be safely omitted.\n    pub unused_definition_positions: HashSet<u32>,\n}\n\nimpl<Info, Definitions> Module<Info, Definitions> {\n    pub fn erlang_name(&self) -> EcoString {\n        module_erlang_name(&self.name)\n    }\n}\n\nimpl TypedModule {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        let TypedDefinitions {\n            imports,\n            constants,\n            custom_types,\n            type_aliases,\n            functions,\n        } = &self.definitions;\n\n        imports\n            .iter()\n            .find_map(|import| import.find_node(byte_index))\n            .or_else(|| (constants.iter()).find_map(|constant| constant.find_node(byte_index)))\n            .or_else(|| (custom_types.iter()).find_map(|type_| type_.find_node(byte_index)))\n            .or_else(|| (type_aliases.iter()).find_map(|alias| alias.find_node(byte_index)))\n            .or_else(|| (functions.iter()).find_map(|function| function.find_node(byte_index)))\n    }\n\n    pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> {\n        // Statements can only be found inside a module function, there's no\n        // need to go over all the other module definitions.\n        self.definitions\n            .functions\n            .iter()\n            .find_map(|function| function.find_statement(byte_index))\n    }\n\n    pub fn definitions_len(&self) -> usize {\n        let TypedDefinitions {\n            imports,\n            constants,\n            custom_types,\n            type_aliases,\n            functions,\n        } = &self.definitions;\n\n        imports.len() + constants.len() + custom_types.len() + type_aliases.len() + functions.len()\n    }\n}\n\n#[derive(Debug)]\npub struct TypedDefinitions {\n    pub imports: Vec<TypedImport>,\n    pub constants: Vec<TypedModuleConstant>,\n    pub custom_types: Vec<TypedCustomType>,\n    pub type_aliases: Vec<TypedTypeAlias>,\n    pub functions: Vec<TypedFunction>,\n}\n\n/// The `@target(erlang)` and `@target(javascript)` attributes can be used to\n/// mark a definition as only being for a specific target.\n///\n/// ```gleam\n/// const x: Int = 1\n///\n/// @target(erlang)\n/// pub fn main(a) { ...}\n/// ```\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TargetedDefinition {\n    pub definition: UntypedDefinition,\n    pub target: Option<Target>,\n}\n\nimpl TargetedDefinition {\n    pub fn is_for(&self, target: Target) -> bool {\n        self.target.map(|t| t == target).unwrap_or(true)\n    }\n}\n\nimpl UntypedModule {\n    pub fn dependencies(&self, target: Target) -> Vec<(EcoString, SrcSpan)> {\n        self.iter_definitions(target)\n            .flat_map(|definition| match definition {\n                Definition::Import(Import {\n                    module, location, ..\n                }) => Some((module.clone(), *location)),\n                Definition::Function(_)\n                | Definition::TypeAlias(_)\n                | Definition::CustomType(_)\n                | Definition::ModuleConstant(_) => None,\n            })\n            .collect()\n    }\n\n    pub fn iter_definitions(&self, target: Target) -> impl Iterator<Item = &UntypedDefinition> {\n        self.definitions\n            .iter()\n            .filter(move |definition| definition.is_for(target))\n            .map(|definition| &definition.definition)\n    }\n\n    pub fn into_iter_definitions(self, target: Target) -> impl Iterator<Item = UntypedDefinition> {\n        self.definitions\n            .into_iter()\n            .filter(move |definition| definition.is_for(target))\n            .map(|definition| definition.definition)\n    }\n}\n\n#[test]\nfn module_dependencies_test() {\n    let parsed = crate::parse::parse_module(\n        camino::Utf8PathBuf::from(\"test/path\"),\n        \"import one\n         @target(erlang)\n         import two\n\n         @target(javascript)\n         import three\n\n         import four\",\n        &crate::warning::WarningEmitter::null(),\n    )\n    .expect(\"syntax error\");\n    let module = parsed.module;\n\n    assert_eq!(\n        vec![\n            (\"one\".into(), SrcSpan::new(0, 10)),\n            (\"two\".into(), SrcSpan::new(45, 55)),\n            (\"four\".into(), SrcSpan::new(118, 129)),\n        ],\n        module.dependencies(Target::Erlang)\n    );\n}\n\npub type TypedArg = Arg<Arc<Type>>;\npub type UntypedArg = Arg<()>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Arg<T> {\n    pub names: ArgNames,\n    pub location: SrcSpan,\n    pub annotation: Option<TypeAst>,\n    pub type_: T,\n}\n\nimpl<A> Arg<A> {\n    pub fn set_type<B>(self, t: B) -> Arg<B> {\n        Arg {\n            type_: t,\n            names: self.names,\n            location: self.location,\n            annotation: self.annotation,\n        }\n    }\n\n    pub fn get_variable_name(&self) -> Option<&EcoString> {\n        self.names.get_variable_name()\n    }\n\n    pub fn is_capture_hole(&self) -> bool {\n        match &self.names {\n            ArgNames::Named { name, .. } if name == CAPTURE_VARIABLE => true,\n            ArgNames::Discard { .. }\n            | ArgNames::LabelledDiscard { .. }\n            | ArgNames::Named { .. }\n            | ArgNames::NamedLabelled { .. } => false,\n        }\n    }\n}\n\nimpl TypedArg {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if self.location.contains(byte_index) {\n            if let Some(annotation) = &self.annotation {\n                return annotation\n                    .find_node(byte_index, self.type_.clone())\n                    .or(Some(Located::Arg(self)));\n            }\n            Some(Located::Arg(self))\n        } else {\n            None\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum ArgNames {\n    Discard {\n        name: EcoString,\n        location: SrcSpan,\n    },\n    LabelledDiscard {\n        label: EcoString,\n        label_location: SrcSpan,\n        name: EcoString,\n        name_location: SrcSpan,\n    },\n    Named {\n        name: EcoString,\n        location: SrcSpan,\n    },\n    NamedLabelled {\n        label: EcoString,\n        label_location: SrcSpan,\n        name: EcoString,\n        name_location: SrcSpan,\n    },\n}\n\nimpl ArgNames {\n    pub fn get_label(&self) -> Option<&EcoString> {\n        match self {\n            ArgNames::Discard { .. } | ArgNames::Named { .. } => None,\n            ArgNames::LabelledDiscard { label, .. } | ArgNames::NamedLabelled { label, .. } => {\n                Some(label)\n            }\n        }\n    }\n    pub fn get_variable_name(&self) -> Option<&EcoString> {\n        match self {\n            ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None,\n            ArgNames::NamedLabelled { name, .. } | ArgNames::Named { name, .. } => Some(name),\n        }\n    }\n}\n\npub type TypedRecordConstructor = RecordConstructor<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct RecordConstructor<T> {\n    pub location: SrcSpan,\n    pub name_location: SrcSpan,\n    pub name: EcoString,\n    pub arguments: Vec<RecordConstructorArg<T>>,\n    pub documentation: Option<(u32, EcoString)>,\n    pub deprecation: Deprecation,\n}\n\nimpl<A> RecordConstructor<A> {\n    pub fn put_doc(&mut self, new_doc: (u32, EcoString)) {\n        self.documentation = Some(new_doc);\n    }\n}\n\npub type TypedRecordConstructorArg = RecordConstructorArg<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct RecordConstructorArg<T> {\n    pub label: Option<SpannedString>,\n    pub ast: TypeAst,\n    pub location: SrcSpan,\n    pub type_: T,\n    pub doc: Option<(u32, EcoString)>,\n}\n\nimpl<T: PartialEq> RecordConstructorArg<T> {\n    pub fn put_doc(&mut self, new_doc: (u32, EcoString)) {\n        self.doc = Some(new_doc);\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TypeAstConstructor {\n    pub location: SrcSpan,\n    pub name_location: SrcSpan,\n    pub module: Option<(EcoString, SrcSpan)>,\n    pub name: EcoString,\n    pub arguments: Vec<TypeAst>,\n    pub start_parentheses: Option<u32>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TypeAstFn {\n    pub location: SrcSpan,\n    pub arguments: Vec<TypeAst>,\n    pub return_: Box<TypeAst>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TypeAstVar {\n    pub location: SrcSpan,\n    pub name: EcoString,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TypeAstTuple {\n    pub location: SrcSpan,\n    pub elements: Vec<TypeAst>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TypeAstHole {\n    pub location: SrcSpan,\n    pub name: EcoString,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum TypeAst {\n    Constructor(TypeAstConstructor),\n    Fn(TypeAstFn),\n    Var(TypeAstVar),\n    Tuple(TypeAstTuple),\n    Hole(TypeAstHole),\n}\n\nimpl TypeAst {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            TypeAst::Fn(TypeAstFn { location, .. })\n            | TypeAst::Var(TypeAstVar { location, .. })\n            | TypeAst::Hole(TypeAstHole { location, .. })\n            | TypeAst::Tuple(TypeAstTuple { location, .. })\n            | TypeAst::Constructor(TypeAstConstructor { location, .. }) => *location,\n        }\n    }\n\n    pub fn is_logically_equal(&self, other: &TypeAst) -> bool {\n        match self {\n            TypeAst::Constructor(TypeAstConstructor {\n                module,\n                name,\n                arguments,\n                location: _,\n                name_location: _,\n                start_parentheses: _,\n            }) => match other {\n                TypeAst::Constructor(TypeAstConstructor {\n                    module: o_module,\n                    name: o_name,\n                    arguments: o_arguments,\n                    location: _,\n                    name_location: _,\n                    start_parentheses: _,\n                }) => {\n                    let module_name =\n                        |m: &Option<(EcoString, _)>| m.as_ref().map(|(m, _)| m.clone());\n                    module_name(module) == module_name(o_module)\n                        && name == o_name\n                        && arguments.len() == o_arguments.len()\n                        && arguments\n                            .iter()\n                            .zip(o_arguments)\n                            .all(|a| a.0.is_logically_equal(a.1))\n                }\n                TypeAst::Fn(_) | TypeAst::Var(_) | TypeAst::Tuple(_) | TypeAst::Hole(_) => false,\n            },\n            TypeAst::Fn(TypeAstFn {\n                arguments,\n                return_,\n                location: _,\n            }) => match other {\n                TypeAst::Fn(TypeAstFn {\n                    arguments: o_arguments,\n                    return_: o_return_,\n                    location: _,\n                }) => {\n                    arguments.len() == o_arguments.len()\n                        && arguments\n                            .iter()\n                            .zip(o_arguments)\n                            .all(|a| a.0.is_logically_equal(a.1))\n                        && return_.is_logically_equal(o_return_)\n                }\n                TypeAst::Constructor(_)\n                | TypeAst::Var(_)\n                | TypeAst::Tuple(_)\n                | TypeAst::Hole(_) => false,\n            },\n            TypeAst::Var(TypeAstVar { name, location: _ }) => match other {\n                TypeAst::Var(TypeAstVar {\n                    name: o_name,\n                    location: _,\n                }) => name == o_name,\n                TypeAst::Constructor(_) | TypeAst::Fn(_) | TypeAst::Tuple(_) | TypeAst::Hole(_) => {\n                    false\n                }\n            },\n            TypeAst::Tuple(TypeAstTuple {\n                elements,\n                location: _,\n            }) => match other {\n                TypeAst::Tuple(TypeAstTuple {\n                    elements: other_elements,\n                    location: _,\n                }) => {\n                    elements.len() == other_elements.len()\n                        && elements\n                            .iter()\n                            .zip(other_elements)\n                            .all(|a| a.0.is_logically_equal(a.1))\n                }\n                TypeAst::Constructor(_) | TypeAst::Fn(_) | TypeAst::Var(_) | TypeAst::Hole(_) => {\n                    false\n                }\n            },\n            TypeAst::Hole(TypeAstHole { name, location: _ }) => match other {\n                TypeAst::Hole(TypeAstHole {\n                    name: o_name,\n                    location: _,\n                }) => name == o_name,\n                TypeAst::Constructor(_) | TypeAst::Fn(_) | TypeAst::Var(_) | TypeAst::Tuple(_) => {\n                    false\n                }\n            },\n        }\n    }\n\n    pub fn find_node(&self, byte_index: u32, type_: Arc<Type>) -> Option<Located<'_>> {\n        if !self.location().contains(byte_index) {\n            return None;\n        }\n\n        match self {\n            TypeAst::Fn(TypeAstFn {\n                arguments, return_, ..\n            }) => type_\n                .fn_types()\n                .and_then(|(arg_types, ret_type)| {\n                    if let Some(arg) = arguments\n                        .iter()\n                        .zip(arg_types)\n                        .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone()))\n                    {\n                        return Some(arg);\n                    }\n                    if let Some(ret) = return_.find_node(byte_index, ret_type) {\n                        return Some(ret);\n                    }\n\n                    None\n                })\n                .or(Some(Located::Annotation { ast: self, type_ })),\n            TypeAst::Constructor(TypeAstConstructor {\n                arguments, module, ..\n            }) => type_\n                .named_type_information()\n                .and_then(|(module_name, _, arg_types)| {\n                    if let Some(arg) = arguments\n                        .iter()\n                        .zip(arg_types)\n                        .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone()))\n                    {\n                        return Some(arg);\n                    }\n\n                    if let Some((module_alias, location)) = module\n                        && location.contains(byte_index)\n                    {\n                        return Some(Located::ModuleName {\n                            location: *location,\n                            module_name,\n                            module_alias: module_alias.clone(),\n                            layer: Layer::Type,\n                        });\n                    }\n\n                    None\n                })\n                .or(Some(Located::Annotation { ast: self, type_ })),\n            TypeAst::Tuple(TypeAstTuple { elements, .. }) => type_\n                .tuple_types()\n                .and_then(|elem_types| {\n                    if let Some(e) = elements\n                        .iter()\n                        .zip(elem_types)\n                        .find_map(|(e, e_type)| e.find_node(byte_index, e_type.clone()))\n                    {\n                        return Some(e);\n                    }\n\n                    None\n                })\n                .or(Some(Located::Annotation { ast: self, type_ })),\n            TypeAst::Var(_) | TypeAst::Hole(_) => Some(Located::Annotation { ast: self, type_ }),\n        }\n    }\n\n    /// Generates an annotation corresponding to the type.\n    pub fn print(&self, buffer: &mut EcoString) {\n        match &self {\n            TypeAst::Var(var) => buffer.push_str(&var.name),\n            TypeAst::Hole(hole) => buffer.push_str(&hole.name),\n            TypeAst::Tuple(tuple) => {\n                buffer.push_str(\"#(\");\n                for (i, element) in tuple.elements.iter().enumerate() {\n                    element.print(buffer);\n                    if i < tuple.elements.len() - 1 {\n                        buffer.push_str(\", \");\n                    }\n                }\n                buffer.push(')')\n            }\n            TypeAst::Fn(func) => {\n                buffer.push_str(\"fn(\");\n                for (i, argument) in func.arguments.iter().enumerate() {\n                    argument.print(buffer);\n                    if i < func.arguments.len() - 1 {\n                        buffer.push_str(\", \");\n                    }\n                }\n                buffer.push(')');\n                buffer.push_str(\" -> \");\n                func.return_.print(buffer);\n            }\n            TypeAst::Constructor(constructor) => {\n                if let Some((module, _)) = &constructor.module {\n                    buffer.push_str(module);\n                    buffer.push('.');\n                }\n                buffer.push_str(&constructor.name);\n                if !constructor.arguments.is_empty() {\n                    buffer.push('(');\n                    for (i, argument) in constructor.arguments.iter().enumerate() {\n                        argument.print(buffer);\n                        if i < constructor.arguments.len() - 1 {\n                            buffer.push_str(\", \");\n                        }\n                    }\n                    buffer.push(')');\n                }\n            }\n        }\n    }\n}\n\n#[test]\nfn type_ast_print_fn() {\n    let mut buffer = EcoString::new();\n    let ast = TypeAst::Fn(TypeAstFn {\n        location: SrcSpan { start: 1, end: 1 },\n        arguments: vec![\n            TypeAst::Var(TypeAstVar {\n                location: SrcSpan { start: 1, end: 1 },\n                name: \"String\".into(),\n            }),\n            TypeAst::Var(TypeAstVar {\n                location: SrcSpan { start: 1, end: 1 },\n                name: \"Bool\".into(),\n            }),\n        ],\n        return_: Box::new(TypeAst::Var(TypeAstVar {\n            location: SrcSpan { start: 1, end: 1 },\n            name: \"Int\".into(),\n        })),\n    });\n    ast.print(&mut buffer);\n    assert_eq!(&buffer, \"fn(String, Bool) -> Int\")\n}\n\n#[test]\nfn type_ast_print_constructor() {\n    let mut buffer = EcoString::new();\n    let ast = TypeAst::Constructor(TypeAstConstructor {\n        name: \"SomeType\".into(),\n        module: Some((\"some_module\".into(), SrcSpan { start: 1, end: 1 })),\n        location: SrcSpan { start: 1, end: 1 },\n        name_location: SrcSpan { start: 1, end: 1 },\n        arguments: vec![\n            TypeAst::Var(TypeAstVar {\n                location: SrcSpan { start: 1, end: 1 },\n                name: \"String\".into(),\n            }),\n            TypeAst::Var(TypeAstVar {\n                location: SrcSpan { start: 1, end: 1 },\n                name: \"Bool\".into(),\n            }),\n        ],\n        start_parentheses: Some(1),\n    });\n    ast.print(&mut buffer);\n    assert_eq!(&buffer, \"some_module.SomeType(String, Bool)\")\n}\n\n#[test]\nfn type_ast_print_tuple() {\n    let mut buffer = EcoString::new();\n    let ast = TypeAst::Tuple(TypeAstTuple {\n        location: SrcSpan { start: 1, end: 1 },\n        elements: vec![\n            TypeAst::Constructor(TypeAstConstructor {\n                name: \"SomeType\".into(),\n                module: Some((\"some_module\".into(), SrcSpan { start: 1, end: 1 })),\n                location: SrcSpan { start: 1, end: 1 },\n                name_location: SrcSpan { start: 1, end: 1 },\n                arguments: vec![\n                    TypeAst::Var(TypeAstVar {\n                        location: SrcSpan { start: 1, end: 1 },\n                        name: \"String\".into(),\n                    }),\n                    TypeAst::Var(TypeAstVar {\n                        location: SrcSpan { start: 1, end: 1 },\n                        name: \"Bool\".into(),\n                    }),\n                ],\n                start_parentheses: Some(1),\n            }),\n            TypeAst::Fn(TypeAstFn {\n                location: SrcSpan { start: 1, end: 1 },\n                arguments: vec![\n                    TypeAst::Var(TypeAstVar {\n                        location: SrcSpan { start: 1, end: 1 },\n                        name: \"String\".into(),\n                    }),\n                    TypeAst::Var(TypeAstVar {\n                        location: SrcSpan { start: 1, end: 1 },\n                        name: \"Bool\".into(),\n                    }),\n                ],\n                return_: Box::new(TypeAst::Var(TypeAstVar {\n                    location: SrcSpan { start: 1, end: 1 },\n                    name: \"Int\".into(),\n                })),\n            }),\n        ],\n    });\n    ast.print(&mut buffer);\n    assert_eq!(\n        &buffer,\n        \"#(some_module.SomeType(String, Bool), fn(String, Bool) -> Int)\"\n    )\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Publicity {\n    Public,\n    Private,\n    Internal { attribute_location: Option<SrcSpan> },\n}\n\nimpl Publicity {\n    pub fn is_private(&self) -> bool {\n        match self {\n            Self::Private => true,\n            Self::Public | Self::Internal { .. } => false,\n        }\n    }\n\n    pub fn is_internal(&self) -> bool {\n        match self {\n            Self::Internal { .. } => true,\n            Self::Public | Self::Private => false,\n        }\n    }\n\n    pub fn is_public(&self) -> bool {\n        match self {\n            Self::Public => true,\n            Self::Internal { .. } | Self::Private => false,\n        }\n    }\n\n    pub fn is_importable(&self) -> bool {\n        match self {\n            Self::Internal { .. } | Self::Public => true,\n            Self::Private => false,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n/// A function definition\n///\n/// Note that an anonymous function will have `None` as the name field, while a\n/// named function will have `Some`.\n///\n/// # Example(s)\n///\n/// ```gleam\n/// // Public function\n/// pub fn wobble() -> String { ... }\n/// // Private function\n/// fn wibble(x: Int) -> Int { ... }\n/// // Anonymous function\n/// fn(x: Int) { ... }\n/// ```\npub struct Function<T, Expr> {\n    pub location: SrcSpan,\n    pub body_start: Option<u32>,\n    pub end_position: u32,\n    pub name: Option<SpannedString>,\n    pub arguments: Vec<Arg<T>>,\n    pub body: Vec<Statement<T, Expr>>,\n    pub publicity: Publicity,\n    pub deprecation: Deprecation,\n    pub return_annotation: Option<TypeAst>,\n    pub return_type: T,\n    pub documentation: Option<(u32, EcoString)>,\n    pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>,\n    pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>,\n    pub implementations: Implementations,\n    pub purity: Purity,\n}\n\npub type TypedFunction = Function<Arc<Type>, TypedExpr>;\npub type UntypedFunction = Function<(), UntypedExpr>;\n\nimpl<T, E> Function<T, E> {\n    pub fn full_location(&self) -> SrcSpan {\n        SrcSpan::new(self.location.start, self.end_position)\n    }\n}\n\nimpl TypedFunction {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        // Search for the corresponding node inside the function\n        // only if the index falls within the function's full location.\n        if !self.full_location().contains(byte_index) {\n            return None;\n        }\n\n        if let Some(found) = self\n            .body\n            .iter()\n            .find_map(|statement| statement.find_node(byte_index))\n        {\n            return Some(found);\n        }\n\n        if let Some(found_arg) = self\n            .arguments\n            .iter()\n            .find_map(|arg| arg.find_node(byte_index))\n        {\n            return Some(found_arg);\n        };\n\n        if let Some(found_statement) = self\n            .body\n            .iter()\n            .find(|statement| statement.location().contains(byte_index))\n        {\n            return Some(Located::Statement(found_statement));\n        };\n\n        // Check if location is within the return annotation.\n        if let Some(located) = self\n            .return_annotation\n            .iter()\n            .find_map(|annotation| annotation.find_node(byte_index, self.return_type.clone()))\n        {\n            return Some(located);\n        };\n\n        // Note that the fn `.location` covers the function head, not\n        // the entire statement.\n        if self.location.contains(byte_index) {\n            Some(Located::ModuleFunction(self))\n        } else if self.full_location().contains(byte_index) {\n            Some(Located::FunctionBody(self))\n        } else {\n            None\n        }\n    }\n\n    pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> {\n        if !self.full_location().contains(byte_index) {\n            return None;\n        }\n\n        self.body\n            .iter()\n            .find_map(|statement| statement.find_statement(byte_index))\n    }\n\n    pub fn main_function(&self) -> Option<&TypedFunction> {\n        if let Some((_, name)) = &self.name\n            && name == \"main\"\n        {\n            Some(self)\n        } else {\n            None\n        }\n    }\n}\n\npub type UntypedImport = Import<()>;\npub type TypedImport = Import<EcoString>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n/// Import another Gleam module so the current module can use the types and\n/// values it defines.\n///\n/// # Example(s)\n///\n/// ```gleam\n/// import unix/cat\n/// // Import with alias\n/// import animal/cat as kitty\n/// ```\npub struct Import<PackageName> {\n    pub documentation: Option<EcoString>,\n    pub location: SrcSpan,\n    pub module_location: SrcSpan,\n    pub module: EcoString,\n    pub as_name: Option<(AssignName, SrcSpan)>,\n    pub unqualified_values: Vec<UnqualifiedImport>,\n    pub unqualified_types: Vec<UnqualifiedImport>,\n    pub package: PackageName,\n}\n\nimpl<T> Import<T> {\n    pub fn used_name(&self) -> Option<EcoString> {\n        match self.as_name.as_ref() {\n            Some((AssignName::Variable(name), _)) => Some(name.clone()),\n            Some((AssignName::Discard(_), _)) => None,\n            None => self.module.split('/').next_back().map(EcoString::from),\n        }\n    }\n\n    pub(crate) fn alias_location(&self) -> Option<SrcSpan> {\n        self.as_name.as_ref().map(|(_, location)| *location)\n    }\n}\n\nimpl TypedImport {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if !self.location.contains(byte_index) {\n            return None;\n        }\n\n        if let Some(unqualified) = self\n            .unqualified_values\n            .iter()\n            .find(|unqualified_value| unqualified_value.location.contains(byte_index))\n        {\n            return Some(Located::UnqualifiedImport(\n                crate::build::UnqualifiedImport {\n                    name: &unqualified.name,\n                    module: &self.module,\n                    is_type: false,\n                    location: &unqualified.location,\n                },\n            ));\n        }\n\n        if let Some(unqualified) = self\n            .unqualified_types\n            .iter()\n            .find(|unqualified_value| unqualified_value.location.contains(byte_index))\n        {\n            return Some(Located::UnqualifiedImport(\n                crate::build::UnqualifiedImport {\n                    name: &unqualified.name,\n                    module: &self.module,\n                    is_type: true,\n                    location: &unqualified.location,\n                },\n            ));\n        }\n\n        Some(Located::ModuleImport(self))\n    }\n}\n\npub type UntypedModuleConstant = ModuleConstant<(), ()>;\npub type TypedModuleConstant = ModuleConstant<Arc<Type>, EcoString>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n/// A certain fixed value that can be used in multiple places\n///\n/// # Example(s)\n///\n/// ```gleam\n/// pub const start_year = 2101\n/// pub const end_year = 2111\n/// ```\npub struct ModuleConstant<T, ConstantRecordTag> {\n    pub documentation: Option<(u32, EcoString)>,\n    /// The location of the constant, starting at the \"(pub) const\" keywords and\n    /// ending after the \": Type\" annotation, or (without an annotation) after its name.\n    pub location: SrcSpan,\n    pub publicity: Publicity,\n    pub name: EcoString,\n    pub name_location: SrcSpan,\n    pub annotation: Option<TypeAst>,\n    pub value: Box<Constant<T, ConstantRecordTag>>,\n    pub type_: T,\n    pub deprecation: Deprecation,\n    pub implementations: Implementations,\n}\n\nimpl TypedModuleConstant {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        // Check if location is within the annotation.\n        if let Some(annotation) = &self.annotation\n            && let Some(located) = annotation.find_node(byte_index, self.type_.clone())\n        {\n            return Some(located);\n        }\n\n        if let Some(located) = self.value.find_node(byte_index) {\n            return Some(located);\n        }\n\n        if self.location.contains(byte_index) {\n            Some(Located::ModuleConstant(self))\n        } else {\n            None\n        }\n    }\n}\n\npub type UntypedCustomType = CustomType<()>;\npub type TypedCustomType = CustomType<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n/// A newly defined type with one or more constructors.\n/// Each variant of the custom type can contain different types, so the type is\n/// the product of the types contained by each variant.\n///\n/// This might be called an algebraic data type (ADT) or tagged union in other\n/// languages and type systems.\n///\n///\n/// # Example(s)\n///\n/// ```gleam\n/// pub type Cat {\n///   Cat(name: String, cuteness: Int)\n/// }\n/// ```\npub struct CustomType<T> {\n    pub location: SrcSpan,\n    pub end_position: u32,\n    pub name: EcoString,\n    pub name_location: SrcSpan,\n    pub publicity: Publicity,\n    pub constructors: Vec<RecordConstructor<T>>,\n    pub documentation: Option<(u32, EcoString)>,\n    pub deprecation: Deprecation,\n    pub opaque: bool,\n    /// The names of the type parameters.\n    pub parameters: Vec<SpannedString>,\n    /// Once type checked this field will contain the type information for the\n    /// type parameters.\n    pub typed_parameters: Vec<T>,\n    pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>,\n    pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>,\n}\n\nimpl<T> CustomType<T> {\n    /// The `location` field of a `CustomType` is only the location of `pub type\n    /// TheName`. This method returns a `SrcSpan` that includes the entire type\n    /// definition.\n    pub fn full_location(&self) -> SrcSpan {\n        SrcSpan::new(self.location.start, self.end_position)\n    }\n}\n\nimpl TypedCustomType {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        // Check if location is within the type of one of the arguments of a constructor.\n        if let Some(constructor) = self\n            .constructors\n            .iter()\n            .find(|constructor| constructor.location.contains(byte_index))\n        {\n            if let Some(annotation) = constructor\n                .arguments\n                .iter()\n                .find(|arg| arg.location.contains(byte_index))\n                .and_then(|arg| arg.ast.find_node(byte_index, arg.type_.clone()))\n            {\n                return Some(annotation);\n            }\n\n            return Some(Located::VariantConstructorDefinition(constructor));\n        }\n\n        // Note that the custom type `.location` covers the function\n        // head, not the entire statement.\n        if self.full_location().contains(byte_index) {\n            Some(Located::ModuleCustomType(self))\n        } else {\n            None\n        }\n    }\n}\n\npub type UntypedTypeAlias = TypeAlias<()>;\npub type TypedTypeAlias = TypeAlias<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n/// A new name for an existing type\n///\n/// # Example(s)\n///\n/// ```gleam\n/// pub type Headers =\n///   List(#(String, String))\n/// ```\npub struct TypeAlias<T> {\n    pub location: SrcSpan,\n    pub alias: EcoString,\n    pub name_location: SrcSpan,\n    pub parameters: Vec<SpannedString>,\n    pub type_ast: TypeAst,\n    pub type_: T,\n    pub publicity: Publicity,\n    pub documentation: Option<(u32, EcoString)>,\n    pub deprecation: Deprecation,\n}\n\nimpl TypedTypeAlias {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        // Check if location is within the type being aliased.\n        if let Some(located) = self.type_ast.find_node(byte_index, self.type_.clone()) {\n            return Some(located);\n        }\n\n        if self.location.contains(byte_index) {\n            Some(Located::ModuleTypeAlias(self))\n        } else {\n            None\n        }\n    }\n}\n\npub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Definition<T, Expr, ConstantRecordTag, PackageName> {\n    Function(Function<T, Expr>),\n    TypeAlias(TypeAlias<T>),\n    CustomType(CustomType<T>),\n    Import(Import<PackageName>),\n    ModuleConstant(ModuleConstant<T, ConstantRecordTag>),\n}\n\nimpl<A, B, C, E> Definition<A, B, C, E> {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Definition::Function(Function { location, .. })\n            | Definition::Import(Import { location, .. })\n            | Definition::TypeAlias(TypeAlias { location, .. })\n            | Definition::CustomType(CustomType { location, .. })\n            | Definition::ModuleConstant(ModuleConstant { location, .. }) => *location,\n        }\n    }\n\n    /// Returns `true` if the definition is [`Import`].\n    ///\n    /// [`Import`]: Definition::Import\n    #[must_use]\n    pub fn is_import(&self) -> bool {\n        matches!(self, Self::Import(..))\n    }\n\n    /// Returns `true` if the module statement is [`Function`].\n    ///\n    /// [`Function`]: ModuleStatement::Function\n    #[must_use]\n    pub fn is_function(&self) -> bool {\n        matches!(self, Self::Function(..))\n    }\n\n    /// Returns `true` if the module statement is [`CustomType`].\n    ///\n    /// [`CustomType`]: ModuleStatement::CustomType\n    #[must_use]\n    pub fn is_custom_type(&self) -> bool {\n        matches!(self, Self::CustomType(..))\n    }\n\n    pub fn get_doc(&self) -> Option<EcoString> {\n        match self {\n            Definition::Import(Import { .. }) => None,\n\n            Definition::Function(Function {\n                documentation: doc, ..\n            })\n            | Definition::TypeAlias(TypeAlias {\n                documentation: doc, ..\n            })\n            | Definition::CustomType(CustomType {\n                documentation: doc, ..\n            })\n            | Definition::ModuleConstant(ModuleConstant {\n                documentation: doc, ..\n            }) => doc.as_ref().map(|(_, doc)| doc.clone()),\n        }\n    }\n\n    pub fn is_internal(&self) -> bool {\n        match self {\n            Definition::Function(Function { publicity, .. })\n            | Definition::CustomType(CustomType { publicity, .. })\n            | Definition::ModuleConstant(ModuleConstant { publicity, .. })\n            | Definition::TypeAlias(TypeAlias { publicity, .. }) => publicity.is_internal(),\n\n            Definition::Import(_) => false,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct UnqualifiedImport {\n    pub location: SrcSpan,\n    /// The location excluding the potential `as ...` clause, or the `type` keyword\n    pub imported_name_location: SrcSpan,\n    pub name: EcoString,\n    pub as_name: Option<EcoString>,\n}\n\nimpl UnqualifiedImport {\n    pub fn used_name(&self) -> &EcoString {\n        self.as_name.as_ref().unwrap_or(&self.name)\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, serde::Serialize, serde::Deserialize)]\npub enum Layer {\n    #[default]\n    Value,\n    Type,\n}\n\nimpl Layer {\n    /// Returns `true` if the layer is [`Value`].\n    pub fn is_value(&self) -> bool {\n        matches!(self, Self::Value)\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum BinOp {\n    // Boolean logic\n    And,\n    Or,\n\n    // Equality\n    Eq,\n    NotEq,\n\n    // Order comparison\n    LtInt,\n    LtEqInt,\n    LtFloat,\n    LtEqFloat,\n    GtEqInt,\n    GtInt,\n    GtEqFloat,\n    GtFloat,\n\n    // Maths\n    AddInt,\n    AddFloat,\n    SubInt,\n    SubFloat,\n    MultInt,\n    MultFloat,\n    DivInt,\n    DivFloat,\n    RemainderInt,\n\n    // Strings\n    Concatenate,\n}\n\n#[derive(Clone, Copy, Debug, PartialEq)]\npub enum OperatorKind {\n    BooleanLogic,\n    Equality,\n    IntComparison,\n    FLoatComparison,\n    IntMath,\n    FloatMath,\n    StringConcatenation,\n}\n\npub const PIPE_PRECEDENCE: u8 = 6;\n\nimpl BinOp {\n    pub fn precedence(&self) -> u8 {\n        // Ensure that this matches the other precedence function for guards\n        match self {\n            Self::Or => 1,\n\n            Self::And => 2,\n\n            Self::Eq | Self::NotEq => 3,\n\n            Self::LtInt\n            | Self::LtEqInt\n            | Self::LtFloat\n            | Self::LtEqFloat\n            | Self::GtEqInt\n            | Self::GtInt\n            | Self::GtEqFloat\n            | Self::GtFloat => 4,\n\n            Self::Concatenate => 5,\n\n            // Pipe is 6\n            Self::AddInt | Self::AddFloat | Self::SubInt | Self::SubFloat => 7,\n\n            Self::MultInt\n            | Self::MultFloat\n            | Self::DivInt\n            | Self::DivFloat\n            | Self::RemainderInt => 8,\n        }\n    }\n\n    pub fn name(&self) -> &'static str {\n        match self {\n            Self::And => \"&&\",\n            Self::Or => \"||\",\n            Self::LtInt => \"<\",\n            Self::LtEqInt => \"<=\",\n            Self::LtFloat => \"<.\",\n            Self::LtEqFloat => \"<=.\",\n            Self::Eq => \"==\",\n            Self::NotEq => \"!=\",\n            Self::GtEqInt => \">=\",\n            Self::GtInt => \">\",\n            Self::GtEqFloat => \">=.\",\n            Self::GtFloat => \">.\",\n            Self::AddInt => \"+\",\n            Self::AddFloat => \"+.\",\n            Self::SubInt => \"-\",\n            Self::SubFloat => \"-.\",\n            Self::MultInt => \"*\",\n            Self::MultFloat => \"*.\",\n            Self::DivInt => \"/\",\n            Self::DivFloat => \"/.\",\n            Self::RemainderInt => \"%\",\n            Self::Concatenate => \"<>\",\n        }\n    }\n\n    pub fn operator_kind(&self) -> OperatorKind {\n        match self {\n            Self::Concatenate => OperatorKind::StringConcatenation,\n            Self::Eq | Self::NotEq => OperatorKind::Equality,\n            Self::And | Self::Or => OperatorKind::BooleanLogic,\n            Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => {\n                OperatorKind::IntComparison\n            }\n            Self::LtFloat | Self::LtEqFloat | Self::GtEqFloat | Self::GtFloat => {\n                OperatorKind::FLoatComparison\n            }\n            Self::AddInt | Self::SubInt | Self::MultInt | Self::RemainderInt | Self::DivInt => {\n                OperatorKind::IntMath\n            }\n            Self::AddFloat | Self::SubFloat | Self::MultFloat | Self::DivFloat => {\n                OperatorKind::FloatMath\n            }\n        }\n    }\n\n    pub fn can_be_grouped_with(&self, other: &BinOp) -> bool {\n        self.operator_kind() == other.operator_kind()\n    }\n\n    pub fn is_float_operator(&self) -> bool {\n        match self {\n            BinOp::LtFloat\n            | BinOp::LtEqFloat\n            | BinOp::GtEqFloat\n            | BinOp::GtFloat\n            | BinOp::AddFloat\n            | BinOp::SubFloat\n            | BinOp::MultFloat\n            | BinOp::DivFloat => true,\n\n            BinOp::And\n            | BinOp::Or\n            | BinOp::Eq\n            | BinOp::NotEq\n            | BinOp::LtInt\n            | BinOp::LtEqInt\n            | BinOp::GtEqInt\n            | BinOp::GtInt\n            | BinOp::AddInt\n            | BinOp::SubInt\n            | BinOp::MultInt\n            | BinOp::DivInt\n            | BinOp::RemainderInt\n            | BinOp::Concatenate => false,\n        }\n    }\n\n    fn is_bool_operator(&self) -> bool {\n        match self {\n            BinOp::And | BinOp::Or => true,\n            BinOp::Eq\n            | BinOp::NotEq\n            | BinOp::LtInt\n            | BinOp::LtEqInt\n            | BinOp::LtFloat\n            | BinOp::LtEqFloat\n            | BinOp::GtEqInt\n            | BinOp::GtInt\n            | BinOp::GtEqFloat\n            | BinOp::GtFloat\n            | BinOp::AddInt\n            | BinOp::AddFloat\n            | BinOp::SubInt\n            | BinOp::SubFloat\n            | BinOp::MultInt\n            | BinOp::MultFloat\n            | BinOp::DivInt\n            | BinOp::DivFloat\n            | BinOp::RemainderInt\n            | BinOp::Concatenate => false,\n        }\n    }\n\n    pub fn is_int_operator(&self) -> bool {\n        match self {\n            BinOp::LtInt\n            | BinOp::LtEqInt\n            | BinOp::GtEqInt\n            | BinOp::GtInt\n            | BinOp::AddInt\n            | BinOp::SubInt\n            | BinOp::MultInt\n            | BinOp::DivInt\n            | BinOp::RemainderInt => true,\n\n            BinOp::And\n            | BinOp::Or\n            | BinOp::Eq\n            | BinOp::NotEq\n            | BinOp::LtFloat\n            | BinOp::LtEqFloat\n            | BinOp::GtEqFloat\n            | BinOp::GtFloat\n            | BinOp::AddFloat\n            | BinOp::SubFloat\n            | BinOp::MultFloat\n            | BinOp::DivFloat\n            | BinOp::Concatenate => false,\n        }\n    }\n\n    pub fn float_equivalent(&self) -> Option<BinOp> {\n        match self {\n            BinOp::LtInt => Some(BinOp::LtFloat),\n            BinOp::LtEqInt => Some(BinOp::LtEqFloat),\n            BinOp::GtEqInt => Some(BinOp::GtEqFloat),\n            BinOp::GtInt => Some(BinOp::GtFloat),\n            BinOp::AddInt => Some(BinOp::AddFloat),\n            BinOp::SubInt => Some(BinOp::SubFloat),\n            BinOp::MultInt => Some(BinOp::MultFloat),\n            BinOp::DivInt => Some(BinOp::DivFloat),\n            BinOp::And\n            | BinOp::Or\n            | BinOp::Eq\n            | BinOp::NotEq\n            | BinOp::LtFloat\n            | BinOp::LtEqFloat\n            | BinOp::GtEqFloat\n            | BinOp::GtFloat\n            | BinOp::AddFloat\n            | BinOp::SubFloat\n            | BinOp::MultFloat\n            | BinOp::DivFloat\n            | BinOp::RemainderInt\n            | BinOp::Concatenate => None,\n        }\n    }\n\n    pub fn int_equivalent(&self) -> Option<BinOp> {\n        match self {\n            BinOp::LtFloat => Some(BinOp::LtInt),\n            BinOp::LtEqFloat => Some(BinOp::LtEqInt),\n            BinOp::GtEqFloat => Some(BinOp::GtEqInt),\n            BinOp::GtFloat => Some(BinOp::GtInt),\n            BinOp::AddFloat => Some(BinOp::AddInt),\n            BinOp::SubFloat => Some(BinOp::SubInt),\n            BinOp::MultFloat => Some(BinOp::MultInt),\n            BinOp::DivFloat => Some(BinOp::DivInt),\n            BinOp::And\n            | BinOp::Or\n            | BinOp::Eq\n            | BinOp::NotEq\n            | BinOp::LtInt\n            | BinOp::LtEqInt\n            | BinOp::GtEqInt\n            | BinOp::GtInt\n            | BinOp::AddInt\n            | BinOp::SubInt\n            | BinOp::MultInt\n            | BinOp::DivInt\n            | BinOp::RemainderInt\n            | BinOp::Concatenate => None,\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]\npub struct CallArg<A> {\n    pub label: Option<EcoString>,\n    pub location: SrcSpan,\n    pub value: A,\n    pub implicit: Option<ImplicitCallArgOrigin>,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)]\npub enum ImplicitCallArgOrigin {\n    /// The implicit callback argument passed as the last argument to the\n    /// function on the right hand side of `use`.\n    ///\n    Use,\n    /// An argument added by the compiler when rewriting a pipe `left |> right`.\n    ///\n    Pipe,\n    /// An argument added by the compiler to fill in all the missing fields of a\n    /// record that are being ignored with the `..` syntax.\n    ///\n    PatternFieldSpread,\n    /// An argument used to fill in the missing args when a function on the\n    /// right hand side of `use` is being called with the wrong arity.\n    ///\n    IncorrectArityUse,\n    /// An argument added by the compiler to fill in the missing args when using\n    /// the record update synax.\n    ///\n    RecordUpdate,\n}\n\nimpl<A> CallArg<A> {\n    #[must_use]\n    pub fn is_implicit(&self) -> bool {\n        self.implicit.is_some()\n    }\n\n    #[must_use]\n    pub fn is_use_implicit_callback(&self) -> bool {\n        match self.implicit {\n            Some(ImplicitCallArgOrigin::Use | ImplicitCallArgOrigin::IncorrectArityUse) => true,\n            Some(_) | None => false,\n        }\n    }\n}\n\nimpl CallArg<TypedExpr> {\n    pub fn find_node<'a>(\n        &'a self,\n        byte_index: u32,\n        called_function: &'a TypedExpr,\n        function_arguments: &'a [TypedCallArg],\n    ) -> Option<Located<'a>> {\n        match (self.implicit, &self.value) {\n            // If a call argument is the implicit use callback then we don't\n            // want to look at its arguments and body but we don't want to\n            // return the whole anonymous function if anything else doesn't\n            // match.\n            //\n            // In addition, if the callback is invalid because it couldn't be\n            // typed, we don't want to return it as it would make it hard for\n            // the LSP to give any suggestions on the use function being typed.\n            //\n            (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None,\n            // So the code below is exactly the same as\n            // `TypedExpr::Fn{}.find_node()` except we do not return self as a\n            // fallback.\n            //\n            (\n                Some(ImplicitCallArgOrigin::Use),\n                TypedExpr::Fn {\n                    arguments, body, ..\n                },\n            ) => arguments\n                .iter()\n                .find_map(|argument| argument.find_node(byte_index))\n                .or_else(|| body.iter().find_map(|s| s.find_node(byte_index))),\n            // In all other cases we're happy with the default behaviour.\n            //\n            _ => match self.value.find_node(byte_index) {\n                Some(Located::Expression { expression, .. })\n                // This is only possibly a label if we are at the end of the expression\n                // (so not in the middle like `[abc|]`) and if this argument doesn't\n                // already have a label.\n                    if byte_index == self.value.location().end && self.label.is_none() =>\n                {\n                    Some(Located::Expression {\n                        expression,\n                        position: ExpressionPosition::ArgumentOrLabel {\n                            called_function,\n                            function_arguments,\n                        },\n                    })\n                }\n                Some(located) => Some(located),\n                None => {\n                    if self.location.contains(byte_index) && self.label.is_some() {\n                        Some(Located::Label(self.location, self.value.type_()))\n                    } else {\n                        None\n                    }\n                }\n            },\n        }\n    }\n\n    pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> {\n        match (self.implicit, &self.value) {\n            (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None,\n            (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { body, .. }) => {\n                body.iter().find_map(|s| s.find_statement(byte_index))\n            }\n\n            _ => self.value.find_statement(byte_index),\n        }\n    }\n\n    pub fn is_capture_hole(&self) -> bool {\n        match &self.value {\n            TypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE,\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => false,\n        }\n    }\n}\n\nimpl CallArg<TypedPattern> {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        match self.value.find_node(byte_index) {\n            Some(located) => Some(located),\n            _ => {\n                if self.location.contains(byte_index) && self.label.is_some() {\n                    Some(Located::Label(self.location, self.value.type_()))\n                } else {\n                    None\n                }\n            }\n        }\n    }\n}\n\nimpl CallArg<TypedConstant> {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        match self.value.find_node(byte_index) {\n            Some(located) => Some(located),\n            _ => {\n                if self.location.contains(byte_index) && self.label.is_some() {\n                    Some(Located::Label(self.location, self.value.type_()))\n                } else {\n                    None\n                }\n            }\n        }\n    }\n}\n\nimpl CallArg<UntypedExpr> {\n    pub fn is_capture_hole(&self) -> bool {\n        match &self.value {\n            UntypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE,\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::BinOp { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => false,\n        }\n    }\n}\n\nimpl<T> CallArg<T>\nwhere\n    T: HasLocation,\n{\n    #[must_use]\n    pub fn uses_label_shorthand(&self) -> bool {\n        self.label_shorthand_name().is_some()\n    }\n\n    /// If the call arg is defined using a label shorthand, this will return the\n    /// label name.\n    ///\n    pub fn label_shorthand_name(&self) -> Option<&EcoString> {\n        if !self.is_implicit() && self.location == self.value.location() {\n            self.label.as_ref()\n        } else {\n            None\n        }\n    }\n}\n\nimpl<T> HasLocation for CallArg<T> {\n    fn location(&self) -> SrcSpan {\n        self.location\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct RecordBeingUpdated<A> {\n    pub base: Box<A>,\n    pub location: SrcSpan,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct RecordUpdateArg<A> {\n    pub label: EcoString,\n    pub location: SrcSpan,\n    pub value: A,\n}\n\npub type UntypedRecordUpdateArg = RecordUpdateArg<UntypedExpr>;\n\nimpl<A> HasLocation for RecordUpdateArg<A> {\n    fn location(&self) -> SrcSpan {\n        self.location\n    }\n}\n\nimpl<A: HasLocation> RecordUpdateArg<A> {\n    #[must_use]\n    pub fn uses_label_shorthand(&self) -> bool {\n        self.value.location() == self.location\n    }\n}\n\npub type MultiPattern<Type> = Vec<Pattern<Type>>;\n\npub type UntypedMultiPattern = MultiPattern<()>;\npub type TypedMultiPattern = MultiPattern<Arc<Type>>;\n\npub type TypedClause = Clause<TypedExpr, Arc<Type>, EcoString>;\n\npub type UntypedClause = Clause<UntypedExpr, (), ()>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Clause<Expr, Type, RecordTag> {\n    pub location: SrcSpan,\n    pub pattern: MultiPattern<Type>,\n    pub alternative_patterns: Vec<MultiPattern<Type>>,\n    pub guard: Option<ClauseGuard<Type, RecordTag>>,\n    pub then: Expr,\n}\n\nimpl<A, B, C> Clause<A, B, C> {\n    pub fn pattern_count(&self) -> usize {\n        1 + self.alternative_patterns.len()\n    }\n}\n\nimpl TypedClause {\n    pub fn location(&self) -> SrcSpan {\n        SrcSpan {\n            start: self\n                .pattern\n                .first()\n                .map(|p| p.location().start)\n                .unwrap_or_default(),\n            end: self.then.location().end,\n        }\n    }\n\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        self.pattern\n            .iter()\n            .find_map(|p| p.find_node(byte_index))\n            .or_else(|| {\n                self.alternative_patterns\n                    .iter()\n                    .flat_map(|p| p.iter())\n                    .find_map(|p| p.find_node(byte_index))\n            })\n            .or_else(|| {\n                self.guard\n                    .as_ref()\n                    .and_then(|guard| guard.find_node(byte_index))\n            })\n            .or_else(|| self.then.find_node(byte_index))\n    }\n\n    pub fn pattern_location(&self) -> SrcSpan {\n        let start = self.pattern.first().map(|pattern| pattern.location().start);\n\n        let end = if let Some(last_pattern) = self\n            .alternative_patterns\n            .last()\n            .and_then(|patterns| patterns.last())\n        {\n            Some(last_pattern.location().end)\n        } else {\n            self.pattern.last().map(|pattern| pattern.location().end)\n        };\n\n        SrcSpan::new(start.unwrap_or_default(), end.unwrap_or_default())\n    }\n\n    /// If the branch is rebuilding exactly one of the matched subjects and\n    /// returning it, this will return the index of that subject.\n    ///\n    /// For example:\n    /// - `n -> n`, `1 -> 1`, `Ok(1) -> Ok(1)` all return `Some(0)`\n    /// - `\"a\", n -> n`, `n, m if n == m -> a` all return `Some(1)`\n    /// - `_ -> 1`, `Ok(1), _ -> Ok(2)` all return `None`\n    /// ```\n    ///\n    pub fn returned_subject(&self) -> Option<usize> {\n        // The pattern must not have any alternative patterns.\n        if !self.alternative_patterns.is_empty() {\n            return None;\n        }\n\n        self.pattern\n            .iter()\n            .find_position(|pattern| pattern_and_expression_are_the_same(pattern, &self.then))\n            .map(|(position, _)| position)\n    }\n\n    /// This returns the names of all the variables bound in this case clause.\n    /// For example if we had `#(a, b) | c` this will return \"a\", \"b\", and \"c\".\n    pub fn bound_variables(&self) -> impl Iterator<Item = BoundVariable> {\n        std::iter::once(&self.pattern)\n            .chain(&self.alternative_patterns)\n            .flatten()\n            .flat_map(|pattern| pattern.bound_variables())\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        let patterns_are_equal = pairwise_all(&self.pattern, &other.pattern, |(one, other)| {\n            one.syntactically_eq(other)\n        });\n\n        let alternatives_are_equal = pairwise_all(\n            &self.alternative_patterns,\n            &other.alternative_patterns,\n            |(patterns_one, patterns_other)| {\n                pairwise_all(patterns_one, patterns_other, |(one, other)| -> bool {\n                    one.syntactically_eq(other)\n                })\n            },\n        );\n\n        let guards_are_equal = match (&self.guard, &other.guard) {\n            (None, None) => true,\n            (None, Some(_)) | (Some(_), None) => false,\n            (Some(one), Some(other)) => one.syntactically_eq(other),\n        };\n\n        patterns_are_equal\n            && alternatives_are_equal\n            && guards_are_equal\n            && self.then.syntactically_eq(&other.then)\n    }\n}\n\n/// Returns true if a pattern and an expression are the same: that is the expression\n/// would be building the exact matched value back.\n/// For example, if I had a branch like this:\n///\n/// ```gleam\n/// [a, b, c] -> [a, b, c]\n/// ```\n///\n/// The pattern and the expression would indeed be the same. However, if I had\n/// something like this:\n///\n/// ```gleam\n/// [first, ..rest] -> [first]\n/// ```\n///\n/// They wouldn't be the same! I'm not building back exactly the value the\n/// pattern can match on.\n///\nfn pattern_and_expression_are_the_same(pattern: &TypedPattern, expression: &TypedExpr) -> bool {\n    match (pattern, expression) {\n        // A pattern could be the same as a block if the block is wrapping just\n        // a single expression that is the same as the pattern itself!\n        (pattern, TypedExpr::Block { statements, .. }) if statements.len() == 1 => {\n            match statements.first() {\n                Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => false,\n                Statement::Expression(expression) => {\n                    pattern_and_expression_are_the_same(pattern, expression)\n                }\n            }\n        }\n        // If the block has many statements then it can never be the same as a\n        // pattern.\n        (_, TypedExpr::Block { .. }) => false,\n\n        // A pattern and an expression are the same if they're a simple variable\n        // with exactly the same name: `x -> x`, `a -> a`\n        (\n            TypedPattern::Variable {\n                name: pattern_var, ..\n            },\n            TypedExpr::Var { name: body_var, .. },\n        ) => pattern_var == body_var,\n        (TypedPattern::Variable { .. }, _) => false,\n\n        // Floats, Ints, and Strings are the same if they are exactly the same\n        // literal.\n        // `1 -> 1`\n        // `1.1 -> 1.1`\n        // `\"wibble\" -> \"wibble\"`\n        (\n            TypedPattern::Float {\n                float_value: pattern_value,\n                ..\n            },\n            TypedExpr::Float { float_value, .. },\n        ) => pattern_value == float_value,\n        (TypedPattern::Float { .. }, _) => false,\n\n        (\n            TypedPattern::Int {\n                int_value: pattern_value,\n                ..\n            },\n            TypedExpr::Int { int_value, .. },\n        ) => pattern_value == int_value,\n        (TypedPattern::Int { .. }, _) => false,\n\n        (\n            TypedPattern::String {\n                value: pattern_value,\n                ..\n            },\n            TypedExpr::String { value, .. },\n        ) => pattern_value == value,\n        (TypedPattern::String { .. }, _) => false,\n\n        // A string prefix is equivalent to building the string back:\n        // `\"wibble\" <> wobble -> \"wibble\" <> wobble`\n        // `\"wibble\" as a <> wobble -> a <> wobble`\n        (\n            TypedPattern::StringPrefix {\n                left_side_assignment,\n                left_side_string,\n                right_side_assignment,\n                ..\n            },\n            TypedExpr::BinOp {\n                name: BinOp::Concatenate,\n                left,\n                right,\n                ..\n            },\n        ) => {\n            let left_side_matches = match (left_side_assignment, left_side_string, left.as_ref()) {\n                (_, left_side_string, TypedExpr::String { value, .. }) => value == left_side_string,\n                (Some((left_side_name, _)), _, TypedExpr::Var { name, .. }) => {\n                    left_side_name == name\n                }\n                (_, _, _) => false,\n            };\n            let right_side_matches = match (right_side_assignment, right.as_ref()) {\n                (AssignName::Variable(right_side_name), TypedExpr::Var { name, .. }) => {\n                    name == right_side_name\n                }\n                (AssignName::Variable(_) | AssignName::Discard(_), _) => false,\n            };\n            left_side_matches && right_side_matches\n        }\n        (TypedPattern::StringPrefix { .. }, _) => false,\n\n        // Two tuples where each element is equivalent to the other:\n        // `#(a, 1, \"wibble\") -> #(a, 1, \"wibble\")`\n        // `#(a, b) -> #(a, b)`\n        (\n            TypedPattern::Tuple {\n                elements: pattern_elements,\n                ..\n            },\n            TypedExpr::Tuple { elements, .. },\n        ) => {\n            pattern_elements.len() == elements.len()\n                && pattern_elements\n                    .iter()\n                    .zip(elements)\n                    .all(|(pattern, expression)| {\n                        pattern_and_expression_are_the_same(pattern, expression)\n                    })\n        }\n        (TypedPattern::Tuple { .. }, _) => false,\n\n        // Two lists are the same if each element is equivalent to the other:\n        // `[] -> []`\n        // `[a, b] -> [a, b]`\n        // `[1, ..rest] -> [1, ..rest]`\n        (\n            TypedPattern::List {\n                elements: pattern_elements,\n                tail: pattern_tail,\n                ..\n            },\n            TypedExpr::List { elements, tail, .. },\n        ) => {\n            let tails_are_the_same = match (pattern_tail, tail) {\n                (None, None) => true,\n                (None, Some(_)) | (Some(_), None) => false,\n                (Some(tail_pattern), Some(tail_expression)) => {\n                    pattern_and_expression_are_the_same(&tail_pattern.pattern, tail_expression)\n                }\n            };\n\n            tails_are_the_same\n                && pattern_elements.len() == elements.len()\n                && pattern_elements\n                    .iter()\n                    .zip(elements)\n                    .all(|(pattern, expression)| {\n                        pattern_and_expression_are_the_same(pattern, expression)\n                    })\n        }\n        (TypedPattern::List { .. }, _) => false,\n\n        // Two constructors are the same if the expression is building exactly\n        // the same value being matched on (regardless of qualification).\n        // `Ok(a) -> Ok(a)`\n        // `Ok(1) -> Ok(1)`\n        // `Wibble(a, b, c) -> Wibble(a, b, c)`\n        // `Ok(a) -> gleam.Ok(a)`\n        // `gleam.Ok(1) -> Ok(1)`\n        (\n            TypedPattern::Constructor {\n                constructor:\n                    Inferred::Known(PatternConstructor {\n                        module: pattern_module,\n                        name: pattern_name,\n                        ..\n                    }),\n                arguments: pattern_arguments,\n                spread: None,\n                ..\n            },\n            TypedExpr::Call { fun, arguments, .. },\n        ) => match fun.as_ref() {\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { name, module, .. },\n                        ..\n                    },\n                ..\n            }\n            | TypedExpr::ModuleSelect {\n                constructor: ModuleValueConstructor::Record { name, .. },\n                module_name: module,\n                ..\n            } => {\n                pattern_module == module\n                    && pattern_name == name\n                    && pattern_arguments.len() == arguments.len()\n                    && pattern_arguments\n                        .iter()\n                        .zip(arguments)\n                        .all(|(pattern, expression)| {\n                            pattern_and_expression_are_the_same(&pattern.value, &expression.value)\n                        })\n            }\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => false,\n        },\n\n        // A pattern for a constructor with no arguments:\n        // `Nil -> Nil`\n        // `gleam.Nil -> Nil`\n        // `Nil -> gleam.Nil`\n        // `Wibble -> Wibble`\n        (\n            TypedPattern::Constructor {\n                constructor:\n                    Inferred::Known(PatternConstructor {\n                        module: pattern_module,\n                        name: pattern_name,\n                        ..\n                    }),\n                arguments: pattern_arguments,\n                spread: None,\n                ..\n            },\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { name, module, .. },\n                        ..\n                    },\n                ..\n            }\n            | TypedExpr::ModuleSelect {\n                constructor: ModuleValueConstructor::Record { name, .. },\n                module_name: module,\n                ..\n            },\n        ) => pattern_module == module && pattern_name == name && pattern_arguments.is_empty(),\n        (TypedPattern::Constructor { .. }, _) => false,\n\n        // An assignment is the same if the corresponding expression is a\n        // variable with the same name, or if the inner pattern is the same:\n        // `Ok(1) as a -> a`\n        // `Ok(1) as a -> Ok(1)`\n        (\n            TypedPattern::Assign {\n                name: pattern_name, ..\n            },\n            TypedExpr::Var { name, .. },\n        ) => pattern_name == name,\n        (TypedPattern::Assign { pattern, .. }, expression) => {\n            pattern_and_expression_are_the_same(pattern, expression)\n        }\n\n        // Bit arrays are trickier as they can use existing variables in their\n        // pattern and shadow existing variables so for now we just ignore\n        // those.\n        (TypedPattern::BitArray { .. } | TypedPattern::BitArraySize { .. }, _) => false,\n\n        // A discard is never the same as an expression, same goes for an\n        // invalid pattern: there's no way to check if it matches an expression!\n        (TypedPattern::Discard { .. } | TypedPattern::Invalid { .. }, _) => false,\n    }\n}\n\npub type UntypedClauseGuard = ClauseGuard<(), ()>;\npub type TypedClauseGuard = ClauseGuard<Arc<Type>, EcoString>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum ClauseGuard<Type, RecordTag> {\n    Block {\n        location: SrcSpan,\n        value: Box<ClauseGuard<Type, RecordTag>>,\n    },\n\n    BinaryOperator {\n        location: SrcSpan,\n        operator: BinOp,\n        left: Box<Self>,\n        right: Box<Self>,\n    },\n\n    Not {\n        location: SrcSpan,\n        expression: Box<Self>,\n    },\n\n    Var {\n        location: SrcSpan,\n        type_: Type,\n        name: EcoString,\n        definition_location: SrcSpan,\n        origin: VariableOrigin,\n    },\n\n    TupleIndex {\n        location: SrcSpan,\n        index: u64,\n        type_: Type,\n        tuple: Box<Self>,\n    },\n\n    FieldAccess {\n        label_location: SrcSpan,\n        index: Option<u64>,\n        label: EcoString,\n        type_: Type,\n        container: Box<Self>,\n    },\n\n    ModuleSelect {\n        location: SrcSpan,\n        field_start: u32,\n        definition_location: SrcSpan,\n        type_: Type,\n        label: EcoString,\n        module_name: EcoString,\n        module_alias: EcoString,\n        literal: Constant<Type, RecordTag>,\n    },\n\n    Constant(Constant<Type, RecordTag>),\n}\n\nimpl<A, B> ClauseGuard<A, B> {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            ClauseGuard::Constant(constant) => constant.location(),\n            ClauseGuard::BinaryOperator { location, .. }\n            | ClauseGuard::Not { location, .. }\n            | ClauseGuard::Var { location, .. }\n            | ClauseGuard::TupleIndex { location, .. }\n            | ClauseGuard::ModuleSelect { location, .. }\n            | ClauseGuard::Block { location, .. } => *location,\n            ClauseGuard::FieldAccess {\n                label_location,\n                container,\n                ..\n            } => container.location().merge(label_location),\n        }\n    }\n\n    pub fn precedence(&self) -> u8 {\n        // Ensure that this matches the other precedence function for guards\n        match self.bin_op_name() {\n            Some(name) => name.precedence(),\n            None => u8::MAX,\n        }\n    }\n\n    pub fn bin_op_name(&self) -> Option<BinOp> {\n        match self {\n            ClauseGuard::BinaryOperator { operator, .. } => Some(*operator),\n\n            ClauseGuard::Constant(_)\n            | ClauseGuard::Var { .. }\n            | ClauseGuard::Not { .. }\n            | ClauseGuard::TupleIndex { .. }\n            | ClauseGuard::FieldAccess { .. }\n            | ClauseGuard::ModuleSelect { .. }\n            | ClauseGuard::Block { .. } => None,\n        }\n    }\n}\n\nimpl TypedClauseGuard {\n    pub fn type_(&self) -> Arc<Type> {\n        match self {\n            ClauseGuard::Var { type_, .. } => type_.clone(),\n            ClauseGuard::TupleIndex { type_, .. } => type_.clone(),\n            ClauseGuard::FieldAccess { type_, .. } => type_.clone(),\n            ClauseGuard::ModuleSelect { type_, .. } => type_.clone(),\n            ClauseGuard::Constant(constant) => constant.type_(),\n            ClauseGuard::Block { value, .. } => value.type_(),\n\n            ClauseGuard::Not { .. } => type_::bool(),\n\n            ClauseGuard::BinaryOperator { operator, .. } => match operator {\n                BinOp::AddInt\n                | BinOp::SubInt\n                | BinOp::MultInt\n                | BinOp::DivInt\n                | BinOp::RemainderInt => type_::int(),\n                BinOp::AddFloat | BinOp::SubFloat | BinOp::MultFloat | BinOp::DivFloat => {\n                    type_::float()\n                }\n                BinOp::Concatenate => type_::string(),\n                BinOp::Or\n                | BinOp::And\n                | BinOp::Eq\n                | BinOp::NotEq\n                | BinOp::GtInt\n                | BinOp::GtEqInt\n                | BinOp::LtInt\n                | BinOp::LtEqInt\n                | BinOp::GtFloat\n                | BinOp::GtEqFloat\n                | BinOp::LtFloat\n                | BinOp::LtEqFloat => type_::bool(),\n            },\n        }\n    }\n\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if !self.location().contains(byte_index) {\n            return None;\n        }\n\n        match self {\n            ClauseGuard::ModuleSelect {\n                location,\n                module_name,\n                module_alias,\n                ..\n            } => {\n                let module_span =\n                    SrcSpan::new(location.start, location.start + (module_alias.len() as u32));\n\n                if module_span.contains(byte_index) {\n                    Some(Located::ModuleName {\n                        location: module_span,\n                        module_name: module_name.clone(),\n                        module_alias: module_alias.clone(),\n                        layer: Layer::Value,\n                    })\n                } else {\n                    Some(Located::ClauseGuard(self))\n                }\n            }\n\n            ClauseGuard::BinaryOperator { left, right, .. } => left\n                .find_node(byte_index)\n                .or_else(|| right.find_node(byte_index)),\n\n            ClauseGuard::Not {\n                expression: value, ..\n            }\n            | ClauseGuard::TupleIndex { tuple: value, .. }\n            | ClauseGuard::FieldAccess {\n                container: value, ..\n            }\n            | ClauseGuard::Block { value, .. } => value.find_node(byte_index),\n            ClauseGuard::Constant(constant) => constant.find_node(byte_index),\n            ClauseGuard::Var { .. } => Some(Located::ClauseGuard(self)),\n        }\n    }\n\n    pub(crate) fn referenced_variables(&self) -> im::HashSet<&EcoString> {\n        match self {\n            ClauseGuard::Var { name, .. } => im::hashset![name],\n\n            ClauseGuard::Block { value, .. } => value.referenced_variables(),\n            ClauseGuard::Not { expression, .. } => expression.referenced_variables(),\n            ClauseGuard::TupleIndex { tuple, .. } => tuple.referenced_variables(),\n            ClauseGuard::FieldAccess { container, .. } => container.referenced_variables(),\n            ClauseGuard::Constant(constant) => constant.referenced_variables(),\n            ClauseGuard::ModuleSelect { .. } => im::HashSet::new(),\n\n            ClauseGuard::BinaryOperator { left, right, .. } => left\n                .referenced_variables()\n                .union(right.referenced_variables()),\n        }\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (\n                ClauseGuard::Block { value, .. },\n                ClauseGuard::Block {\n                    value: other_value, ..\n                },\n            ) => value.syntactically_eq(other_value),\n            (ClauseGuard::Block { .. }, _) => false,\n\n            (\n                ClauseGuard::BinaryOperator { left, right, .. },\n                ClauseGuard::BinaryOperator {\n                    left: other_left,\n                    right: other_right,\n                    ..\n                },\n            ) => left.syntactically_eq(other_left) && right.syntactically_eq(other_right),\n            (ClauseGuard::BinaryOperator { .. }, _) => false,\n\n            (\n                ClauseGuard::Not { expression, .. },\n                ClauseGuard::Not {\n                    expression: other_expression,\n                    ..\n                },\n            ) => expression.syntactically_eq(other_expression),\n            (ClauseGuard::Not { .. }, _) => false,\n\n            (\n                ClauseGuard::Var { name, .. },\n                ClauseGuard::Var {\n                    name: other_name, ..\n                },\n            ) => name == other_name,\n            (ClauseGuard::Var { .. }, _) => false,\n\n            (\n                ClauseGuard::TupleIndex { index, tuple, .. },\n                ClauseGuard::TupleIndex {\n                    index: other_index,\n                    tuple: other_tuple,\n                    ..\n                },\n            ) => index == other_index && tuple.syntactically_eq(other_tuple),\n            (ClauseGuard::TupleIndex { .. }, _) => false,\n\n            (\n                ClauseGuard::FieldAccess {\n                    label, container, ..\n                },\n                ClauseGuard::FieldAccess {\n                    label: other_label,\n                    container: other_container,\n                    ..\n                },\n            ) => label == other_label && container.syntactically_eq(other_container),\n            (ClauseGuard::FieldAccess { .. }, _) => false,\n\n            (\n                ClauseGuard::ModuleSelect {\n                    label,\n                    module_alias,\n                    ..\n                },\n                ClauseGuard::ModuleSelect {\n                    label: other_label,\n                    module_alias: other_module_alias,\n                    ..\n                },\n            ) => label == other_label && module_alias == other_module_alias,\n            (ClauseGuard::ModuleSelect { .. }, _) => false,\n\n            (ClauseGuard::Constant(one), ClauseGuard::Constant(other)) => {\n                one.syntactically_eq(other)\n            }\n            (ClauseGuard::Constant(_), _) => false,\n        }\n    }\n\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        match self {\n            ClauseGuard::Block { .. }\n            | ClauseGuard::BinaryOperator { .. }\n            | ClauseGuard::Not { .. }\n            | ClauseGuard::TupleIndex { .. }\n            | ClauseGuard::FieldAccess { .. } => None,\n            ClauseGuard::Constant(constant) => constant.definition_location(),\n            ClauseGuard::Var {\n                definition_location,\n                ..\n            } => Some(DefinitionLocation {\n                module: None,\n                span: *definition_location,\n            }),\n            ClauseGuard::ModuleSelect {\n                module_name,\n                definition_location,\n                ..\n            } => Some(DefinitionLocation {\n                module: Some(module_name.clone()),\n                span: *definition_location,\n            }),\n        }\n    }\n}\n\n#[derive(\n    Debug,\n    PartialEq,\n    Eq,\n    PartialOrd,\n    Ord,\n    Default,\n    Clone,\n    Copy,\n    serde::Serialize,\n    serde::Deserialize,\n    Hash,\n)]\npub struct SrcSpan {\n    pub start: u32,\n    pub end: u32,\n}\n\nimpl SrcSpan {\n    pub fn new(start: u32, end: u32) -> Self {\n        Self { start, end }\n    }\n\n    pub fn contains(&self, byte_index: u32) -> bool {\n        byte_index >= self.start && byte_index <= self.end\n    }\n\n    pub fn contains_span(&self, span: SrcSpan) -> bool {\n        self.contains(span.start) && self.contains(span.end)\n    }\n\n    /// Merges two spans into a new one that starts at the start of the smaller\n    /// one and ends at the end of the bigger one. For example:\n    ///\n    /// ```txt\n    /// wibble    wobble\n    /// ─┬────    ─┬────\n    ///  │         ╰─ one span\n    ///  ╰─ the other span\n    /// ─┬──────────────\n    ///  ╰─ the span you get by merging the two\n    /// ```\n    pub fn merge(&self, with: &SrcSpan) -> SrcSpan {\n        Self {\n            start: self.start.min(with.start),\n            end: self.end.max(with.end),\n        }\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    pub fn len(&self) -> usize {\n        (self.end - self.start) as usize\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct DefinitionLocation {\n    pub module: Option<EcoString>,\n    pub span: SrcSpan,\n}\n\npub type UntypedPattern = Pattern<()>;\npub type TypedPattern = Pattern<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Pattern<Type> {\n    Int {\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    },\n\n    Float {\n        location: SrcSpan,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    },\n\n    String {\n        location: SrcSpan,\n        value: EcoString,\n    },\n\n    /// The creation of a variable.\n    /// e.g. `assert [this_is_a_var, .._] = x`\n    Variable {\n        location: SrcSpan,\n        name: EcoString,\n        type_: Type,\n        origin: VariableOrigin,\n    },\n\n    /// The specified size of a bit array. This can either be a literal integer,\n    /// a reference to a variable, or a maths expression.\n    /// e.g. `let assert <<y:size(somevar)>> = x`\n    BitArraySize(BitArraySize<Type>),\n\n    /// A name given to a sub-pattern using the `as` keyword.\n    /// e.g. `assert #(1, [_, _] as the_list) = x`\n    Assign {\n        name: EcoString,\n        location: SrcSpan,\n        pattern: Box<Self>,\n    },\n\n    /// A pattern that binds to any value but does not assign a variable.\n    /// Always starts with an underscore.\n    Discard {\n        name: EcoString,\n        location: SrcSpan,\n        type_: Type,\n    },\n\n    List {\n        location: SrcSpan,\n        elements: Vec<Self>,\n        tail: Option<Box<TailPattern<Type>>>,\n        /// The type of the list, so this is going to be `List(something)`.\n        ///\n        type_: Type,\n    },\n\n    /// The constructor for a custom type. Starts with an uppercase letter.\n    Constructor {\n        location: SrcSpan,\n        name_location: SrcSpan,\n        name: EcoString,\n        arguments: Vec<CallArg<Self>>,\n        module: Option<(EcoString, SrcSpan)>,\n        constructor: Inferred<PatternConstructor>,\n        spread: Option<SrcSpan>,\n        type_: Type,\n    },\n\n    Tuple {\n        location: SrcSpan,\n        elements: Vec<Self>,\n    },\n\n    BitArray {\n        location: SrcSpan,\n        segments: Vec<BitArraySegment<Self, Type>>,\n    },\n\n    // \"prefix\" <> variable\n    StringPrefix {\n        location: SrcSpan,\n        left_location: SrcSpan,\n        left_side_assignment: Option<(EcoString, SrcSpan)>,\n        right_location: SrcSpan,\n        left_side_string: EcoString,\n        /// The variable on the right hand side of the `<>`.\n        right_side_assignment: AssignName,\n    },\n\n    /// A placeholder pattern used to allow module analysis to continue\n    /// even when there are type errors. Should never end up in generated code.\n    Invalid {\n        location: SrcSpan,\n        type_: Type,\n    },\n}\n\npub type TypedBitArraySize = BitArraySize<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum BitArraySize<Type> {\n    Int {\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    },\n\n    Variable {\n        location: SrcSpan,\n        name: EcoString,\n        constructor: Option<Box<ValueConstructor>>,\n        type_: Type,\n    },\n\n    BinaryOperator {\n        location: SrcSpan,\n        operator: IntOperator,\n        left: Box<Self>,\n        right: Box<Self>,\n    },\n\n    Block {\n        location: SrcSpan,\n        inner: Box<Self>,\n    },\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]\npub enum IntOperator {\n    Add,\n    Subtract,\n    Multiply,\n    Divide,\n    Remainder,\n}\n\nimpl IntOperator {\n    pub fn precedence(&self) -> u8 {\n        match self {\n            Self::Add | Self::Subtract => 7,\n\n            Self::Multiply | Self::Divide | Self::Remainder => 8,\n        }\n    }\n\n    pub fn to_bin_op(&self) -> BinOp {\n        match self {\n            IntOperator::Add => BinOp::AddInt,\n            IntOperator::Subtract => BinOp::SubInt,\n            IntOperator::Multiply => BinOp::MultInt,\n            IntOperator::Divide => BinOp::DivInt,\n            IntOperator::Remainder => BinOp::RemainderInt,\n        }\n    }\n}\n\nimpl<T> BitArraySize<T> {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            BitArraySize::Int { location, .. }\n            | BitArraySize::Variable { location, .. }\n            | BitArraySize::BinaryOperator { location, .. }\n            | BitArraySize::Block { location, .. } => *location,\n        }\n    }\n\n    pub fn non_zero_compile_time_number(&self) -> bool {\n        match self {\n            BitArraySize::Int { int_value, .. } => !int_value.is_zero(),\n            BitArraySize::Block { inner, .. } => inner.non_zero_compile_time_number(),\n            BitArraySize::Variable { .. } | BitArraySize::BinaryOperator { .. } => false,\n        }\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (BitArraySize::Int { int_value: n, .. }, BitArraySize::Int { int_value: m, .. }) => {\n                n == m\n            }\n            (BitArraySize::Int { .. }, _) => false,\n\n            (\n                BitArraySize::Variable { name, .. },\n                BitArraySize::Variable {\n                    name: other_name, ..\n                },\n            ) => name == other_name,\n            (BitArraySize::Variable { .. }, _) => false,\n\n            (\n                BitArraySize::BinaryOperator {\n                    operator,\n                    left,\n                    right,\n                    ..\n                },\n                BitArraySize::BinaryOperator {\n                    operator: other_operator,\n                    left: other_left,\n                    right: other_right,\n                    ..\n                },\n            ) => {\n                operator == other_operator\n                    && left.syntactically_eq(other_left)\n                    && right.syntactically_eq(other_right)\n            }\n            (BitArraySize::BinaryOperator { .. }, _) => false,\n\n            (\n                BitArraySize::Block { inner, .. },\n                BitArraySize::Block {\n                    inner: other_inner, ..\n                },\n            ) => inner.syntactically_eq(other_inner),\n            (BitArraySize::Block { .. }, _) => false,\n        }\n    }\n}\n\npub type TypedTailPattern = TailPattern<Arc<Type>>;\n\npub type UntypedTailPattern = TailPattern<()>;\n\n/// The pattern one can use to match on the rest of a list:\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TailPattern<Type> {\n    /// The entire location of the pattern, covering the `..` as well.\n    ///\n    pub location: SrcSpan,\n\n    /// The name assigned to the rest of the list being matched:\n    ///\n    /// ```gleam\n    /// [wibble, ..]\n    /// //       ^^ no name\n    ///\n    /// [wibble, ..rest]\n    /// //       ^^^^^^ a variable name\n    ///\n    /// [wibble, .._rest]\n    /// //       ^^^^^^^ a discarded name\n    /// ```\n    ///\n    pub pattern: Pattern<Type>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum AssignName {\n    Variable(EcoString),\n    Discard(EcoString),\n}\n\nimpl AssignName {\n    pub fn name(&self) -> &EcoString {\n        match self {\n            AssignName::Variable(name) | AssignName::Discard(name) => name,\n        }\n    }\n\n    pub fn to_arg_names(self, location: SrcSpan) -> ArgNames {\n        match self {\n            AssignName::Variable(name) => ArgNames::Named { name, location },\n            AssignName::Discard(name) => ArgNames::Discard { name, location },\n        }\n    }\n\n    pub fn assigned_name(&self) -> Option<&str> {\n        match self {\n            AssignName::Variable(name) => Some(name),\n            AssignName::Discard(_) => None,\n        }\n    }\n}\n\nimpl<A> Pattern<A> {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Pattern::Assign {\n                pattern, location, ..\n            } => SrcSpan::new(pattern.location().start, location.end),\n            Pattern::Int { location, .. }\n            | Pattern::Variable { location, .. }\n            | Pattern::List { location, .. }\n            | Pattern::Float { location, .. }\n            | Pattern::Discard { location, .. }\n            | Pattern::String { location, .. }\n            | Pattern::Tuple { location, .. }\n            | Pattern::Constructor { location, .. }\n            | Pattern::StringPrefix { location, .. }\n            | Pattern::BitArray { location, .. }\n            | Pattern::Invalid { location, .. } => *location,\n            Pattern::BitArraySize(size) => size.location(),\n        }\n    }\n\n    /// Returns `true` if the pattern is [`Discard`].\n    ///\n    /// [`Discard`]: Pattern::Discard\n    #[must_use]\n    pub fn is_discard(&self) -> bool {\n        matches!(self, Self::Discard { .. })\n    }\n\n    #[must_use]\n    pub fn is_variable(&self) -> bool {\n        matches!(self, Pattern::Variable { .. })\n    }\n\n    #[must_use]\n    pub fn is_string(&self) -> bool {\n        matches!(self, Self::String { .. })\n    }\n}\n\nimpl TypedPattern {\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Pattern::Int { int_value: n, .. }, Pattern::Int { int_value: m, .. }) => n == m,\n            (Pattern::Int { .. }, _) => false,\n\n            (Pattern::Float { float_value: n, .. }, Pattern::Float { float_value: m, .. }) => {\n                n == m\n            }\n            (Pattern::Float { .. }, _) => false,\n\n            (\n                Pattern::String { value, .. },\n                Pattern::String {\n                    value: other_value, ..\n                },\n            ) => value == other_value,\n            (Pattern::String { .. }, _) => false,\n\n            (\n                Pattern::Variable { name, .. },\n                Pattern::Variable {\n                    name: other_name, ..\n                },\n            ) => name == other_name,\n            (Pattern::Variable { .. }, _) => false,\n\n            (Pattern::BitArraySize(one), Pattern::BitArraySize(other)) => {\n                one.syntactically_eq(other)\n            }\n            (Pattern::BitArraySize(..), _) => false,\n\n            (\n                Pattern::Assign { name, pattern, .. },\n                Pattern::Assign {\n                    name: other_name,\n                    pattern: other_pattern,\n                    ..\n                },\n            ) => name == other_name && pattern.syntactically_eq(other_pattern),\n            (Pattern::Assign { .. }, _) => false,\n\n            (\n                Pattern::Discard { name, .. },\n                Pattern::Discard {\n                    name: other_name, ..\n                },\n            ) => name == other_name,\n            (Pattern::Discard { .. }, _) => false,\n\n            (\n                Pattern::List { elements, tail, .. },\n                Pattern::List {\n                    elements: other_elements,\n                    tail: other_tail,\n                    ..\n                },\n            ) => {\n                let tails_are_equal = match (tail, other_tail) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some(one), Some(other)) => one.pattern.syntactically_eq(&other.pattern),\n                };\n                tails_are_equal\n                    && pairwise_all(elements, other_elements, |(one, other)| {\n                        one.syntactically_eq(other)\n                    })\n            }\n            (Pattern::List { .. }, _) => false,\n\n            (\n                Pattern::Constructor {\n                    name,\n                    arguments,\n                    module,\n                    ..\n                },\n                Pattern::Constructor {\n                    name: other_name,\n                    arguments: other_arguments,\n                    module: other_module,\n                    ..\n                },\n            ) => {\n                let modules_are_equal = match (module, other_module) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some((one, _)), Some((other, _))) => one == other,\n                };\n                modules_are_equal\n                    && name == other_name\n                    && pairwise_all(arguments, other_arguments, |(one, other)| {\n                        one.label == other.label && one.value.syntactically_eq(&other.value)\n                    })\n            }\n            (Pattern::Constructor { .. }, _) => false,\n\n            (\n                Pattern::Tuple { elements, .. },\n                Pattern::Tuple {\n                    elements: other_elements,\n                    ..\n                },\n            ) => pairwise_all(elements, other_elements, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (Pattern::Tuple { .. }, _) => false,\n\n            (\n                Pattern::BitArray { segments, .. },\n                Pattern::BitArray {\n                    segments: other_segments,\n                    ..\n                },\n            ) => pairwise_all(segments, other_segments, |(one, other)| {\n                one.syntactically_eq(other)\n            }),\n            (Pattern::BitArray { .. }, _) => false,\n\n            (\n                Pattern::StringPrefix {\n                    left_side_assignment,\n                    left_side_string,\n                    right_side_assignment,\n                    ..\n                },\n                Pattern::StringPrefix {\n                    left_side_assignment: other_left_side_assignment,\n                    left_side_string: other_left_side_string,\n                    right_side_assignment: other_right_side_assignment,\n                    ..\n                },\n            ) => {\n                let left_side_assignments_are_equal =\n                    match (left_side_assignment, other_left_side_assignment) {\n                        (None, None) => true,\n                        (None, Some(_)) | (Some(_), None) => false,\n                        (Some((one, _)), Some((other, _))) => one == other,\n                    };\n                let right_side_assignments_are_equal =\n                    match (right_side_assignment, other_right_side_assignment) {\n                        (AssignName::Variable(one), AssignName::Variable(other)) => one == other,\n                        (AssignName::Variable(_), AssignName::Discard(_)) => false,\n                        (AssignName::Discard(one), AssignName::Discard(other)) => one == other,\n                        (AssignName::Discard(_), AssignName::Variable(_)) => false,\n                    };\n                left_side_string == other_left_side_string\n                    && left_side_assignments_are_equal\n                    && right_side_assignments_are_equal\n            }\n            (Pattern::StringPrefix { .. }, _) => false,\n\n            (Pattern::Invalid { .. }, _) => false,\n        }\n    }\n}\n\n/// A variable bound inside a pattern.\n#[derive(Debug, Clone)]\npub struct BoundVariable {\n    pub name: BoundVariableName,\n    pub location: SrcSpan,\n    pub type_: Arc<Type>,\n}\n\n#[derive(Debug, Clone)]\npub enum BoundVariableName {\n    /// A record's labelled field introduced with the shorthand syntax.\n    ShorthandLabel { name: EcoString },\n    ListTail {\n        name: EcoString,\n        /// The location of the whole tail, from the `..` prefix until the end of the variable.\n        tail_location: SrcSpan,\n    },\n    /// Any other variable name.\n    Regular { name: EcoString },\n}\n\nimpl BoundVariable {\n    pub fn name(&self) -> EcoString {\n        match &self.name {\n            BoundVariableName::ShorthandLabel { name }\n            | BoundVariableName::ListTail { name, .. }\n            | BoundVariableName::Regular { name } => name.clone(),\n        }\n    }\n}\n\nimpl TypedPattern {\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        match self {\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Variable { .. }\n            | Pattern::BitArraySize { .. }\n            | Pattern::Assign { .. }\n            | Pattern::Discard { .. }\n            | Pattern::List { .. }\n            | Pattern::Tuple { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => None,\n\n            Pattern::Constructor { constructor, .. } => constructor.definition_location(),\n        }\n    }\n\n    pub fn get_documentation(&self) -> Option<&str> {\n        match self {\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Variable { .. }\n            | Pattern::BitArraySize { .. }\n            | Pattern::Assign { .. }\n            | Pattern::Discard { .. }\n            | Pattern::List { .. }\n            | Pattern::Tuple { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => None,\n\n            Pattern::Constructor { constructor, .. } => constructor.get_documentation(),\n        }\n    }\n\n    pub fn type_(&self) -> Arc<Type> {\n        match self {\n            Pattern::Int { .. } => type_::int(),\n            Pattern::Float { .. } => type_::float(),\n            Pattern::String { .. } => type_::string(),\n            Pattern::BitArray { .. } => type_::bit_array(),\n            Pattern::StringPrefix { .. } => type_::string(),\n\n            Pattern::Variable { type_, .. }\n            | Pattern::List { type_, .. }\n            | Pattern::Constructor { type_, .. }\n            | Pattern::Invalid { type_, .. } => type_.clone(),\n\n            Pattern::Assign { pattern, .. } => pattern.type_(),\n\n            // Bit array sizes should always be integers\n            Pattern::BitArraySize(_) => type_::int(),\n\n            Pattern::Discard { type_, .. } => type_.clone(),\n\n            Pattern::Tuple { elements, .. } => {\n                type_::tuple(elements.iter().map(|p| p.type_()).collect())\n            }\n        }\n    }\n\n    fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if !self.location().contains(byte_index) {\n            return None;\n        }\n\n        if let Pattern::Variable { name, .. } = self {\n            // For pipes the pattern can't be pointed to\n            if name.as_str().eq(PIPE_VARIABLE) {\n                return None;\n            }\n        }\n\n        match self {\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Variable { .. }\n            | Pattern::BitArraySize { .. }\n            | Pattern::Discard { .. }\n            | Pattern::Invalid { .. } => Some(Located::Pattern(self)),\n            Pattern::StringPrefix {\n                left_side_assignment,\n                right_side_assignment,\n                right_location,\n                ..\n            } => {\n                // Handle the prefix alias: \"prefix\" as name\n                if let Some((name, left_side_assignment_location)) = left_side_assignment\n                    && left_side_assignment_location.contains(byte_index)\n                {\n                    return Some(Located::StringPrefixPatternVariable {\n                        location: *left_side_assignment_location,\n                        name,\n                    });\n                }\n\n                // Handle the suffix: <> name\n                if let AssignName::Variable(name) = right_side_assignment\n                    && right_location.contains(byte_index)\n                {\n                    return Some(Located::StringPrefixPatternVariable {\n                        location: *right_location,\n                        name,\n                    });\n                }\n\n                Some(Located::Pattern(self))\n            }\n            Pattern::Assign { pattern, .. } => pattern\n                .find_node(byte_index)\n                .or_else(|| Some(Located::Pattern(self))),\n\n            Pattern::Constructor {\n                module,\n                spread,\n                arguments,\n                constructor,\n                ..\n            } => {\n                if let Some((module_alias, module_location)) = module\n                    && let Inferred::Known(constructor) = constructor\n                    && module_location.contains(byte_index)\n                {\n                    Some(Located::ModuleName {\n                        location: *module_location,\n                        module_name: constructor.module.clone(),\n                        module_alias: module_alias.clone(),\n                        layer: Layer::Value,\n                    })\n                } else if let Some(spread_location) = spread\n                    && spread_location.contains(byte_index)\n                {\n                    Some(Located::PatternSpread {\n                        spread_location: *spread_location,\n                        pattern: self,\n                    })\n                } else {\n                    arguments\n                        .iter()\n                        .find_map(|argument| argument.find_node(byte_index))\n                }\n            }\n\n            Pattern::List { elements, tail, .. } => elements\n                .iter()\n                .find_map(|element| element.find_node(byte_index))\n                .or_else(|| {\n                    tail.as_ref()\n                        .and_then(|tail| tail.pattern.find_node(byte_index))\n                }),\n\n            Pattern::Tuple { elements, .. } => elements\n                .iter()\n                .find_map(|element| element.find_node(byte_index)),\n\n            Pattern::BitArray { segments, .. } => segments\n                .iter()\n                .find_map(|segment| segment.find_node(byte_index))\n                .or(Some(Located::Pattern(self))),\n        }\n        .or(Some(Located::Pattern(self)))\n    }\n\n    /// If the pattern is a `Constructor` with a spread, it returns a tuple with\n    /// all the ignored fields. Split in unlabelled and labelled ones.\n    ///\n    pub fn unused_arguments(&self) -> Option<PatternUnusedArguments> {\n        let TypedPattern::Constructor {\n            arguments,\n            spread: Some(_),\n            ..\n        } = self\n        else {\n            return None;\n        };\n\n        let mut positional = vec![];\n        let mut labelled = vec![];\n        for argument in arguments {\n            // We only want to display the arguments that were ignored using `..`.\n            // Any argument ignored that way is marked as implicit, so if it is\n            // not implicit we just ignore it.\n            if !argument.is_implicit() {\n                continue;\n            }\n            let type_ = argument.value.type_();\n            match &argument.label {\n                Some(label) => labelled.push((label.clone(), type_)),\n                None => positional.push(type_),\n            }\n        }\n\n        Some(PatternUnusedArguments {\n            positional,\n            labelled,\n        })\n    }\n\n    /// Whether the pattern always matches. For example, a tuple or simple\n    /// variable assignment always match and can never fail.\n    #[must_use]\n    pub fn always_matches(&self) -> bool {\n        match self {\n            Pattern::Variable { .. } | Pattern::Discard { .. } => true,\n            Pattern::Assign { pattern, .. } => pattern.always_matches(),\n            Pattern::Tuple { elements, .. } => {\n                elements.iter().all(|element| element.always_matches())\n            }\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::BitArraySize { .. }\n            | Pattern::List { .. }\n            | Pattern::Constructor { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => false,\n        }\n    }\n\n    pub fn bound_variables(&self) -> Vec<BoundVariable> {\n        let mut variables = Vec::new();\n        self.collect_bound_variables(&mut variables);\n        variables\n    }\n\n    fn collect_bound_variables(&self, variables: &mut Vec<BoundVariable>) {\n        match self {\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Discard { .. }\n            | Pattern::Invalid { .. } => {}\n\n            Pattern::Variable {\n                name,\n                location,\n                type_,\n                ..\n            } => variables.push(BoundVariable {\n                name: BoundVariableName::Regular { name: name.clone() },\n                location: *location,\n                type_: type_.clone(),\n            }),\n            Pattern::BitArraySize { .. } => {}\n            Pattern::Assign {\n                name,\n                pattern,\n                location,\n            } => {\n                variables.push(BoundVariable {\n                    name: BoundVariableName::Regular { name: name.clone() },\n                    location: *location,\n                    type_: pattern.type_(),\n                });\n                pattern.collect_bound_variables(variables);\n            }\n            Pattern::List {\n                elements,\n                tail,\n                type_,\n                ..\n            } => {\n                for element in elements {\n                    element.collect_bound_variables(variables);\n                }\n                if let Some(tail) = tail\n                    && let Pattern::Variable { name, location, .. } = tail.pattern.to_owned()\n                {\n                    variables.push(BoundVariable {\n                        name: BoundVariableName::ListTail {\n                            name,\n                            tail_location: tail.location,\n                        },\n                        location,\n                        type_: type_.clone(),\n                    })\n                };\n            }\n            Pattern::Constructor { arguments, .. } => {\n                for argument in arguments {\n                    if let Some(name) = argument.label_shorthand_name() {\n                        variables.push(BoundVariable {\n                            name: BoundVariableName::ShorthandLabel { name: name.clone() },\n                            location: argument.location,\n                            type_: argument.value.type_(),\n                        })\n                    } else {\n                        argument.value.collect_bound_variables(variables);\n                    }\n                }\n            }\n            Pattern::Tuple { elements, .. } => {\n                for element in elements {\n                    element.collect_bound_variables(variables);\n                }\n            }\n            Pattern::BitArray { segments, .. } => {\n                for segment in segments {\n                    segment.value.collect_bound_variables(variables);\n                }\n            }\n            Pattern::StringPrefix {\n                left_side_assignment,\n                right_side_assignment,\n                right_location,\n                ..\n            } => {\n                if let Some((name, location)) = left_side_assignment {\n                    variables.push(BoundVariable {\n                        name: BoundVariableName::Regular { name: name.clone() },\n                        location: *location,\n                        type_: type_::string(),\n                    });\n                }\n                match right_side_assignment {\n                    AssignName::Variable(name) => variables.push(BoundVariable {\n                        name: BoundVariableName::Regular { name: name.clone() },\n                        location: *right_location,\n                        type_: type_::string(),\n                    }),\n                    AssignName::Discard(_) => {}\n                }\n            }\n        }\n    }\n}\n\n#[derive(Debug, Default)]\npub struct PatternUnusedArguments {\n    pub positional: Vec<Arc<Type>>,\n    pub labelled: Vec<(EcoString, Arc<Type>)>,\n}\n\nimpl<A> HasLocation for Pattern<A> {\n    fn location(&self) -> SrcSpan {\n        self.location()\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum AssignmentKind<Expression> {\n    /// let x = ...\n    Let,\n    /// This is a let assignment generated by the compiler for intermediate variables\n    /// needed by record updates and `use`.\n    /// Like a regular `Let` assignment this can never fail.\n    ///\n    Generated,\n    /// let assert x = ...\n    Assert {\n        /// The src byte span of the `let assert`\n        ///\n        /// ```gleam\n        /// let assert Wibble = todo\n        /// ^^^^^^^^^^\n        /// ```\n        location: SrcSpan,\n\n        /// The byte index of the start of `assert`\n        ///\n        /// ```gleam\n        /// let assert Wibble = todo\n        ///     ^\n        /// ```\n        assert_keyword_start: u32,\n\n        /// The message given to the assertion:\n        ///\n        /// ```gleam\n        /// let asset Ok(a) = something() as \"This will never fail\"\n        ///                                  ^^^^^^^^^^^^^^^^^^^^^^\n        /// ```\n        message: Option<Expression>,\n    },\n}\n\nimpl<Expression> AssignmentKind<Expression> {\n    /// Returns `true` if the assignment kind is [`Assert`].\n    ///\n    /// [`Assert`]: AssignmentKind::Assert\n    #[must_use]\n    pub fn is_assert(&self) -> bool {\n        match self {\n            Self::Assert { .. } => true,\n            Self::Let | Self::Generated => false,\n        }\n    }\n}\n\n// BitArrays\n\npub type UntypedExprBitArraySegment = BitArraySegment<UntypedExpr, ()>;\npub type TypedExprBitArraySegment = BitArraySegment<TypedExpr, Arc<Type>>;\n\npub type UntypedConstantBitArraySegment = BitArraySegment<UntypedConstant, ()>;\npub type TypedConstantBitArraySegment = BitArraySegment<TypedConstant, Arc<Type>>;\n\npub type UntypedPatternBitArraySegment = BitArraySegment<UntypedPattern, ()>;\npub type TypedPatternBitArraySegment = BitArraySegment<TypedPattern, Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct BitArraySegment<Value, Type> {\n    pub location: SrcSpan,\n    pub value: Box<Value>,\n    pub options: Vec<BitArrayOption<Value>>,\n    pub type_: Type,\n}\n\n#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, serde::Serialize, serde::Deserialize)]\npub enum Endianness {\n    Big,\n    Little,\n}\n\nimpl Endianness {\n    pub fn is_big(&self) -> bool {\n        *self == Endianness::Big\n    }\n}\n\nimpl<Value, Type> HasLocation for BitArraySegment<Value, Type> {\n    fn location(&self) -> SrcSpan {\n        self.location\n    }\n}\n\nimpl<Type> BitArraySegment<Pattern<Type>, Type> {\n    /// Returns the value of the pattern unwrapping any assign pattern.\n    ///\n    pub fn value_unwrapping_assign(&self) -> &Pattern<Type> {\n        match self.value.as_ref() {\n            Pattern::Assign { pattern, .. } => pattern,\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Variable { .. }\n            | Pattern::BitArraySize { .. }\n            | Pattern::Discard { .. }\n            | Pattern::List { .. }\n            | Pattern::Constructor { .. }\n            | Pattern::Tuple { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => self.value.as_ref(),\n        }\n    }\n}\n\nimpl<Value, Type> BitArraySegment<Value, Type> {\n    #[must_use]\n    pub fn has_native_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Native { .. }))\n    }\n\n    #[must_use]\n    pub fn has_utf16_codepoint_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Utf16Codepoint { .. }))\n    }\n\n    #[must_use]\n    pub fn has_utf32_codepoint_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Utf32Codepoint { .. }))\n    }\n\n    #[must_use]\n    pub fn has_utf16_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Utf16 { .. }))\n    }\n\n    #[must_use]\n    pub fn has_utf32_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Utf32 { .. }))\n    }\n\n    pub fn endianness(&self) -> Endianness {\n        if self\n            .options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Little { .. }))\n        {\n            Endianness::Little\n        } else {\n            Endianness::Big\n        }\n    }\n\n    pub(crate) fn signed(&self) -> bool {\n        self.options\n            .iter()\n            .any(|x| matches!(x, BitArrayOption::Signed { .. }))\n    }\n\n    pub fn size(&self) -> Option<&Value> {\n        self.options.iter().find_map(|x| match x {\n            BitArrayOption::Size { value, .. } => Some(value.as_ref()),\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n        })\n    }\n\n    pub fn unit(&self) -> u8 {\n        self.options\n            .iter()\n            .find_map(|option| match option {\n                BitArrayOption::Unit { value, .. } => Some(*value),\n                BitArrayOption::Bytes { .. } => Some(8),\n                BitArrayOption::Int { .. }\n                | BitArrayOption::Float { .. }\n                | BitArrayOption::Bits { .. }\n                | BitArrayOption::Utf8 { .. }\n                | BitArrayOption::Utf16 { .. }\n                | BitArrayOption::Utf32 { .. }\n                | BitArrayOption::Utf8Codepoint { .. }\n                | BitArrayOption::Utf16Codepoint { .. }\n                | BitArrayOption::Utf32Codepoint { .. }\n                | BitArrayOption::Signed { .. }\n                | BitArrayOption::Unsigned { .. }\n                | BitArrayOption::Big { .. }\n                | BitArrayOption::Little { .. }\n                | BitArrayOption::Native { .. }\n                | BitArrayOption::Size { .. } => None,\n            })\n            .unwrap_or(1)\n    }\n\n    pub(crate) fn has_bits_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|option| matches!(option, BitArrayOption::Bits { .. }))\n    }\n\n    pub(crate) fn has_bytes_option(&self) -> bool {\n        self.options\n            .iter()\n            .any(|option| matches!(option, BitArrayOption::Bytes { .. }))\n    }\n}\n\nimpl<Value, Type> BitArraySegment<Value, Type> {\n    #[must_use]\n    pub(crate) fn has_type_option(&self) -> bool {\n        self.options.iter().any(|option| option.is_type_option())\n    }\n}\n\nimpl TypedExprBitArraySegment {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        self.value.find_node(byte_index)\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        self.value.syntactically_eq(&other.value)\n            && pairwise_all(&self.options, &other.options, |(option, other_option)| {\n                option.syntactically_eq(other_option, |size, other_size| {\n                    size.syntactically_eq(other_size)\n                })\n            })\n    }\n}\n\nimpl<TypedValue> BitArraySegment<TypedValue, Arc<Type>>\nwhere\n    TypedValue: HasType + HasLocation + Clone + bit_array::GetLiteralValue,\n{\n    pub fn check_for_truncated_value(&self) -> Option<BitArraySegmentTruncation> {\n        // Both the size and the value must be two compile-time known constants.\n        let segment_bits = self.bits_size()?.to_i64()?;\n        let literal_value = self.value.as_int_literal()?;\n        if segment_bits <= 0 {\n            return None;\n        }\n\n        let safe_range = match literal_value.sign() {\n            Sign::NoSign => return None,\n            Sign::Minus => {\n                (-(BigInt::one() << (segment_bits - 1)))\n                    ..((BigInt::one() << (segment_bits - 1)) - 1)\n            }\n            Sign::Plus => BigInt::ZERO..(BigInt::one() << segment_bits),\n        };\n\n        if !safe_range.contains(&literal_value) {\n            Some(BitArraySegmentTruncation {\n                truncated_value: literal_value.clone(),\n                truncated_into: truncate(&literal_value, segment_bits),\n                value_location: self.value.location(),\n                segment_bits,\n            })\n        } else {\n            None\n        }\n    }\n\n    /// If the segment size is a compile-time known constant this returns the\n    /// segment size in bits, taking the segment's unit into consideration!\n    ///\n    fn bits_size(&self) -> Option<BigInt> {\n        let size = match self.size() {\n            None if self.type_.is_int() => 8.into(),\n            None => 64.into(),\n            Some(value) => value.as_int_literal()?,\n        };\n\n        let unit = self.unit();\n        Some(size * unit)\n    }\n}\n\n/// As Björn said, when a value is smaller than the segment's size it will be\n/// truncated, only taking the first `n` bits:\n///\n/// > It will be silently truncated. In general, when storing value an integer\n/// > `I` into a segment of size `N`, the actual value stored will be\n/// > `I band ((1 bsl N) - 1)`.\n///\n/// <https://erlangforums.com/t/what-happens-when-a-bit-array-segment-size-is-smaller-than-its-value/4650/2?u=giacomocavalieri>\n///\n/// Thank you Björn!\n///\nfn truncate(literal_value: &BigInt, segment_bits: i64) -> BigInt {\n    literal_value & ((BigInt::one() << segment_bits) - BigInt::one())\n}\n\n#[derive(serde::Deserialize, serde::Serialize, Eq, PartialEq, Clone, Debug)]\npub struct BitArraySegmentTruncation {\n    /// The value that would end up being truncated.\n    pub truncated_value: BigInt,\n    /// What the value would be truncated into.\n    pub truncated_into: BigInt,\n    /// The span of the segment's value being truncated.\n    pub value_location: SrcSpan,\n    /// The size of the segment.\n    pub segment_bits: i64,\n}\n\nimpl TypedPatternBitArraySegment {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        self.value.find_node(byte_index).or_else(|| {\n            self.options\n                .iter()\n                .find_map(|option| option.find_node(byte_index))\n        })\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        self.value.syntactically_eq(&other.value)\n            && pairwise_all(&self.options, &other.options, |(option, other_option)| {\n                option.syntactically_eq(other_option, |size, other_size| {\n                    size.syntactically_eq(other_size)\n                })\n            })\n    }\n}\n\nimpl TypedConstantBitArraySegment {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        self.value.find_node(byte_index).or_else(|| {\n            self.options\n                .iter()\n                .find_map(|option| option.find_node(byte_index))\n        })\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        self.value.syntactically_eq(&other.value)\n            && pairwise_all(&self.options, &other.options, |(option, other_option)| {\n                option.syntactically_eq(other_option, |size, other_size| {\n                    size.syntactically_eq(other_size)\n                })\n            })\n    }\n}\n\npub type TypedConstantBitArraySegmentOption = BitArrayOption<TypedConstant>;\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]\npub enum BitArrayOption<Value> {\n    Bytes {\n        location: SrcSpan,\n    },\n\n    Int {\n        location: SrcSpan,\n    },\n\n    Float {\n        location: SrcSpan,\n    },\n\n    Bits {\n        location: SrcSpan,\n    },\n\n    Utf8 {\n        location: SrcSpan,\n    },\n\n    Utf16 {\n        location: SrcSpan,\n    },\n\n    Utf32 {\n        location: SrcSpan,\n    },\n\n    Utf8Codepoint {\n        location: SrcSpan,\n    },\n\n    Utf16Codepoint {\n        location: SrcSpan,\n    },\n\n    Utf32Codepoint {\n        location: SrcSpan,\n    },\n\n    Signed {\n        location: SrcSpan,\n    },\n\n    Unsigned {\n        location: SrcSpan,\n    },\n\n    Big {\n        location: SrcSpan,\n    },\n\n    Little {\n        location: SrcSpan,\n    },\n\n    Native {\n        location: SrcSpan,\n    },\n\n    Size {\n        location: SrcSpan,\n        value: Box<Value>,\n        short_form: bool,\n    },\n\n    Unit {\n        location: SrcSpan,\n        value: u8,\n    },\n}\n\nimpl<A> BitArrayOption<A> {\n    pub fn value(&self) -> Option<&A> {\n        match self {\n            BitArrayOption::Size { value, .. } => Some(value),\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n        }\n    }\n\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            BitArrayOption::Bytes { location }\n            | BitArrayOption::Int { location }\n            | BitArrayOption::Float { location }\n            | BitArrayOption::Bits { location }\n            | BitArrayOption::Utf8 { location }\n            | BitArrayOption::Utf16 { location }\n            | BitArrayOption::Utf32 { location }\n            | BitArrayOption::Utf8Codepoint { location }\n            | BitArrayOption::Utf16Codepoint { location }\n            | BitArrayOption::Utf32Codepoint { location }\n            | BitArrayOption::Signed { location }\n            | BitArrayOption::Unsigned { location }\n            | BitArrayOption::Big { location }\n            | BitArrayOption::Little { location }\n            | BitArrayOption::Native { location }\n            | BitArrayOption::Size { location, .. }\n            | BitArrayOption::Unit { location, .. } => *location,\n        }\n    }\n\n    pub fn label(&self) -> EcoString {\n        match self {\n            BitArrayOption::Bytes { .. } => \"bytes\".into(),\n            BitArrayOption::Int { .. } => \"int\".into(),\n            BitArrayOption::Float { .. } => \"float\".into(),\n            BitArrayOption::Bits { .. } => \"bits\".into(),\n            BitArrayOption::Utf8 { .. } => \"utf8\".into(),\n            BitArrayOption::Utf16 { .. } => \"utf16\".into(),\n            BitArrayOption::Utf32 { .. } => \"utf32\".into(),\n            BitArrayOption::Utf8Codepoint { .. } => \"utf8_codepoint\".into(),\n            BitArrayOption::Utf16Codepoint { .. } => \"utf16_codepoint\".into(),\n            BitArrayOption::Utf32Codepoint { .. } => \"utf32_codepoint\".into(),\n            BitArrayOption::Signed { .. } => \"signed\".into(),\n            BitArrayOption::Unsigned { .. } => \"unsigned\".into(),\n            BitArrayOption::Big { .. } => \"big\".into(),\n            BitArrayOption::Little { .. } => \"little\".into(),\n            BitArrayOption::Native { .. } => \"native\".into(),\n            BitArrayOption::Size { .. } => \"size\".into(),\n            BitArrayOption::Unit { .. } => \"unit\".into(),\n        }\n    }\n\n    fn is_type_option(&self) -> bool {\n        match self {\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. } => true,\n\n            BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Size { .. }\n            | BitArrayOption::Unit { .. } => false,\n        }\n    }\n\n    fn syntactically_eq(&self, other: &Self, compare_sizes: impl Fn(&A, &A) -> bool) -> bool {\n        match (self, other) {\n            (BitArrayOption::Bytes { .. }, BitArrayOption::Bytes { .. }) => true,\n            (BitArrayOption::Bytes { .. }, _) => false,\n\n            (BitArrayOption::Int { .. }, BitArrayOption::Int { .. }) => true,\n            (BitArrayOption::Int { .. }, _) => false,\n\n            (BitArrayOption::Float { .. }, BitArrayOption::Float { .. }) => true,\n            (BitArrayOption::Float { .. }, _) => false,\n\n            (BitArrayOption::Bits { .. }, BitArrayOption::Bits { .. }) => true,\n            (BitArrayOption::Bits { .. }, _) => false,\n\n            (BitArrayOption::Utf8 { .. }, BitArrayOption::Utf8 { .. }) => true,\n            (BitArrayOption::Utf8 { .. }, _) => false,\n\n            (BitArrayOption::Utf16 { .. }, BitArrayOption::Utf16 { .. }) => true,\n            (BitArrayOption::Utf16 { .. }, _) => false,\n\n            (BitArrayOption::Utf32 { .. }, BitArrayOption::Utf32 { .. }) => true,\n            (BitArrayOption::Utf32 { .. }, _) => false,\n\n            (BitArrayOption::Utf8Codepoint { .. }, BitArrayOption::Utf8Codepoint { .. }) => true,\n            (BitArrayOption::Utf8Codepoint { .. }, _) => false,\n\n            (BitArrayOption::Utf16Codepoint { .. }, BitArrayOption::Utf16Codepoint { .. }) => true,\n            (BitArrayOption::Utf16Codepoint { .. }, _) => false,\n\n            (BitArrayOption::Utf32Codepoint { .. }, BitArrayOption::Utf32Codepoint { .. }) => true,\n            (BitArrayOption::Utf32Codepoint { .. }, _) => false,\n\n            (BitArrayOption::Signed { .. }, BitArrayOption::Signed { .. }) => true,\n            (BitArrayOption::Signed { .. }, _) => false,\n\n            (BitArrayOption::Unsigned { .. }, BitArrayOption::Unsigned { .. }) => true,\n            (BitArrayOption::Unsigned { .. }, _) => false,\n\n            (BitArrayOption::Big { .. }, BitArrayOption::Big { .. }) => true,\n            (BitArrayOption::Big { .. }, _) => false,\n\n            (BitArrayOption::Little { .. }, BitArrayOption::Little { .. }) => true,\n            (BitArrayOption::Little { .. }, _) => false,\n\n            (BitArrayOption::Native { .. }, BitArrayOption::Native { .. }) => true,\n            (BitArrayOption::Native { .. }, _) => false,\n\n            (\n                BitArrayOption::Unit { value, .. },\n                BitArrayOption::Unit {\n                    value: other_value, ..\n                },\n            ) => value == other_value,\n            (BitArrayOption::Unit { .. }, _) => false,\n\n            (\n                BitArrayOption::Size {\n                    value, short_form, ..\n                },\n                BitArrayOption::Size {\n                    value: other_value,\n                    short_form: other_short_form,\n                    ..\n                },\n            ) => short_form == other_short_form && compare_sizes(value, other_value),\n            (BitArrayOption::Size { .. }, _) => false,\n        }\n    }\n}\n\nimpl BitArrayOption<TypedConstant> {\n    fn referenced_variables(&self) -> im::HashSet<&EcoString> {\n        match self {\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Unit { .. }\n            | BitArrayOption::Native { .. } => im::hashset![],\n\n            BitArrayOption::Size { value, .. } => value.referenced_variables(),\n        }\n    }\n}\n\nimpl BitArrayOption<TypedPattern> {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        match self {\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n            BitArrayOption::Size { value, .. } => value.find_node(byte_index),\n        }\n    }\n}\n\nimpl BitArrayOption<TypedConstant> {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        match self {\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n            BitArrayOption::Size { value, .. } => value.find_node(byte_index),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum TodoKind {\n    Keyword,\n    EmptyFunction { function_location: SrcSpan },\n    IncompleteUse,\n    EmptyBlock,\n}\n\n#[derive(Debug, Default)]\npub struct GroupedDefinitions {\n    pub functions: Vec<UntypedFunction>,\n    pub constants: Vec<UntypedModuleConstant>,\n    pub custom_types: Vec<UntypedCustomType>,\n    pub imports: Vec<UntypedImport>,\n    pub type_aliases: Vec<UntypedTypeAlias>,\n}\n\nimpl GroupedDefinitions {\n    pub fn new(definitions: impl IntoIterator<Item = UntypedDefinition>) -> Self {\n        let mut this = Self::default();\n\n        for definition in definitions {\n            this.add(definition)\n        }\n\n        this\n    }\n\n    pub fn len(&self) -> usize {\n        let Self {\n            custom_types,\n            functions,\n            constants,\n            imports,\n            type_aliases,\n        } = self;\n        functions.len() + constants.len() + imports.len() + custom_types.len() + type_aliases.len()\n    }\n\n    fn add(&mut self, statement: UntypedDefinition) {\n        match statement {\n            Definition::Import(import) => self.imports.push(import),\n            Definition::Function(function) => self.functions.push(function),\n            Definition::TypeAlias(type_alias) => self.type_aliases.push(type_alias),\n            Definition::CustomType(custom_type) => self.custom_types.push(custom_type),\n            Definition::ModuleConstant(constant) => self.constants.push(constant),\n        }\n    }\n}\n\n/// A statement with in a function body.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Statement<TypeT, ExpressionT> {\n    /// A bare expression that is not assigned to any variable.\n    Expression(ExpressionT),\n    /// Assigning an expression to variables using a pattern.\n    Assignment(Box<Assignment<TypeT, ExpressionT>>),\n    /// A `use` expression.\n    Use(Use<TypeT, ExpressionT>),\n    /// A bool assertion.\n    Assert(Assert<ExpressionT>),\n}\n\npub type UntypedUse = Use<(), UntypedExpr>;\npub type TypedUse = Use<Arc<Type>, TypedExpr>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Use<TypeT, ExpressionT> {\n    /// In an untyped use this is the expression with the untyped code of the\n    /// callback function.\n    ///\n    /// In a typed use this is the typed function call the use expression\n    /// desugars to.\n    ///\n    pub call: Box<ExpressionT>,\n\n    /// This is the location of the whole use line, starting from the `use`\n    /// keyword and ending with the function call on the right hand side of\n    /// `<-`.\n    ///\n    /// ```gleam\n    /// use a <- result.try(result)\n    /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    /// ```\n    ///\n    pub location: SrcSpan,\n\n    /// This is the location of the expression on the right hand side of the use\n    /// arrow.\n    ///\n    /// ```gleam\n    /// use a <- result.try(result)\n    ///          ^^^^^^^^^^^^^^^^^^\n    /// ```\n    ///\n    pub right_hand_side_location: SrcSpan,\n\n    /// This is the SrcSpan of the patterns you find on the left hand side of\n    /// `<-` in a use expression.\n    ///\n    /// ```gleam\n    /// use pattern1, pattern2 <- todo\n    ///     ^^^^^^^^^^^^^^^^^^\n    /// ```\n    ///\n    /// In case there's no patterns it will be corresponding to the SrcSpan of\n    /// the `use` keyword itself.\n    ///\n    pub assignments_location: SrcSpan,\n\n    /// The patterns on the left hand side of `<-` in a use expression.\n    ///\n    pub assignments: Vec<UseAssignment<TypeT>>,\n}\n\npub type UntypedUseAssignment = UseAssignment<()>;\npub type TypedUseAssignment = UseAssignment<Arc<Type>>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct UseAssignment<TypeT> {\n    pub location: SrcSpan,\n    pub pattern: Pattern<TypeT>,\n    pub annotation: Option<TypeAst>,\n}\n\nimpl TypedUse {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        for assignment in self.assignments.iter() {\n            if let Some(found) = assignment.pattern.find_node(byte_index) {\n                return Some(found);\n            }\n            if let Some(found) = assignment\n                .annotation\n                .as_ref()\n                .and_then(|annotation| annotation.find_node(byte_index, assignment.pattern.type_()))\n            {\n                return Some(found);\n            }\n        }\n        self.call.find_node(byte_index)\n    }\n\n    pub fn callback_arguments(&self) -> Option<&Vec<TypedArg>> {\n        let TypedExpr::Call { arguments, .. } = self.call.as_ref() else {\n            return None;\n        };\n        let callback = arguments.iter().last()?;\n        let TypedExpr::Fn { arguments, .. } = &callback.value else {\n            // The expression might be invalid so we have to return a None here\n            return None;\n        };\n        Some(arguments)\n    }\n}\n\npub type TypedStatement = Statement<Arc<Type>, TypedExpr>;\npub type UntypedStatement = Statement<(), UntypedExpr>;\n\nimpl<T, E> Statement<T, E> {\n    /// Returns `true` if the statement is [`Expression`].\n    ///\n    /// [`Expression`]: Statement::Expression\n    #[must_use]\n    pub fn is_expression(&self) -> bool {\n        matches!(self, Self::Expression(..))\n    }\n\n    #[must_use]\n    pub fn is_use(&self) -> bool {\n        matches!(self, Self::Use(_))\n    }\n}\n\nimpl UntypedStatement {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Statement::Expression(expression) => expression.location(),\n            Statement::Assignment(assignment) => assignment.location,\n            Statement::Use(use_) => use_.location.merge(&use_.call.location()),\n            Statement::Assert(assert) => assert.location,\n        }\n    }\n\n    pub fn start_byte_index(&self) -> u32 {\n        match self {\n            Statement::Expression(expression) => expression.start_byte_index(),\n            Statement::Assignment(assignment) => assignment.location.start,\n            Statement::Use(use_) => use_.location.start,\n            Statement::Assert(assert) => assert.location.start,\n        }\n    }\n}\n\nimpl TypedStatement {\n    pub fn is_println(&self) -> bool {\n        match self {\n            Statement::Expression(e) => e.is_println(),\n            Statement::Assignment(_) => false,\n            Statement::Use(_) => false,\n            Statement::Assert(_) => false,\n        }\n    }\n\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Statement::Expression(expression) => expression.location(),\n            Statement::Assignment(assignment) => assignment.location,\n            // A use statement covers the entire block: `use_.location` covers\n            // just the use's first line and not what comes after it.\n            Statement::Use(use_) => use_.location.merge(&use_.call.location()),\n            Statement::Assert(assert) => assert.location,\n        }\n    }\n\n    /// Returns the location of the last element of a statement. This means that\n    /// if the statement is a use you'll get the location of the last item at\n    /// the end of its block.\n    pub fn last_location(&self) -> SrcSpan {\n        match self {\n            Statement::Expression(expression) => expression.last_location(),\n            Statement::Assignment(assignment) => assignment.value.last_location(),\n            Statement::Use(use_) => use_.call.last_location(),\n            Statement::Assert(assert) => assert.value.last_location(),\n        }\n    }\n\n    pub fn type_(&self) -> Arc<Type> {\n        match self {\n            Statement::Expression(expression) => expression.type_(),\n            Statement::Assignment(assignment) => assignment.type_(),\n            Statement::Use(use_) => use_.call.type_(),\n            Statement::Assert(_) => nil(),\n        }\n    }\n\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        match self {\n            Statement::Expression(expression) => expression.definition_location(),\n            Statement::Assignment(_) => None,\n            Statement::Use(use_) => use_.call.definition_location(),\n            Statement::Assert(_) => None,\n        }\n    }\n\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        match self {\n            Statement::Use(use_) => use_.find_node(byte_index),\n            Statement::Expression(expression) => expression.find_node(byte_index),\n            Statement::Assignment(assignment) => assignment.find_node(byte_index).or_else(|| {\n                if assignment.location.contains(byte_index) {\n                    Some(Located::Statement(self))\n                } else {\n                    None\n                }\n            }),\n            Statement::Assert(assert) => assert.find_node(byte_index).or_else(|| {\n                if assert.location.contains(byte_index) {\n                    Some(Located::Statement(self))\n                } else {\n                    None\n                }\n            }),\n        }\n    }\n\n    pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> {\n        match self {\n            Statement::Use(use_) => use_.call.find_statement(byte_index),\n            Statement::Expression(expression) => expression.find_statement(byte_index),\n            Statement::Assignment(assignment) => {\n                assignment.value.find_statement(byte_index).or_else(|| {\n                    if assignment.location.contains(byte_index) {\n                        Some(self)\n                    } else {\n                        None\n                    }\n                })\n            }\n            Statement::Assert(assert) => assert.value.find_statement(byte_index).or_else(|| {\n                if assert.location.contains(byte_index) {\n                    Some(self)\n                } else {\n                    None\n                }\n            }),\n        }\n    }\n\n    pub fn type_defining_location(&self) -> SrcSpan {\n        match self {\n            Statement::Expression(expression) => expression.type_defining_location(),\n            Statement::Assignment(assignment) => assignment.location,\n            Statement::Use(use_) => use_.location,\n            Statement::Assert(assert) => assert.location,\n        }\n    }\n\n    fn is_pure_value_constructor(&self) -> bool {\n        match self {\n            Statement::Expression(expression) => expression.is_pure_value_constructor(),\n            Statement::Assignment(assignment) => {\n                // A let assert is not considered a pure value constructor\n                // as it could crash the program!\n                !assignment.kind.is_assert() && assignment.value.is_pure_value_constructor()\n            }\n            Statement::Use(Use { call, .. }) => call.is_pure_value_constructor(),\n            // Assert statements by definition are not pure\n            Statement::Assert(_) => false,\n        }\n    }\n\n    fn syntactically_eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Statement::Expression(one), Statement::Expression(other)) => {\n                one.syntactically_eq(other)\n            }\n            (Statement::Expression(_), _) => false,\n\n            (Statement::Assignment(one), Statement::Assignment(other)) => {\n                one.pattern.syntactically_eq(&other.pattern)\n                    && one.value.syntactically_eq(&other.value)\n            }\n            (Statement::Assignment(_), _) => false,\n\n            (Statement::Use(one), Statement::Use(other)) => one.call.syntactically_eq(&other.call),\n            (Statement::Use(_), _) => false,\n\n            (Statement::Assert(one), Statement::Assert(other)) => {\n                let messages_are_equal = match (&one.message, &other.message) {\n                    (None, None) => true,\n                    (None, Some(_)) | (Some(_), None) => false,\n                    (Some(one), Some(other)) => one.syntactically_eq(other),\n                };\n                messages_are_equal && one.value.syntactically_eq(&other.value)\n            }\n            (Statement::Assert(_), _) => false,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Assignment<TypeT, ExpressionT> {\n    pub location: SrcSpan,\n    pub value: ExpressionT,\n    pub pattern: Pattern<TypeT>,\n    pub kind: AssignmentKind<ExpressionT>,\n    pub compiled_case: CompiledCase,\n    /// This will be true for assignments that are automatically generated by\n    /// the compiler.\n    pub annotation: Option<TypeAst>,\n}\n\npub type TypedAssignment = Assignment<Arc<Type>, TypedExpr>;\npub type UntypedAssignment = Assignment<(), UntypedExpr>;\n\nimpl TypedAssignment {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if let Some(annotation) = &self.annotation\n            && let Some(l) = annotation.find_node(byte_index, self.pattern.type_())\n        {\n            return Some(l);\n        }\n        self.pattern\n            .find_node(byte_index)\n            .or_else(|| self.value.find_node(byte_index))\n    }\n\n    pub fn type_(&self) -> Arc<Type> {\n        self.value.type_()\n    }\n}\n\npub type TypedAssert = Assert<TypedExpr>;\npub type UntypedAssert = Assert<UntypedExpr>;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Assert<Expression> {\n    pub location: SrcSpan,\n    pub value: Expression,\n    pub message: Option<Expression>,\n}\n\nimpl TypedAssert {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        if let Some(found) = self.value.find_node(byte_index) {\n            return Some(found);\n        }\n        if let Some(message) = &self.message\n            && let Some(found) = message.find_node(byte_index)\n        {\n            return Some(found);\n        }\n        None\n    }\n}\n\n/// A pipeline is desugared to a series of assignments:\n///\n/// ```gleam\n/// wibble |> wobble |> woo\n/// ```\n///\n/// Becomes:\n///\n/// ```erl\n/// Pipe1 = wibble\n/// Pipe2 = wobble(Pipe1)\n/// woo(Pipe2)\n/// ```\n///\n/// This represents one of such assignments once the pipeline has been desugared\n/// and each step has been typed.\n///\n/// > We're not using a more general `TypedAssignment` node since that has much\n/// > more informations to carry around. This one is limited since we know it\n/// > will always be in the form `VarName = <Expr>`, with no patterns on the\n/// > left hand side of the assignment.\n/// > Being more constrained simplifies code generation for pipelines!\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TypedPipelineAssignment {\n    pub location: SrcSpan,\n    pub name: EcoString,\n    pub value: Box<TypedExpr>,\n}\n\nimpl TypedPipelineAssignment {\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        self.value.find_node(byte_index)\n    }\n\n    pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> {\n        self.value.find_statement(byte_index)\n    }\n\n    pub fn type_(&self) -> Arc<Type> {\n        self.value.type_()\n    }\n}\n\n/// The kind of desugaring that might take place when rewriting a pipeline to\n/// regular assignments.\n///\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum PipelineAssignmentKind {\n    /// In case `a |> b(c)` is desugared to `b(a, c)`.\n    FirstArgument {\n        /// The location of the second argument of the call, in case there's any:\n        /// - `a |> b(c, d)`: here it's `Some` wrapping the location of `c`.\n        /// - `a |> b()`: here it's `None`.\n        second_argument: Option<SrcSpan>,\n    },\n\n    /// In case there's an explicit hole and `a |> b(_, c)` is desugared to\n    /// `b(a, c)`.\n    Hole { hole: SrcSpan },\n\n    /// In case `a |> b(c)` is desugared to `b(c)(a)`\n    FunctionCall,\n\n    /// In case there's an echo in the middle of a pipeline `a |> echo`\n    Echo,\n}\n"
  },
  {
    "path": "compiler-core/src/ast_folder.rs",
    "content": "use ecow::EcoString;\nuse itertools::Itertools;\nuse num_bigint::BigInt;\nuse vec1::Vec1;\n\nuse crate::{\n    analyse::Inferred,\n    ast::{\n        Assert, AssignName, Assignment, BinOp, BitArraySize, CallArg, Constant, Definition,\n        FunctionLiteralKind, InvalidExpression, Pattern, RecordBeingUpdated, RecordUpdateArg,\n        SrcSpan, Statement, TailPattern, TargetedDefinition, TodoKind, TypeAst, TypeAstConstructor,\n        TypeAstFn, TypeAstHole, TypeAstTuple, TypeAstVar, UntypedArg, UntypedAssert,\n        UntypedAssignment, UntypedClause, UntypedConstant, UntypedConstantBitArraySegment,\n        UntypedCustomType, UntypedDefinition, UntypedExpr, UntypedExprBitArraySegment,\n        UntypedFunction, UntypedImport, UntypedModule, UntypedModuleConstant, UntypedPattern,\n        UntypedPatternBitArraySegment, UntypedRecordUpdateArg, UntypedStatement,\n        UntypedTailPattern, UntypedTypeAlias, UntypedUse, UntypedUseAssignment, Use, UseAssignment,\n    },\n    build::Target,\n    parse::LiteralFloatValue,\n    type_::error::VariableOrigin,\n};\n\n#[allow(dead_code)]\npub trait UntypedModuleFolder: TypeAstFolder + UntypedExprFolder {\n    /// You probably don't want to override this method.\n    fn fold_module(&mut self, mut module: UntypedModule) -> UntypedModule {\n        module.definitions = module\n            .definitions\n            .into_iter()\n            .map(|definition| {\n                let TargetedDefinition { definition, target } = definition;\n                match definition {\n                    Definition::Function(function) => {\n                        let function = self.fold_function_definition(function, target);\n                        let definition = self.walk_function_definition(function);\n                        TargetedDefinition { definition, target }\n                    }\n\n                    Definition::TypeAlias(type_alias) => {\n                        let type_alias = self.fold_type_alias(type_alias, target);\n                        let definition = self.walk_type_alias(type_alias);\n                        TargetedDefinition { definition, target }\n                    }\n\n                    Definition::CustomType(custom_type) => {\n                        let custom_type = self.fold_custom_type(custom_type, target);\n                        let definition = self.walk_custom_type(custom_type);\n                        TargetedDefinition { definition, target }\n                    }\n\n                    Definition::Import(import) => {\n                        let import = self.fold_import(import, target);\n                        let definition = self.walk_import(import);\n                        TargetedDefinition { definition, target }\n                    }\n\n                    Definition::ModuleConstant(constant) => {\n                        let constant = self.fold_module_constant(constant, target);\n                        let definition = self.walk_module_constant(constant);\n                        TargetedDefinition { definition, target }\n                    }\n                }\n            })\n            .collect();\n        module\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_function_definition(&mut self, mut function: UntypedFunction) -> UntypedDefinition {\n        function.body = function\n            .body\n            .into_iter()\n            .map(|statement| self.fold_statement(statement))\n            .collect_vec();\n        function.return_annotation = function\n            .return_annotation\n            .map(|type_| self.fold_type(type_));\n        function.arguments = function\n            .arguments\n            .into_iter()\n            .map(|mut argument| {\n                argument.annotation = argument.annotation.map(|type_| self.fold_type(type_));\n                argument\n            })\n            .collect();\n        Definition::Function(function)\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_type_alias(&mut self, mut type_alias: UntypedTypeAlias) -> UntypedDefinition {\n        type_alias.type_ast = self.fold_type(type_alias.type_ast);\n        Definition::TypeAlias(type_alias)\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_custom_type(&mut self, mut custom_type: UntypedCustomType) -> UntypedDefinition {\n        custom_type.constructors = custom_type\n            .constructors\n            .into_iter()\n            .map(|mut constructor| {\n                constructor.arguments = constructor\n                    .arguments\n                    .into_iter()\n                    .map(|mut argument| {\n                        argument.ast = self.fold_type(argument.ast);\n                        argument\n                    })\n                    .collect();\n                constructor\n            })\n            .collect();\n\n        Definition::CustomType(custom_type)\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_import(&mut self, i: UntypedImport) -> UntypedDefinition {\n        Definition::Import(i)\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_module_constant(&mut self, mut constant: UntypedModuleConstant) -> UntypedDefinition {\n        constant.annotation = constant.annotation.map(|type_| self.fold_type(type_));\n        constant.value = Box::new(self.fold_constant(*constant.value));\n        Definition::ModuleConstant(constant)\n    }\n\n    fn fold_function_definition(\n        &mut self,\n        function: UntypedFunction,\n        _target: Option<Target>,\n    ) -> UntypedFunction {\n        function\n    }\n\n    fn fold_type_alias(\n        &mut self,\n        function: UntypedTypeAlias,\n        _target: Option<Target>,\n    ) -> UntypedTypeAlias {\n        function\n    }\n\n    fn fold_custom_type(\n        &mut self,\n        custom_type: UntypedCustomType,\n        _target: Option<Target>,\n    ) -> UntypedCustomType {\n        custom_type\n    }\n\n    fn fold_import(&mut self, import: UntypedImport, _target: Option<Target>) -> UntypedImport {\n        import\n    }\n\n    fn fold_module_constant(\n        &mut self,\n        constant: UntypedModuleConstant,\n        _target: Option<Target>,\n    ) -> UntypedModuleConstant {\n        constant\n    }\n}\n\n#[allow(dead_code)]\npub trait TypeAstFolder {\n    /// Visit a node and potentially replace it with another node using the\n    /// `fold_*` methods. Afterwards, the `walk` method is called on the new\n    /// node to continue traversing.\n    ///\n    /// You probably don't want to override this method.\n    fn fold_type(&mut self, type_: TypeAst) -> TypeAst {\n        let type_ = self.update_type(type_);\n        self.walk_type(type_)\n    }\n\n    /// You probably don't want to override this method.\n    fn update_type(&mut self, type_: TypeAst) -> TypeAst {\n        match type_ {\n            TypeAst::Constructor(constructor) => self.fold_type_constructor(constructor),\n            TypeAst::Fn(fn_) => self.fold_type_fn(fn_),\n            TypeAst::Var(var) => self.fold_type_var(var),\n            TypeAst::Tuple(tuple) => self.fold_type_tuple(tuple),\n            TypeAst::Hole(hole) => self.fold_type_hole(hole),\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_type(&mut self, type_: TypeAst) -> TypeAst {\n        match type_ {\n            TypeAst::Constructor(mut constructor) => {\n                constructor.arguments = self.fold_all_types(constructor.arguments);\n                TypeAst::Constructor(constructor)\n            }\n\n            TypeAst::Fn(mut fn_) => {\n                fn_.arguments = self.fold_all_types(fn_.arguments);\n                fn_.return_ = Box::new(self.fold_type(*fn_.return_));\n                TypeAst::Fn(fn_)\n            }\n\n            TypeAst::Tuple(mut tuple) => {\n                tuple.elements = self.fold_all_types(tuple.elements);\n                TypeAst::Tuple(tuple)\n            }\n\n            TypeAst::Var(_) | TypeAst::Hole(_) => type_,\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn fold_all_types(&mut self, types: Vec<TypeAst>) -> Vec<TypeAst> {\n        types\n            .into_iter()\n            .map(|type_| self.fold_type(type_))\n            .collect()\n    }\n\n    fn fold_type_constructor(&mut self, constructor: TypeAstConstructor) -> TypeAst {\n        TypeAst::Constructor(constructor)\n    }\n\n    fn fold_type_fn(&mut self, function: TypeAstFn) -> TypeAst {\n        TypeAst::Fn(function)\n    }\n\n    fn fold_type_tuple(&mut self, tuple: TypeAstTuple) -> TypeAst {\n        TypeAst::Tuple(tuple)\n    }\n\n    fn fold_type_var(&mut self, var: TypeAstVar) -> TypeAst {\n        TypeAst::Var(var)\n    }\n\n    fn fold_type_hole(&mut self, hole: TypeAstHole) -> TypeAst {\n        TypeAst::Hole(hole)\n    }\n}\n\n#[allow(dead_code)]\npub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFolder {\n    /// Visit a node and potentially replace it with another node using the\n    /// `fold_*` methods. Afterwards, the `walk` method is called on the new\n    /// node to continue traversing.\n    ///\n    /// You probably don't want to override this method.\n    fn fold_expr(&mut self, expression: UntypedExpr) -> UntypedExpr {\n        let expression = self.update_expr(expression);\n        self.walk_expr(expression)\n    }\n\n    /// You probably don't want to override this method.\n    fn update_expr(&mut self, expression: UntypedExpr) -> UntypedExpr {\n        match expression {\n            UntypedExpr::Var { location, name } => self.fold_var(location, name),\n            UntypedExpr::Int {\n                location,\n                value,\n                int_value,\n            } => self.fold_int(location, value, int_value),\n            UntypedExpr::Float {\n                location,\n                value,\n                float_value,\n            } => self.fold_float(location, value, float_value),\n            UntypedExpr::String { location, value } => self.fold_string(location, value),\n\n            UntypedExpr::Block {\n                location,\n                statements,\n            } => self.fold_block(location, statements),\n\n            UntypedExpr::Fn {\n                location,\n                end_of_head_byte_index,\n                kind,\n                arguments,\n                body,\n                return_annotation,\n            } => self.fold_fn(\n                location,\n                end_of_head_byte_index,\n                kind,\n                arguments,\n                body,\n                return_annotation,\n            ),\n\n            UntypedExpr::List {\n                location,\n                elements,\n                tail,\n            } => self.fold_list(location, elements, tail),\n\n            UntypedExpr::Call {\n                location,\n                fun,\n                arguments,\n            } => self.fold_call(location, fun, arguments),\n\n            UntypedExpr::BinOp {\n                location,\n                name,\n                name_location,\n                left,\n                right,\n            } => self.fold_bin_op(location, name, name_location, left, right),\n\n            UntypedExpr::PipeLine { expressions } => self.fold_pipe_line(expressions),\n\n            UntypedExpr::Case {\n                location,\n                subjects,\n                clauses,\n            } => self.fold_case(location, subjects, clauses),\n\n            UntypedExpr::FieldAccess {\n                location,\n                label_location,\n                label,\n                container,\n            } => self.fold_field_access(location, label_location, label, container),\n\n            UntypedExpr::Tuple { location, elements } => self.fold_tuple(location, elements),\n\n            UntypedExpr::TupleIndex {\n                location,\n                index,\n                tuple,\n            } => self.fold_tuple_index(location, index, tuple),\n\n            UntypedExpr::Todo {\n                kind,\n                location,\n                message,\n            } => self.fold_todo(kind, location, message),\n\n            UntypedExpr::Echo {\n                location,\n                keyword_end,\n                expression,\n                message,\n            } => self.fold_echo(location, keyword_end, expression, message),\n\n            UntypedExpr::Panic { location, message } => self.fold_panic(location, message),\n\n            UntypedExpr::BitArray { location, segments } => self.fold_bit_array(location, segments),\n\n            UntypedExpr::RecordUpdate {\n                location,\n                constructor,\n                record,\n                arguments,\n            } => self.fold_record_update(location, constructor, record, arguments),\n\n            UntypedExpr::NegateBool { location, value } => self.fold_negate_bool(location, value),\n\n            UntypedExpr::NegateInt { location, value } => self.fold_negate_int(location, value),\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_expr(&mut self, expression: UntypedExpr) -> UntypedExpr {\n        match expression {\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::NegateInt { .. }\n            | UntypedExpr::NegateBool { .. } => expression,\n\n            UntypedExpr::Todo {\n                kind,\n                location,\n                message,\n            } => UntypedExpr::Todo {\n                kind,\n                location,\n                message: message.map(|msg_expr| Box::new(self.fold_expr(*msg_expr))),\n            },\n\n            UntypedExpr::Panic { location, message } => UntypedExpr::Panic {\n                location,\n                message: message.map(|msg_expr| Box::new(self.fold_expr(*msg_expr))),\n            },\n\n            UntypedExpr::Echo {\n                location,\n                expression,\n                keyword_end,\n                message,\n            } => UntypedExpr::Echo {\n                location,\n                keyword_end,\n                expression: expression.map(|expression| Box::new(self.fold_expr(*expression))),\n                message: message.map(|message| Box::new(self.fold_expr(*message))),\n            },\n\n            UntypedExpr::Block {\n                location,\n                statements,\n            } => {\n                let statements = statements.mapped(|s| self.fold_statement(s));\n                UntypedExpr::Block {\n                    location,\n                    statements,\n                }\n            }\n\n            UntypedExpr::Fn {\n                location,\n                kind,\n                end_of_head_byte_index,\n                arguments,\n                body,\n                return_annotation,\n            } => {\n                let arguments = arguments.into_iter().map(|a| self.fold_arg(a)).collect();\n                let return_annotation = return_annotation.map(|type_| self.fold_type(type_));\n                let body = body.mapped(|s| self.fold_statement(s));\n                UntypedExpr::Fn {\n                    location,\n                    end_of_head_byte_index,\n                    kind,\n                    arguments,\n                    body,\n                    return_annotation,\n                }\n            }\n\n            UntypedExpr::List {\n                location,\n                elements,\n                tail,\n            } => {\n                let elements = elements\n                    .into_iter()\n                    .map(|element| self.fold_expr(element))\n                    .collect();\n                let tail = tail.map(|e| Box::new(self.fold_expr(*e)));\n                UntypedExpr::List {\n                    location,\n                    elements,\n                    tail,\n                }\n            }\n\n            UntypedExpr::Call {\n                location,\n                fun,\n                arguments,\n            } => {\n                let fun = Box::new(self.fold_expr(*fun));\n                let arguments = arguments\n                    .into_iter()\n                    .map(|mut a| {\n                        a.value = self.fold_expr(a.value);\n                        a\n                    })\n                    .collect();\n                UntypedExpr::Call {\n                    location,\n                    fun,\n                    arguments,\n                }\n            }\n\n            UntypedExpr::BinOp {\n                location,\n                name,\n                name_location,\n                left,\n                right,\n            } => {\n                let left = Box::new(self.fold_expr(*left));\n                let right = Box::new(self.fold_expr(*right));\n                UntypedExpr::BinOp {\n                    location,\n                    name,\n                    name_location,\n                    left,\n                    right,\n                }\n            }\n\n            UntypedExpr::PipeLine { expressions } => {\n                let expressions = expressions.mapped(|e| self.fold_expr(e));\n                UntypedExpr::PipeLine { expressions }\n            }\n\n            UntypedExpr::Case {\n                location,\n                subjects,\n                clauses,\n            } => {\n                let subjects = subjects.into_iter().map(|e| self.fold_expr(e)).collect();\n                let clauses = clauses.map(|clauses| {\n                    clauses\n                        .into_iter()\n                        .map(|mut c| {\n                            c.pattern = c\n                                .pattern\n                                .into_iter()\n                                .map(|p| self.fold_pattern(p))\n                                .collect();\n                            c.alternative_patterns = c\n                                .alternative_patterns\n                                .into_iter()\n                                .map(|p| p.into_iter().map(|p| self.fold_pattern(p)).collect())\n                                .collect();\n                            c.then = self.fold_expr(c.then);\n                            c\n                        })\n                        .collect()\n                });\n                UntypedExpr::Case {\n                    location,\n                    subjects,\n                    clauses,\n                }\n            }\n\n            UntypedExpr::FieldAccess {\n                location,\n                label_location,\n                label,\n                container,\n            } => {\n                let container = Box::new(self.fold_expr(*container));\n                UntypedExpr::FieldAccess {\n                    location,\n                    label_location,\n                    label,\n                    container,\n                }\n            }\n\n            UntypedExpr::Tuple { location, elements } => {\n                let elements = elements\n                    .into_iter()\n                    .map(|element| self.fold_expr(element))\n                    .collect();\n                UntypedExpr::Tuple { location, elements }\n            }\n\n            UntypedExpr::TupleIndex {\n                location,\n                index,\n                tuple,\n            } => {\n                let tuple = Box::new(self.fold_expr(*tuple));\n                UntypedExpr::TupleIndex {\n                    location,\n                    index,\n                    tuple,\n                }\n            }\n\n            UntypedExpr::BitArray { location, segments } => {\n                let segments = segments\n                    .into_iter()\n                    .map(|mut s| {\n                        s.value = Box::new(self.fold_expr(*s.value));\n                        s\n                    })\n                    .collect();\n                UntypedExpr::BitArray { location, segments }\n            }\n\n            UntypedExpr::RecordUpdate {\n                location,\n                constructor,\n                record,\n                arguments,\n            } => {\n                let constructor = Box::new(self.fold_expr(*constructor));\n                let arguments = arguments\n                    .into_iter()\n                    .map(|mut a| {\n                        a.value = self.fold_expr(a.value);\n                        a\n                    })\n                    .collect();\n                UntypedExpr::RecordUpdate {\n                    location,\n                    constructor,\n                    record,\n                    arguments,\n                }\n            }\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn fold_arg(&mut self, arg: UntypedArg) -> UntypedArg {\n        let UntypedArg {\n            location,\n            names,\n            annotation,\n            type_,\n        } = arg;\n        let annotation = annotation.map(|type_| self.fold_type(type_));\n        UntypedArg {\n            location,\n            names,\n            annotation,\n            type_,\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn fold_statement(&mut self, statement: UntypedStatement) -> UntypedStatement {\n        let statement = self.update_statement(statement);\n        self.walk_statement(statement)\n    }\n\n    /// You probably don't want to override this method.\n    fn update_statement(&mut self, statement: UntypedStatement) -> UntypedStatement {\n        match statement {\n            Statement::Expression(expression) => Statement::Expression(expression),\n            Statement::Assignment(assignment) => {\n                Statement::Assignment(Box::new(self.fold_assignment(*assignment)))\n            }\n            Statement::Use(use_) => Statement::Use(self.fold_use(use_)),\n            Statement::Assert(assert) => Statement::Assert(self.fold_assert(assert)),\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_statement(&mut self, statement: UntypedStatement) -> UntypedStatement {\n        match statement {\n            Statement::Expression(expression) => Statement::Expression(self.fold_expr(expression)),\n\n            Statement::Assignment(assignment) => {\n                let Assignment {\n                    location,\n                    value,\n                    pattern,\n                    kind,\n                    annotation,\n                    compiled_case,\n                } = *assignment;\n\n                let pattern = self.fold_pattern(pattern);\n                let annotation = annotation.map(|type_| self.fold_type(type_));\n                let value = self.fold_expr(value);\n                Statement::Assignment(Box::new(Assignment {\n                    location,\n                    value,\n                    pattern,\n                    kind,\n                    annotation,\n                    compiled_case,\n                }))\n            }\n\n            Statement::Use(Use {\n                location,\n                right_hand_side_location,\n                assignments_location,\n                call,\n                assignments,\n            }) => {\n                let assignments = assignments\n                    .into_iter()\n                    .map(|assignment| {\n                        let mut use_ = self.fold_use_assignment(assignment);\n                        use_.pattern = self.fold_pattern(use_.pattern);\n                        use_\n                    })\n                    .collect();\n                let call = Box::new(self.fold_expr(*call));\n                Statement::Use(Use {\n                    location,\n                    right_hand_side_location,\n                    assignments_location,\n                    call,\n                    assignments,\n                })\n            }\n\n            Statement::Assert(Assert {\n                location,\n                value,\n                message,\n            }) => {\n                let value = self.fold_expr(value);\n                let message = message.map(|message| self.fold_expr(message));\n                Statement::Assert(Assert {\n                    location,\n                    value,\n                    message,\n                })\n            }\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn fold_use_assignment(&mut self, use_: UntypedUseAssignment) -> UntypedUseAssignment {\n        let UseAssignment {\n            location,\n            pattern,\n            annotation,\n        } = use_;\n        let annotation = annotation.map(|type_| self.fold_type(type_));\n        UseAssignment {\n            location,\n            pattern,\n            annotation,\n        }\n    }\n\n    fn fold_int(&mut self, location: SrcSpan, value: EcoString, int_value: BigInt) -> UntypedExpr {\n        UntypedExpr::Int {\n            location,\n            value,\n            int_value,\n        }\n    }\n\n    fn fold_float(\n        &mut self,\n        location: SrcSpan,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    ) -> UntypedExpr {\n        UntypedExpr::Float {\n            location,\n            value,\n            float_value,\n        }\n    }\n\n    fn fold_string(&mut self, location: SrcSpan, value: EcoString) -> UntypedExpr {\n        UntypedExpr::String { location, value }\n    }\n\n    fn fold_block(&mut self, location: SrcSpan, statements: Vec1<UntypedStatement>) -> UntypedExpr {\n        UntypedExpr::Block {\n            location,\n            statements,\n        }\n    }\n\n    fn fold_var(&mut self, location: SrcSpan, name: EcoString) -> UntypedExpr {\n        UntypedExpr::Var { location, name }\n    }\n\n    fn fold_fn(\n        &mut self,\n        location: SrcSpan,\n        end_of_head_byte_index: u32,\n        kind: FunctionLiteralKind,\n        arguments: Vec<UntypedArg>,\n        body: Vec1<UntypedStatement>,\n        return_annotation: Option<TypeAst>,\n    ) -> UntypedExpr {\n        UntypedExpr::Fn {\n            location,\n            end_of_head_byte_index,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n        }\n    }\n\n    fn fold_list(\n        &mut self,\n        location: SrcSpan,\n        elements: Vec<UntypedExpr>,\n        tail: Option<Box<UntypedExpr>>,\n    ) -> UntypedExpr {\n        UntypedExpr::List {\n            location,\n            elements,\n            tail,\n        }\n    }\n\n    fn fold_call(\n        &mut self,\n        location: SrcSpan,\n        fun: Box<UntypedExpr>,\n        arguments: Vec<CallArg<UntypedExpr>>,\n    ) -> UntypedExpr {\n        UntypedExpr::Call {\n            location,\n            fun,\n            arguments,\n        }\n    }\n\n    fn fold_bin_op(\n        &mut self,\n        location: SrcSpan,\n        name: BinOp,\n        name_location: SrcSpan,\n        left: Box<UntypedExpr>,\n        right: Box<UntypedExpr>,\n    ) -> UntypedExpr {\n        UntypedExpr::BinOp {\n            location,\n            name,\n            name_location,\n            left,\n            right,\n        }\n    }\n\n    fn fold_pipe_line(&mut self, expressions: Vec1<UntypedExpr>) -> UntypedExpr {\n        UntypedExpr::PipeLine { expressions }\n    }\n\n    fn fold_case(\n        &mut self,\n        location: SrcSpan,\n        subjects: Vec<UntypedExpr>,\n        clauses: Option<Vec<UntypedClause>>,\n    ) -> UntypedExpr {\n        UntypedExpr::Case {\n            location,\n            subjects,\n            clauses,\n        }\n    }\n\n    fn fold_field_access(\n        &mut self,\n        location: SrcSpan,\n        label_location: SrcSpan,\n        label: EcoString,\n        container: Box<UntypedExpr>,\n    ) -> UntypedExpr {\n        UntypedExpr::FieldAccess {\n            location,\n            label_location,\n            label,\n            container,\n        }\n    }\n\n    fn fold_tuple(&mut self, location: SrcSpan, elements: Vec<UntypedExpr>) -> UntypedExpr {\n        UntypedExpr::Tuple { location, elements }\n    }\n\n    fn fold_tuple_index(\n        &mut self,\n        location: SrcSpan,\n        index: u64,\n        tuple: Box<UntypedExpr>,\n    ) -> UntypedExpr {\n        UntypedExpr::TupleIndex {\n            location,\n            index,\n            tuple,\n        }\n    }\n\n    fn fold_todo(\n        &mut self,\n        kind: TodoKind,\n        location: SrcSpan,\n        message: Option<Box<UntypedExpr>>,\n    ) -> UntypedExpr {\n        UntypedExpr::Todo {\n            kind,\n            location,\n            message,\n        }\n    }\n\n    fn fold_echo(\n        &mut self,\n        location: SrcSpan,\n        keyword_end: u32,\n        expression: Option<Box<UntypedExpr>>,\n        message: Option<Box<UntypedExpr>>,\n    ) -> UntypedExpr {\n        UntypedExpr::Echo {\n            location,\n            keyword_end,\n            expression,\n            message,\n        }\n    }\n\n    fn fold_panic(&mut self, location: SrcSpan, message: Option<Box<UntypedExpr>>) -> UntypedExpr {\n        UntypedExpr::Panic { location, message }\n    }\n\n    fn fold_bit_array(\n        &mut self,\n        location: SrcSpan,\n        segments: Vec<UntypedExprBitArraySegment>,\n    ) -> UntypedExpr {\n        UntypedExpr::BitArray { location, segments }\n    }\n\n    fn fold_record_update(\n        &mut self,\n        location: SrcSpan,\n        constructor: Box<UntypedExpr>,\n        record: RecordBeingUpdated<UntypedExpr>,\n        arguments: Vec<UntypedRecordUpdateArg>,\n    ) -> UntypedExpr {\n        UntypedExpr::RecordUpdate {\n            location,\n            constructor,\n            record,\n            arguments,\n        }\n    }\n\n    fn fold_negate_bool(&mut self, location: SrcSpan, value: Box<UntypedExpr>) -> UntypedExpr {\n        UntypedExpr::NegateBool { location, value }\n    }\n\n    fn fold_negate_int(&mut self, location: SrcSpan, value: Box<UntypedExpr>) -> UntypedExpr {\n        UntypedExpr::NegateInt { location, value }\n    }\n\n    fn fold_assignment(&mut self, assignment: UntypedAssignment) -> UntypedAssignment {\n        assignment\n    }\n\n    fn fold_use(&mut self, use_: UntypedUse) -> UntypedUse {\n        use_\n    }\n\n    fn fold_assert(&mut self, assert: UntypedAssert) -> UntypedAssert {\n        assert\n    }\n}\n\n#[allow(dead_code)]\npub trait UntypedConstantFolder {\n    /// You probably don't want to override this method.\n    fn fold_constant(&mut self, constant: UntypedConstant) -> UntypedConstant {\n        let constant = self.update_constant(constant);\n        self.walk_constant(constant)\n    }\n\n    /// You probably don't want to override this method.\n    fn update_constant(&mut self, constant: UntypedConstant) -> UntypedConstant {\n        match constant {\n            Constant::Int {\n                location,\n                value,\n                int_value,\n            } => self.fold_constant_int(location, value, int_value),\n\n            Constant::Float {\n                location,\n                value,\n                float_value,\n            } => self.fold_constant_float(location, value, float_value),\n\n            Constant::String { location, value } => self.fold_constant_string(location, value),\n\n            Constant::Tuple {\n                location,\n                elements,\n                type_: (),\n            } => self.fold_constant_tuple(location, elements),\n\n            Constant::List {\n                location,\n                elements,\n                type_: (),\n                tail,\n            } => self.fold_constant_list(location, elements, tail),\n\n            Constant::Record {\n                location,\n                module,\n                name,\n                arguments,\n                tag: (),\n                type_: (),\n                field_map: _,\n                record_constructor: _,\n            } => self.fold_constant_record(location, module, name, arguments),\n\n            Constant::RecordUpdate {\n                location,\n                constructor_location,\n                module,\n                name,\n                record,\n                arguments,\n                tag: (),\n                type_: (),\n                field_map: _,\n            } => self.fold_constant_record_update(\n                location,\n                constructor_location,\n                module,\n                name,\n                record,\n                arguments,\n            ),\n\n            Constant::BitArray { location, segments } => {\n                self.fold_constant_bit_array(location, segments)\n            }\n\n            Constant::Var {\n                location,\n                module,\n                name,\n                constructor: _,\n                type_: (),\n            } => self.fold_constant_var(location, module, name),\n\n            Constant::StringConcatenation {\n                location,\n                left,\n                right,\n            } => self.fold_constant_string_concatenation(location, left, right),\n\n            Constant::Invalid {\n                location,\n                type_: (),\n                extra_information,\n            } => self.fold_constant_invalid(location, extra_information),\n        }\n    }\n\n    fn fold_constant_int(\n        &mut self,\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    ) -> UntypedConstant {\n        Constant::Int {\n            location,\n            value,\n            int_value,\n        }\n    }\n\n    fn fold_constant_float(\n        &mut self,\n        location: SrcSpan,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    ) -> UntypedConstant {\n        Constant::Float {\n            location,\n            value,\n            float_value,\n        }\n    }\n\n    fn fold_constant_string(&mut self, location: SrcSpan, value: EcoString) -> UntypedConstant {\n        Constant::String { location, value }\n    }\n\n    fn fold_constant_tuple(\n        &mut self,\n        location: SrcSpan,\n        elements: Vec<UntypedConstant>,\n    ) -> UntypedConstant {\n        Constant::Tuple {\n            location,\n            elements,\n            type_: (),\n        }\n    }\n\n    fn fold_constant_list(\n        &mut self,\n        location: SrcSpan,\n        elements: Vec<UntypedConstant>,\n        tail: Option<Box<UntypedConstant>>,\n    ) -> UntypedConstant {\n        Constant::List {\n            location,\n            elements,\n            type_: (),\n            tail,\n        }\n    }\n\n    fn fold_constant_record(\n        &mut self,\n        location: SrcSpan,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        arguments: Vec<CallArg<UntypedConstant>>,\n    ) -> UntypedConstant {\n        Constant::Record {\n            location,\n            module,\n            name,\n            arguments,\n            tag: (),\n            type_: (),\n            field_map: Inferred::Unknown,\n            record_constructor: None,\n        }\n    }\n\n    fn fold_constant_record_update(\n        &mut self,\n        location: SrcSpan,\n        constructor_location: SrcSpan,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        record: RecordBeingUpdated<UntypedConstant>,\n        arguments: Vec<RecordUpdateArg<UntypedConstant>>,\n    ) -> UntypedConstant {\n        Constant::RecordUpdate {\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag: (),\n            type_: (),\n            field_map: Inferred::Unknown,\n        }\n    }\n\n    fn fold_constant_bit_array(\n        &mut self,\n        location: SrcSpan,\n        segments: Vec<UntypedConstantBitArraySegment>,\n    ) -> UntypedConstant {\n        Constant::BitArray { location, segments }\n    }\n\n    fn fold_constant_var(\n        &mut self,\n        location: SrcSpan,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n    ) -> UntypedConstant {\n        Constant::Var {\n            location,\n            module,\n            name,\n            constructor: None,\n            type_: (),\n        }\n    }\n\n    fn fold_constant_string_concatenation(\n        &mut self,\n        location: SrcSpan,\n        left: Box<UntypedConstant>,\n        right: Box<UntypedConstant>,\n    ) -> UntypedConstant {\n        Constant::StringConcatenation {\n            location,\n            left,\n            right,\n        }\n    }\n\n    fn fold_constant_invalid(\n        &mut self,\n        location: SrcSpan,\n        extra_information: Option<InvalidExpression>,\n    ) -> UntypedConstant {\n        Constant::Invalid {\n            location,\n            type_: (),\n            extra_information,\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_constant(&mut self, constant: UntypedConstant) -> UntypedConstant {\n        match constant {\n            Constant::Var { .. }\n            | Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Tuple { .. }\n            | Constant::Invalid { .. } => constant,\n\n            Constant::List {\n                location,\n                elements,\n                type_,\n                tail,\n            } => {\n                let elements = elements\n                    .into_iter()\n                    .map(|element| self.fold_constant(element))\n                    .collect();\n                let tail = tail.map(|tail| Box::new(self.fold_constant(*tail)));\n                Constant::List {\n                    location,\n                    elements,\n                    type_,\n                    tail,\n                }\n            }\n\n            Constant::Record {\n                location,\n                module,\n                name,\n                arguments,\n                tag,\n                type_,\n                field_map,\n                record_constructor,\n            } => {\n                let arguments = arguments\n                    .into_iter()\n                    .map(|mut argument| {\n                        argument.value = self.fold_constant(argument.value);\n                        argument\n                    })\n                    .collect();\n                Constant::Record {\n                    location,\n                    module,\n                    name,\n                    arguments,\n                    tag,\n                    type_,\n                    field_map,\n                    record_constructor,\n                }\n            }\n\n            Constant::RecordUpdate {\n                location,\n                constructor_location,\n                module,\n                name,\n                record,\n                arguments,\n                tag,\n                type_,\n                field_map,\n            } => {\n                let record = RecordBeingUpdated {\n                    base: Box::new(self.fold_constant(*record.base)),\n                    location: record.location,\n                };\n                let arguments = arguments\n                    .into_iter()\n                    .map(|argument| RecordUpdateArg {\n                        label: argument.label,\n                        location: argument.location,\n                        value: self.fold_constant(argument.value),\n                    })\n                    .collect();\n                Constant::RecordUpdate {\n                    location,\n                    constructor_location,\n                    module,\n                    name,\n                    record,\n                    arguments,\n                    tag,\n                    type_,\n                    field_map,\n                }\n            }\n\n            Constant::BitArray { location, segments } => {\n                let segments = segments\n                    .into_iter()\n                    .map(|mut segment| {\n                        segment.value = Box::new(self.fold_constant(*segment.value));\n                        segment\n                    })\n                    .collect();\n                Constant::BitArray { location, segments }\n            }\n\n            Constant::StringConcatenation {\n                location,\n                left,\n                right,\n            } => {\n                let left = Box::new(self.fold_constant(*left));\n                let right = Box::new(self.fold_constant(*right));\n                Constant::StringConcatenation {\n                    location,\n                    left,\n                    right,\n                }\n            }\n        }\n    }\n}\n\n#[allow(dead_code)]\npub trait PatternFolder {\n    /// You probably don't want to override this method.\n    fn fold_pattern(&mut self, pattern: UntypedPattern) -> UntypedPattern {\n        let pattern = self.update_pattern(pattern);\n        self.walk_pattern(pattern)\n    }\n\n    /// You probably don't want to override this method.\n    fn update_pattern(&mut self, pattern: UntypedPattern) -> UntypedPattern {\n        match pattern {\n            Pattern::Int {\n                location,\n                value,\n                int_value,\n            } => self.fold_pattern_int(location, value, int_value),\n\n            Pattern::Float {\n                location,\n                value,\n                float_value,\n            } => self.fold_pattern_float(location, value, float_value),\n\n            Pattern::String { location, value } => self.fold_pattern_string(location, value),\n\n            Pattern::Variable {\n                location,\n                name,\n                type_: (),\n                origin,\n            } => self.fold_pattern_var(location, name, origin),\n\n            Pattern::BitArraySize(size) => self.fold_pattern_bit_array_size(size),\n\n            Pattern::Assign {\n                name,\n                location,\n                pattern,\n            } => self.fold_pattern_assign(name, location, pattern),\n\n            Pattern::Discard {\n                name,\n                location,\n                type_: (),\n            } => self.fold_pattern_discard(name, location),\n\n            Pattern::List {\n                location,\n                elements,\n                tail,\n                type_: (),\n            } => self.fold_pattern_list(location, elements, tail),\n\n            Pattern::Constructor {\n                location,\n                name_location,\n                name,\n                arguments,\n                module,\n                spread,\n                constructor: _,\n                type_: (),\n            } => self.fold_pattern_constructor(\n                location,\n                name_location,\n                name,\n                arguments,\n                module,\n                spread,\n            ),\n\n            Pattern::Tuple { location, elements } => self.fold_pattern_tuple(location, elements),\n\n            Pattern::BitArray { location, segments } => {\n                self.fold_pattern_bit_array(location, segments)\n            }\n\n            Pattern::StringPrefix {\n                location,\n                left_location,\n                left_side_assignment,\n                right_location,\n                left_side_string,\n                right_side_assignment,\n            } => self.fold_pattern_string_prefix(\n                location,\n                left_location,\n                left_side_assignment,\n                right_location,\n                left_side_string,\n                right_side_assignment,\n            ),\n\n            Pattern::Invalid { location, .. } => self.fold_pattern_invalid(location),\n        }\n    }\n\n    fn fold_pattern_int(\n        &mut self,\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    ) -> UntypedPattern {\n        Pattern::Int {\n            location,\n            value,\n            int_value,\n        }\n    }\n\n    fn fold_pattern_float(\n        &mut self,\n        location: SrcSpan,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    ) -> UntypedPattern {\n        Pattern::Float {\n            location,\n            value,\n            float_value,\n        }\n    }\n\n    fn fold_pattern_string(&mut self, location: SrcSpan, value: EcoString) -> UntypedPattern {\n        Pattern::String { location, value }\n    }\n\n    fn fold_pattern_var(\n        &mut self,\n        location: SrcSpan,\n        name: EcoString,\n        origin: VariableOrigin,\n    ) -> UntypedPattern {\n        Pattern::Variable {\n            location,\n            name,\n            type_: (),\n            origin,\n        }\n    }\n\n    fn fold_pattern_bit_array_size(&mut self, size: BitArraySize<()>) -> UntypedPattern {\n        Pattern::BitArraySize(self.fold_bit_array_size(size))\n    }\n\n    fn fold_bit_array_size(&mut self, size: BitArraySize<()>) -> BitArraySize<()> {\n        match size {\n            BitArraySize::Int {\n                location,\n                value,\n                int_value,\n            } => self.fold_bit_array_size_int(location, value, int_value),\n            BitArraySize::Variable { location, name, .. } => {\n                self.fold_bit_array_size_variable(location, name)\n            }\n            BitArraySize::BinaryOperator {\n                location,\n                operator,\n                left,\n                right,\n            } => BitArraySize::BinaryOperator {\n                location,\n                operator,\n                left: Box::new(self.fold_bit_array_size(*left)),\n                right: Box::new(self.fold_bit_array_size(*right)),\n            },\n            BitArraySize::Block { location, inner } => BitArraySize::Block {\n                location,\n                inner: Box::new(self.fold_bit_array_size(*inner)),\n            },\n        }\n    }\n\n    fn fold_bit_array_size_int(\n        &mut self,\n        location: SrcSpan,\n        value: EcoString,\n        int_value: BigInt,\n    ) -> BitArraySize<()> {\n        BitArraySize::Int {\n            location,\n            value,\n            int_value,\n        }\n    }\n\n    fn fold_bit_array_size_variable(\n        &mut self,\n        location: SrcSpan,\n        name: EcoString,\n    ) -> BitArraySize<()> {\n        BitArraySize::Variable {\n            location,\n            name,\n            constructor: None,\n            type_: (),\n        }\n    }\n\n    fn fold_pattern_assign(\n        &mut self,\n        name: EcoString,\n        location: SrcSpan,\n        pattern: Box<UntypedPattern>,\n    ) -> UntypedPattern {\n        Pattern::Assign {\n            name,\n            location,\n            pattern,\n        }\n    }\n\n    fn fold_pattern_discard(&mut self, name: EcoString, location: SrcSpan) -> UntypedPattern {\n        Pattern::Discard {\n            name,\n            location,\n            type_: (),\n        }\n    }\n\n    fn fold_pattern_list(\n        &mut self,\n        location: SrcSpan,\n        elements: Vec<UntypedPattern>,\n        tail: Option<Box<UntypedTailPattern>>,\n    ) -> UntypedPattern {\n        Pattern::List {\n            location,\n            elements,\n            tail,\n            type_: (),\n        }\n    }\n\n    fn fold_pattern_constructor(\n        &mut self,\n        location: SrcSpan,\n        name_location: SrcSpan,\n        name: EcoString,\n        arguments: Vec<CallArg<UntypedPattern>>,\n        module: Option<(EcoString, SrcSpan)>,\n        spread: Option<SrcSpan>,\n    ) -> UntypedPattern {\n        Pattern::Constructor {\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor: Inferred::Unknown,\n            spread,\n            type_: (),\n        }\n    }\n\n    fn fold_pattern_tuple(\n        &mut self,\n        location: SrcSpan,\n        elements: Vec<UntypedPattern>,\n    ) -> UntypedPattern {\n        Pattern::Tuple { location, elements }\n    }\n\n    fn fold_pattern_bit_array(\n        &mut self,\n        location: SrcSpan,\n        segments: Vec<UntypedPatternBitArraySegment>,\n    ) -> UntypedPattern {\n        Pattern::BitArray { location, segments }\n    }\n\n    fn fold_pattern_string_prefix(\n        &mut self,\n        location: SrcSpan,\n        left_location: SrcSpan,\n        left_side_assignment: Option<(EcoString, SrcSpan)>,\n        right_location: SrcSpan,\n        left_side_string: EcoString,\n        right_side_assignment: AssignName,\n    ) -> UntypedPattern {\n        Pattern::StringPrefix {\n            location,\n            left_location,\n            left_side_assignment,\n            right_location,\n            left_side_string,\n            right_side_assignment,\n        }\n    }\n\n    fn fold_pattern_invalid(&mut self, location: SrcSpan) -> UntypedPattern {\n        Pattern::Invalid {\n            location,\n            type_: (),\n        }\n    }\n\n    /// You probably don't want to override this method.\n    fn walk_pattern(&mut self, pattern: UntypedPattern) -> UntypedPattern {\n        match pattern {\n            Pattern::Int { .. }\n            | Pattern::Variable { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Discard { .. }\n            | Pattern::BitArraySize { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => pattern,\n\n            Pattern::Assign {\n                name,\n                location,\n                pattern,\n            } => {\n                let pattern = Box::new(self.fold_pattern(*pattern));\n                Pattern::Assign {\n                    name,\n                    location,\n                    pattern,\n                }\n            }\n\n            Pattern::List {\n                location,\n                elements,\n                tail,\n                type_,\n            } => {\n                let elements = elements\n                    .into_iter()\n                    .map(|pattern| self.fold_pattern(pattern))\n                    .collect();\n                let tail = tail.map(|tail_pattern| {\n                    Box::new(TailPattern {\n                        location: tail_pattern.location,\n                        pattern: self.fold_pattern(tail_pattern.pattern),\n                    })\n                });\n                Pattern::List {\n                    location,\n                    elements,\n                    tail,\n                    type_,\n                }\n            }\n\n            Pattern::Constructor {\n                location,\n                name_location,\n                name,\n                arguments,\n                module,\n                constructor,\n                spread,\n                type_,\n            } => {\n                let arguments = arguments\n                    .into_iter()\n                    .map(|mut argument| {\n                        argument.value = self.fold_pattern(argument.value);\n                        argument\n                    })\n                    .collect();\n                Pattern::Constructor {\n                    location,\n                    name_location,\n                    name,\n                    arguments,\n                    module,\n                    constructor,\n                    spread,\n                    type_,\n                }\n            }\n\n            Pattern::Tuple { location, elements } => {\n                let elements = elements\n                    .into_iter()\n                    .map(|pattern| self.fold_pattern(pattern))\n                    .collect();\n                Pattern::Tuple { location, elements }\n            }\n\n            Pattern::BitArray { location, segments } => {\n                let segments = segments\n                    .into_iter()\n                    .map(|mut segment| {\n                        segment.value = Box::new(self.fold_pattern(*segment.value));\n                        segment\n                    })\n                    .collect();\n                Pattern::BitArray { location, segments }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/bit_array.rs",
    "content": "use ecow::EcoString;\nuse num_bigint::BigInt;\n\nuse crate::ast::{self, BitArrayOption, SrcSpan};\nuse crate::build::Target;\nuse crate::type_::Type;\nuse std::sync::Arc;\n\n//\n//  Public Interface\n//\n\npub fn type_options_for_value<TypedValue>(\n    input_options: &[BitArrayOption<TypedValue>],\n    target: Target,\n) -> Result<Arc<Type>, Error>\nwhere\n    TypedValue: GetLiteralValue,\n{\n    type_options(input_options, TypeOptionsMode::Expression, false, target)\n}\n\npub fn type_options_for_pattern<TypedValue>(\n    input_options: &[BitArrayOption<TypedValue>],\n    must_have_size: bool,\n    target: Target,\n) -> Result<Arc<Type>, Error>\nwhere\n    TypedValue: GetLiteralValue,\n{\n    type_options(\n        input_options,\n        TypeOptionsMode::Pattern,\n        must_have_size,\n        target,\n    )\n}\n\nstruct SegmentOptionCategories<'a, T> {\n    type_: Option<&'a BitArrayOption<T>>,\n    signed: Option<&'a BitArrayOption<T>>,\n    endian: Option<&'a BitArrayOption<T>>,\n    unit: Option<&'a BitArrayOption<T>>,\n    size: Option<&'a BitArrayOption<T>>,\n}\n\nimpl<T> SegmentOptionCategories<'_, T> {\n    fn new() -> Self {\n        SegmentOptionCategories {\n            type_: None,\n            signed: None,\n            endian: None,\n            unit: None,\n            size: None,\n        }\n    }\n\n    fn segment_type(&self) -> Arc<Type> {\n        use BitArrayOption::*;\n        let default = Int {\n            location: SrcSpan::default(),\n        };\n\n        match self.type_.unwrap_or(&default) {\n            Int { .. } => crate::type_::int(),\n            Float { .. } => crate::type_::float(),\n            Utf8 { .. } | Utf16 { .. } | Utf32 { .. } => crate::type_::string(),\n            Bytes { .. } | Bits { .. } => crate::type_::bit_array(),\n            Utf8Codepoint { .. } | Utf16Codepoint { .. } | Utf32Codepoint { .. } => {\n                crate::type_::utf_codepoint()\n            }\n\n            Signed { .. }\n            | Unsigned { .. }\n            | Big { .. }\n            | Little { .. }\n            | Native { .. }\n            | Size { .. }\n            | Unit { .. } => panic!(\"Tried to type a non type kind BitArray option.\"),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq)]\n/// Whether we're typing options for a bit array segment that's part of a pattern\n/// or an expression.\n///\nenum TypeOptionsMode {\n    Expression,\n    Pattern,\n}\n\nfn type_options<TypedValue>(\n    input_options: &[BitArrayOption<TypedValue>],\n    mode: TypeOptionsMode,\n    must_have_size: bool,\n    target: Target,\n) -> Result<Arc<Type>, Error>\nwhere\n    TypedValue: GetLiteralValue,\n{\n    use BitArrayOption::*;\n\n    let mut categories = SegmentOptionCategories::new();\n    // Basic category checking\n    for option in input_options {\n        match option {\n            Utf8Codepoint { .. } | Utf16Codepoint { .. } | Utf32Codepoint { .. }\n                if mode == TypeOptionsMode::Pattern && target == Target::JavaScript =>\n            {\n                return err(\n                    ErrorType::OptionNotSupportedForTarget {\n                        target,\n                        option: UnsupportedOption::UtfCodepointPattern,\n                    },\n                    option.location(),\n                );\n            }\n\n            Bytes { .. }\n            | Int { .. }\n            | Float { .. }\n            | Bits { .. }\n            | Utf8 { .. }\n            | Utf16 { .. }\n            | Utf32 { .. }\n            | Utf8Codepoint { .. }\n            | Utf16Codepoint { .. }\n            | Utf32Codepoint { .. } => {\n                if let Some(previous) = categories.type_ {\n                    return err(\n                        ErrorType::ConflictingTypeOptions {\n                            existing_type: previous.label(),\n                        },\n                        option.location(),\n                    );\n                } else {\n                    categories.type_ = Some(option);\n                }\n            }\n\n            Signed { .. } | Unsigned { .. } => {\n                if let Some(previous) = categories.signed {\n                    return err(\n                        ErrorType::ConflictingSignednessOptions {\n                            existing_signed: previous.label(),\n                        },\n                        option.location(),\n                    );\n                } else {\n                    categories.signed = Some(option);\n                }\n            }\n\n            Native { .. } if target == Target::JavaScript => {\n                return err(\n                    ErrorType::OptionNotSupportedForTarget {\n                        target,\n                        option: UnsupportedOption::NativeEndianness,\n                    },\n                    option.location(),\n                );\n            }\n\n            Big { .. } | Little { .. } | Native { .. } => {\n                if let Some(previous) = categories.endian {\n                    return err(\n                        ErrorType::ConflictingEndiannessOptions {\n                            existing_endianness: previous.label(),\n                        },\n                        option.location(),\n                    );\n                } else {\n                    categories.endian = Some(option);\n                }\n            }\n\n            Size { .. } => {\n                if categories.size.is_some() {\n                    return err(ErrorType::ConflictingSizeOptions, option.location());\n                } else {\n                    categories.size = Some(option);\n                }\n            }\n\n            Unit { .. } => {\n                if categories.unit.is_some() {\n                    return err(ErrorType::ConflictingUnitOptions, option.location());\n                } else {\n                    categories.unit = Some(option);\n                }\n            }\n        };\n    }\n\n    // Some options are not allowed in value mode\n    if mode == TypeOptionsMode::Expression {\n        match categories {\n            SegmentOptionCategories {\n                signed: Some(opt), ..\n            }\n            | SegmentOptionCategories {\n                type_: Some(opt @ Bytes { .. }),\n                ..\n            } => return err(ErrorType::OptionNotAllowedInValue, opt.location()),\n            _ => (),\n        }\n    }\n\n    // All but the last segment in a pattern must have an exact size\n    if must_have_size\n        && let SegmentOptionCategories {\n            type_: Some(opt @ (Bytes { .. } | Bits { .. })),\n            size: None,\n            ..\n        } = categories\n    {\n        return err(ErrorType::SegmentMustHaveSize, opt.location());\n    }\n\n    // Endianness is only valid for int, utf16, utf16_codepoint, utf32,\n    // utf32_codepoint and float\n    match categories {\n        SegmentOptionCategories {\n            type_:\n                None\n                | Some(\n                    Int { .. }\n                    | Utf16 { .. }\n                    | Utf32 { .. }\n                    | Utf16Codepoint { .. }\n                    | Utf32Codepoint { .. }\n                    | Float { .. },\n                ),\n            ..\n        } => {}\n\n        SegmentOptionCategories {\n            endian: Some(endian),\n            ..\n        } => return err(ErrorType::InvalidEndianness, endian.location()),\n\n        _ => {}\n    }\n\n    // signed and unsigned can only be used with int types\n    match categories {\n        SegmentOptionCategories {\n            type_: None | Some(Int { .. }),\n            ..\n        } => {}\n\n        SegmentOptionCategories {\n            type_: Some(opt),\n            signed: Some(sign),\n            ..\n        } => {\n            return err(\n                ErrorType::SignednessUsedOnNonInt { type_: opt.label() },\n                sign.location(),\n            );\n        }\n\n        _ => {}\n    }\n\n    // utf8, utf16, utf32 exclude unit and size\n    match categories {\n        SegmentOptionCategories {\n            type_: Some(type_),\n            unit: Some(unit),\n            ..\n        } if is_unicode(type_) => {\n            return err(\n                ErrorType::TypeDoesNotAllowUnit {\n                    type_: type_.label(),\n                },\n                unit.location(),\n            );\n        }\n\n        SegmentOptionCategories {\n            type_: Some(type_),\n            size: Some(size),\n            ..\n        } if is_unicode(type_) => {\n            return err(\n                ErrorType::TypeDoesNotAllowSize {\n                    type_: type_.label(),\n                },\n                size.location(),\n            );\n        }\n\n        _ => {}\n    }\n\n    // if unit specified, size must be specified\n    if let SegmentOptionCategories {\n        unit: Some(unit),\n        size: None,\n        ..\n    } = categories\n    {\n        return err(ErrorType::UnitMustHaveSize, unit.location());\n    }\n\n    // float only 16/32/64\n    if let SegmentOptionCategories {\n        type_: Some(Float { .. }),\n        size: Some(size),\n        ..\n    } = categories\n        && let Some(abox) = size.value()\n    {\n        match abox.as_int_literal() {\n            None => (),\n            Some(value) if value == 16.into() || value == 32.into() || value == 64.into() => (),\n            _ => return err(ErrorType::FloatWithSize, size.location()),\n        }\n    }\n\n    // Segment patterns with a zero or negative constant size must be rejected,\n    // we know they will never match!\n    // A negative size is still allowed in expressions as it will just result\n    // in an empty segment.\n    if let (Some(size @ Size { value, .. }), TypeOptionsMode::Pattern) = (categories.size, mode) {\n        match value.as_int_literal() {\n            Some(n) if n <= BigInt::ZERO => {\n                return err(ErrorType::ConstantSizeNotPositive, size.location());\n            }\n            Some(_) | None => (),\n        }\n    }\n\n    Ok(categories.segment_type())\n}\n\npub trait GetLiteralValue {\n    fn as_int_literal(&self) -> Option<BigInt>;\n}\n\nimpl GetLiteralValue for ast::TypedPattern {\n    fn as_int_literal(&self) -> Option<BigInt> {\n        match self {\n            ast::Pattern::Int { int_value, .. }\n            | ast::Pattern::BitArraySize(ast::BitArraySize::Int { int_value, .. }) => {\n                Some(int_value.clone())\n            }\n            ast::Pattern::Float { .. }\n            | ast::Pattern::String { .. }\n            | ast::Pattern::Variable { .. }\n            | ast::Pattern::BitArraySize(_)\n            | ast::Pattern::Assign { .. }\n            | ast::Pattern::Discard { .. }\n            | ast::Pattern::List { .. }\n            | ast::Pattern::Constructor { .. }\n            | ast::Pattern::Tuple { .. }\n            | ast::Pattern::BitArray { .. }\n            | ast::Pattern::StringPrefix { .. }\n            | ast::Pattern::Invalid { .. } => None,\n        }\n    }\n}\n\nfn is_unicode<T>(opt: &BitArrayOption<T>) -> bool {\n    use BitArrayOption::*;\n\n    matches!(\n        opt,\n        Utf8 { .. }\n            | Utf16 { .. }\n            | Utf32 { .. }\n            | Utf8Codepoint { .. }\n            | Utf16Codepoint { .. }\n            | Utf32Codepoint { .. }\n    )\n}\n\nfn err<A>(error: ErrorType, location: SrcSpan) -> Result<A, Error> {\n    Err(Error { location, error })\n}\n\n#[derive(Debug)]\npub struct Error {\n    pub location: SrcSpan,\n    pub error: ErrorType,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum ErrorType {\n    ConflictingEndiannessOptions {\n        existing_endianness: EcoString,\n    },\n    ConflictingSignednessOptions {\n        existing_signed: EcoString,\n    },\n    ConflictingSizeOptions,\n    ConflictingTypeOptions {\n        existing_type: EcoString,\n    },\n    ConflictingUnitOptions,\n    FloatWithSize,\n    InvalidEndianness,\n    OptionNotAllowedInValue,\n    SegmentMustHaveSize,\n    SignednessUsedOnNonInt {\n        type_: EcoString,\n    },\n    TypeDoesNotAllowSize {\n        type_: EcoString,\n    },\n    TypeDoesNotAllowUnit {\n        type_: EcoString,\n    },\n    UnitMustHaveSize,\n    VariableUtfSegmentInPattern,\n    ConstantSizeNotPositive,\n    OptionNotSupportedForTarget {\n        target: Target,\n        option: UnsupportedOption,\n    },\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum UnsupportedOption {\n    UtfCodepointPattern,\n    NativeEndianness,\n}\n"
  },
  {
    "path": "compiler-core/src/build/elixir_libraries.rs",
    "content": "use crate::{\n    Error,\n    error::ShellCommandFailureReason,\n    io::{Command, CommandExecutor, FileSystemReader, FileSystemWriter, Stdio},\n};\nuse camino::Utf8PathBuf;\n\n#[cfg(not(target_os = \"windows\"))]\nconst ELIXIR_EXECUTABLE: &str = \"elixir\";\n#[cfg(target_os = \"windows\")]\nconst ELIXIR_EXECUTABLE: &str = \"elixir.bat\";\n\n// These Elixir core libs will be loaded with the current project\nconst ELIXIR_LIBS: [&str; 4] = [\"eex\", \"elixir\", \"logger\", \"mix\"];\n\npub struct ElixirLibraries<'a, IO> {\n    io: &'a IO,\n    build_dir: &'a Utf8PathBuf,\n    subprocess_stdio: Stdio,\n}\n\nimpl<'a, IO> ElixirLibraries<'a, IO> {\n    fn new(io: &'a IO, build_dir: &'a Utf8PathBuf, subprocess_stdio: Stdio) -> Self {\n        Self {\n            io,\n            build_dir,\n            subprocess_stdio,\n        }\n    }\n}\n\nimpl<'a, IO> ElixirLibraries<'a, IO>\nwhere\n    IO: CommandExecutor + FileSystemReader + FileSystemWriter + Clone,\n{\n    pub fn make_available(\n        io: &'a IO,\n        build_dir: &'a Utf8PathBuf,\n        subprocess_stdio: Stdio,\n    ) -> Result<(), Error> {\n        let it = Self::new(io, build_dir, subprocess_stdio);\n        let result = it.run();\n\n        if result.is_err() {\n            it.cleanup();\n        }\n\n        result\n    }\n\n    fn cleanup(&self) {\n        self.io\n            .delete_file(&self.paths_cache_path())\n            .expect(\"deleting paths cache in cleanup\");\n    }\n\n    fn paths_cache_filename(&self) -> &'static str {\n        \"gleam_elixir_paths\"\n    }\n\n    fn paths_cache_path(&self) -> Utf8PathBuf {\n        self.build_dir.join(self.paths_cache_filename())\n    }\n\n    fn run(&self) -> Result<(), Error> {\n        // The pathfinder is a file in build/{target}/erlang\n        // It contains the full path for each Elixir core lib we need, new-line delimited\n        // The pathfinder saves us from repeatedly loading Elixir to get this info\n        let mut update_links = false;\n        let cache = self.paths_cache_path();\n        if !self.io.is_file(&cache) {\n            // The pathfinder must be written\n            // Any existing core lib links will get updated\n            update_links = true;\n            // TODO: test\n            let env = vec![(\"TERM\".to_string(), \"dumb\".to_string())];\n            // Prepare the libs for Erlang's code:lib_dir function\n            let elixir_atoms: Vec<String> =\n                ELIXIR_LIBS.iter().map(|lib| format!(\":{}\", lib)).collect();\n            // Use Elixir to find its core lib paths and write the pathfinder file\n            let args = vec![\n                \"--eval\".to_string(),\n                format!(\n                    \":ok = File.write(~s({}), [{}] |> Stream.map(fn(lib) -> lib |> :code.lib_dir |> Path.expand end) |> Enum.join(~s(\\\\n)))\",\n                    self.paths_cache_filename(),\n                    elixir_atoms.join(\", \"),\n                ),\n            ];\n            tracing::debug!(\"writing_elixir_paths_to_build\");\n            let status = self.io.exec(Command {\n                program: ELIXIR_EXECUTABLE.into(),\n                args,\n                env,\n                cwd: Some(self.build_dir.clone()),\n                stdio: self.subprocess_stdio,\n            })?;\n            if status != 0 {\n                return Err(Error::ShellCommand {\n                    program: \"elixir\".into(),\n                    reason: ShellCommandFailureReason::Unknown,\n                });\n            }\n        }\n\n        // Each pathfinder line is a system path for an Elixir core library\n        let read_pathfinder = self.io.read(&cache)?;\n        for lib_path in read_pathfinder.split('\\n') {\n            let source = Utf8PathBuf::from(lib_path);\n            let name = source.as_path().file_name().expect(&format!(\n                \"Unexpanded path in {}\",\n                self.paths_cache_filename()\n            ));\n            let dest = self.build_dir.join(name);\n            let ebin = dest.join(\"ebin\");\n            if !update_links || self.io.is_directory(&ebin) {\n                // Either links don't need updating\n                // Or this library is already linked\n                continue;\n            }\n            // TODO: unit test\n            if self.io.is_directory(&dest) {\n                // Delete the existing link\n                self.io.delete_directory(&dest)?;\n            }\n            tracing::debug!(\"linking_{}_to_build\", name,);\n            self.io.symlink_dir(&source, &dest)?;\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/build/module_loader/tests.rs",
    "content": "use super::*;\nuse crate::{\n    build::SourceFingerprint,\n    io::{FileSystemWriter, memory::InMemoryFileSystem},\n    line_numbers::LineNumbers,\n};\nuse std::time::Duration;\n\n#[test]\nfn no_cache_present() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n\n    fs.write(&Utf8Path::new(\"/src/main.gleam\"), \"const x = 1\")\n        .unwrap();\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_new());\n}\n\n#[test]\nfn cache_present_and_fresh() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n\n    // The mtime of the source is older than that of the cache\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 0);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_cached());\n}\n\n#[test]\nfn cache_present_and_stale() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n\n    // The mtime of the source is newer than that of the cache\n    write_src(&fs, TEST_SOURCE_2, \"/src/main.gleam\", 2);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_new());\n}\n\n#[test]\nfn cache_present_and_stale_but_source_is_the_same() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n\n    // The mtime of the source is newer than that of the cache\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 2);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_cached());\n}\n\n#[test]\nfn cache_present_and_stale_source_is_the_same_lsp_mode() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let mut loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n    loader.mode = Mode::Lsp;\n\n    // The mtime of the source is newer than that of the cache\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 2);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_cached());\n}\n\n#[test]\nfn cache_present_and_stale_source_is_the_same_lsp_mode_and_invalidated() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let mut incomplete_modules = HashSet::new();\n    let _ = incomplete_modules.insert(\"main\".into());\n    let mut loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n    loader.mode = Mode::Lsp;\n\n    // The mtime of the source is newer than that of the cache\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 2);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_new());\n}\n\n#[test]\nfn cache_present_without_codegen_when_required() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let mut loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n    loader.codegen = CodegenRequired::Yes;\n\n    // The mtime of the cache is newer than that of the source\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 0);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_new());\n}\n\n#[test]\nfn cache_present_with_codegen_when_required() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let mut loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n    loader.codegen = CodegenRequired::Yes;\n\n    // The mtime of the cache is newer than that of the source\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 0);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, true);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_cached());\n}\n\n#[test]\nfn cache_present_without_codegen_when_not_required() {\n    let name = \"package\".into();\n    let artefact = Utf8Path::new(\"/artefact\");\n    let fs = InMemoryFileSystem::new();\n    let warnings = WarningEmitter::null();\n    let incomplete_modules = HashSet::new();\n    let mut loader = make_loader(&warnings, &name, &fs, artefact, &incomplete_modules);\n    loader.codegen = CodegenRequired::No;\n\n    // The mtime of the cache is newer than that of the source\n    write_src(&fs, TEST_SOURCE_1, \"/src/main.gleam\", 0);\n    write_cache(&fs, TEST_SOURCE_1, \"/artefact/main.cache_meta\", 1, false);\n\n    let file = GleamFile::new(\"/src\".into(), \"/src/main.gleam\".into());\n    let result = loader.load(file).unwrap();\n\n    assert!(result.is_cached());\n}\n\nconst TEST_SOURCE_1: &'static str = \"const x = 1\";\nconst TEST_SOURCE_2: &'static str = \"const x = 2\";\n\nfn write_cache(\n    fs: &InMemoryFileSystem,\n    source: &str,\n    path: &str,\n    seconds: u64,\n    codegen_performed: bool,\n) {\n    let line_numbers = LineNumbers::new(source);\n    let cache_metadata = CacheMetadata {\n        mtime: SystemTime::UNIX_EPOCH + Duration::from_secs(seconds),\n        codegen_performed,\n        dependencies: vec![],\n        fingerprint: SourceFingerprint::new(source),\n        line_numbers,\n    };\n    let path = Utf8Path::new(path);\n    fs.write_bytes(&path, &cache_metadata.to_binary()).unwrap();\n}\n\nfn write_src(fs: &InMemoryFileSystem, source: &str, path: &str, seconds: u64) {\n    let path = Utf8Path::new(path);\n    fs.write(&path, source).unwrap();\n    fs.set_modification_time(&path, SystemTime::UNIX_EPOCH + Duration::from_secs(seconds));\n}\n\nfn make_loader<'a>(\n    warnings: &'a WarningEmitter,\n    package_name: &'a EcoString,\n    fs: &InMemoryFileSystem,\n    artefact: &'a Utf8Path,\n    incomplete_modules: &'a HashSet<EcoString>,\n) -> ModuleLoader<'a, InMemoryFileSystem> {\n    ModuleLoader {\n        warnings,\n        io: fs.clone(),\n        mode: Mode::Dev,\n        target: Target::Erlang,\n        codegen: CodegenRequired::No,\n        package_name,\n        artefact_directory: &artefact,\n        origin: Origin::Src,\n        incomplete_modules,\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/build/module_loader.rs",
    "content": "#[cfg(test)]\nmod tests;\n\nuse std::{collections::HashSet, time::SystemTime};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\nuse ecow::EcoString;\nuse serde::{Deserialize, Serialize};\n\nuse super::{\n    Mode, Origin, SourceFingerprint, Target,\n    package_compiler::{CacheMetadata, CachedModule, Input, UncompiledModule},\n    package_loader::{CodegenRequired, GleamFile},\n};\nuse crate::{\n    Error, Result,\n    error::{FileIoAction, FileKind},\n    io::{CommandExecutor, FileSystemReader, FileSystemWriter},\n    warning::{TypeWarningEmitter, WarningEmitter},\n};\n\n#[derive(Debug)]\npub(crate) struct ModuleLoader<'a, IO> {\n    pub io: IO,\n    pub warnings: &'a WarningEmitter,\n    pub mode: Mode,\n    pub target: Target,\n    pub codegen: CodegenRequired,\n    pub package_name: &'a EcoString,\n    pub artefact_directory: &'a Utf8Path,\n    pub origin: Origin,\n    /// The set of modules that have had partial compilation done since the last\n    /// successful compilation.\n    pub incomplete_modules: &'a HashSet<EcoString>,\n}\n\nimpl<'a, IO> ModuleLoader<'a, IO>\nwhere\n    IO: FileSystemReader + FileSystemWriter + CommandExecutor + Clone,\n{\n    /// Load a module from the given path.\n    ///\n    /// If the module has been compiled before and the source file has not been\n    /// changed since then, load the precompiled data instead.\n    ///\n    /// Whether the module has changed or not is determined by comparing the\n    /// modification time of the source file with the value recorded in the\n    /// `.timestamp` file in the artefact directory.\n    pub fn load(&self, file: GleamFile) -> Result<Input> {\n        let name = file.module_name.clone();\n        let source_mtime = self.io.modification_time(&file.path)?;\n\n        let read_source = |name| self.read_source(file.path.clone(), name, source_mtime);\n\n        let meta = match self.read_cache_metadata(&file)? {\n            Some(meta) => meta,\n            None => return read_source(name).map(Input::New),\n        };\n\n        // The cache currently does not contain enough data to perform codegen,\n        // so if codegen is required in this compiler run then we must check\n        // that codegen has already been performed before using a cache.\n        if self.codegen.is_required() && !meta.codegen_performed {\n            tracing::debug!(?name, \"codegen_required_cache_insufficient\");\n            return read_source(name).map(Input::New);\n        }\n\n        // If the timestamp of the source is newer than the cache entry and\n        // the hash of the source differs from the one in the cache entry,\n        // then we need to recompile.\n        if meta.mtime < source_mtime {\n            let source_module = read_source(name.clone())?;\n            if meta.fingerprint != SourceFingerprint::new(&source_module.code) {\n                tracing::debug!(?name, \"cache_stale\");\n                return Ok(Input::New(source_module));\n            } else if self.mode == Mode::Lsp && self.incomplete_modules.contains(&name) {\n                // Since the lsp can have valid but incorrect intermediate code states between\n                // successful compilations, we need to invalidate the cache even if the fingerprint matches\n                tracing::debug!(?name, \"cache_stale for lsp\");\n                return Ok(Input::New(source_module));\n            }\n        }\n\n        Ok(Input::Cached(self.cached(file, meta)))\n    }\n\n    /// Read the cache metadata file from the artefact directory for the given\n    /// source file. If the file does not exist, return `None`.\n    fn read_cache_metadata(&self, source_file: &GleamFile) -> Result<Option<CacheMetadata>> {\n        let meta_path = source_file.cache_files(&self.artefact_directory).meta_path;\n\n        if !self.io.is_file(&meta_path) {\n            return Ok(None);\n        }\n\n        let binary = self.io.read_bytes(&meta_path)?;\n        let cache_metadata = CacheMetadata::from_binary(&binary).map_err(|e| -> Error {\n            Error::FileIo {\n                action: FileIoAction::Parse,\n                kind: FileKind::File,\n                path: meta_path,\n                err: Some(e),\n            }\n        })?;\n        Ok(Some(cache_metadata))\n    }\n\n    fn read_source(\n        &self,\n        path: Utf8PathBuf,\n        name: EcoString,\n        mtime: SystemTime,\n    ) -> Result<UncompiledModule, Error> {\n        read_source(\n            self.io.clone(),\n            self.target,\n            self.origin,\n            path,\n            name,\n            self.package_name.clone(),\n            mtime,\n            self.warnings.clone(),\n        )\n    }\n\n    fn cached(&self, file: GleamFile, meta: CacheMetadata) -> CachedModule {\n        CachedModule {\n            dependencies: meta.dependencies,\n            source_path: file.path,\n            origin: self.origin,\n            name: file.module_name,\n            line_numbers: meta.line_numbers,\n        }\n    }\n}\n\npub(crate) fn read_source<IO>(\n    io: IO,\n    target: Target,\n    origin: Origin,\n    path: Utf8PathBuf,\n    name: EcoString,\n    package_name: EcoString,\n    mtime: SystemTime,\n    emitter: WarningEmitter,\n) -> Result<UncompiledModule>\nwhere\n    IO: FileSystemReader + FileSystemWriter + CommandExecutor + Clone,\n{\n    let code: EcoString = io.read(&path)?.into();\n\n    let parsed = crate::parse::parse_module(path.clone(), &code, &emitter).map_err(|error| {\n        Error::Parse {\n            path: path.clone(),\n            src: code.clone(),\n            error: Box::new(error),\n        }\n    })?;\n    let mut ast = parsed.module;\n    let extra = parsed.extra;\n    let dependencies = ast.dependencies(target);\n\n    ast.name = name.clone();\n    let module = UncompiledModule {\n        package: package_name,\n        dependencies,\n        origin,\n        extra,\n        mtime,\n        path,\n        name,\n        code,\n        ast,\n    };\n    Ok(module)\n}\n"
  },
  {
    "path": "compiler-core/src/build/native_file_copier/tests.rs",
    "content": "use super::NativeFileCopier;\nuse crate::{\n    build::{native_file_copier::CopiedNativeFiles, package_compiler::CheckModuleConflicts},\n    io::{FileSystemWriter, memory::InMemoryFileSystem},\n};\nuse std::{\n    collections::HashMap,\n    sync::OnceLock,\n    time::{Duration, SystemTime, UNIX_EPOCH},\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\nfn root() -> &'static Utf8PathBuf {\n    static ROOT: OnceLock<Utf8PathBuf> = OnceLock::new();\n    ROOT.get_or_init(|| Utf8PathBuf::from(\"/\").to_owned())\n}\n\nfn root_out() -> &'static Utf8PathBuf {\n    static OUT: OnceLock<Utf8PathBuf> = OnceLock::new();\n    OUT.get_or_init(|| Utf8PathBuf::from(\"/out\"))\n}\n\n#[test]\nfn javascript_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.js\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.js\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.js\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn javascript_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.js\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.js\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.js\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn javascript_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.js\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.js\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.js\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn mjavascript_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.mjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.mjs\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn mjavascript_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.mjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.mjs\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn mjavascript_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.mjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.mjs\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn cjavascript_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.cjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.cjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.cjs\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn cjavascript_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.cjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.cjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.cjs\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn cjavascript_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.cjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.cjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.cjs\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn typescript_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.ts\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.ts\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.ts\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn typescript_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.ts\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.ts\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.ts\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn typescript_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.ts\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.ts\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.ts\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn all_javascript_files_are_copied_from_src_subfolders() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/abc/def/wibble.mjs\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/abc/ghi/wibble.js\"), \"2\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/abc/jkl/wibble.cjs\"), \"3\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/def/wobble.ts\"), \"4\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/abc/def/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/abc/def/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/src/abc/ghi/wibble.js\"), \"2\".into()),\n            (Utf8PathBuf::from(\"/out/abc/ghi/wibble.js\"), \"2\".into()),\n            (Utf8PathBuf::from(\"/src/abc/jkl/wibble.cjs\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/out/abc/jkl/wibble.cjs\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/src/def/wobble.ts\"), \"4\".into()),\n            (Utf8PathBuf::from(\"/out/def/wobble.ts\"), \"4\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn all_javascript_files_are_copied_from_test_subfolders() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/abc/def/wibble.mjs\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/abc/ghi/wibble.js\"), \"2\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/abc/jkl/wibble.cjs\"), \"3\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/def/wobble.ts\"), \"4\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/abc/def/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/abc/def/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/test/abc/ghi/wibble.js\"), \"2\".into()),\n            (Utf8PathBuf::from(\"/out/abc/ghi/wibble.js\"), \"2\".into()),\n            (Utf8PathBuf::from(\"/test/abc/jkl/wibble.cjs\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/out/abc/jkl/wibble.cjs\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/test/def/wobble.ts\"), \"4\".into()),\n            (Utf8PathBuf::from(\"/out/def/wobble.ts\"), \"4\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn all_javascript_files_are_copied_from_dev_subfolders() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/abc/def/wibble.mjs\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/dev/abc/ghi/wibble.js\"), \"2\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/dev/abc/jkl/wibble.cjs\"), \"3\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/dev/def/wobble.ts\"), \"4\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/abc/def/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/abc/def/wibble.mjs\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/dev/abc/ghi/wibble.js\"), \"2\".into()),\n            (Utf8PathBuf::from(\"/out/abc/ghi/wibble.js\"), \"2\".into()),\n            (Utf8PathBuf::from(\"/dev/abc/jkl/wibble.cjs\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/out/abc/jkl/wibble.cjs\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/dev/def/wobble.ts\"), \"4\".into()),\n            (Utf8PathBuf::from(\"/out/def/wobble.ts\"), \"4\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn erlang_header_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.hrl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.hrl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.hrl\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn erlang_header_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.hrl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.hrl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.hrl\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn erlang_header_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.hrl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.hrl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.hrl\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn erlang_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.erl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert_eq!(copied.to_compile, vec![Utf8PathBuf::from(\"wibble.erl\")]);\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.erl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.erl\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn erlang_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.erl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert_eq!(copied.to_compile, vec![Utf8PathBuf::from(\"wibble.erl\")]);\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.erl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.erl\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn erlang_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.erl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert_eq!(copied.to_compile, vec![Utf8PathBuf::from(\"wibble.erl\")]);\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.erl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.erl\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn elixir_files_are_copied_from_src() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.ex\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(copied.any_elixir);\n    assert_eq!(copied.to_compile, vec![Utf8PathBuf::from(\"wibble.ex\")]);\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.ex\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.ex\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn elixir_files_are_copied_from_test() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/wibble.ex\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(copied.any_elixir);\n    assert_eq!(copied.to_compile, vec![Utf8PathBuf::from(\"wibble.ex\")]);\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/wibble.ex\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.ex\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn elixir_files_are_copied_from_dev() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/wibble.ex\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(copied.any_elixir);\n    assert_eq!(copied.to_compile, vec![Utf8PathBuf::from(\"wibble.ex\")]);\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/wibble.ex\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.ex\"), \"1\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn all_erlang_files_are_copied_from_src_subfolders() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/abc/def/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/abc/ghi/wibble_header.hrl\"), \"2\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/def/wobble.ex\"), \"3\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(copied.any_elixir);\n    assert_eq!(\n        copied.to_compile,\n        vec![\n            Utf8PathBuf::from(\"abc/def/wibble.erl\"),\n            Utf8PathBuf::from(\"def/wobble.ex\")\n        ]\n    );\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/abc/def/wibble.erl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/abc/def/wibble.erl\"), \"1\".into()),\n            (\n                Utf8PathBuf::from(\"/src/abc/ghi/wibble_header.hrl\"),\n                \"2\".into()\n            ),\n            (\n                Utf8PathBuf::from(\"/out/abc/ghi/wibble_header.hrl\"),\n                \"2\".into()\n            ),\n            (Utf8PathBuf::from(\"/src/def/wobble.ex\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/out/def/wobble.ex\"), \"3\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn all_erlang_files_are_copied_from_test_subfolders() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/test/abc/def/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/abc/ghi/wibble_header.hrl\"), \"2\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/def/wobble.ex\"), \"3\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(copied.any_elixir);\n    assert_eq!(\n        copied.to_compile,\n        vec![\n            Utf8PathBuf::from(\"abc/def/wibble.erl\"),\n            Utf8PathBuf::from(\"def/wobble.ex\")\n        ]\n    );\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/test/abc/def/wibble.erl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/abc/def/wibble.erl\"), \"1\".into()),\n            (\n                Utf8PathBuf::from(\"/test/abc/ghi/wibble_header.hrl\"),\n                \"2\".into()\n            ),\n            (\n                Utf8PathBuf::from(\"/out/abc/ghi/wibble_header.hrl\"),\n                \"2\".into()\n            ),\n            (Utf8PathBuf::from(\"/test/def/wobble.ex\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/out/def/wobble.ex\"), \"3\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn all_erlang_files_are_copied_from_dev_subfolders() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/abc/def/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/dev/abc/ghi/wibble_header.hrl\"), \"2\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/dev/def/wobble.ex\"), \"3\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(copied.any_elixir);\n    assert_eq!(\n        copied.to_compile,\n        vec![\n            Utf8PathBuf::from(\"abc/def/wibble.erl\"),\n            Utf8PathBuf::from(\"def/wobble.ex\")\n        ]\n    );\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/dev/abc/def/wibble.erl\"), \"1\".into()),\n            (Utf8PathBuf::from(\"/out/abc/def/wibble.erl\"), \"1\".into()),\n            (\n                Utf8PathBuf::from(\"/dev/abc/ghi/wibble_header.hrl\"),\n                \"2\".into()\n            ),\n            (\n                Utf8PathBuf::from(\"/out/abc/ghi/wibble_header.hrl\"),\n                \"2\".into()\n            ),\n            (Utf8PathBuf::from(\"/dev/def/wobble.ex\"), \"3\".into()),\n            (Utf8PathBuf::from(\"/out/def/wobble.ex\"), \"3\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn other_files_are_ignored() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.cpp\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([(Utf8PathBuf::from(\"/src/wibble.cpp\"), \"1\".into())]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn files_do_not_get_copied_if_there_already_is_a_new_version() {\n    let fs = InMemoryFileSystem::new();\n    let out = Utf8Path::new(\"/out/wibble.mjs\");\n    let src = Utf8Path::new(\"/src/wibble.mjs\");\n    fs.write(&out, \"in-out\").unwrap();\n    fs.write(&src, \"in-src\").unwrap();\n    fs.set_modification_time(&out, UNIX_EPOCH + Duration::from_secs(1));\n    fs.set_modification_time(&src, UNIX_EPOCH);\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.mjs\"), \"in-src\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.mjs\"), \"in-out\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn files_get_copied_if_the_previously_copied_version_is_older() {\n    let fs = InMemoryFileSystem::new();\n    let out = Utf8Path::new(\"/out/wibble.mjs\");\n    let src = Utf8Path::new(\"/src/wibble.mjs\");\n    fs.write(&out, \"in-out\").unwrap();\n    fs.write(&src, \"in-src\").unwrap();\n    fs.set_modification_time(&out, UNIX_EPOCH);\n    fs.set_modification_time(&src, UNIX_EPOCH + Duration::from_secs(1));\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    let copied = copier.run().unwrap();\n\n    assert!(!copied.any_elixir);\n    assert!(copied.to_compile.is_empty());\n    assert_eq!(\n        HashMap::from([\n            (Utf8PathBuf::from(\"/src/wibble.mjs\"), \"in-src\".into()),\n            (Utf8PathBuf::from(\"/out/wibble.mjs\"), \"in-src\".into())\n        ]),\n        fs.into_contents(),\n    );\n}\n\n#[test]\nfn duplicate_native_files_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.mjs\"), \"1\").unwrap();\n    fs.write(&Utf8Path::new(\"/test/wibble.mjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_erlang_modules_in_src_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/a/b/c/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/e/f/wibble.erl\"), \"1\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_erlang_modules_in_src_and_test_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/a/b/c/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/e/f/wibble.erl\"), \"1\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_erlang_modules_in_src_and_dev_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/a/b/c/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/dev/e/f/wibble.erl\"), \"1\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_erlang_modules_in_dev_and_test_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/dev/a/b/c/wibble.erl\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/test/e/f/wibble.erl\"), \"1\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_gleam_and_javascript_modules_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.gleam\"), \"1\").unwrap();\n    fs.write(&Utf8Path::new(\"/src/wibble.mjs\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn differently_nested_gleam_and_javascript_modules_with_same_name_are_ok() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/a/b/c/wibble.gleam\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/d/e/wibble.mjs\"), \"1\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_ok());\n}\n\n#[test]\nfn conflicting_gleam_and_erlang_modules_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.gleam\"), \"1\").unwrap();\n    fs.write(&Utf8Path::new(\"/src/wibble.erl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_nested_gleam_and_erlang_modules_result_in_an_error() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble/wobble.gleam\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/wibble@wobble.erl\"), \"1\")\n        .unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_err());\n}\n\n#[test]\nfn conflicting_nested_gleam_file_does_not_conflict_with_root_erlang_file() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble/wobble.gleam\"), \"1\")\n        .unwrap();\n    fs.write(&Utf8Path::new(\"/src/wobble.erl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(fs.clone(), root(), root_out(), CheckModuleConflicts::Check);\n    assert!(copier.run().is_ok());\n}\n\n#[test]\nfn conflicting_gleam_and_erlang_modules_produce_no_error_in_dependency() {\n    let fs = InMemoryFileSystem::new();\n    fs.write(&Utf8Path::new(\"/src/wibble.gleam\"), \"1\").unwrap();\n    fs.write(&Utf8Path::new(\"/src/wibble.erl\"), \"1\").unwrap();\n\n    let copier = NativeFileCopier::new(\n        fs.clone(),\n        root(),\n        root_out(),\n        CheckModuleConflicts::DoNotCheck,\n    );\n    assert!(copier.run().is_ok());\n}\n"
  },
  {
    "path": "compiler-core/src/build/native_file_copier.rs",
    "content": "#[cfg(test)]\nmod tests;\n\nuse std::collections::{HashMap, HashSet};\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::{EcoString, eco_format};\n\nuse crate::{\n    Error, Result,\n    io::{DirWalker, FileSystemReader, FileSystemWriter},\n    paths::ProjectPaths,\n};\n\nuse super::package_compiler::CheckModuleConflicts;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) struct CopiedNativeFiles {\n    pub any_elixir: bool,\n    pub to_compile: Vec<Utf8PathBuf>,\n}\n\npub(crate) struct NativeFileCopier<'a, IO> {\n    io: IO,\n    paths: ProjectPaths,\n    destination_dir: &'a Utf8Path,\n    seen_native_files: HashSet<Utf8PathBuf>,\n    seen_modules: HashMap<EcoString, Utf8PathBuf>,\n    to_compile: Vec<Utf8PathBuf>,\n    elixir_files_copied: bool,\n    check_module_conflicts: CheckModuleConflicts,\n}\n\nimpl<'a, IO> NativeFileCopier<'a, IO>\nwhere\n    IO: FileSystemReader + FileSystemWriter + Clone,\n{\n    pub(crate) fn new(\n        io: IO,\n        root: &'a Utf8Path,\n        out: &'a Utf8Path,\n        check_module_conflicts: CheckModuleConflicts,\n    ) -> Self {\n        Self {\n            io,\n            paths: ProjectPaths::new(root.into()),\n            destination_dir: out,\n            to_compile: Vec::new(),\n            seen_native_files: HashSet::new(),\n            seen_modules: HashMap::new(),\n            elixir_files_copied: false,\n            check_module_conflicts,\n        }\n    }\n\n    /// Copy native files from the given directory to the build directory.\n    ///\n    /// Errors if any duplicate files are found.\n    ///\n    /// Returns a list of files that need to be compiled (Elixir and Erlang).\n    ///\n    pub fn run(mut self) -> Result<CopiedNativeFiles> {\n        self.io.mkdir(&self.destination_dir)?;\n\n        let src = self.paths.src_directory();\n        self.copy_files(&src)?;\n\n        let test = self.paths.test_directory();\n        if self.io.is_directory(&test) {\n            self.copy_files(&test)?;\n        }\n\n        let dev = self.paths.dev_directory();\n        if self.io.is_directory(&dev) {\n            self.copy_files(&dev)?;\n        }\n\n        // Sort for deterministic output\n        self.to_compile.sort_unstable();\n\n        Ok(CopiedNativeFiles {\n            to_compile: self.to_compile,\n            any_elixir: self.elixir_files_copied,\n        })\n    }\n\n    fn copy_files(&mut self, src_root: &Utf8Path) -> Result<()> {\n        let mut dir_walker = DirWalker::new(src_root.to_path_buf());\n        while let Some(path) = dir_walker.next_file(&self.io)? {\n            self.copy(path, &src_root)?;\n        }\n        Ok(())\n    }\n\n    fn copy(&mut self, file: Utf8PathBuf, src_root: &Utf8Path) -> Result<()> {\n        let extension = file.extension().unwrap_or_default();\n\n        let relative_path = file\n            .strip_prefix(src_root)\n            .expect(\"copy_native_files strip prefix\")\n            .to_path_buf();\n\n        // No need to run duplicate native file checks for .gleam files, but we\n        // still need to check for conflicting `.gleam` and `.mjs` files, so we\n        // add a special case for `.gleam`.\n        if extension == \"gleam\" {\n            self.check_for_conflicting_javascript_modules(&relative_path)?;\n            self.check_for_conflicting_erlang_modules(&relative_path)?;\n\n            return Ok(());\n        }\n\n        // Skip unknown file formats that are not supported native files\n        if !crate::io::is_native_file_extension(extension) {\n            return Ok(());\n        }\n\n        let destination = self.destination_dir.join(&relative_path);\n\n        // Check that this native file was not already copied\n        self.check_for_duplicate(&relative_path)?;\n\n        // Check for JavaScript modules conflicting between each other within\n        // the same relative path. We need to do this as '.gleam' files can\n        // also cause a conflict, despite not being native files, as they are\n        // compiled to `.mjs`.\n        self.check_for_conflicting_javascript_modules(&relative_path)?;\n\n        // Check for Erlang modules conflicting between each other anywhere in\n        // the tree.\n        self.check_for_conflicting_erlang_modules(&relative_path)?;\n\n        // If the source file's mtime is older than the destination file's mtime\n        // then it has not changed and as such does not need to be copied.\n        //\n        // This makes no practical difference for JavaScript etc files, but for\n        // Erlang and Elixir files it mean we can skip compiling them.\n        if self.io.is_file(&destination)\n            && self.io.modification_time(&file)? <= self.io.modification_time(&destination)?\n        {\n            tracing::debug!(?file, \"skipping_unchanged_native_file_unchanged\");\n            return Ok(());\n        }\n\n        tracing::debug!(?file, \"copying_native_file\");\n\n        // Ensure destination exists (subdir might not exist yet in the output)\n        if let Some(parent) = destination.parent() {\n            self.io.mkdir(parent)?;\n        }\n\n        self.io.copy(&file, &destination)?;\n        self.elixir_files_copied = self.elixir_files_copied || extension == \"ex\";\n\n        // BEAM native modules need to be compiled\n        if matches!(extension, \"erl\" | \"ex\") {\n            _ = self.to_compile.push(relative_path.clone());\n        }\n\n        Ok(())\n    }\n\n    fn check_for_duplicate(&mut self, relative_path: &Utf8PathBuf) -> Result<(), Error> {\n        if !self.seen_native_files.insert(relative_path.clone()) {\n            return Err(Error::DuplicateSourceFile {\n                file: relative_path.to_string(),\n            });\n        }\n        Ok(())\n    }\n\n    /// Gleam files are compiled to `.mjs` files, which must not conflict with\n    /// an FFI `.mjs` file with the same name, so we check for this case here.\n    fn check_for_conflicting_javascript_modules(\n        &mut self,\n        relative_path: &Utf8PathBuf,\n    ) -> Result<(), Error> {\n        let mjs_path = match relative_path.extension() {\n            Some(\"gleam\") => eco_format!(\"{}\", relative_path.with_extension(\"mjs\")),\n            Some(\"mjs\") => eco_format!(\"{}\", relative_path),\n            _ => return Ok(()),\n        };\n\n        // Insert the full relative `.mjs` path in `seen_modules` as there is\n        // no conflict if two `.mjs` files have the same name but are in\n        // different subpaths, unlike Erlang files.\n        let existing = self\n            .seen_modules\n            .insert(mjs_path.clone(), relative_path.clone());\n\n        // If there was no already existing one then there's no problem.\n        let Some(existing) = existing else {\n            return Ok(());\n        };\n\n        let existing_is_gleam = existing.extension() == Some(\"gleam\");\n        if existing_is_gleam || relative_path.extension() == Some(\"gleam\") {\n            let (gleam_file, native_file) = if existing_is_gleam {\n                (&existing, relative_path)\n            } else {\n                (relative_path, &existing)\n            };\n            return Err(Error::ClashingGleamModuleAndNativeFileName {\n                module: eco_format!(\"{}\", gleam_file.with_extension(\"\")),\n                gleam_file: gleam_file.clone(),\n                native_file: native_file.clone(),\n            });\n        }\n\n        // The only way for two `.mjs` files to clash is by having\n        // the exact same path.\n        assert_eq!(&existing, relative_path);\n        return Err(Error::DuplicateSourceFile {\n            file: existing.to_string(),\n        });\n    }\n\n    /// Erlang module files cannot have the same name regardless of their\n    /// relative positions within the project. Ensure we raise an error if the\n    /// user attempts to create `.erl` files with the same name.\n    fn check_for_conflicting_erlang_modules(\n        &mut self,\n        relative_path: &Utf8PathBuf,\n    ) -> Result<(), Error> {\n        let erlang_module_name = match relative_path.extension() {\n            Some(\"erl\") => {\n                eco_format!(\"{}\", relative_path.file_name().expect(\"path has file name\"))\n            }\n            Some(\"gleam\") if self.check_module_conflicts.should_check() => relative_path\n                .with_extension(\"erl\")\n                .as_str()\n                .replace(\"/\", \"@\")\n                .into(),\n            _ => return Ok(()),\n        };\n\n        // Insert just the `.erl` module filename in `seen_modules` instead of\n        // its full relative path, because `.erl` files with the same name\n        // cause a conflict when targetting Erlang regardless of subpath.\n        if let Some(existing) = self\n            .seen_modules\n            .insert(erlang_module_name, relative_path.clone())\n        {\n            let existing_is_gleam = existing.extension() == Some(\"gleam\");\n            if existing_is_gleam || relative_path.extension() == Some(\"gleam\") {\n                let (gleam_file, native_file) = if existing_is_gleam {\n                    (&existing, relative_path)\n                } else {\n                    (relative_path, &existing)\n                };\n                return Err(Error::ClashingGleamModuleAndNativeFileName {\n                    module: eco_format!(\"{}\", gleam_file.with_extension(\"\")),\n                    gleam_file: gleam_file.clone(),\n                    native_file: native_file.clone(),\n                });\n            }\n\n            return Err(Error::DuplicateNativeErlangModule {\n                module: eco_format!(\"{}\", relative_path.file_stem().expect(\"path has file stem\")),\n                first: existing,\n                second: relative_path.clone(),\n            });\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/build/package_compiler/snapshots/gleam_core__build__package_compiler__tests__different_packages_defining_duplicate_module.snap",
    "content": "---\nsource: compiler-core/src/build/package_compiler/tests.rs\nexpression: output\n---\nerror: Duplicate module\n\nThe module `a_module` is defined multiple times.\n\nIt is first defined by the package dep1\nIt is defined a second time by the package a_package\n"
  },
  {
    "path": "compiler-core/src/build/package_compiler/snapshots/gleam_core__build__package_compiler__tests__same_package_defining_duplicate_module.snap",
    "content": "---\nsource: compiler-core/src/build/package_compiler/tests.rs\nexpression: output\n---\nerror: Duplicate module\n\nThe module `a_module` is defined multiple times.\n\nIt is first defined at a_package/a_module.gleam\nIt is defined a second time at /src/a_module.gleam\n"
  },
  {
    "path": "compiler-core/src/build/package_compiler/tests.rs",
    "content": "use std::collections::HashSet;\n\nuse camino::Utf8Path;\nuse ecow::EcoString;\n\nuse crate::{\n    Error,\n    build::{\n        self, NullTelemetry, Outcome, PackageCompiler, StaleTracker, Target,\n        TargetCodegenConfiguration, Telemetry, package_compiler::Compiled,\n    },\n    config::PackageConfig,\n    error::DefinedModuleOrigin,\n    io::{FileSystemWriter, memory::InMemoryFileSystem},\n    uid::UniqueIdGenerator,\n    warning::WarningEmitter,\n};\n\nfn compile_modules(\n    package_name: &str,\n    module: &str,\n    existing_modules: Vec<(&str, &str)>,\n) -> Outcome<Compiled, Error> {\n    let mut fs = InMemoryFileSystem::new();\n    fs.write(\n        Utf8Path::new(&format!(\"/src/{module}.gleam\")),\n        \"pub fn main() -> Nil { Nil }\",\n    )\n    .expect(\"write module\");\n\n    let mut config = PackageConfig::default();\n    config.name = package_name.into();\n\n    let compiler = PackageCompiler::new(\n        &config,\n        build::Mode::Dev,\n        Utf8Path::new(\"/\"),\n        Utf8Path::new(\"/out\"),\n        Utf8Path::new(\"/lib\"),\n        &TargetCodegenConfiguration::Erlang { app_file: None },\n        UniqueIdGenerator::new(),\n        fs,\n    );\n\n    let mut already_defined_modules = existing_modules\n        .into_iter()\n        .map(|(package_name, module_name)| {\n            (\n                EcoString::from(module_name),\n                DefinedModuleOrigin {\n                    package_name: EcoString::from(package_name),\n                    path: Utf8Path::new(&format!(\"{package_name}/{module_name}.gleam\"))\n                        .to_path_buf(),\n                },\n            )\n        })\n        .collect();\n\n    compiler.compile(\n        &WarningEmitter::null(),\n        &mut im::HashMap::new(),\n        &mut already_defined_modules,\n        &mut StaleTracker::default(),\n        &mut HashSet::new(),\n        &NullTelemetry,\n    )\n}\n\n#[test]\npub fn different_packages_defining_duplicate_module() {\n    let output = compile_modules(\"a_package\", \"a_module\", vec![(\"dep1\", \"a_module\")])\n        .into_result()\n        .expect_err(\"should produce an error\")\n        .pretty_string();\n\n    insta::assert_snapshot!(insta::internals::AutoName, output);\n}\n\n#[test]\npub fn same_package_defining_duplicate_module() {\n    let output = compile_modules(\"a_package\", \"a_module\", vec![(\"a_package\", \"a_module\")])\n        .into_result()\n        .expect_err(\"should produce an error\")\n        .pretty_string();\n\n    insta::assert_snapshot!(insta::internals::AutoName, output);\n}\n"
  },
  {
    "path": "compiler-core/src/build/package_compiler.rs",
    "content": "#[cfg(test)]\nmod tests;\n\nuse crate::analyse::{ModuleAnalyzerConstructor, TargetSupport};\nuse crate::build::package_loader::CacheFiles;\n\nuse crate::error::DefinedModuleOrigin;\nuse crate::io::files_with_extension;\nuse crate::line_numbers::{self, LineNumbers};\nuse crate::type_::PRELUDE_MODULE_NAME;\nuse crate::{\n    Error, Result, Warning,\n    ast::{SrcSpan, TypedModule, UntypedModule},\n    build::{\n        Mode, Module, Origin, Outcome, Package, SourceFingerprint, Target,\n        elixir_libraries::ElixirLibraries,\n        native_file_copier::NativeFileCopier,\n        package_loader::{CodegenRequired, PackageLoader, StaleTracker},\n    },\n    codegen::{Erlang, ErlangApp, JavaScript, TypeScriptDeclarations},\n    config::PackageConfig,\n    dep_tree, error,\n    io::{BeamCompiler, CommandExecutor, FileSystemReader, FileSystemWriter, Stdio},\n    parse::extra::ModuleExtra,\n    paths, type_,\n    uid::UniqueIdGenerator,\n    warning::{TypeWarningEmitter, WarningEmitter},\n};\nuse crate::{inline, metadata};\nuse askama::Template;\nuse ecow::EcoString;\nuse std::collections::HashSet;\nuse std::{collections::HashMap, fmt::write, time::SystemTime};\nuse vec1::Vec1;\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\nuse super::{ErlangAppCodegenConfiguration, TargetCodegenConfiguration, Telemetry};\n\n#[derive(Debug)]\npub struct Compiled {\n    /// The modules which were just compiled\n    pub modules: Vec<Module>,\n    /// The names of all cached modules, which are not present in the `modules` field.\n    pub cached_module_names: Vec<EcoString>,\n}\n\n#[derive(Debug)]\npub struct PackageCompiler<'a, IO> {\n    pub io: IO,\n    pub out: &'a Utf8Path,\n    pub lib: &'a Utf8Path,\n    pub root: &'a Utf8Path,\n    pub mode: Mode,\n    pub target: &'a TargetCodegenConfiguration,\n    pub config: &'a PackageConfig,\n    pub ids: UniqueIdGenerator,\n    pub write_metadata: bool,\n    pub perform_codegen: bool,\n    /// If set to false the compiler won't load and analyse any of the package's\n    /// modules and always succeed compilation returning no compile modules.\n    ///\n    /// Code generation is still carried out so that a root package will have an\n    /// entry point nonetheless.\n    ///\n    pub compile_modules: bool,\n    pub write_entrypoint: bool,\n    pub copy_native_files: bool,\n    pub compile_beam_bytecode: bool,\n    pub subprocess_stdio: Stdio,\n    pub target_support: TargetSupport,\n    pub cached_warnings: CachedWarnings,\n    pub check_module_conflicts: CheckModuleConflicts,\n}\n\nimpl<'a, IO> PackageCompiler<'a, IO>\nwhere\n    IO: FileSystemReader + FileSystemWriter + CommandExecutor + BeamCompiler + Clone,\n{\n    pub fn new(\n        config: &'a PackageConfig,\n        mode: Mode,\n        root: &'a Utf8Path,\n        out: &'a Utf8Path,\n        lib: &'a Utf8Path,\n        target: &'a TargetCodegenConfiguration,\n        ids: UniqueIdGenerator,\n        io: IO,\n    ) -> Self {\n        Self {\n            io,\n            ids,\n            out,\n            lib,\n            root,\n            mode,\n            config,\n            target,\n            write_metadata: true,\n            perform_codegen: true,\n            compile_modules: true,\n            write_entrypoint: false,\n            copy_native_files: true,\n            compile_beam_bytecode: true,\n            subprocess_stdio: Stdio::Inherit,\n            target_support: TargetSupport::NotEnforced,\n            cached_warnings: CachedWarnings::Ignore,\n            check_module_conflicts: CheckModuleConflicts::DoNotCheck,\n        }\n    }\n\n    /// Compile the package.\n    /// Returns a list of modules that were compiled. Any modules that were read\n    /// from the cache will not be returned.\n    // TODO: return the cached modules.\n    pub fn compile(\n        mut self,\n        warnings: &WarningEmitter,\n        existing_modules: &mut im::HashMap<EcoString, type_::ModuleInterface>,\n        already_defined_modules: &mut im::HashMap<EcoString, DefinedModuleOrigin>,\n        stale_modules: &mut StaleTracker,\n        incomplete_modules: &mut HashSet<EcoString>,\n        telemetry: &dyn Telemetry,\n    ) -> Outcome<Compiled, Error> {\n        let span = tracing::info_span!(\"compile\", package = %self.config.name.as_str());\n        let _enter = span.enter();\n\n        // Ensure that the package is compatible with this version of Gleam\n        if let Err(e) = self.config.check_gleam_compatibility() {\n            return e.into();\n        }\n\n        let artefact_directory = self.out.join(paths::ARTEFACT_DIRECTORY_NAME);\n        let codegen_required = if self.perform_codegen {\n            CodegenRequired::Yes\n        } else {\n            CodegenRequired::No\n        };\n\n        let loader = PackageLoader::new(\n            self.io.clone(),\n            self.ids.clone(),\n            self.mode,\n            self.root,\n            self.cached_warnings,\n            warnings,\n            codegen_required,\n            &artefact_directory,\n            self.target.target(),\n            &self.config.name,\n            stale_modules,\n            already_defined_modules,\n            incomplete_modules,\n        );\n\n        let loaded = if self.compile_modules {\n            match loader.run() {\n                Ok(loaded) => loaded,\n                Err(error) => return error.into(),\n            }\n        } else {\n            Loaded::empty()\n        };\n\n        let mut cached_module_names = Vec::new();\n\n        // Load the cached modules that have previously been compiled\n        for module in loaded.cached.into_iter() {\n            // Emit any cached warnings.\n            // Note that `self.cached_warnings` is set to `Ignore` (such as for\n            // dependency packages) then this field will not be populated.\n            if let Err(e) = self.emit_warnings(warnings, &module) {\n                return e.into();\n            }\n\n            cached_module_names.push(module.name.clone());\n\n            // Register the cached module so its type information etc can be\n            // used for compiling futher modules.\n            _ = existing_modules.insert(module.name.clone(), module);\n        }\n\n        if !loaded.to_compile.is_empty() {\n            // Print that work is being done\n            if self.perform_codegen {\n                telemetry.compiling_package(&self.config.name);\n            } else {\n                telemetry.checking_package(&self.config.name)\n            }\n        }\n\n        // Type check the modules that are new or have changed\n        tracing::info!(count=%loaded.to_compile.len(), \"analysing_modules\");\n        let outcome = analyse(\n            &self.config,\n            self.target.target(),\n            self.mode,\n            &self.ids,\n            loaded.to_compile,\n            existing_modules,\n            warnings,\n            self.target_support,\n            incomplete_modules,\n        );\n\n        let mut modules = match outcome {\n            Outcome::Ok(modules) => modules,\n            Outcome::PartialFailure(modules, error) => {\n                return Outcome::PartialFailure(\n                    Compiled {\n                        modules,\n                        cached_module_names,\n                    },\n                    error,\n                );\n            }\n            Outcome::TotalFailure(error) => return Outcome::TotalFailure(error),\n        };\n\n        tracing::debug!(\"performing_code_generation\");\n\n        // Inlining is currently disabled. See\n        // https://github.com/gleam-lang/gleam/pull/5010 for information.\n\n        // let modules = if self.perform_codegen {\n        //     modules\n        //         .into_iter()\n        //         .map(|mut module| {\n        //             module.ast = inline::module(module.ast, &existing_modules);\n        //             module\n        //         })\n        //         .collect()\n        // } else {\n        //     modules\n        // };\n\n        if let Err(error) = self.perform_codegen(&modules) {\n            return error.into();\n        }\n\n        if let Err(error) = self.encode_and_write_metadata(&mut modules) {\n            return error.into();\n        }\n\n        Outcome::Ok(Compiled {\n            modules,\n            cached_module_names,\n        })\n    }\n\n    fn compile_erlang_to_beam(\n        &mut self,\n        modules: &HashSet<Utf8PathBuf>,\n    ) -> Result<Vec<EcoString>, Error> {\n        if modules.is_empty() {\n            tracing::debug!(\"no_erlang_to_compile\");\n            return Ok(Vec::new());\n        }\n\n        tracing::debug!(\"compiling_erlang\");\n\n        self.io\n            .compile_beam(self.out, self.lib, modules, self.subprocess_stdio)\n            .map(|modules| modules.iter().map(|str| EcoString::from(str)).collect())\n    }\n\n    fn copy_project_native_files(\n        &mut self,\n        destination_dir: &Utf8Path,\n        to_compile_modules: &mut HashSet<Utf8PathBuf>,\n    ) -> Result<(), Error> {\n        tracing::debug!(\"copying_native_source_files\");\n\n        // TODO: unit test\n        let priv_source = self.root.join(\"priv\");\n        let priv_build = self.out.join(\"priv\");\n        if self.io.is_directory(&priv_source) && !self.io.is_directory(&priv_build) {\n            tracing::debug!(\"linking_priv_to_build\");\n            self.io.symlink_dir(&priv_source, &priv_build)?;\n        }\n\n        let copier = NativeFileCopier::new(\n            self.io.clone(),\n            self.root.clone(),\n            destination_dir,\n            self.check_module_conflicts,\n        );\n        let copied = copier.run()?;\n\n        to_compile_modules.extend(copied.to_compile.into_iter());\n\n        // If there are any Elixir files then we need to locate Elixir\n        // installed on this system for use in compilation.\n        if copied.any_elixir {\n            ElixirLibraries::make_available(\n                &self.io,\n                &self.lib.to_path_buf(),\n                self.subprocess_stdio,\n            )?;\n        }\n\n        Ok(())\n    }\n\n    fn encode_and_write_metadata(&mut self, modules: &mut [Module]) -> Result<()> {\n        if !self.write_metadata {\n            tracing::debug!(\"package_metadata_writing_disabled\");\n            return Ok(());\n        }\n        if modules.is_empty() {\n            return Ok(());\n        }\n\n        let artefact_dir = self.out.join(paths::ARTEFACT_DIRECTORY_NAME);\n\n        tracing::debug!(\"writing_module_caches\");\n        for module in modules {\n            let cache_files = CacheFiles::new(&artefact_dir, &module.name);\n\n            let result = if self.cached_warnings.should_use() {\n                metadata::encode(&module.ast.type_info)\n            } else {\n                // Dependency packages don't get warnings persisted as the\n                // programmer doesn't want to be told every time about warnings they\n                // cannot fix directly.\n                let warnings = std::mem::take(&mut module.ast.type_info.warnings);\n                let result = metadata::encode(&module.ast.type_info);\n                module.ast.type_info.warnings = warnings;\n                result\n            };\n\n            // Write cache file\n            let bytes = result.expect(\"Failed to serialise module cache\");\n            self.io.write_bytes(&cache_files.cache_path, &bytes)?;\n\n            // Write cache metadata\n            let info = CacheMetadata {\n                mtime: module.mtime,\n                codegen_performed: self.perform_codegen,\n                dependencies: module.dependencies.clone(),\n                fingerprint: SourceFingerprint::new(&module.code),\n                line_numbers: module.ast.type_info.line_numbers.clone(),\n            };\n            self.io\n                .write_bytes(&cache_files.meta_path, &info.to_binary())?;\n        }\n        Ok(())\n    }\n\n    fn perform_codegen(&mut self, modules: &[Module]) -> Result<()> {\n        if !self.perform_codegen {\n            tracing::debug!(\"skipping_codegen\");\n            return Ok(());\n        }\n\n        match self.target {\n            TargetCodegenConfiguration::JavaScript {\n                emit_typescript_definitions,\n                prelude_location,\n            } => self.perform_javascript_codegen(\n                modules,\n                *emit_typescript_definitions,\n                prelude_location,\n            ),\n            TargetCodegenConfiguration::Erlang { app_file } => {\n                self.perform_erlang_codegen(modules, app_file.as_ref())\n            }\n        }\n    }\n\n    fn perform_erlang_codegen(\n        &mut self,\n        modules: &[Module],\n        app_file_config: Option<&ErlangAppCodegenConfiguration>,\n    ) -> Result<(), Error> {\n        let mut written = HashSet::new();\n        let build_dir = self.out.join(paths::ARTEFACT_DIRECTORY_NAME);\n        let include_dir = self.out.join(\"include\");\n        let io = self.io.clone();\n\n        io.mkdir(&build_dir)?;\n\n        if self.copy_native_files {\n            self.copy_project_native_files(&build_dir, &mut written)?;\n        } else {\n            tracing::debug!(\"skipping_native_file_copying\");\n        }\n\n        if self.compile_beam_bytecode && self.write_entrypoint {\n            self.render_erlang_entrypoint_module(&build_dir, &mut written)?;\n        } else {\n            tracing::debug!(\"skipping_entrypoint_generation\");\n        }\n\n        // NOTE: This must come after `copy_project_native_files` to ensure that\n        // we overwrite any precompiled Erlang that was included in the Hex\n        // package. Otherwise we will build the potentially outdated precompiled\n        // version and not the newly compiled version.\n        Erlang::new(&build_dir, &include_dir).render(io.clone(), modules, self.root)?;\n\n        let native_modules: Vec<EcoString> = if self.compile_beam_bytecode {\n            written.extend(modules.iter().map(Module::compiled_erlang_path));\n            self.compile_erlang_to_beam(&written)?\n        } else {\n            tracing::debug!(\"skipping_erlang_bytecode_compilation\");\n            Vec::new()\n        };\n\n        if let Some(config) = app_file_config {\n            ErlangApp::new(&self.out.join(\"ebin\"), config).render(\n                io,\n                &self.config,\n                modules,\n                native_modules,\n            )?;\n        }\n        Ok(())\n    }\n\n    fn perform_javascript_codegen(\n        &mut self,\n        modules: &[Module],\n        typescript: bool,\n        prelude_location: &Utf8Path,\n    ) -> Result<(), Error> {\n        let mut written = HashSet::new();\n        let typescript = if typescript {\n            TypeScriptDeclarations::Emit\n        } else {\n            TypeScriptDeclarations::None\n        };\n\n        JavaScript::new(&self.out, typescript, prelude_location, &self.root).render(\n            &self.io,\n            modules,\n            self.stdlib_package(),\n        )?;\n\n        if self.copy_native_files {\n            self.copy_project_native_files(&self.out, &mut written)?;\n        } else {\n            tracing::debug!(\"skipping_native_file_copying\");\n        }\n\n        Ok(())\n    }\n\n    fn render_erlang_entrypoint_module(\n        &mut self,\n        out: &Utf8Path,\n        modules_to_compile: &mut HashSet<Utf8PathBuf>,\n    ) -> Result<(), Error> {\n        let name = format!(\"{name}@@main.erl\", name = self.config.name);\n        let path = out.join(&name);\n\n        // If the entrypoint module has already been created then we don't need\n        // to write and compile it again.\n        if self.io.is_file(&path) {\n            tracing::debug!(\"erlang_entrypoint_already_exists\");\n            return Ok(());\n        }\n\n        let template = ErlangEntrypointModule {\n            application: &self.config.name,\n        };\n        let module = template.render().expect(\"Erlang entrypoint rendering\");\n        self.io.write(&path, &module)?;\n        let _ = modules_to_compile.insert(name.into());\n        tracing::debug!(\"erlang_entrypoint_written\");\n        Ok(())\n    }\n\n    fn emit_warnings(\n        &self,\n        warnings: &WarningEmitter,\n        module: &type_::ModuleInterface,\n    ) -> Result<()> {\n        for warning in &module.warnings {\n            let src = self.io.read(&module.src_path)?;\n            warnings.emit(Warning::Type {\n                path: module.src_path.clone(),\n                src: src.into(),\n                warning: warning.clone(),\n            });\n        }\n\n        Ok(())\n    }\n\n    fn stdlib_package(&self) -> StdlibPackage {\n        if self.config.dependencies.contains_key(\"gleam_stdlib\")\n            || self.config.dev_dependencies.contains_key(\"gleam_stdlib\")\n        {\n            StdlibPackage::Present\n        } else {\n            StdlibPackage::Missing\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub enum StdlibPackage {\n    Present,\n    Missing,\n}\n\nfn analyse(\n    package_config: &PackageConfig,\n    target: Target,\n    mode: Mode,\n    ids: &UniqueIdGenerator,\n    mut parsed_modules: Vec<UncompiledModule>,\n    module_types: &mut im::HashMap<EcoString, type_::ModuleInterface>,\n    warnings: &WarningEmitter,\n    target_support: TargetSupport,\n    incomplete_modules: &mut HashSet<EcoString>,\n) -> Outcome<Vec<Module>, Error> {\n    let mut modules = Vec::with_capacity(parsed_modules.len() + 1);\n    let direct_dependencies = package_config.dependencies_for(mode).expect(\"Package deps\");\n    let dev_dependencies = package_config.dev_dependencies.keys().cloned().collect();\n\n    // Insert the prelude\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = module_types.insert(PRELUDE_MODULE_NAME.into(), type_::build_prelude(ids));\n\n    for UncompiledModule {\n        name,\n        code,\n        ast,\n        path,\n        mtime,\n        origin,\n        package,\n        dependencies,\n        extra,\n    } in parsed_modules\n    {\n        tracing::debug!(module = ?name, \"Type checking\");\n\n        let line_numbers = LineNumbers::new(&code);\n\n        let analysis = crate::analyse::ModuleAnalyzerConstructor {\n            target,\n            ids,\n            origin,\n            importable_modules: module_types,\n            warnings: &TypeWarningEmitter::new(path.clone(), code.clone(), warnings.clone()),\n            direct_dependencies: &direct_dependencies,\n            dev_dependencies: &dev_dependencies,\n            target_support,\n            package_config,\n        }\n        .infer_module(ast, line_numbers, path.clone());\n\n        match analysis {\n            Outcome::Ok(ast) => {\n                // Module has compiled successfully. Make sure it isn't marked as incomplete.\n                let _ = incomplete_modules.remove(&name.clone());\n\n                let mut module = Module {\n                    dependencies,\n                    origin,\n                    extra,\n                    mtime,\n                    name,\n                    code,\n                    ast,\n                    input_path: path,\n                };\n                module.attach_doc_and_module_comments();\n\n                // Register the types from this module so they can be imported into\n                // other modules.\n                let _ = module_types.insert(module.name.clone(), module.ast.type_info.clone());\n\n                // Check for empty modules and emit warning\n                // Only emit the empty module warning if the module has no definitions at all.\n                // Modules with only private definitions already emit their own warnings.\n                if module_types\n                    .get(&module.name)\n                    .map(|interface| interface.values.is_empty() && interface.types.is_empty())\n                    .unwrap_or(false)\n                {\n                    warnings.emit(crate::warning::Warning::EmptyModule {\n                        path: module.input_path.clone(),\n                        name: module.name.clone(),\n                    });\n                }\n\n                // Register the successfully type checked module data so that it can be\n                // used for code generation and in the language server.\n                modules.push(module);\n            }\n\n            Outcome::PartialFailure(ast, errors) => {\n                let error = Error::Type {\n                    names: Box::new(ast.names.clone()),\n                    path: path.clone(),\n                    src: code.clone(),\n                    errors,\n                };\n                // Mark as incomplete so that this module isn't reloaded from cache.\n                let _ = incomplete_modules.insert(name.clone());\n                // Register the partially type checked module data so that it can be\n                // used in the language server.\n                let mut module = Module {\n                    dependencies,\n                    origin,\n                    extra,\n                    mtime,\n                    name,\n                    code,\n                    ast,\n                    input_path: path,\n                };\n                module.attach_doc_and_module_comments();\n\n                let _ = module_types.insert(module.ast.name.clone(), module.ast.type_info.clone());\n\n                modules.push(module);\n                // WARNING: This cannot be used for code generation as the code has errors.\n                return Outcome::PartialFailure(modules, error);\n            }\n\n            Outcome::TotalFailure(errors) => {\n                return Outcome::TotalFailure(Error::Type {\n                    names: Default::default(),\n                    path: path.clone(),\n                    src: code.clone(),\n                    errors,\n                });\n            }\n        };\n    }\n\n    Outcome::Ok(modules)\n}\n\n#[derive(Debug)]\npub(crate) enum Input {\n    New(UncompiledModule),\n    Cached(CachedModule),\n}\n\nimpl Input {\n    pub fn name(&self) -> &EcoString {\n        match self {\n            Input::New(m) => &m.name,\n            Input::Cached(m) => &m.name,\n        }\n    }\n\n    pub fn source_path(&self) -> &Utf8Path {\n        match self {\n            Input::New(m) => &m.path,\n            Input::Cached(m) => &m.source_path,\n        }\n    }\n\n    pub fn dependencies(&self) -> Vec<EcoString> {\n        match self {\n            Input::New(m) => m.dependencies.iter().map(|(n, _)| n.clone()).collect(),\n            Input::Cached(m) => m.dependencies.iter().map(|(n, _)| n.clone()).collect(),\n        }\n    }\n\n    /// Returns `true` if the input is [`New`].\n    ///\n    /// [`New`]: Input::New\n    #[must_use]\n    pub(crate) fn is_new(&self) -> bool {\n        matches!(self, Self::New(..))\n    }\n\n    /// Returns `true` if the input is [`Cached`].\n    ///\n    /// [`Cached`]: Input::Cached\n    #[must_use]\n    pub(crate) fn is_cached(&self) -> bool {\n        matches!(self, Self::Cached(..))\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct CachedModule {\n    pub name: EcoString,\n    pub origin: Origin,\n    pub dependencies: Vec<(EcoString, SrcSpan)>,\n    pub source_path: Utf8PathBuf,\n    pub line_numbers: LineNumbers,\n}\n\n#[derive(Debug, serde::Serialize, serde::Deserialize)]\npub(crate) struct CacheMetadata {\n    pub mtime: SystemTime,\n    pub codegen_performed: bool,\n    pub dependencies: Vec<(EcoString, SrcSpan)>,\n    pub fingerprint: SourceFingerprint,\n    pub line_numbers: LineNumbers,\n}\n\nimpl CacheMetadata {\n    pub fn to_binary(&self) -> Vec<u8> {\n        bincode::serde::encode_to_vec(self, bincode::config::legacy())\n            .expect(\"Serializing cache info\")\n    }\n\n    pub fn from_binary(bytes: &[u8]) -> Result<Self, String> {\n        match bincode::serde::decode_from_slice(bytes, bincode::config::legacy()) {\n            Ok((data, _)) => Ok(data),\n            Err(e) => Err(e.to_string()),\n        }\n    }\n}\n\n#[derive(Debug, Default, PartialEq, Eq)]\npub(crate) struct Loaded {\n    pub to_compile: Vec<UncompiledModule>,\n    pub cached: Vec<type_::ModuleInterface>,\n}\n\nimpl Loaded {\n    fn empty() -> Self {\n        Self {\n            to_compile: vec![],\n            cached: vec![],\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub(crate) struct UncompiledModule {\n    pub path: Utf8PathBuf,\n    pub name: EcoString,\n    pub code: EcoString,\n    pub mtime: SystemTime,\n    pub origin: Origin,\n    pub package: EcoString,\n    pub dependencies: Vec<(EcoString, SrcSpan)>,\n    pub ast: UntypedModule,\n    pub extra: ModuleExtra,\n}\n\n#[derive(Template)]\n#[template(path = \"gleam@@main.erl\", escape = \"none\")]\nstruct ErlangEntrypointModule<'a> {\n    application: &'a str,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum CachedWarnings {\n    Use,\n    Ignore,\n}\nimpl CachedWarnings {\n    pub(crate) fn should_use(&self) -> bool {\n        match self {\n            CachedWarnings::Use => true,\n            CachedWarnings::Ignore => false,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum CheckModuleConflicts {\n    Check,\n    DoNotCheck,\n}\nimpl CheckModuleConflicts {\n    pub(crate) fn should_check(&self) -> bool {\n        match self {\n            CheckModuleConflicts::Check => true,\n            CheckModuleConflicts::DoNotCheck => false,\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/build/package_loader/tests.rs",
    "content": "use ecow::{EcoString, eco_format};\nuse hexpm::version::Version;\n\nuse super::*;\nuse crate::{\n    Warning,\n    build::SourceFingerprint,\n    io::{FileSystemWriter, memory::InMemoryFileSystem},\n    line_numbers,\n    parse::extra::ModuleExtra,\n    warning::NullWarningEmitterIO,\n};\n\nuse std::time::Duration;\n\n#[derive(Debug)]\nstruct LoaderTestOutput {\n    to_compile: Vec<EcoString>,\n    cached: Vec<EcoString>,\n    warnings: Vec<Warning>,\n}\n\nconst TEST_SOURCE_1: &'static str = \"const x = 1\";\nconst TEST_SOURCE_2: &'static str = \"const x = 2\";\n\nfn write_src(fs: &InMemoryFileSystem, path: &str, seconds: u64, src: &str) {\n    let path = Utf8Path::new(path);\n    fs.write(&path, src).unwrap();\n    fs.set_modification_time(&path, SystemTime::UNIX_EPOCH + Duration::from_secs(seconds));\n}\n\nfn write_cache(\n    fs: &InMemoryFileSystem,\n    name: &str,\n    seconds: u64,\n    deps: Vec<(EcoString, SrcSpan)>,\n    src: &str,\n) {\n    let line_numbers = line_numbers::LineNumbers::new(src);\n    let mtime = SystemTime::UNIX_EPOCH + Duration::from_secs(seconds);\n    let cache_metadata = CacheMetadata {\n        mtime,\n        codegen_performed: true,\n        dependencies: deps,\n        fingerprint: SourceFingerprint::new(src),\n        line_numbers: line_numbers.clone(),\n    };\n\n    let artefact_name = name.replace(\"/\", \"@\");\n    let path = Utf8Path::new(\"/artefact\").join(format!(\"{artefact_name}.cache_meta\"));\n    fs.write_bytes(&path, &cache_metadata.to_binary()).unwrap();\n\n    let cache = crate::type_::ModuleInterface {\n        name: name.into(),\n        origin: Origin::Src,\n        package: \"my_package\".into(),\n        types: Default::default(),\n        types_value_constructors: Default::default(),\n        values: Default::default(),\n        accessors: Default::default(),\n        line_numbers: line_numbers.clone(),\n        is_internal: false,\n        src_path: Utf8PathBuf::from(format!(\"/src/{}.gleam\", name)),\n        warnings: vec![],\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: Default::default(),\n        documentation: Default::default(),\n        contains_echo: false,\n        references: Default::default(),\n        inline_functions: Default::default(),\n    };\n    let path = Utf8Path::new(\"/artefact\").join(format!(\"{artefact_name}.cache\"));\n    fs.write_bytes(&path, &metadata::encode(&cache).unwrap())\n        .unwrap();\n}\n\nfn run_loader(fs: InMemoryFileSystem, root: &Utf8Path, artefact: &Utf8Path) -> LoaderTestOutput {\n    let mut defined = im::HashMap::new();\n    let ids = UniqueIdGenerator::new();\n    let (emitter, warnings) = WarningEmitter::vector();\n\n    let loader = PackageLoader {\n        io: fs.clone(),\n        ids,\n        mode: Mode::Dev,\n        paths: ProjectPaths::new(root.into()),\n        warnings: &emitter,\n        codegen: CodegenRequired::Yes,\n        artefact_directory: &artefact,\n        package_name: &\"my_package\".into(),\n        target: Target::JavaScript,\n        stale_modules: &mut StaleTracker::default(),\n        already_defined_modules: &mut defined,\n        incomplete_modules: &mut HashSet::new(),\n        cached_warnings: CachedWarnings::Ignore,\n    };\n    let loaded = loader.run().unwrap();\n\n    LoaderTestOutput {\n        to_compile: loaded.to_compile.into_iter().map(|m| m.name).collect(),\n        cached: loaded.cached.into_iter().map(|m| m.name).collect(),\n        warnings: warnings.take(),\n    }\n}\n\n#[test]\nfn no_modules() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n}\n\n#[test]\nfn one_src_module() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    write_src(&fs, \"/src/main.gleam\", 0, \"const x = 1\");\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(loaded.to_compile, vec![EcoString::from(\"main\")]);\n    assert!(loaded.cached.is_empty());\n}\n\n#[test]\nfn one_test_module() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    write_src(&fs, \"/test/main.gleam\", 0, \"const x = 1\");\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(loaded.to_compile, vec![EcoString::from(\"main\")]);\n    assert!(loaded.cached.is_empty());\n}\n\n#[test]\nfn one_dev_module() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    write_src(&fs, \"/dev/main.gleam\", 0, \"const x = 1\");\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(loaded.to_compile, vec![EcoString::from(\"main\")]);\n    assert!(loaded.cached.is_empty());\n}\n\n#[test]\nfn importing() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    write_src(&fs, \"/src/three.gleam\", 0, \"import two\");\n    write_src(&fs, \"/src/one.gleam\", 0, \"\");\n    write_src(&fs, \"/src/two.gleam\", 0, \"import one\");\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(\n        loaded.to_compile,\n        vec![\n            EcoString::from(\"one\"),\n            EcoString::from(\"two\"),\n            EcoString::from(\"three\")\n        ]\n    );\n    assert!(loaded.cached.is_empty());\n}\n\n#[test]\nfn reading_cache() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    write_src(&fs, \"/src/one.gleam\", 0, TEST_SOURCE_1);\n    write_cache(&fs, \"one\", 0, vec![], TEST_SOURCE_1);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert_eq!(loaded.cached, vec![EcoString::from(\"one\")]);\n}\n\n#[test]\nfn module_is_stale_if_cache_older() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    write_src(&fs, \"/src/one.gleam\", 1, TEST_SOURCE_2);\n    write_cache(&fs, \"one\", 0, vec![], TEST_SOURCE_1);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(loaded.to_compile, vec![EcoString::from(\"one\")]);\n    assert!(loaded.cached.is_empty());\n}\n\n#[test]\nfn module_is_stale_if_deps_are_stale() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/src/one.gleam\", 1, TEST_SOURCE_2);\n    write_cache(&fs, \"one\", 0, vec![], TEST_SOURCE_1);\n\n    // Cache is fresh but dep is stale\n    write_src(&fs, \"/src/two.gleam\", 1, \"import one\");\n    write_cache(\n        &fs,\n        \"two\",\n        2,\n        vec![(EcoString::from(\"one\"), SrcSpan { start: 0, end: 0 })],\n        \"import one\",\n    );\n\n    // Cache is fresh\n    write_src(&fs, \"/src/three.gleam\", 1, TEST_SOURCE_1);\n    write_cache(&fs, \"three\", 2, vec![], TEST_SOURCE_1);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(\n        loaded.to_compile,\n        vec![EcoString::from(\"one\"), EcoString::from(\"two\")]\n    );\n    assert_eq!(loaded.cached, vec![EcoString::from(\"three\")]);\n}\n\n#[test]\nfn module_is_stale_if_deps_removed() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Source is removed, cache is present\n    write_cache(&fs, \"nested/one\", 0, vec![], TEST_SOURCE_1);\n\n    // Cache is fresh but dep is removed\n    write_src(&fs, \"/src/two.gleam\", 1, \"import one\");\n    write_cache(\n        &fs,\n        \"two\",\n        2,\n        vec![(EcoString::from(\"nested/one\"), SrcSpan { start: 0, end: 0 })],\n        \"import nested/one\",\n    );\n\n    let loaded = run_loader(fs, root, artefact);\n    assert_eq!(loaded.to_compile, vec![EcoString::from(\"two\")]);\n}\n\n#[test]\nfn module_continues_to_be_stale_if_deps_get_updated() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/src/one.gleam\", 1, TEST_SOURCE_2);\n    write_cache(&fs, \"one\", 0, vec![], TEST_SOURCE_1);\n\n    // Cache is fresh but dep is stale\n    write_src(&fs, \"/src/two.gleam\", 1, \"import one\");\n    write_cache(\n        &fs,\n        \"two\",\n        2,\n        vec![(EcoString::from(\"one\"), SrcSpan { start: 0, end: 0 })],\n        \"import one\",\n    );\n\n    // Cache is fresh\n    write_src(&fs, \"/src/three.gleam\", 1, TEST_SOURCE_1);\n    write_cache(&fs, \"three\", 2, vec![], TEST_SOURCE_1);\n\n    let _loaded1 = run_loader(fs.clone(), root, artefact);\n\n    // update the dependency\n    write_cache(&fs, \"one\", 3, vec![], TEST_SOURCE_2);\n    let loaded2 = run_loader(fs, root, artefact);\n\n    assert_eq!(loaded2.to_compile, vec![EcoString::from(\"two\")]);\n    assert_eq!(\n        loaded2.cached,\n        vec![EcoString::from(\"one\"), EcoString::from(\"three\")]\n    );\n}\n\n#[test]\nfn invalid_module_name() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/src/One.gleam\", 1, TEST_SOURCE_2);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n    assert_eq!(\n        loaded.warnings,\n        vec![Warning::InvalidSource {\n            path: Utf8PathBuf::from(\"/src/One.gleam\"),\n        }],\n    );\n}\n\n#[test]\nfn invalid_nested_module_name() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/src/1/one.gleam\", 1, TEST_SOURCE_2);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n    assert_eq!(\n        loaded.warnings,\n        vec![Warning::InvalidSource {\n            path: Utf8PathBuf::from(\"/src/1/one.gleam\"),\n        }],\n    );\n}\n\n#[test]\nfn invalid_module_name_in_test() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/test/One.gleam\", 1, TEST_SOURCE_2);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n    assert_eq!(\n        loaded.warnings,\n        vec![Warning::InvalidSource {\n            path: Utf8PathBuf::from(\"/test/One.gleam\"),\n        }],\n    );\n}\n\n#[test]\nfn invalid_nested_module_name_in_test() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/test/1/one.gleam\", 1, TEST_SOURCE_2);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n    assert_eq!(\n        loaded.warnings,\n        vec![Warning::InvalidSource {\n            path: Utf8PathBuf::from(\"/test/1/one.gleam\"),\n        }],\n    );\n}\n\n#[test]\nfn invalid_module_name_in_dev() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/dev/One.gleam\", 1, TEST_SOURCE_2);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n    assert_eq!(\n        loaded.warnings,\n        vec![Warning::InvalidSource {\n            path: Utf8PathBuf::from(\"/dev/One.gleam\"),\n        }],\n    );\n}\n\n#[test]\nfn invalid_nested_module_name_in_dev() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Cache is stale\n    write_src(&fs, \"/dev/1/one.gleam\", 1, TEST_SOURCE_2);\n\n    let loaded = run_loader(fs, root, artefact);\n    assert!(loaded.to_compile.is_empty());\n    assert!(loaded.cached.is_empty());\n    assert_eq!(\n        loaded.warnings,\n        vec![Warning::InvalidSource {\n            path: Utf8PathBuf::from(\"/dev/1/one.gleam\"),\n        }],\n    );\n}\n\n#[test]\nfn cache_files_are_removed_when_source_removed() {\n    let fs = InMemoryFileSystem::new();\n    let root = Utf8Path::new(\"/\");\n    let artefact = Utf8Path::new(\"/artefact\");\n\n    // Source is removed, cache is present\n    write_cache(&fs, \"nested/one\", 0, vec![], TEST_SOURCE_1);\n\n    _ = run_loader(fs.clone(), root, artefact);\n\n    assert_eq!(fs.files().len(), 0);\n}\n"
  },
  {
    "path": "compiler-core/src/build/package_loader.rs",
    "content": "#[cfg(test)]\nmod tests;\n\nuse std::{\n    collections::{HashMap, HashSet},\n    time::{Duration, SystemTime},\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\n// TODO: emit warnings for cached modules even if they are not compiled again.\n\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse vec1::Vec1;\n\nuse crate::{\n    Error, Result,\n    ast::SrcSpan,\n    build::{Module, Origin, module_loader::ModuleLoader},\n    config::PackageConfig,\n    dep_tree,\n    error::{DefinedModuleOrigin, FileIoAction, FileKind, ImportCycleLocationDetails},\n    io::{self, CommandExecutor, FileSystemReader, FileSystemWriter, files_with_extension},\n    metadata,\n    paths::ProjectPaths,\n    type_,\n    uid::UniqueIdGenerator,\n    warning::WarningEmitter,\n};\n\nuse super::{\n    Mode, Target,\n    module_loader::read_source,\n    package_compiler::{\n        CacheMetadata, CachedModule, CachedWarnings, Input, Loaded, UncompiledModule,\n    },\n};\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum CodegenRequired {\n    Yes,\n    No,\n}\n\nimpl CodegenRequired {\n    /// Returns `true` if the codegen required is [`Yes`].\n    ///\n    /// [`Yes`]: CodegenRequired::Yes\n    #[must_use]\n    pub fn is_required(&self) -> bool {\n        matches!(self, Self::Yes)\n    }\n}\n\n#[derive(Debug)]\npub struct PackageLoader<'a, IO> {\n    io: IO,\n    ids: UniqueIdGenerator,\n    mode: Mode,\n    paths: ProjectPaths,\n    warnings: &'a WarningEmitter,\n    codegen: CodegenRequired,\n    artefact_directory: &'a Utf8Path,\n    package_name: &'a EcoString,\n    target: Target,\n    stale_modules: &'a mut StaleTracker,\n    already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,\n    incomplete_modules: &'a HashSet<EcoString>,\n    cached_warnings: CachedWarnings,\n}\n\nimpl<'a, IO> PackageLoader<'a, IO>\nwhere\n    IO: FileSystemWriter + FileSystemReader + CommandExecutor + Clone,\n{\n    pub(crate) fn new(\n        io: IO,\n        ids: UniqueIdGenerator,\n        mode: Mode,\n        root: &'a Utf8Path,\n        cached_warnings: CachedWarnings,\n        warnings: &'a WarningEmitter,\n        codegen: CodegenRequired,\n        artefact_directory: &'a Utf8Path,\n        target: Target,\n        package_name: &'a EcoString,\n        stale_modules: &'a mut StaleTracker,\n        already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,\n        incomplete_modules: &'a HashSet<EcoString>,\n    ) -> Self {\n        Self {\n            io,\n            ids,\n            mode,\n            paths: ProjectPaths::new(root.into()),\n            warnings,\n            codegen,\n            target,\n            package_name,\n            cached_warnings,\n            artefact_directory,\n            stale_modules,\n            already_defined_modules,\n            incomplete_modules,\n        }\n    }\n\n    pub(crate) fn run(mut self) -> Result<Loaded> {\n        // First read the source files. This will use the `ModuleLoader`, which\n        // will check the mtimes and hashes of sources and caches to determine\n        // which should be loaded.\n        let mut inputs = self.read_sources_and_caches()?;\n\n        // Check for any removed modules, by looking at cache files that don't exist in inputs.\n        // Delete the cache files for removed modules and mark them as stale\n        // to trigger refreshing dependent modules.\n        for module in CacheFiles::modules_with_meta_files(&self.io, &self.artefact_directory) {\n            if (!inputs.contains_key(&module)) {\n                tracing::debug!(%module, \"module_removed\");\n                CacheFiles::new(&self.artefact_directory, &module).delete(&self.io)?;\n                self.stale_modules.add(module);\n            }\n        }\n\n        // Determine order in which modules are to be processed\n        let mut dep_location_map = HashMap::new();\n        let deps = inputs\n            .values()\n            .map(|(_, module)| {\n                let name = module.name().clone();\n                let _ = dep_location_map.insert(name.clone(), module);\n                (name, module.dependencies())\n            })\n            // Making sure that the module order is deterministic, to prevent different\n            // compilations of the same project compiling in different orders. This could impact\n            // any bugged outcomes, though not any where the compiler is working correctly, so it's\n            // mostly to aid debugging.\n            .sorted_by(|(a, _), (b, _)| a.cmp(b))\n            .collect();\n        let sequence = dep_tree::toposort_deps(deps)\n            .map_err(|error| self.convert_deps_tree_error(error, dep_location_map))?;\n\n        // Now that we have loaded sources and caches we check to see if any of\n        // the caches need to be invalidated because their dependencies have\n        // changed.\n        let mut loaded = Loaded::default();\n        for name in sequence {\n            let (_, input) = inputs\n                .remove(&name)\n                .expect(\"Getting parsed module for name\");\n\n            match input {\n                // A new uncached module is to be compiled\n                Input::New(module) => {\n                    tracing::debug!(module = %module.name, \"new_module_to_be_compiled\");\n                    self.stale_modules.add(module.name.clone());\n                    loaded.to_compile.push(module);\n                }\n\n                // A cached module with dependencies that are stale must be\n                // recompiled as the changes in the dependencies may have affect\n                // the output, making the cache invalid.\n                Input::Cached(info) if self.stale_modules.includes_any(&info.dependencies) => {\n                    tracing::debug!(module = %info.name, \"stale_module_to_be_compiled\");\n                    self.stale_modules.add(info.name.clone());\n                    let module = self.load_stale_module(info)?;\n                    loaded.to_compile.push(module);\n                }\n\n                // A cached module with no stale dependencies can be used as-is\n                // and does not need to be recompiled.\n                Input::Cached(info) => {\n                    tracing::debug!(module = %info.name, \"module_to_load_from_cache\");\n                    let module = self.load_cached_module(info)?;\n                    loaded.cached.push(module);\n                }\n            }\n        }\n\n        Ok(loaded)\n    }\n\n    fn load_cached_module(&self, info: CachedModule) -> Result<type_::ModuleInterface, Error> {\n        let cache_files = CacheFiles::new(&self.artefact_directory, &info.name);\n        let bytes = self.io.read_bytes(&cache_files.cache_path)?;\n        let mut module = match metadata::decode(bytes.as_slice(), self.ids.clone()) {\n            Ok(module) => module,\n            Err(e) => {\n                return Err(Error::FileIo {\n                    kind: FileKind::File,\n                    action: FileIoAction::Parse,\n                    path: cache_files.cache_path,\n                    err: Some(e.to_string()),\n                });\n            }\n        };\n\n        // Discard warnings if they should not be cached\n        if !self.cached_warnings.should_use() {\n            module.warnings.clear();\n        }\n\n        Ok(module)\n    }\n\n    fn read_sources_and_caches(\n        &mut self,\n    ) -> Result<HashMap<EcoString, (DefinedModuleOrigin, Input)>> {\n        let span = tracing::info_span!(\"load\");\n        let _enter = span.enter();\n\n        let mut inputs = Inputs::new(self.package_name.clone(), self.already_defined_modules);\n\n        let src = self.paths.src_directory();\n        let mut loader = ModuleLoader {\n            io: self.io.clone(),\n            warnings: self.warnings,\n            mode: self.mode,\n            target: self.target,\n            codegen: self.codegen,\n            package_name: self.package_name,\n            artefact_directory: self.artefact_directory,\n            origin: Origin::Src,\n            incomplete_modules: self.incomplete_modules,\n        };\n\n        // Src\n        for file in GleamFile::iterate_files_in_directory(&self.io, &src) {\n            match file {\n                Ok(file) => {\n                    let input = loader.load(file)?;\n                    inputs.insert(input)?;\n                }\n                Err(warning) => self.warnings.emit(warning),\n            }\n        }\n\n        // Test and dev\n        if self.mode.includes_dev_code() {\n            let test = self.paths.test_directory();\n            loader.origin = Origin::Test;\n\n            for file in GleamFile::iterate_files_in_directory(&self.io, &test) {\n                match file {\n                    Ok(file) => {\n                        let input = loader.load(file)?;\n                        inputs.insert(input)?;\n                    }\n                    Err(warning) => self.warnings.emit(warning),\n                }\n            }\n\n            let dev = self.paths.dev_directory();\n            loader.origin = Origin::Dev;\n\n            for file in GleamFile::iterate_files_in_directory(&self.io, &dev) {\n                match file {\n                    Ok(file) => {\n                        let input = loader.load(file)?;\n                        inputs.insert(input)?;\n                    }\n                    Err(warning) => self.warnings.emit(warning),\n                }\n            }\n        }\n\n        // If we are compiling for Erlang then modules all live in a single\n        // namespace. If we were to name a module the same as a module that\n        // is included in the standard Erlang distribution then this new\n        // Gleam module would overwrite the existing Erlang one, likely\n        // resulting in cryptic errors.\n        // This would most commonly happen for modules like \"user\" and\n        // \"code\". Emit an error so this never happens.\n        if self.target.is_erlang() {\n            for (_, input) in inputs.collection.values() {\n                ensure_gleam_module_does_not_overwrite_standard_erlang_module(&input)?;\n            }\n        }\n\n        Ok(inputs.collection)\n    }\n\n    fn load_stale_module(&self, cached: CachedModule) -> Result<UncompiledModule> {\n        let mtime = self.io.modification_time(&cached.source_path)?;\n\n        // We need to delete any existing cache files for this module.\n        // While we figured it out this time because the module has stale dependencies,\n        // next time the dependencies might no longer be stale, but we still need to be able to tell\n        // that this module needs to be recompiled until it successfully compiles at least once.\n        // This can happen if the stale dependency includes breaking changes.\n        CacheFiles::new(&self.artefact_directory, &cached.name).delete(&self.io)?;\n\n        read_source(\n            self.io.clone(),\n            self.target,\n            cached.origin,\n            cached.source_path,\n            cached.name,\n            self.package_name.clone(),\n            mtime,\n            self.warnings.clone(),\n        )\n    }\n\n    fn convert_deps_tree_error(\n        &self,\n        e: dep_tree::Error,\n        dep_location_map: HashMap<EcoString, &Input>,\n    ) -> Error {\n        match e {\n            dep_tree::Error::Cycle(modules) => {\n                let modules = modules\n                    .iter()\n                    .enumerate()\n                    .map(|(i, module)| {\n                        // cycles are in order of reference so get next in list or loop back to first\n                        let index_of_imported = if i == 0 { modules.len() - 1 } else { i - 1 };\n                        let imported_module = modules\n                            .get(index_of_imported)\n                            .expect(\"importing module must exist\");\n                        let input = dep_location_map.get(module).expect(\"dependency must exist\");\n                        let location = match input {\n                            Input::New(module) => {\n                                let (_, location) = module\n                                    .dependencies\n                                    .iter()\n                                    .find(|d| &d.0 == imported_module)\n                                    .expect(\"import must exist for there to be a cycle\");\n                                ImportCycleLocationDetails {\n                                    location: *location,\n                                    path: module.path.clone(),\n                                    src: module.code.clone(),\n                                }\n                            }\n                            Input::Cached(cached_module) => {\n                                let (_, location) = cached_module\n                                    .dependencies\n                                    .iter()\n                                    .find(|d| &d.0 == imported_module)\n                                    .expect(\"import must exist for there to be a cycle\");\n                                let src = self\n                                    .io\n                                    .read(&cached_module.source_path)\n                                    .expect(\"failed to read source\")\n                                    .into();\n                                ImportCycleLocationDetails {\n                                    location: *location,\n                                    path: cached_module.source_path.clone(),\n                                    src,\n                                }\n                            }\n                        };\n                        (module.clone(), location)\n                    })\n                    .collect_vec();\n                Error::ImportCycle {\n                    modules: Vec1::try_from(modules)\n                        .expect(\"at least 1 module must exist in cycle\"),\n                }\n            }\n        }\n    }\n}\n\nfn ensure_gleam_module_does_not_overwrite_standard_erlang_module(input: &Input) -> Result<()> {\n    // We only need to check uncached modules as it's not possible for these\n    // to have compiled successfully.\n    let Input::New(input) = input else {\n        return Ok(());\n    };\n\n    // These names were got with this Erlang\n    //\n    // ```erl\n    // file:write_file(\"names.txt\", lists:join(\"\\n\",lists:map(fun(T) -> erlang:element(1, T) end, code:all_available()))).\n    // ```\n    //\n    match input.name.as_str() {\n        \"alarm_handler\"\n        | \"application\"\n        | \"application_controller\"\n        | \"application_master\"\n        | \"application_starter\"\n        | \"appmon_info\"\n        | \"argparse\"\n        | \"array\"\n        | \"asn1_db\"\n        | \"asn1ct\"\n        | \"asn1ct_check\"\n        | \"asn1ct_constructed_ber_bin_v2\"\n        | \"asn1ct_constructed_per\"\n        | \"asn1ct_eval_ext\"\n        | \"asn1ct_func\"\n        | \"asn1ct_gen\"\n        | \"asn1ct_gen_ber_bin_v2\"\n        | \"asn1ct_gen_check\"\n        | \"asn1ct_gen_jer\"\n        | \"asn1ct_gen_per\"\n        | \"asn1ct_imm\"\n        | \"asn1ct_name\"\n        | \"asn1ct_parser2\"\n        | \"asn1ct_pretty_format\"\n        | \"asn1ct_rtt\"\n        | \"asn1ct_table\"\n        | \"asn1ct_tok\"\n        | \"asn1ct_value\"\n        | \"asn1rt_nif\"\n        | \"atomics\"\n        | \"auth\"\n        | \"base64\"\n        | \"beam_a\"\n        | \"beam_asm\"\n        | \"beam_block\"\n        | \"beam_bounds\"\n        | \"beam_call_types\"\n        | \"beam_clean\"\n        | \"beam_dict\"\n        | \"beam_digraph\"\n        | \"beam_disasm\"\n        | \"beam_flatten\"\n        | \"beam_jump\"\n        | \"beam_kernel_to_ssa\"\n        | \"beam_lib\"\n        | \"beam_listing\"\n        | \"beam_opcodes\"\n        | \"beam_ssa\"\n        | \"beam_ssa_alias\"\n        | \"beam_ssa_bc_size\"\n        | \"beam_ssa_bool\"\n        | \"beam_ssa_bsm\"\n        | \"beam_ssa_check\"\n        | \"beam_ssa_codegen\"\n        | \"beam_ssa_dead\"\n        | \"beam_ssa_lint\"\n        | \"beam_ssa_opt\"\n        | \"beam_ssa_pp\"\n        | \"beam_ssa_pre_codegen\"\n        | \"beam_ssa_private_append\"\n        | \"beam_ssa_recv\"\n        | \"beam_ssa_share\"\n        | \"beam_ssa_throw\"\n        | \"beam_ssa_type\"\n        | \"beam_trim\"\n        | \"beam_types\"\n        | \"beam_utils\"\n        | \"beam_validator\"\n        | \"beam_z\"\n        | \"binary\"\n        | \"c\"\n        | \"calendar\"\n        | \"cdv_atom_cb\"\n        | \"cdv_bin_cb\"\n        | \"cdv_detail_wx\"\n        | \"cdv_dist_cb\"\n        | \"cdv_ets_cb\"\n        | \"cdv_fun_cb\"\n        | \"cdv_gen_cb\"\n        | \"cdv_html_wx\"\n        | \"cdv_info_wx\"\n        | \"cdv_int_tab_cb\"\n        | \"cdv_mem_cb\"\n        | \"cdv_mod_cb\"\n        | \"cdv_multi_wx\"\n        | \"cdv_persistent_cb\"\n        | \"cdv_port_cb\"\n        | \"cdv_proc_cb\"\n        | \"cdv_sched_cb\"\n        | \"cdv_table_wx\"\n        | \"cdv_term_cb\"\n        | \"cdv_timer_cb\"\n        | \"cdv_virtual_list_wx\"\n        | \"cdv_wx\"\n        | \"cerl\"\n        | \"cerl_clauses\"\n        | \"cerl_inline\"\n        | \"cerl_prettypr\"\n        | \"cerl_trees\"\n        | \"code\"\n        | \"code_server\"\n        | \"compile\"\n        | \"core_lib\"\n        | \"core_lint\"\n        | \"core_parse\"\n        | \"core_pp\"\n        | \"core_scan\"\n        | \"counters\"\n        | \"cover\"\n        | \"cprof\"\n        | \"cpu_sup\"\n        | \"crashdump_viewer\"\n        | \"crypto\"\n        | \"crypto_ec_curves\"\n        | \"ct\"\n        | \"ct_config\"\n        | \"ct_config_plain\"\n        | \"ct_config_xml\"\n        | \"ct_conn_log_h\"\n        | \"ct_cover\"\n        | \"ct_default_gl\"\n        | \"ct_event\"\n        | \"ct_framework\"\n        | \"ct_ftp\"\n        | \"ct_gen_conn\"\n        | \"ct_groups\"\n        | \"ct_hooks\"\n        | \"ct_hooks_lock\"\n        | \"ct_logs\"\n        | \"ct_make\"\n        | \"ct_master\"\n        | \"ct_master_event\"\n        | \"ct_master_logs\"\n        | \"ct_master_status\"\n        | \"ct_netconfc\"\n        | \"ct_property_test\"\n        | \"ct_release_test\"\n        | \"ct_repeat\"\n        | \"ct_rpc\"\n        | \"ct_run\"\n        | \"ct_slave\"\n        | \"ct_snmp\"\n        | \"ct_ssh\"\n        | \"ct_suite\"\n        | \"ct_telnet\"\n        | \"ct_telnet_client\"\n        | \"ct_testspec\"\n        | \"ct_util\"\n        | \"cth_conn_log\"\n        | \"cth_log_redirect\"\n        | \"cth_surefire\"\n        | \"dbg\"\n        | \"dbg_debugged\"\n        | \"dbg_icmd\"\n        | \"dbg_idb\"\n        | \"dbg_ieval\"\n        | \"dbg_iload\"\n        | \"dbg_iserver\"\n        | \"dbg_istk\"\n        | \"dbg_wx_break\"\n        | \"dbg_wx_break_win\"\n        | \"dbg_wx_code\"\n        | \"dbg_wx_filedialog_win\"\n        | \"dbg_wx_interpret\"\n        | \"dbg_wx_mon\"\n        | \"dbg_wx_mon_win\"\n        | \"dbg_wx_settings\"\n        | \"dbg_wx_src_view\"\n        | \"dbg_wx_trace\"\n        | \"dbg_wx_trace_win\"\n        | \"dbg_wx_view\"\n        | \"dbg_wx_win\"\n        | \"dbg_wx_winman\"\n        | \"debugger\"\n        | \"dets\"\n        | \"dets_server\"\n        | \"dets_sup\"\n        | \"dets_utils\"\n        | \"dets_v9\"\n        | \"dialyzer\"\n        | \"dialyzer_analysis_callgraph\"\n        | \"dialyzer_behaviours\"\n        | \"dialyzer_callgraph\"\n        | \"dialyzer_cl\"\n        | \"dialyzer_cl_parse\"\n        | \"dialyzer_clean_core\"\n        | \"dialyzer_codeserver\"\n        | \"dialyzer_contracts\"\n        | \"dialyzer_coordinator\"\n        | \"dialyzer_cplt\"\n        | \"dialyzer_dataflow\"\n        | \"dialyzer_dep\"\n        | \"dialyzer_dot\"\n        | \"dialyzer_explanation\"\n        | \"dialyzer_gui_wx\"\n        | \"dialyzer_incremental\"\n        | \"dialyzer_iplt\"\n        | \"dialyzer_options\"\n        | \"dialyzer_plt\"\n        | \"dialyzer_succ_typings\"\n        | \"dialyzer_timing\"\n        | \"dialyzer_typegraph\"\n        | \"dialyzer_typesig\"\n        | \"dialyzer_utils\"\n        | \"dialyzer_worker\"\n        | \"diameter\"\n        | \"diameter_app\"\n        | \"diameter_callback\"\n        | \"diameter_capx\"\n        | \"diameter_codec\"\n        | \"diameter_codegen\"\n        | \"diameter_config\"\n        | \"diameter_config_sup\"\n        | \"diameter_dbg\"\n        | \"diameter_dict_parser\"\n        | \"diameter_dict_scanner\"\n        | \"diameter_dict_util\"\n        | \"diameter_dist\"\n        | \"diameter_etcp\"\n        | \"diameter_etcp_sup\"\n        | \"diameter_exprecs\"\n        | \"diameter_gen\"\n        | \"diameter_gen_acct_rfc6733\"\n        | \"diameter_gen_base_accounting\"\n        | \"diameter_gen_base_rfc3588\"\n        | \"diameter_gen_base_rfc6733\"\n        | \"diameter_gen_doic_rfc7683\"\n        | \"diameter_gen_relay\"\n        | \"diameter_info\"\n        | \"diameter_lib\"\n        | \"diameter_make\"\n        | \"diameter_misc_sup\"\n        | \"diameter_peer\"\n        | \"diameter_peer_fsm\"\n        | \"diameter_peer_fsm_sup\"\n        | \"diameter_reg\"\n        | \"diameter_sctp\"\n        | \"diameter_sctp_sup\"\n        | \"diameter_service\"\n        | \"diameter_service_sup\"\n        | \"diameter_session\"\n        | \"diameter_stats\"\n        | \"diameter_sup\"\n        | \"diameter_sync\"\n        | \"diameter_tcp\"\n        | \"diameter_tcp_sup\"\n        | \"diameter_traffic\"\n        | \"diameter_transport\"\n        | \"diameter_transport_sup\"\n        | \"diameter_types\"\n        | \"diameter_watchdog\"\n        | \"diameter_watchdog_sup\"\n        | \"dict\"\n        | \"digraph\"\n        | \"digraph_utils\"\n        | \"disk_log\"\n        | \"disk_log_1\"\n        | \"disk_log_server\"\n        | \"disk_log_sup\"\n        | \"disksup\"\n        | \"dist_ac\"\n        | \"dist_util\"\n        | \"docgen_edoc_xml_cb\"\n        | \"docgen_otp_specs\"\n        | \"docgen_xmerl_xml_cb\"\n        | \"docgen_xml_to_chunk\"\n        | \"dtls_connection\"\n        | \"dtls_connection_sup\"\n        | \"dtls_gen_connection\"\n        | \"dtls_handshake\"\n        | \"dtls_listener_sup\"\n        | \"dtls_packet_demux\"\n        | \"dtls_record\"\n        | \"dtls_server_session_cache_sup\"\n        | \"dtls_server_sup\"\n        | \"dtls_socket\"\n        | \"dtls_sup\"\n        | \"dtls_v1\"\n        | \"dyntrace\"\n        | \"edlin\"\n        | \"edlin_context\"\n        | \"edlin_expand\"\n        | \"edlin_key\"\n        | \"edlin_type_suggestion\"\n        | \"edoc\"\n        | \"edoc_cli\"\n        | \"edoc_data\"\n        | \"edoc_doclet\"\n        | \"edoc_doclet_chunks\"\n        | \"edoc_extract\"\n        | \"edoc_layout\"\n        | \"edoc_layout_chunks\"\n        | \"edoc_lib\"\n        | \"edoc_macros\"\n        | \"edoc_parser\"\n        | \"edoc_refs\"\n        | \"edoc_report\"\n        | \"edoc_run\"\n        | \"edoc_scanner\"\n        | \"edoc_specs\"\n        | \"edoc_tags\"\n        | \"edoc_types\"\n        | \"edoc_wiki\"\n        | \"eldap\"\n        | \"epp\"\n        | \"epp_dodger\"\n        | \"eprof\"\n        | \"erl2html2\"\n        | \"erl_abstract_code\"\n        | \"erl_anno\"\n        | \"erl_bif_types\"\n        | \"erl_bifs\"\n        | \"erl_bits\"\n        | \"erl_boot_server\"\n        | \"erl_comment_scan\"\n        | \"erl_compile\"\n        | \"erl_compile_server\"\n        | \"erl_ddll\"\n        | \"erl_distribution\"\n        | \"erl_epmd\"\n        | \"erl_error\"\n        | \"erl_erts_errors\"\n        | \"erl_eval\"\n        | \"erl_expand_records\"\n        | \"erl_features\"\n        | \"erl_init\"\n        | \"erl_internal\"\n        | \"erl_kernel_errors\"\n        | \"erl_lint\"\n        | \"erl_parse\"\n        | \"erl_posix_msg\"\n        | \"erl_pp\"\n        | \"erl_prettypr\"\n        | \"erl_prim_loader\"\n        | \"erl_recomment\"\n        | \"erl_reply\"\n        | \"erl_scan\"\n        | \"erl_signal_handler\"\n        | \"erl_stdlib_errors\"\n        | \"erl_syntax\"\n        | \"erl_syntax_lib\"\n        | \"erl_tar\"\n        | \"erl_tracer\"\n        | \"erl_types\"\n        | \"erlang\"\n        | \"erlsrv\"\n        | \"erpc\"\n        | \"error_handler\"\n        | \"error_logger\"\n        | \"error_logger_file_h\"\n        | \"error_logger_tty_h\"\n        | \"erts_alloc_config\"\n        | \"erts_code_purger\"\n        | \"erts_debug\"\n        | \"erts_dirty_process_signal_handler\"\n        | \"erts_internal\"\n        | \"erts_literal_area_collector\"\n        | \"escript\"\n        | \"et\"\n        | \"et_collector\"\n        | \"et_selector\"\n        | \"et_viewer\"\n        | \"et_wx_contents_viewer\"\n        | \"et_wx_viewer\"\n        | \"etop\"\n        | \"etop_tr\"\n        | \"etop_txt\"\n        | \"ets\"\n        | \"eunit\"\n        | \"eunit_autoexport\"\n        | \"eunit_data\"\n        | \"eunit_lib\"\n        | \"eunit_listener\"\n        | \"eunit_proc\"\n        | \"eunit_serial\"\n        | \"eunit_server\"\n        | \"eunit_striptests\"\n        | \"eunit_surefire\"\n        | \"eunit_test\"\n        | \"eunit_tests\"\n        | \"eunit_tty\"\n        | \"eval_bits\"\n        | \"file\"\n        | \"file_io_server\"\n        | \"file_server\"\n        | \"file_sorter\"\n        | \"filelib\"\n        | \"filename\"\n        | \"format_lib_supp\"\n        | \"fprof\"\n        | \"ftp\"\n        | \"ftp_app\"\n        | \"ftp_internal\"\n        | \"ftp_progress\"\n        | \"ftp_response\"\n        | \"ftp_sup\"\n        | \"gb_sets\"\n        | \"gb_trees\"\n        | \"gen\"\n        | \"gen_event\"\n        | \"gen_fsm\"\n        | \"gen_sctp\"\n        | \"gen_server\"\n        | \"gen_statem\"\n        | \"gen_tcp\"\n        | \"gen_tcp_socket\"\n        | \"gen_udp\"\n        | \"gen_udp_socket\"\n        | \"gl\"\n        | \"global\"\n        | \"global_group\"\n        | \"global_search\"\n        | \"glu\"\n        | \"group\"\n        | \"group_history\"\n        | \"heart\"\n        | \"http_chunk\"\n        | \"http_request\"\n        | \"http_response\"\n        | \"http_transport\"\n        | \"http_uri\"\n        | \"http_util\"\n        | \"httpc\"\n        | \"httpc_cookie\"\n        | \"httpc_handler\"\n        | \"httpc_handler_sup\"\n        | \"httpc_manager\"\n        | \"httpc_profile_sup\"\n        | \"httpc_request\"\n        | \"httpc_response\"\n        | \"httpc_sup\"\n        | \"httpd\"\n        | \"httpd_acceptor\"\n        | \"httpd_acceptor_sup\"\n        | \"httpd_cgi\"\n        | \"httpd_conf\"\n        | \"httpd_connection_sup\"\n        | \"httpd_custom\"\n        | \"httpd_custom_api\"\n        | \"httpd_esi\"\n        | \"httpd_example\"\n        | \"httpd_file\"\n        | \"httpd_instance_sup\"\n        | \"httpd_log\"\n        | \"httpd_logger\"\n        | \"httpd_manager\"\n        | \"httpd_misc_sup\"\n        | \"httpd_request\"\n        | \"httpd_request_handler\"\n        | \"httpd_response\"\n        | \"httpd_script_env\"\n        | \"httpd_socket\"\n        | \"httpd_sup\"\n        | \"httpd_util\"\n        | \"i\"\n        | \"inet\"\n        | \"inet6_sctp\"\n        | \"inet6_tcp\"\n        | \"inet6_tcp_dist\"\n        | \"inet6_tls_dist\"\n        | \"inet6_udp\"\n        | \"inet_config\"\n        | \"inet_db\"\n        | \"inet_dns\"\n        | \"inet_epmd_dist\"\n        | \"inet_epmd_socket\"\n        | \"inet_gethost_native\"\n        | \"inet_hosts\"\n        | \"inet_parse\"\n        | \"inet_res\"\n        | \"inet_sctp\"\n        | \"inet_tcp\"\n        | \"inet_tcp_dist\"\n        | \"inet_tls_dist\"\n        | \"inet_udp\"\n        | \"inets\"\n        | \"inets_app\"\n        | \"inets_lib\"\n        | \"inets_service\"\n        | \"inets_sup\"\n        | \"inets_trace\"\n        | \"init\"\n        | \"instrument\"\n        | \"int\"\n        | \"io\"\n        | \"io_lib\"\n        | \"io_lib_format\"\n        | \"io_lib_fread\"\n        | \"io_lib_pretty\"\n        | \"json\"\n        | \"kernel\"\n        | \"kernel_config\"\n        | \"kernel_refc\"\n        | \"lcnt\"\n        | \"leex\"\n        | \"lists\"\n        | \"local_tcp\"\n        | \"local_udp\"\n        | \"log_mf_h\"\n        | \"logger\"\n        | \"logger_backend\"\n        | \"logger_config\"\n        | \"logger_disk_log_h\"\n        | \"logger_filters\"\n        | \"logger_formatter\"\n        | \"logger_h_common\"\n        | \"logger_handler_watcher\"\n        | \"logger_olp\"\n        | \"logger_proxy\"\n        | \"logger_server\"\n        | \"logger_simple_h\"\n        | \"logger_std_h\"\n        | \"logger_sup\"\n        | \"make\"\n        | \"maps\"\n        | \"math\"\n        | \"megaco\"\n        | \"megaco_ber_encoder\"\n        | \"megaco_ber_media_gateway_control_v1\"\n        | \"megaco_ber_media_gateway_control_v2\"\n        | \"megaco_ber_media_gateway_control_v3\"\n        | \"megaco_binary_encoder\"\n        | \"megaco_binary_encoder_lib\"\n        | \"megaco_binary_name_resolver_v1\"\n        | \"megaco_binary_name_resolver_v2\"\n        | \"megaco_binary_name_resolver_v3\"\n        | \"megaco_binary_term_id\"\n        | \"megaco_binary_term_id_gen\"\n        | \"megaco_binary_transformer_v1\"\n        | \"megaco_binary_transformer_v2\"\n        | \"megaco_binary_transformer_v3\"\n        | \"megaco_compact_text_encoder\"\n        | \"megaco_compact_text_encoder_v1\"\n        | \"megaco_compact_text_encoder_v2\"\n        | \"megaco_compact_text_encoder_v3\"\n        | \"megaco_config\"\n        | \"megaco_config_misc\"\n        | \"megaco_digit_map\"\n        | \"megaco_edist_compress\"\n        | \"megaco_encoder\"\n        | \"megaco_erl_dist_encoder\"\n        | \"megaco_erl_dist_encoder_mc\"\n        | \"megaco_filter\"\n        | \"megaco_flex_scanner\"\n        | \"megaco_flex_scanner_handler\"\n        | \"megaco_messenger\"\n        | \"megaco_messenger_misc\"\n        | \"megaco_misc_sup\"\n        | \"megaco_monitor\"\n        | \"megaco_per_encoder\"\n        | \"megaco_per_media_gateway_control_v1\"\n        | \"megaco_per_media_gateway_control_v2\"\n        | \"megaco_per_media_gateway_control_v3\"\n        | \"megaco_pretty_text_encoder\"\n        | \"megaco_pretty_text_encoder_v1\"\n        | \"megaco_pretty_text_encoder_v2\"\n        | \"megaco_pretty_text_encoder_v3\"\n        | \"megaco_sdp\"\n        | \"megaco_stats\"\n        | \"megaco_sup\"\n        | \"megaco_tcp\"\n        | \"megaco_tcp_accept\"\n        | \"megaco_tcp_accept_sup\"\n        | \"megaco_tcp_connection\"\n        | \"megaco_tcp_connection_sup\"\n        | \"megaco_tcp_sup\"\n        | \"megaco_text_mini_decoder\"\n        | \"megaco_text_mini_parser\"\n        | \"megaco_text_parser_v1\"\n        | \"megaco_text_parser_v2\"\n        | \"megaco_text_parser_v3\"\n        | \"megaco_text_scanner\"\n        | \"megaco_timer\"\n        | \"megaco_trans_sender\"\n        | \"megaco_trans_sup\"\n        | \"megaco_transport\"\n        | \"megaco_udp\"\n        | \"megaco_udp_server\"\n        | \"megaco_udp_sup\"\n        | \"megaco_user\"\n        | \"megaco_user_default\"\n        | \"memsup\"\n        | \"merl\"\n        | \"merl_transform\"\n        | \"misc_supp\"\n        | \"mnesia\"\n        | \"mnesia_app\"\n        | \"mnesia_backend_type\"\n        | \"mnesia_backup\"\n        | \"mnesia_bup\"\n        | \"mnesia_checkpoint\"\n        | \"mnesia_checkpoint_sup\"\n        | \"mnesia_controller\"\n        | \"mnesia_dumper\"\n        | \"mnesia_event\"\n        | \"mnesia_ext_sup\"\n        | \"mnesia_frag\"\n        | \"mnesia_frag_hash\"\n        | \"mnesia_index\"\n        | \"mnesia_kernel_sup\"\n        | \"mnesia_late_loader\"\n        | \"mnesia_lib\"\n        | \"mnesia_loader\"\n        | \"mnesia_locker\"\n        | \"mnesia_log\"\n        | \"mnesia_monitor\"\n        | \"mnesia_recover\"\n        | \"mnesia_registry\"\n        | \"mnesia_rpc\"\n        | \"mnesia_schema\"\n        | \"mnesia_snmp_hook\"\n        | \"mnesia_sp\"\n        | \"mnesia_subscr\"\n        | \"mnesia_sup\"\n        | \"mnesia_text\"\n        | \"mnesia_tm\"\n        | \"mod_actions\"\n        | \"mod_alias\"\n        | \"mod_auth\"\n        | \"mod_auth_dets\"\n        | \"mod_auth_mnesia\"\n        | \"mod_auth_plain\"\n        | \"mod_auth_server\"\n        | \"mod_cgi\"\n        | \"mod_dir\"\n        | \"mod_disk_log\"\n        | \"mod_esi\"\n        | \"mod_get\"\n        | \"mod_head\"\n        | \"mod_log\"\n        | \"mod_range\"\n        | \"mod_responsecontrol\"\n        | \"mod_security\"\n        | \"mod_security_server\"\n        | \"mod_trace\"\n        | \"ms_transform\"\n        | \"msacc\"\n        | \"net\"\n        | \"net_adm\"\n        | \"net_kernel\"\n        | \"nteventlog\"\n        | \"observer\"\n        | \"observer_alloc_wx\"\n        | \"observer_app_wx\"\n        | \"observer_backend\"\n        | \"observer_html_lib\"\n        | \"observer_lib\"\n        | \"observer_perf_wx\"\n        | \"observer_port_wx\"\n        | \"observer_pro_wx\"\n        | \"observer_procinfo\"\n        | \"observer_sock_wx\"\n        | \"observer_sys_wx\"\n        | \"observer_trace_wx\"\n        | \"observer_traceoptions_wx\"\n        | \"observer_tv_table\"\n        | \"observer_tv_wx\"\n        | \"observer_wx\"\n        | \"orddict\"\n        | \"ordsets\"\n        | \"os\"\n        | \"os_mon\"\n        | \"os_mon_mib\"\n        | \"os_mon_sysinfo\"\n        | \"os_sup\"\n        | \"otp_internal\"\n        | \"peer\"\n        | \"persistent_term\"\n        | \"pg\"\n        | \"pg2\"\n        | \"pool\"\n        | \"prettypr\"\n        | \"prim_buffer\"\n        | \"prim_eval\"\n        | \"prim_file\"\n        | \"prim_inet\"\n        | \"prim_net\"\n        | \"prim_socket\"\n        | \"prim_tty\"\n        | \"prim_zip\"\n        | \"proc_lib\"\n        | \"proplists\"\n        | \"pubkey_cert\"\n        | \"pubkey_cert_records\"\n        | \"pubkey_crl\"\n        | \"pubkey_ocsp\"\n        | \"pubkey_os_cacerts\"\n        | \"pubkey_pbe\"\n        | \"pubkey_pem\"\n        | \"pubkey_policy_tree\"\n        | \"pubkey_ssh\"\n        | \"public_key\"\n        | \"qlc\"\n        | \"qlc_pt\"\n        | \"queue\"\n        | \"ram_file\"\n        | \"rand\"\n        | \"random\"\n        | \"raw_file_io\"\n        | \"raw_file_io_compressed\"\n        | \"raw_file_io_deflate\"\n        | \"raw_file_io_delayed\"\n        | \"raw_file_io_inflate\"\n        | \"raw_file_io_list\"\n        | \"rb\"\n        | \"rb_format_supp\"\n        | \"re\"\n        | \"rec_env\"\n        | \"release_handler\"\n        | \"release_handler_1\"\n        | \"reltool\"\n        | \"reltool_app_win\"\n        | \"reltool_fgraph\"\n        | \"reltool_fgraph_win\"\n        | \"reltool_mod_win\"\n        | \"reltool_server\"\n        | \"reltool_sys_win\"\n        | \"reltool_target\"\n        | \"reltool_utils\"\n        | \"rpc\"\n        | \"runtime_tools\"\n        | \"runtime_tools_sup\"\n        | \"sasl\"\n        | \"sasl_report\"\n        | \"sasl_report_file_h\"\n        | \"sasl_report_tty_h\"\n        | \"scheduler\"\n        | \"seq_trace\"\n        | \"sets\"\n        | \"shell\"\n        | \"shell_default\"\n        | \"shell_docs\"\n        | \"slave\"\n        | \"snmp\"\n        | \"snmp_app\"\n        | \"snmp_app_sup\"\n        | \"snmp_community_mib\"\n        | \"snmp_conf\"\n        | \"snmp_config\"\n        | \"snmp_framework_mib\"\n        | \"snmp_generic\"\n        | \"snmp_generic_mnesia\"\n        | \"snmp_index\"\n        | \"snmp_log\"\n        | \"snmp_mini_mib\"\n        | \"snmp_misc\"\n        | \"snmp_note_store\"\n        | \"snmp_notification_mib\"\n        | \"snmp_pdus\"\n        | \"snmp_shadow_table\"\n        | \"snmp_standard_mib\"\n        | \"snmp_target_mib\"\n        | \"snmp_user_based_sm_mib\"\n        | \"snmp_usm\"\n        | \"snmp_verbosity\"\n        | \"snmp_view_based_acm_mib\"\n        | \"snmpa\"\n        | \"snmpa_acm\"\n        | \"snmpa_agent\"\n        | \"snmpa_agent_sup\"\n        | \"snmpa_app\"\n        | \"snmpa_authentication_service\"\n        | \"snmpa_conf\"\n        | \"snmpa_discovery_handler\"\n        | \"snmpa_discovery_handler_default\"\n        | \"snmpa_error\"\n        | \"snmpa_error_io\"\n        | \"snmpa_error_logger\"\n        | \"snmpa_error_report\"\n        | \"snmpa_get\"\n        | \"snmpa_get_lib\"\n        | \"snmpa_get_mechanism\"\n        | \"snmpa_local_db\"\n        | \"snmpa_mib\"\n        | \"snmpa_mib_data\"\n        | \"snmpa_mib_data_tttn\"\n        | \"snmpa_mib_lib\"\n        | \"snmpa_mib_storage\"\n        | \"snmpa_mib_storage_dets\"\n        | \"snmpa_mib_storage_ets\"\n        | \"snmpa_mib_storage_mnesia\"\n        | \"snmpa_misc_sup\"\n        | \"snmpa_mpd\"\n        | \"snmpa_net_if\"\n        | \"snmpa_net_if_filter\"\n        | \"snmpa_network_interface\"\n        | \"snmpa_network_interface_filter\"\n        | \"snmpa_notification_delivery_info_receiver\"\n        | \"snmpa_notification_filter\"\n        | \"snmpa_set\"\n        | \"snmpa_set_lib\"\n        | \"snmpa_set_mechanism\"\n        | \"snmpa_supervisor\"\n        | \"snmpa_svbl\"\n        | \"snmpa_symbolic_store\"\n        | \"snmpa_target_cache\"\n        | \"snmpa_trap\"\n        | \"snmpa_usm\"\n        | \"snmpa_vacm\"\n        | \"snmpc\"\n        | \"snmpc_lib\"\n        | \"snmpc_mib_gram\"\n        | \"snmpc_mib_to_hrl\"\n        | \"snmpc_misc\"\n        | \"snmpc_tok\"\n        | \"snmpm\"\n        | \"snmpm_conf\"\n        | \"snmpm_config\"\n        | \"snmpm_misc_sup\"\n        | \"snmpm_mpd\"\n        | \"snmpm_net_if\"\n        | \"snmpm_net_if_filter\"\n        | \"snmpm_net_if_mt\"\n        | \"snmpm_network_interface\"\n        | \"snmpm_network_interface_filter\"\n        | \"snmpm_server\"\n        | \"snmpm_server_sup\"\n        | \"snmpm_supervisor\"\n        | \"snmpm_user\"\n        | \"snmpm_user_default\"\n        | \"snmpm_user_old\"\n        | \"snmpm_usm\"\n        | \"socket\"\n        | \"socket_registry\"\n        | \"sofs\"\n        | \"ssh\"\n        | \"ssh_acceptor\"\n        | \"ssh_acceptor_sup\"\n        | \"ssh_agent\"\n        | \"ssh_app\"\n        | \"ssh_auth\"\n        | \"ssh_bits\"\n        | \"ssh_channel\"\n        | \"ssh_channel_sup\"\n        | \"ssh_cli\"\n        | \"ssh_client_channel\"\n        | \"ssh_client_key_api\"\n        | \"ssh_connection\"\n        | \"ssh_connection_handler\"\n        | \"ssh_daemon_channel\"\n        | \"ssh_dbg\"\n        | \"ssh_file\"\n        | \"ssh_fsm_kexinit\"\n        | \"ssh_fsm_userauth_client\"\n        | \"ssh_fsm_userauth_server\"\n        | \"ssh_info\"\n        | \"ssh_io\"\n        | \"ssh_lib\"\n        | \"ssh_message\"\n        | \"ssh_no_io\"\n        | \"ssh_options\"\n        | \"ssh_server_channel\"\n        | \"ssh_server_key_api\"\n        | \"ssh_sftp\"\n        | \"ssh_sftpd\"\n        | \"ssh_sftpd_file\"\n        | \"ssh_sftpd_file_api\"\n        | \"ssh_shell\"\n        | \"ssh_subsystem_sup\"\n        | \"ssh_system_sup\"\n        | \"ssh_tcpip_forward_acceptor\"\n        | \"ssh_tcpip_forward_acceptor_sup\"\n        | \"ssh_tcpip_forward_client\"\n        | \"ssh_tcpip_forward_srv\"\n        | \"ssh_transport\"\n        | \"ssh_xfer\"\n        | \"ssl\"\n        | \"ssl_admin_sup\"\n        | \"ssl_alert\"\n        | \"ssl_app\"\n        | \"ssl_certificate\"\n        | \"ssl_cipher\"\n        | \"ssl_cipher_format\"\n        | \"ssl_client_session_cache_db\"\n        | \"ssl_config\"\n        | \"ssl_connection_sup\"\n        | \"ssl_crl\"\n        | \"ssl_crl_cache\"\n        | \"ssl_crl_cache_api\"\n        | \"ssl_crl_hash_dir\"\n        | \"ssl_dh_groups\"\n        | \"ssl_dist_admin_sup\"\n        | \"ssl_dist_connection_sup\"\n        | \"ssl_dist_sup\"\n        | \"ssl_gen_statem\"\n        | \"ssl_handshake\"\n        | \"ssl_listen_tracker_sup\"\n        | \"ssl_logger\"\n        | \"ssl_manager\"\n        | \"ssl_pem_cache\"\n        | \"ssl_pkix_db\"\n        | \"ssl_record\"\n        | \"ssl_server_session_cache\"\n        | \"ssl_server_session_cache_db\"\n        | \"ssl_server_session_cache_sup\"\n        | \"ssl_session\"\n        | \"ssl_session_cache_api\"\n        | \"ssl_srp_primes\"\n        | \"ssl_sup\"\n        | \"ssl_trace\"\n        | \"ssl_upgrade_server_session_cache_sup\"\n        | \"standard_error\"\n        | \"string\"\n        | \"supervisor\"\n        | \"supervisor_bridge\"\n        | \"sys\"\n        | \"sys_core_alias\"\n        | \"sys_core_bsm\"\n        | \"sys_core_fold\"\n        | \"sys_core_fold_lists\"\n        | \"sys_core_inline\"\n        | \"sys_core_prepare\"\n        | \"sys_messages\"\n        | \"sys_pre_attributes\"\n        | \"system_information\"\n        | \"systools\"\n        | \"systools_lib\"\n        | \"systools_make\"\n        | \"systools_rc\"\n        | \"systools_relup\"\n        | \"tags\"\n        | \"test_server\"\n        | \"test_server_ctrl\"\n        | \"test_server_gl\"\n        | \"test_server_io\"\n        | \"test_server_node\"\n        | \"test_server_sup\"\n        | \"tftp\"\n        | \"tftp_app\"\n        | \"tftp_binary\"\n        | \"tftp_engine\"\n        | \"tftp_file\"\n        | \"tftp_lib\"\n        | \"tftp_logger\"\n        | \"tftp_sup\"\n        | \"timer\"\n        | \"tls_bloom_filter\"\n        | \"tls_client_connection_1_3\"\n        | \"tls_client_ticket_store\"\n        | \"tls_connection\"\n        | \"tls_connection_sup\"\n        | \"tls_dist_server_sup\"\n        | \"tls_dist_sup\"\n        | \"tls_dtls_connection\"\n        | \"tls_dyn_connection_sup\"\n        | \"tls_gen_connection\"\n        | \"tls_gen_connection_1_3\"\n        | \"tls_handshake\"\n        | \"tls_handshake_1_3\"\n        | \"tls_record\"\n        | \"tls_record_1_3\"\n        | \"tls_sender\"\n        | \"tls_server_connection_1_3\"\n        | \"tls_server_session_ticket\"\n        | \"tls_server_session_ticket_sup\"\n        | \"tls_server_sup\"\n        | \"tls_socket\"\n        | \"tls_sup\"\n        | \"tls_v1\"\n        | \"ttb\"\n        | \"ttb_autostart\"\n        | \"ttb_et\"\n        | \"typer\"\n        | \"typer_core\"\n        | \"unicode\"\n        | \"unicode_util\"\n        | \"unix_telnet\"\n        | \"uri_string\"\n        | \"user_drv\"\n        | \"user_sup\"\n        | \"v3_core\"\n        | \"v3_kernel\"\n        | \"v3_kernel_pp\"\n        | \"win32reg\"\n        | \"wrap_log_reader\"\n        | \"wx\"\n        | \"wxAcceleratorEntry\"\n        | \"wxAcceleratorTable\"\n        | \"wxActivateEvent\"\n        | \"wxArtProvider\"\n        | \"wxAuiDockArt\"\n        | \"wxAuiManager\"\n        | \"wxAuiManagerEvent\"\n        | \"wxAuiNotebook\"\n        | \"wxAuiNotebookEvent\"\n        | \"wxAuiPaneInfo\"\n        | \"wxAuiSimpleTabArt\"\n        | \"wxAuiTabArt\"\n        | \"wxBitmap\"\n        | \"wxBitmapButton\"\n        | \"wxBitmapDataObject\"\n        | \"wxBookCtrlBase\"\n        | \"wxBookCtrlEvent\"\n        | \"wxBoxSizer\"\n        | \"wxBrush\"\n        | \"wxBufferedDC\"\n        | \"wxBufferedPaintDC\"\n        | \"wxButton\"\n        | \"wxCalendarCtrl\"\n        | \"wxCalendarDateAttr\"\n        | \"wxCalendarEvent\"\n        | \"wxCaret\"\n        | \"wxCheckBox\"\n        | \"wxCheckListBox\"\n        | \"wxChildFocusEvent\"\n        | \"wxChoice\"\n        | \"wxChoicebook\"\n        | \"wxClientDC\"\n        | \"wxClipboard\"\n        | \"wxClipboardTextEvent\"\n        | \"wxCloseEvent\"\n        | \"wxColourData\"\n        | \"wxColourDialog\"\n        | \"wxColourPickerCtrl\"\n        | \"wxColourPickerEvent\"\n        | \"wxComboBox\"\n        | \"wxCommandEvent\"\n        | \"wxContextMenuEvent\"\n        | \"wxControl\"\n        | \"wxControlWithItems\"\n        | \"wxCursor\"\n        | \"wxDC\"\n        | \"wxDCOverlay\"\n        | \"wxDataObject\"\n        | \"wxDateEvent\"\n        | \"wxDatePickerCtrl\"\n        | \"wxDialog\"\n        | \"wxDirDialog\"\n        | \"wxDirPickerCtrl\"\n        | \"wxDisplay\"\n        | \"wxDisplayChangedEvent\"\n        | \"wxDropFilesEvent\"\n        | \"wxEraseEvent\"\n        | \"wxEvent\"\n        | \"wxEvtHandler\"\n        | \"wxFileDataObject\"\n        | \"wxFileDialog\"\n        | \"wxFileDirPickerEvent\"\n        | \"wxFilePickerCtrl\"\n        | \"wxFindReplaceData\"\n        | \"wxFindReplaceDialog\"\n        | \"wxFlexGridSizer\"\n        | \"wxFocusEvent\"\n        | \"wxFont\"\n        | \"wxFontData\"\n        | \"wxFontDialog\"\n        | \"wxFontPickerCtrl\"\n        | \"wxFontPickerEvent\"\n        | \"wxFrame\"\n        | \"wxGBSizerItem\"\n        | \"wxGCDC\"\n        | \"wxGLCanvas\"\n        | \"wxGLContext\"\n        | \"wxGauge\"\n        | \"wxGenericDirCtrl\"\n        | \"wxGraphicsBrush\"\n        | \"wxGraphicsContext\"\n        | \"wxGraphicsFont\"\n        | \"wxGraphicsGradientStops\"\n        | \"wxGraphicsMatrix\"\n        | \"wxGraphicsObject\"\n        | \"wxGraphicsPath\"\n        | \"wxGraphicsPen\"\n        | \"wxGraphicsRenderer\"\n        | \"wxGrid\"\n        | \"wxGridBagSizer\"\n        | \"wxGridCellAttr\"\n        | \"wxGridCellBoolEditor\"\n        | \"wxGridCellBoolRenderer\"\n        | \"wxGridCellChoiceEditor\"\n        | \"wxGridCellEditor\"\n        | \"wxGridCellFloatEditor\"\n        | \"wxGridCellFloatRenderer\"\n        | \"wxGridCellNumberEditor\"\n        | \"wxGridCellNumberRenderer\"\n        | \"wxGridCellRenderer\"\n        | \"wxGridCellStringRenderer\"\n        | \"wxGridCellTextEditor\"\n        | \"wxGridEvent\"\n        | \"wxGridSizer\"\n        | \"wxHelpEvent\"\n        | \"wxHtmlEasyPrinting\"\n        | \"wxHtmlLinkEvent\"\n        | \"wxHtmlWindow\"\n        | \"wxIcon\"\n        | \"wxIconBundle\"\n        | \"wxIconizeEvent\"\n        | \"wxIdleEvent\"\n        | \"wxImage\"\n        | \"wxImageList\"\n        | \"wxInitDialogEvent\"\n        | \"wxJoystickEvent\"\n        | \"wxKeyEvent\"\n        | \"wxLayoutAlgorithm\"\n        | \"wxListBox\"\n        | \"wxListCtrl\"\n        | \"wxListEvent\"\n        | \"wxListItem\"\n        | \"wxListItemAttr\"\n        | \"wxListView\"\n        | \"wxListbook\"\n        | \"wxLocale\"\n        | \"wxLogNull\"\n        | \"wxMDIChildFrame\"\n        | \"wxMDIClientWindow\"\n        | \"wxMDIParentFrame\"\n        | \"wxMask\"\n        | \"wxMaximizeEvent\"\n        | \"wxMemoryDC\"\n        | \"wxMenu\"\n        | \"wxMenuBar\"\n        | \"wxMenuEvent\"\n        | \"wxMenuItem\"\n        | \"wxMessageDialog\"\n        | \"wxMiniFrame\"\n        | \"wxMirrorDC\"\n        | \"wxMouseCaptureChangedEvent\"\n        | \"wxMouseCaptureLostEvent\"\n        | \"wxMouseEvent\"\n        | \"wxMoveEvent\"\n        | \"wxMultiChoiceDialog\"\n        | \"wxNavigationKeyEvent\"\n        | \"wxNotebook\"\n        | \"wxNotificationMessage\"\n        | \"wxNotifyEvent\"\n        | \"wxOverlay\"\n        | \"wxPageSetupDialog\"\n        | \"wxPageSetupDialogData\"\n        | \"wxPaintDC\"\n        | \"wxPaintEvent\"\n        | \"wxPalette\"\n        | \"wxPaletteChangedEvent\"\n        | \"wxPanel\"\n        | \"wxPasswordEntryDialog\"\n        | \"wxPen\"\n        | \"wxPickerBase\"\n        | \"wxPopupTransientWindow\"\n        | \"wxPopupWindow\"\n        | \"wxPostScriptDC\"\n        | \"wxPreviewCanvas\"\n        | \"wxPreviewControlBar\"\n        | \"wxPreviewFrame\"\n        | \"wxPrintData\"\n        | \"wxPrintDialog\"\n        | \"wxPrintDialogData\"\n        | \"wxPrintPreview\"\n        | \"wxPrinter\"\n        | \"wxPrintout\"\n        | \"wxProgressDialog\"\n        | \"wxQueryNewPaletteEvent\"\n        | \"wxRadioBox\"\n        | \"wxRadioButton\"\n        | \"wxRegion\"\n        | \"wxSashEvent\"\n        | \"wxSashLayoutWindow\"\n        | \"wxSashWindow\"\n        | \"wxScreenDC\"\n        | \"wxScrollBar\"\n        | \"wxScrollEvent\"\n        | \"wxScrollWinEvent\"\n        | \"wxScrolledWindow\"\n        | \"wxSetCursorEvent\"\n        | \"wxShowEvent\"\n        | \"wxSingleChoiceDialog\"\n        | \"wxSizeEvent\"\n        | \"wxSizer\"\n        | \"wxSizerFlags\"\n        | \"wxSizerItem\"\n        | \"wxSlider\"\n        | \"wxSpinButton\"\n        | \"wxSpinCtrl\"\n        | \"wxSpinEvent\"\n        | \"wxSplashScreen\"\n        | \"wxSplitterEvent\"\n        | \"wxSplitterWindow\"\n        | \"wxStaticBitmap\"\n        | \"wxStaticBox\"\n        | \"wxStaticBoxSizer\"\n        | \"wxStaticLine\"\n        | \"wxStaticText\"\n        | \"wxStatusBar\"\n        | \"wxStdDialogButtonSizer\"\n        | \"wxStyledTextCtrl\"\n        | \"wxStyledTextEvent\"\n        | \"wxSysColourChangedEvent\"\n        | \"wxSystemOptions\"\n        | \"wxSystemSettings\"\n        | \"wxTaskBarIcon\"\n        | \"wxTaskBarIconEvent\"\n        | \"wxTextAttr\"\n        | \"wxTextCtrl\"\n        | \"wxTextDataObject\"\n        | \"wxTextEntryDialog\"\n        | \"wxToggleButton\"\n        | \"wxToolBar\"\n        | \"wxToolTip\"\n        | \"wxToolbook\"\n        | \"wxTopLevelWindow\"\n        | \"wxTreeCtrl\"\n        | \"wxTreeEvent\"\n        | \"wxTreebook\"\n        | \"wxUpdateUIEvent\"\n        | \"wxWebView\"\n        | \"wxWebViewEvent\"\n        | \"wxWindow\"\n        | \"wxWindowCreateEvent\"\n        | \"wxWindowDC\"\n        | \"wxWindowDestroyEvent\"\n        | \"wxXmlResource\"\n        | \"wx_misc\"\n        | \"wx_object\"\n        | \"wxe_master\"\n        | \"wxe_server\"\n        | \"wxe_util\"\n        | \"xmerl\"\n        | \"xmerl_b64Bin\"\n        | \"xmerl_b64Bin_scan\"\n        | \"xmerl_eventp\"\n        | \"xmerl_html\"\n        | \"xmerl_lib\"\n        | \"xmerl_otpsgml\"\n        | \"xmerl_regexp\"\n        | \"xmerl_sax_old_dom\"\n        | \"xmerl_sax_parser\"\n        | \"xmerl_sax_parser_latin1\"\n        | \"xmerl_sax_parser_list\"\n        | \"xmerl_sax_parser_utf16be\"\n        | \"xmerl_sax_parser_utf16le\"\n        | \"xmerl_sax_parser_utf8\"\n        | \"xmerl_sax_simple_dom\"\n        | \"xmerl_scan\"\n        | \"xmerl_sgml\"\n        | \"xmerl_simple\"\n        | \"xmerl_text\"\n        | \"xmerl_ucs\"\n        | \"xmerl_uri\"\n        | \"xmerl_validate\"\n        | \"xmerl_xlate\"\n        | \"xmerl_xml\"\n        | \"xmerl_xpath\"\n        | \"xmerl_xpath_lib\"\n        | \"xmerl_xpath_parse\"\n        | \"xmerl_xpath_pred\"\n        | \"xmerl_xpath_scan\"\n        | \"xmerl_xs\"\n        | \"xmerl_xsd\"\n        | \"xmerl_xsd_type\"\n        | \"xref\"\n        | \"xref_base\"\n        | \"xref_compiler\"\n        | \"xref_parser\"\n        | \"xref_reader\"\n        | \"xref_scanner\"\n        | \"xref_utils\"\n        | \"yecc\"\n        | \"yeccparser\"\n        | \"yeccscan\"\n        | \"zip\"\n        | \"zlib\" => (),\n        _ => return Ok(()),\n    }\n\n    Err(Error::GleamModuleWouldOverwriteStandardErlangModule {\n        name: input.name.clone(),\n        path: input.path.to_owned(),\n    })\n}\n#[derive(Debug, Default)]\npub struct StaleTracker(HashSet<EcoString>);\n\nimpl StaleTracker {\n    fn add(&mut self, name: EcoString) {\n        _ = self.0.insert(name);\n    }\n\n    fn includes_any(&self, names: &[(EcoString, SrcSpan)]) -> bool {\n        names.iter().any(|n| self.0.contains(n.0.as_str()))\n    }\n\n    pub fn empty(&mut self) {\n        let _ = self.0.drain(); // Clears the set but retains allocated memory\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n}\n\n#[derive(Debug)]\npub struct Inputs<'a> {\n    /// The name of the package for which we're loading the inputs.\n    package: EcoString,\n    collection: HashMap<EcoString, (DefinedModuleOrigin, Input)>,\n    already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,\n}\n\nimpl<'a> Inputs<'a> {\n    fn new(\n        package: EcoString,\n        already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,\n    ) -> Self {\n        Self {\n            package,\n            collection: Default::default(),\n            already_defined_modules,\n        }\n    }\n\n    /// Insert a module into the hashmap. If there is already a module with the\n    /// same name then an error is returned.\n    fn insert(&mut self, input: Input) -> Result<()> {\n        let name = input.name().clone();\n\n        let origin = DefinedModuleOrigin {\n            package_name: self.package.clone(),\n            path: input.source_path().to_path_buf(),\n        };\n\n        if let Some(first) = self\n            .already_defined_modules\n            .insert(name.clone(), origin.clone())\n        {\n            return Err(Error::DuplicateModule {\n                module: name.clone(),\n                first,\n                second: origin,\n            });\n        }\n\n        if let Some((first, _)) = self\n            .collection\n            .insert(name.clone(), (origin.clone(), input))\n        {\n            return Err(Error::DuplicateModule {\n                module: name,\n                first,\n                second: origin,\n            });\n        }\n\n        Ok(())\n    }\n}\n\n/// A Gleam source file (`.gleam`) and the module name deduced from it\npub struct GleamFile {\n    pub path: Utf8PathBuf,\n    pub module_name: EcoString,\n}\n\nimpl GleamFile {\n    pub fn new(dir: &Utf8Path, path: Utf8PathBuf) -> Self {\n        Self {\n            module_name: Self::module_name(&path, &dir),\n            path,\n        }\n    }\n\n    /// Iterates over Gleam source files (`.gleam`) in a certain directory.\n    /// Symlinks are followed.\n    /// If the there is a .gleam file with a path that would be an\n    /// invalid module name it should not be loaded. For example, if it\n    /// has a uppercase letter in it.\n    pub fn iterate_files_in_directory<'b>(\n        io: &'b impl FileSystemReader,\n        dir: &'b Utf8Path,\n    ) -> impl Iterator<Item = Result<Self, crate::Warning>> + 'b {\n        tracing::trace!(\"gleam_source_files {:?}\", dir);\n        files_with_extension(io, dir, \"gleam\").map(move |path| {\n            if (Self::is_gleam_path(&path, &dir)) {\n                Ok(Self::new(dir, path))\n            } else {\n                Err(crate::Warning::InvalidSource { path })\n            }\n        })\n    }\n\n    pub fn cache_files(&self, artefact_directory: &Utf8Path) -> CacheFiles {\n        CacheFiles::new(artefact_directory, &self.module_name)\n    }\n\n    fn module_name(path: &Utf8Path, dir: &Utf8Path) -> EcoString {\n        // /path/to/project/_build/default/lib/the_package/src/my/module.gleam\n\n        // my/module.gleam\n        let mut module_path = path\n            .strip_prefix(dir)\n            .expect(\"Stripping package prefix from module path\")\n            .to_path_buf();\n\n        // my/module\n        let _ = module_path.set_extension(\"\");\n\n        // Stringify\n        let name = module_path.to_string();\n\n        // normalise windows paths\n        name.replace(\"\\\\\", \"/\").into()\n    }\n\n    fn is_gleam_path(path: &Utf8Path, dir: &Utf8Path) -> bool {\n        use regex::Regex;\n        use std::cell::OnceCell;\n        const RE: OnceCell<Regex> = OnceCell::new();\n\n        RE.get_or_init(|| {\n            Regex::new(&format!(\n                \"^({module}{slash})*{module}\\\\.gleam$\",\n                module = \"[a-z][_a-z0-9]*\",\n                slash = \"(/|\\\\\\\\)\",\n            ))\n            .expect(\"is_gleam_path() RE regex\")\n        })\n        .is_match(\n            path.strip_prefix(dir)\n                .expect(\"is_gleam_path(): strip_prefix\")\n                .as_str(),\n        )\n    }\n}\n\n/// The collection of cache files paths related to a module.\n/// These files are not guaranteed to exist.\npub struct CacheFiles {\n    pub cache_path: Utf8PathBuf,\n    pub meta_path: Utf8PathBuf,\n}\n\nimpl CacheFiles {\n    pub fn new(artefact_directory: &Utf8Path, module_name: &EcoString) -> Self {\n        let file_name = module_name.replace(\"/\", \"@\");\n        let cache_path = artefact_directory\n            .join(file_name.as_str())\n            .with_extension(\"cache\");\n        let meta_path = artefact_directory\n            .join(file_name.as_str())\n            .with_extension(\"cache_meta\");\n\n        Self {\n            cache_path,\n            meta_path,\n        }\n    }\n\n    pub fn delete(&self, io: &dyn io::FileSystemWriter) -> Result<()> {\n        io.delete_file(&self.cache_path)?;\n        io.delete_file(&self.meta_path)\n    }\n\n    /// Iterates over `.cache_meta` files in the given directory,\n    /// and returns the respective module names.\n    /// Symlinks are followed.\n    pub fn modules_with_meta_files<'a>(\n        io: &'a impl FileSystemReader,\n        dir: &'a Utf8Path,\n    ) -> impl Iterator<Item = EcoString> + 'a {\n        tracing::trace!(\"CacheFiles::modules_with_meta_files {:?}\", dir);\n        files_with_extension(io, dir, \"cache_meta\").map(move |path| Self::module_name(&dir, &path))\n    }\n\n    fn module_name(dir: &Utf8Path, path: &Utf8Path) -> EcoString {\n        // /path/to/artefact/dir/my@module.cache_meta\n\n        // my@module.cache_meta\n        let mut module_path = path\n            .strip_prefix(dir)\n            .expect(\"Stripping package prefix from module path\")\n            .to_path_buf();\n\n        // my@module\n        let _ = module_path.set_extension(\"\");\n\n        // my/module\n        module_path.to_string().replace(\"@\", \"/\").into()\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/build/project_compiler.rs",
    "content": "use crate::{\n    Error, Result, Warning,\n    analyse::TargetSupport,\n    build::{\n        Mode, Module, Origin, Package, Target,\n        package_compiler::{self, PackageCompiler},\n        package_loader::StaleTracker,\n        project_compiler,\n        telemetry::Telemetry,\n    },\n    codegen::{self, ErlangApp},\n    config::PackageConfig,\n    dep_tree,\n    error::{DefinedModuleOrigin, FileIoAction, FileKind, ShellCommandFailureReason},\n    io::{BeamCompiler, Command, CommandExecutor, FileSystemReader, FileSystemWriter, Stdio},\n    manifest::{ManifestPackage, ManifestPackageSource},\n    metadata,\n    paths::{self, ProjectPaths},\n    type_::{self, ModuleFunction},\n    uid::UniqueIdGenerator,\n    version::COMPILER_VERSION,\n    warning::{self, WarningEmitter, WarningEmitterIO},\n};\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse itertools::Itertools;\nuse pubgrub::Range;\nuse std::{\n    cmp,\n    collections::{HashMap, HashSet},\n    fmt::Write,\n    io::BufReader,\n    rc::Rc,\n    sync::Arc,\n    time::Instant,\n};\n\nuse super::{\n    Codegen, Compile, ErlangAppCodegenConfiguration, Outcome,\n    elixir_libraries::ElixirLibraries,\n    package_compiler::{CachedWarnings, CheckModuleConflicts, Compiled},\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\n// On Windows we have to call rebar3 via a little wrapper script.\n//\n#[cfg(not(target_os = \"windows\"))]\nconst REBAR_EXECUTABLE: &str = \"rebar3\";\n#[cfg(target_os = \"windows\")]\nconst REBAR_EXECUTABLE: &str = \"rebar3.cmd\";\n\n#[cfg(not(target_os = \"windows\"))]\nconst ELIXIR_EXECUTABLE: &str = \"elixir\";\n#[cfg(target_os = \"windows\")]\nconst ELIXIR_EXECUTABLE: &str = \"elixir.bat\";\n\n#[derive(Debug)]\npub struct Options {\n    pub mode: Mode,\n    pub target: Option<Target>,\n    pub compile: Compile,\n    pub codegen: Codegen,\n    pub warnings_as_errors: bool,\n    pub root_target_support: TargetSupport,\n    pub no_print_progress: bool,\n}\n\n#[derive(Debug)]\npub struct Built {\n    pub root_package: Package,\n    pub module_interfaces: im::HashMap<EcoString, type_::ModuleInterface>,\n    compiled_dependency_modules: Vec<Module>,\n}\n\nimpl Built {\n    pub fn get_main_function(\n        &self,\n        module: &EcoString,\n        target: Target,\n    ) -> Result<ModuleFunction, Error> {\n        match self.module_interfaces.get(module) {\n            Some(module_data) => module_data.get_main_function(target),\n            None => Err(Error::ModuleDoesNotExist {\n                module: module.clone(),\n                suggestion: None,\n            }),\n        }\n    }\n\n    pub fn minimum_required_version(&self) -> Version {\n        self.module_interfaces\n            .values()\n            .map(|interface| &interface.minimum_required_version)\n            .reduce(|one_version, other_version| cmp::max(one_version, other_version))\n            .map(|minimum_required_version| minimum_required_version.clone())\n            .unwrap_or(Version::new(0, 1, 0))\n    }\n}\n\n#[derive(Debug)]\npub struct ProjectCompiler<IO> {\n    // The gleam.toml config for the root package of the project\n    pub config: PackageConfig,\n    pub packages: HashMap<String, ManifestPackage>,\n    importable_modules: im::HashMap<EcoString, type_::ModuleInterface>,\n    pub(crate) defined_modules: im::HashMap<EcoString, DefinedModuleOrigin>,\n    stale_modules: StaleTracker,\n    /// The set of modules that have had partial compilation done since the last\n    /// successful compilation.\n    incomplete_modules: HashSet<EcoString>,\n    warnings: WarningEmitter,\n    telemetry: &'static dyn Telemetry,\n    options: Options,\n    paths: ProjectPaths,\n    ids: UniqueIdGenerator,\n    pub io: IO,\n    /// We may want to silence subprocess stdout if we are running in LSP mode.\n    /// The language server talks over stdio so printing would break that.\n    pub subprocess_stdio: Stdio,\n}\n\n// TODO: test that tests cannot be imported into src\n// TODO: test that dep cycles are not allowed between packages\n\nimpl<IO> ProjectCompiler<IO>\nwhere\n    IO: CommandExecutor + FileSystemWriter + FileSystemReader + BeamCompiler + Clone,\n{\n    pub fn new(\n        config: PackageConfig,\n        options: Options,\n        packages: Vec<ManifestPackage>,\n        telemetry: &'static dyn Telemetry,\n        warning_emitter: Rc<dyn WarningEmitterIO>,\n        paths: ProjectPaths,\n        io: IO,\n    ) -> Self {\n        let packages = packages\n            .into_iter()\n            .map(|p| (p.name.to_string(), p))\n            .collect();\n\n        Self {\n            importable_modules: im::HashMap::new(),\n            defined_modules: im::HashMap::new(),\n            stale_modules: StaleTracker::default(),\n            incomplete_modules: HashSet::new(),\n            ids: UniqueIdGenerator::new(),\n            warnings: WarningEmitter::new(warning_emitter),\n            subprocess_stdio: Stdio::Inherit,\n            telemetry,\n            packages,\n            options,\n            config,\n            paths,\n            io,\n        }\n    }\n\n    pub fn mode(&self) -> Mode {\n        self.options.mode\n    }\n\n    pub fn target(&self) -> Target {\n        self.options.target.unwrap_or(self.config.target)\n    }\n\n    pub fn reset_state_for_new_compile_run(&mut self) {\n        // We make sure the stale module tracker is empty before we start, to\n        // avoid mistakenly thinking a module is stale due to outdated state\n        // from a previous build. A ProjectCompiler instance is re-used by the\n        // LSP engine so state could be reused if we don't reset it.\n\n        self.stale_modules.empty();\n\n        /// We also clear the defined modules, otherwise the language server\n        /// would start throwing errors for modules defined twice when compiling\n        /// a second time!\n        self.defined_modules.clear();\n    }\n\n    fn retain_only_production_packages(&mut self) {\n        let mut production = HashSet::new();\n        let mut queue: Vec<_> = self.config.dependencies.keys().collect();\n        while let Some(name) = queue.pop() {\n            if production.insert(name.clone())\n                && let Some(pkg) = self.packages.get(name.as_str())\n            {\n                queue.extend(pkg.requirements.iter());\n            }\n        }\n        self.packages\n            .retain(|name, _| production.contains(name.as_str()));\n    }\n\n    /// Compiles all packages in the project and returns the compiled\n    /// information from the root package\n    pub fn compile(mut self) -> Result<Built> {\n        self.reset_state_for_new_compile_run();\n\n        // In production mode, skip dev-only dependencies entirely so they\n        // are never compiled.\n        if self.mode() == Mode::Prod {\n            self.retain_only_production_packages();\n        }\n\n        // Each package may specify a Gleam version that it supports, so we\n        // verify that this version is appropriate.\n        self.check_gleam_version()?;\n\n        // The JavaScript target requires a prelude module to be written.\n        self.write_prelude()?;\n\n        // Dependencies are compiled first.\n        let compiled_dependency_modules = self.compile_dependencies()?;\n\n        // We reset the warning count as we don't want to fail the build if a\n        // dependency has warnings, only if the root package does.\n        self.warnings.reset_count();\n\n        let root_package = self.compile_root_package().into_result()?;\n\n        // TODO: test\n        if self.options.warnings_as_errors && self.warnings.count() > 0 {\n            return Err(Error::ForbiddenWarnings {\n                count: self.warnings.count(),\n            });\n        }\n\n        Ok(Built {\n            root_package,\n            module_interfaces: self.importable_modules,\n            compiled_dependency_modules,\n        })\n    }\n\n    pub fn compile_root_package(&mut self) -> Outcome<Package, Error> {\n        let config = self.config.clone();\n        self.compile_gleam_package(&config, true, self.paths.root().to_path_buf())\n            .map(\n                |Compiled {\n                     modules,\n                     cached_module_names,\n                 }| Package {\n                    config,\n                    modules,\n                    cached_module_names,\n                },\n            )\n    }\n\n    /// Checks that version file found in the build directory matches the\n    /// current version of gleam. If not, we will clear the build directory\n    /// before continuing. This will ensure that upgrading gleam will not leave\n    /// one with confusing or hard to debug states.\n    pub fn check_gleam_version(&self) -> Result<(), Error> {\n        let build_path = self\n            .paths\n            .build_directory_for_target(self.mode(), self.target());\n        let version_path = self.paths.build_gleam_version(self.mode(), self.target());\n        if self.io.is_file(&version_path) {\n            let version = self.io.read(&version_path)?;\n            if version == COMPILER_VERSION {\n                return Ok(());\n            }\n        }\n\n        // Either file is missing our the versions do not match. Time to rebuild\n        tracing::info!(\"removing_build_state_from_different_gleam_version\");\n        self.io.delete_directory(&build_path)?;\n\n        // Recreate build directory with new updated version file\n        self.io.mkdir(&build_path)?;\n        self.io\n            .write(&version_path, COMPILER_VERSION)\n            .map_err(|e| Error::FileIo {\n                action: FileIoAction::WriteTo,\n                kind: FileKind::File,\n                path: version_path,\n                err: Some(e.to_string()),\n            })\n    }\n\n    pub fn compile_dependencies(&mut self) -> Result<Vec<Module>, Error> {\n        assert!(\n            self.stale_modules.is_empty(),\n            \"The project compiler stale tracker was not emptied from the previous compilation\"\n        );\n\n        let sequence = order_packages(&self.packages)?;\n        let mut modules = vec![];\n\n        for name in sequence {\n            let compiled = self.load_cache_or_compile_package(&name)?;\n            modules.extend(compiled);\n        }\n\n        Ok(modules)\n    }\n\n    fn write_prelude(&self) -> Result<()> {\n        // Only the JavaScript target has a prelude to write.\n        if !self.target().is_javascript() {\n            return Ok(());\n        }\n\n        let build = self\n            .paths\n            .build_directory_for_target(self.mode(), self.target());\n\n        // Write the JavaScript prelude\n        let path = build.join(\"prelude.mjs\");\n        if !self.io.is_file(&path) {\n            self.io.write(&path, crate::javascript::PRELUDE)?;\n        }\n\n        // Write the TypeScript prelude, if asked for\n        if self.config.javascript.typescript_declarations {\n            let path = build.join(\"prelude.d.mts\");\n            if !self.io.is_file(&path) {\n                self.io.write(&path, crate::javascript::PRELUDE_TS_DEF)?;\n            }\n        }\n\n        Ok(())\n    }\n\n    fn load_cache_or_compile_package(&mut self, name: &str) -> Result<Vec<Module>, Error> {\n        // TODO: We could remove this clone if we split out the compilation of\n        // packages into their own classes and then only mutate self after we no\n        // longer need to have the package borrowed from self.packages.\n        let package = self.packages.get(name).expect(\"Missing package\").clone();\n        let result = match usable_build_tools(&package)?.as_slice() {\n            &[BuildTool::Gleam] => self.compile_gleam_dep_package(&package),\n            &[BuildTool::Rebar3] => self.compile_rebar3_dep_package(&package).map(|_| vec![]),\n            &[BuildTool::Mix] => self.compile_mix_dep_package(&package).map(|_| vec![]),\n            &[BuildTool::Mix, BuildTool::Rebar3] => self\n                .compile_mix_dep_package(&package)\n                .or_else(|_| self.compile_rebar3_dep_package(&package))\n                .map(|_| vec![]),\n            _ => {\n                return Err(Error::UnsupportedBuildTool {\n                    package: package.name.to_string(),\n                    build_tools: package.build_tools.clone(),\n                });\n            }\n        };\n\n        // TODO: test. This one is not covered by the integration tests.\n        if result.is_err() {\n            tracing::debug!(package=%name, \"removing_failed_build\");\n            let path = self.paths.build_directory_for_package(\n                self.mode(),\n                self.target(),\n                package.application_name(),\n            );\n            self.io.delete_directory(&path)?;\n        }\n\n        result\n    }\n\n    // TODO: extract and unit test\n    fn compile_rebar3_dep_package(&mut self, package: &ManifestPackage) -> Result<(), Error> {\n        let application_name = package.application_name();\n        let package_name = &package.name;\n        let mode = self.mode();\n        let target = self.target();\n\n        let package_build = self\n            .paths\n            .build_directory_for_package(mode, target, application_name);\n\n        // TODO: test\n        if self.io.is_directory(&package_build) {\n            tracing::debug!(%package_name, \"using_precompiled_rebar3_package\");\n            return Ok(());\n        }\n\n        // TODO: test\n        if !self.options.codegen.should_codegen(false) {\n            tracing::debug!(%package_name, \"skipping_rebar3_build_as_codegen_disabled\");\n            return Ok(());\n        }\n\n        // TODO: test\n        if target != Target::Erlang {\n            tracing::debug!(%package_name, \"skipping_rebar3_build_for_non_erlang_target\");\n            return Ok(());\n        }\n\n        // Print that work is being done\n        self.telemetry.compiling_package(package_name);\n\n        let package = self.paths.build_packages_package(package_name);\n        let build_packages = self.paths.build_directory_for_target(mode, target);\n        let ebins = self.paths.build_packages_ebins_glob(mode, target);\n        let rebar3_path = |path: &Utf8Path| format!(\"../{}\", path);\n\n        tracing::debug!(\"copying_package_to_build\");\n        self.io.mkdir(&package_build)?;\n        self.io.copy_dir(&package, &package_build)?;\n\n        let env = vec![\n            (\"ERL_LIBS\".to_string(), \"../*/ebin\".to_string()),\n            (\n                \"REBAR_BARE_COMPILER_OUTPUT_DIR\".to_string(),\n                package_build.to_string(),\n            ),\n            (\"REBAR_PROFILE\".to_string(), \"prod\".to_string()),\n            (\"REBAR_SKIP_PROJECT_PLUGINS\".to_string(), \"true\".to_string()),\n            (\"TERM\".to_string(), \"dumb\".to_string()),\n        ];\n        let args = vec![\n            \"bare\".into(),\n            \"compile\".into(),\n            \"--paths\".into(),\n            \"../*/ebin\".into(),\n        ];\n\n        let status = self.io.exec(Command {\n            program: REBAR_EXECUTABLE.into(),\n            args,\n            env,\n            cwd: Some(package_build),\n            stdio: self.subprocess_stdio,\n        })?;\n\n        if status == 0 {\n            Ok(())\n        } else {\n            Err(Error::ShellCommand {\n                program: \"rebar3\".into(),\n                reason: ShellCommandFailureReason::Unknown,\n            })\n        }\n    }\n\n    fn compile_mix_dep_package(&mut self, package: &ManifestPackage) -> Result<(), Error> {\n        let application_name = package.application_name();\n        let package_name = &package.name;\n        let mode = self.mode();\n        let target = self.target();\n        let mix_target = \"prod\";\n\n        let dest = self\n            .paths\n            .build_directory_for_package(mode, target, application_name);\n\n        // TODO: test\n        if self.io.is_directory(&dest) {\n            tracing::debug!(%package_name, \"using_precompiled_mix_package\");\n            return Ok(());\n        }\n\n        // TODO: test\n        if !self.options.codegen.should_codegen(false) {\n            tracing::debug!(%package_name, \"skipping_mix_build_as_codegen_disabled\");\n            return Ok(());\n        }\n\n        // TODO: test\n        if target != Target::Erlang {\n            tracing::debug!(%package_name, \"skipping_mix_build_for_non_erlang_target\");\n            return Ok(());\n        }\n\n        // Print that work is being done\n        self.telemetry.compiling_package(package_name);\n\n        let build_dir = self.paths.build_directory_for_target(mode, target);\n        let project_dir = self.paths.build_packages_package(package_name);\n        let mix_build_dir = project_dir.join(\"_build\").join(mix_target);\n        let mix_build_lib_dir = mix_build_dir.join(\"lib\");\n        let up = paths::unnest(&project_dir);\n        let mix_path = |path: &Utf8Path| up.join(path).to_string();\n        let ebins = self.paths.build_packages_ebins_glob(mode, target);\n\n        // Elixir core libs must be loaded\n        ElixirLibraries::make_available(&self.io, &build_dir, self.subprocess_stdio)?;\n\n        // Prevent Mix.Compilers.ApplicationTracer warnings\n        // mix would make this if it didn't exist, but we make it anyway as\n        // we need to link the compiled dependencies into there\n        self.io.mkdir(&mix_build_lib_dir)?;\n        let deps = &package.requirements;\n        for dep in deps {\n            // TODO: unit test\n            let dep_source = build_dir.join(dep.as_str());\n            let dep_dest = mix_build_lib_dir.join(dep.as_str());\n            if self.io.is_directory(&dep_source) && !self.io.is_directory(&dep_dest) {\n                tracing::debug!(\"linking_{}_to_build\", dep);\n                self.io.symlink_dir(&dep_source, &dep_dest)?;\n            }\n        }\n\n        let env = vec![\n            (\"MIX_BUILD_PATH\".to_string(), mix_path(&mix_build_dir)),\n            (\"MIX_ENV\".to_string(), mix_target.to_string()),\n            (\"MIX_QUIET\".to_string(), \"1\".to_string()),\n            (\"TERM\".to_string(), \"dumb\".to_string()),\n        ];\n        let args = vec![\n            \"-pa\".to_string(),\n            mix_path(&ebins),\n            \"-S\".to_string(),\n            \"mix\".to_string(),\n            \"compile\".to_string(),\n            \"--no-deps-check\".to_string(),\n            \"--no-load-deps\".to_string(),\n            \"--no-protocol-consolidation\".to_string(),\n        ];\n\n        let status = self.io.exec(Command {\n            program: ELIXIR_EXECUTABLE.into(),\n            args,\n            env,\n            cwd: Some(project_dir),\n            stdio: self.subprocess_stdio,\n        })?;\n\n        if status == 0 {\n            // TODO: unit test\n            let source = mix_build_dir.join(\"lib\").join(application_name.as_str());\n            if self.io.is_directory(&source) && !self.io.is_directory(&dest) {\n                tracing::debug!(\"linking_{}_to_build\", application_name);\n                self.io.symlink_dir(&source, &dest)?;\n            }\n            Ok(())\n        } else {\n            Err(Error::ShellCommand {\n                program: \"mix\".into(),\n                reason: ShellCommandFailureReason::Unknown,\n            })\n        }\n    }\n\n    fn compile_gleam_dep_package(\n        &mut self,\n        package: &ManifestPackage,\n    ) -> Result<Vec<Module>, Error> {\n        // TODO: Test\n        let package_root = match &package.source {\n            // If the path is relative it is relative to the root of the\n            // project, not to the current working directory. The language server\n            // could have the working directory and the project root in different\n            // places.\n            ManifestPackageSource::Local { path } if path.is_relative() => {\n                self.io.canonicalise(&self.paths.root().join(path))?\n            }\n\n            // If the path is absolute we can use it as-is.\n            ManifestPackageSource::Local { path } => path.clone(),\n\n            // Hex and Git packages are downloaded into the project's build\n            // directory.\n            ManifestPackageSource::Git { .. } | ManifestPackageSource::Hex { .. } => {\n                self.paths.build_packages_package(&package.name)\n            }\n        };\n        let config_path = package_root.join(\"gleam.toml\");\n        let config = PackageConfig::read(config_path, &self.io)?;\n        self.compile_gleam_package(&config, false, package_root)\n            .into_result()\n            .map(|compiled| compiled.modules)\n    }\n\n    fn compile_gleam_package(\n        &mut self,\n        config: &PackageConfig,\n        is_root: bool,\n        root_path: Utf8PathBuf,\n    ) -> Outcome<Compiled, Error> {\n        let out_path =\n            self.paths\n                .build_directory_for_package(self.mode(), self.target(), &config.name);\n        let lib_path = self\n            .paths\n            .build_directory_for_target(self.mode(), self.target());\n        let mode = if is_root { self.mode() } else { Mode::Prod };\n        let target = match self.target() {\n            Target::Erlang => {\n                let package_name_overrides = self\n                    .packages\n                    .values()\n                    .flat_map(|p| {\n                        let overriden = p.otp_app.as_ref()?;\n                        Some((p.name.clone(), overriden.clone()))\n                    })\n                    .collect();\n                super::TargetCodegenConfiguration::Erlang {\n                    app_file: Some(ErlangAppCodegenConfiguration {\n                        include_dev_deps: is_root && self.mode().includes_dev_dependencies(),\n                        package_name_overrides,\n                    }),\n                }\n            }\n\n            Target::JavaScript => super::TargetCodegenConfiguration::JavaScript {\n                emit_typescript_definitions: self.config.javascript.typescript_declarations,\n                // This path is relative to each package output directory\n                prelude_location: Utf8PathBuf::from(\"../prelude.mjs\"),\n            },\n        };\n\n        let mut compiler = PackageCompiler::new(\n            config,\n            mode,\n            &root_path,\n            &out_path,\n            &lib_path,\n            &target,\n            self.ids.clone(),\n            self.io.clone(),\n        );\n        compiler.write_metadata = true;\n        compiler.write_entrypoint = is_root;\n        compiler.perform_codegen = self.options.codegen.should_codegen(is_root);\n        compiler.compile_beam_bytecode = self.options.codegen.should_codegen(is_root);\n        compiler.compile_modules = !(self.options.compile == Compile::DepsOnly && is_root);\n        compiler.subprocess_stdio = self.subprocess_stdio;\n        compiler.target_support = if is_root {\n            // When compiling the root package it is context specific as to whether we need to\n            // enforce that all functions have an implementation for the current target.\n            // Typically we do, but if we are using `gleam run -m $module` to run a module that\n            // belongs to a dependency we don't need to enforce this as we don't want to fail\n            // compilation. It's impossible for a dependecy module to call functions from the root\n            // package, so it's OK if they could not be compiled.\n            self.options.root_target_support\n        } else {\n            // When compiling dependencies we don't enforce that all functions have an\n            // implementation for the current target. It is OK if they have APIs that are\n            // unaccessible so long as they are not used by the root package.\n            TargetSupport::NotEnforced\n        };\n        if is_root {\n            compiler.cached_warnings = CachedWarnings::Use;\n            // We only check for conflicting Gleam files if this is the root\n            // package, since Hex packages are bundled with the Gleam source files\n            // and compiled Erlang files next to each other.\n            compiler.check_module_conflicts = CheckModuleConflicts::Check;\n        } else {\n            compiler.cached_warnings = CachedWarnings::Ignore;\n            compiler.check_module_conflicts = CheckModuleConflicts::DoNotCheck;\n        };\n\n        // Compile project to Erlang or JavaScript source code\n        compiler.compile(\n            &mut self.warnings,\n            &mut self.importable_modules,\n            &mut self.defined_modules,\n            &mut self.stale_modules,\n            &mut self.incomplete_modules,\n            self.telemetry,\n        )\n    }\n}\n\nimpl<IO> ProjectCompiler<IO> {\n    pub fn get_importable_modules(&self) -> &im::HashMap<EcoString, type_::ModuleInterface> {\n        &self.importable_modules\n    }\n}\n\nfn order_packages(packages: &HashMap<String, ManifestPackage>) -> Result<Vec<EcoString>, Error> {\n    dep_tree::toposort_deps(\n        packages\n            .values()\n            // Making sure that the package order is deterministic, to prevent different\n            // compilations of the same project compiling in different orders. This could impact\n            // any bugged outcomes, though not any where the compiler is working correctly, so it's\n            // mostly to aid debugging.\n            .sorted_by(|a, b| a.name.cmp(&b.name))\n            .map(|package| {\n                (\n                    package.name.as_str().into(),\n                    package\n                        .requirements\n                        .iter()\n                        .map(|r| EcoString::from(r.as_ref()))\n                        .collect(),\n                )\n            })\n            .collect(),\n    )\n    .map_err(convert_deps_tree_error)\n}\n\nfn convert_deps_tree_error(e: dep_tree::Error) -> Error {\n    match e {\n        dep_tree::Error::Cycle(packages) => Error::PackageCycle { packages },\n    }\n}\n\n#[derive(Debug, PartialEq, Clone, Copy)]\npub(crate) enum BuildTool {\n    Gleam,\n    Rebar3,\n    Mix,\n}\n\n/// Determine the build tool we should use to build this package\npub(crate) fn usable_build_tools(package: &ManifestPackage) -> Result<Vec<BuildTool>, Error> {\n    let mut rebar3_present = false;\n    let mut mix_present = false;\n\n    for tool in &package.build_tools {\n        match tool.as_str() {\n            \"gleam\" => return Ok(vec![BuildTool::Gleam]),\n            \"rebar\" => rebar3_present = true,\n            \"rebar3\" => rebar3_present = true,\n            \"mix\" => mix_present = true,\n            _ => (),\n        }\n    }\n\n    if mix_present && rebar3_present {\n        return Ok(vec![BuildTool::Mix, BuildTool::Rebar3]);\n    } else if mix_present {\n        return Ok(vec![BuildTool::Mix]);\n    } else if rebar3_present {\n        return Ok(vec![BuildTool::Rebar3]);\n    }\n\n    Err(Error::UnsupportedBuildTool {\n        package: package.name.to_string(),\n        build_tools: package.build_tools.clone(),\n    })\n}\n"
  },
  {
    "path": "compiler-core/src/build/telemetry.rs",
    "content": "use std::{\n    fmt::Debug,\n    time::{Duration, Instant},\n};\n\nuse crate::{\n    Warning,\n    manifest::{PackageChanges, Resolved},\n};\n\npub trait Telemetry: Debug {\n    fn waiting_for_build_directory_lock(&self);\n    fn running(&self, name: &str);\n    fn resolving_package_versions(&self);\n    fn resolved_package_versions(&self, changes: &PackageChanges);\n    fn downloading_package(&self, name: &str);\n    fn packages_downloaded(&self, start: Instant, count: usize);\n    fn compiled_package(&self, duration: Duration);\n    fn compiling_package(&self, name: &str);\n    fn checked_package(&self, duration: Duration);\n    fn checking_package(&self, name: &str);\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct NullTelemetry;\n\nimpl Telemetry for NullTelemetry {\n    fn waiting_for_build_directory_lock(&self) {}\n    fn running(&self, name: &str) {}\n    fn resolving_package_versions(&self) {}\n    fn downloading_package(&self, _name: &str) {}\n    fn compiled_package(&self, _duration: Duration) {}\n    fn compiling_package(&self, _name: &str) {}\n    fn checked_package(&self, _duration: Duration) {}\n    fn checking_package(&self, _name: &str) {}\n    fn packages_downloaded(&self, _start: Instant, _count: usize) {}\n    fn resolved_package_versions(&self, _changes: &PackageChanges) {}\n}\n"
  },
  {
    "path": "compiler-core/src/build/tests.rs",
    "content": "use crate::{Error, manifest::ManifestPackage};\n\nuse super::project_compiler::{BuildTool, usable_build_tools};\n\n#[test]\nfn usable_build_tool_unknown() {\n    assert_eq!(\n        usable_build_tools(&ManifestPackage::default().with_build_tools(&[\"unknown\"])),\n        Err(Error::UnsupportedBuildTool {\n            package: \"\".into(),\n            build_tools: vec![\"unknown\".into()],\n        })\n    )\n}\n\n#[test]\nfn usable_build_tool_none() {\n    assert_eq!(\n        usable_build_tools(&ManifestPackage::default()),\n        Err(Error::UnsupportedBuildTool {\n            package: \"\".into(),\n            build_tools: vec![],\n        })\n    )\n}\n\n#[test]\nfn usable_build_tool_only_mix() {\n    assert_eq!(\n        usable_build_tools(&ManifestPackage::default().with_build_tools(&[\"mix\"])),\n        Ok(vec![BuildTool::Mix])\n    )\n}\n\n#[test]\nfn usable_build_tool_only_rebar3() {\n    assert_eq!(\n        usable_build_tools(&ManifestPackage::default().with_build_tools(&[\"rebar3\"])),\n        Ok(vec![BuildTool::Rebar3])\n    )\n}\n\n#[test]\nfn usable_build_tool_only_gleam() {\n    assert_eq!(\n        usable_build_tools(&ManifestPackage::default().with_build_tools(&[\"gleam\"])),\n        Ok(vec![BuildTool::Gleam])\n    )\n}\n\n#[test]\nfn usable_build_tool_mix_then_rebar3() {\n    assert_eq!(\n        usable_build_tools(&ManifestPackage::default().with_build_tools(&[\"mix\", \"rebar3\"])),\n        Ok(vec![BuildTool::Mix, BuildTool::Rebar3])\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/build.rs",
    "content": "#![allow(warnings)]\n\nmod elixir_libraries;\nmod module_loader;\nmod native_file_copier;\npub mod package_compiler;\nmod package_loader;\nmod project_compiler;\nmod telemetry;\n\n#[cfg(test)]\nmod tests;\n\npub use self::package_compiler::PackageCompiler;\npub use self::package_loader::StaleTracker;\npub use self::project_compiler::{Built, Options, ProjectCompiler};\npub use self::telemetry::{NullTelemetry, Telemetry};\n\nuse crate::ast::{\n    self, CallArg, CustomType, DefinitionLocation, TypeAst, TypedArg, TypedClauseGuard,\n    TypedConstant, TypedCustomType, TypedDefinitions, TypedExpr, TypedFunction, TypedImport,\n    TypedModuleConstant, TypedPattern, TypedRecordConstructor, TypedStatement, TypedTypeAlias,\n};\nuse crate::type_::{Type, TypedCallArg};\nuse crate::{\n    ast::{Definition, SrcSpan, TypedModule},\n    config::{self, PackageConfig},\n    erlang,\n    error::{Error, FileIoAction, FileKind},\n    io::OutputFile,\n    parse::extra::{Comment, ModuleExtra},\n    type_,\n};\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse serde::{Deserialize, Serialize};\nuse std::fmt::{Debug, Display};\nuse std::sync::Arc;\nuse std::time::SystemTime;\nuse std::{collections::HashMap, ffi::OsString, fs::DirEntry, iter::Peekable, process};\nuse strum::{Display, EnumIter, EnumString, EnumVariantNames, VariantNames};\nuse vec1::Vec1;\n\n#[derive(\n    Debug,\n    Serialize,\n    Deserialize,\n    EnumString,\n    EnumVariantNames,\n    EnumIter,\n    Clone,\n    Copy,\n    PartialEq,\n    Eq,\n)]\n#[strum(serialize_all = \"lowercase\")]\npub enum Target {\n    #[strum(serialize = \"erlang\", serialize = \"erl\")]\n    #[serde(rename = \"erlang\", alias = \"erl\")]\n    Erlang,\n    #[strum(serialize = \"javascript\", serialize = \"js\")]\n    #[serde(rename = \"javascript\", alias = \"js\")]\n    JavaScript,\n}\n\nimpl Target {\n    pub fn as_presentable_str(&self) -> &str {\n        match self {\n            Target::Erlang => \"Erlang\",\n            Target::JavaScript => \"JavaScript\",\n        }\n    }\n\n    pub fn variant_strings() -> Vec<EcoString> {\n        Self::VARIANTS.iter().map(|s| (*s).into()).collect()\n    }\n\n    /// Returns `true` if the target is [`JavaScript`].\n    ///\n    /// [`JavaScript`]: Target::JavaScript\n    #[must_use]\n    pub fn is_javascript(&self) -> bool {\n        matches!(self, Self::JavaScript)\n    }\n\n    /// Returns `true` if the target is [`Erlang`].\n    ///\n    /// [`Erlang`]: Target::Erlang\n    #[must_use]\n    pub fn is_erlang(&self) -> bool {\n        matches!(self, Self::Erlang)\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\n/// This is used to skip compiling the root package when running the main\n/// function coming from a dependency. This way a dependency can be run even\n/// there's compilation errors in the root package.\n///\npub enum Compile {\n    /// The default compiler behaviour, compile all packages.\n    ///\n    All,\n    /// Only compile the dependency packages, skipping the root package.\n    ///\n    DepsOnly,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum Codegen {\n    All,\n    DepsOnly,\n    None,\n}\n\nimpl Codegen {\n    fn should_codegen(&self, is_root_package: bool) -> bool {\n        match self {\n            Codegen::All => true,\n            Codegen::DepsOnly => !is_root_package,\n            Codegen::None => false,\n        }\n    }\n}\n\n#[derive(\n    Debug, Serialize, Deserialize, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq,\n)]\npub enum Runtime {\n    #[strum(serialize = \"nodejs\", serialize = \"node\")]\n    #[serde(rename = \"nodejs\", alias = \"node\")]\n    NodeJs,\n    #[strum(serialize = \"deno\")]\n    #[serde(rename = \"deno\")]\n    Deno,\n    #[strum(serialize = \"bun\")]\n    #[serde(rename = \"bun\")]\n    Bun,\n}\n\nimpl Runtime {\n    pub fn as_presentable_str(&self) -> &str {\n        match self {\n            Runtime::NodeJs => \"NodeJS\",\n            Runtime::Deno => \"Deno\",\n            Runtime::Bun => \"Bun\",\n        }\n    }\n}\n\nimpl Default for Runtime {\n    fn default() -> Self {\n        Self::NodeJs\n    }\n}\n\n#[derive(Debug)]\npub enum TargetCodegenConfiguration {\n    JavaScript {\n        emit_typescript_definitions: bool,\n        prelude_location: Utf8PathBuf,\n    },\n    Erlang {\n        app_file: Option<ErlangAppCodegenConfiguration>,\n    },\n}\n\nimpl TargetCodegenConfiguration {\n    pub fn target(&self) -> Target {\n        match self {\n            Self::JavaScript { .. } => Target::JavaScript,\n            Self::Erlang { .. } => Target::Erlang,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct ErlangAppCodegenConfiguration {\n    pub include_dev_deps: bool,\n    /// Some packages have a different OTP application name than their package\n    /// name, as rebar3 (and Mix?) support this. The .app file must use the OTP\n    /// name, not the package name.\n    pub package_name_overrides: HashMap<EcoString, EcoString>,\n}\n\n#[derive(\n    Debug,\n    Serialize,\n    Deserialize,\n    Display,\n    EnumString,\n    EnumVariantNames,\n    EnumIter,\n    Clone,\n    Copy,\n    PartialEq,\n)]\n#[strum(serialize_all = \"lowercase\")]\npub enum Mode {\n    Dev,\n    Prod,\n    Lsp,\n}\n\nimpl Mode {\n    /// Returns `true` if the mode includes development code.\n    ///\n    pub fn includes_dev_code(&self) -> bool {\n        match self {\n            Self::Dev | Self::Lsp => true,\n            Self::Prod => false,\n        }\n    }\n\n    pub fn includes_dev_dependencies(&self) -> bool {\n        match self {\n            Mode::Dev | Mode::Lsp => true,\n            Mode::Prod => false,\n        }\n    }\n}\n\n#[test]\nfn mode_includes_dev_code() {\n    assert!(Mode::Dev.includes_dev_code());\n    assert!(Mode::Lsp.includes_dev_code());\n    assert!(!Mode::Prod.includes_dev_code());\n}\n\n#[derive(Debug)]\npub struct Package {\n    pub config: PackageConfig,\n    pub modules: Vec<Module>,\n    pub cached_module_names: Vec<EcoString>,\n}\n\nimpl Package {\n    pub fn attach_doc_and_module_comments(&mut self) {\n        for mut module in &mut self.modules {\n            module.attach_doc_and_module_comments();\n        }\n    }\n\n    pub fn into_modules_hashmap(self) -> HashMap<String, Module> {\n        self.modules\n            .into_iter()\n            .map(|m| (m.name.to_string(), m))\n            .collect()\n    }\n}\n\n#[derive(Debug)]\npub struct Module {\n    pub name: EcoString,\n    pub code: EcoString,\n    pub mtime: SystemTime,\n    pub input_path: Utf8PathBuf,\n    pub origin: Origin,\n    pub ast: TypedModule,\n    pub extra: ModuleExtra,\n    pub dependencies: Vec<(EcoString, SrcSpan)>,\n}\n\n#[derive(Debug)]\n/// A data structure used to store all definitions in a single homogeneous\n/// vector and sort them by their position in order to attach to each the right\n/// documentation.\n///\nenum DocumentableDefinition<'a> {\n    Constant(&'a mut TypedModuleConstant),\n    TypeAlias(&'a mut TypedTypeAlias),\n    CustomType(&'a mut TypedCustomType),\n    Function(&'a mut TypedFunction),\n    Import(&'a mut TypedImport),\n}\n\nimpl<'a> DocumentableDefinition<'a> {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            Self::Constant(module_constant) => module_constant.location,\n            Self::TypeAlias(type_alias) => type_alias.location,\n            Self::CustomType(custom_type) => custom_type.location,\n            Self::Function(function) => function.location,\n            Self::Import(import) => import.location,\n        }\n    }\n\n    pub fn put_doc(&mut self, new_documentation: (u32, EcoString)) {\n        match self {\n            Self::Import(_import) => (),\n            Self::Function(function) => {\n                let _ = function.documentation.replace(new_documentation);\n            }\n            Self::TypeAlias(type_alias) => {\n                let _ = type_alias.documentation.replace(new_documentation);\n            }\n            Self::CustomType(custom_type) => {\n                let _ = custom_type.documentation.replace(new_documentation);\n            }\n            Self::Constant(constant) => {\n                let _ = constant.documentation.replace(new_documentation);\n            }\n        }\n    }\n}\n\nimpl Module {\n    pub fn erlang_name(&self) -> EcoString {\n        module_erlang_name(&self.name)\n    }\n\n    pub fn compiled_erlang_path(&self) -> Utf8PathBuf {\n        let mut path = Utf8PathBuf::from(&module_erlang_name(&self.name));\n        assert!(path.set_extension(\"erl\"), \"Couldn't set file extension\");\n        path\n    }\n\n    pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {\n        self.ast.find_node(byte_index)\n    }\n\n    pub fn attach_doc_and_module_comments(&mut self) {\n        // Module Comments\n        self.ast.documentation = self\n            .extra\n            .module_comments\n            .iter()\n            .map(|span| Comment::from((span, self.code.as_str())).content.into())\n            .collect();\n\n        self.ast.type_info.documentation = self.ast.documentation.clone();\n\n        // Order definitions to avoid misassociating doc comments after the\n        // order has changed during compilation.\n        let TypedDefinitions {\n            imports,\n            constants,\n            custom_types,\n            type_aliases,\n            functions,\n        } = &mut self.ast.definitions;\n\n        let mut definitions = ((imports.iter_mut()).map(DocumentableDefinition::Import))\n            .chain((constants.iter_mut()).map(DocumentableDefinition::Constant))\n            .chain((custom_types.iter_mut()).map(DocumentableDefinition::CustomType))\n            .chain((type_aliases.iter_mut()).map(DocumentableDefinition::TypeAlias))\n            .chain((functions.iter_mut()).map(DocumentableDefinition::Function))\n            .sorted_by_key(|definition| definition.location())\n            .collect_vec();\n\n        // Doc Comments\n        let mut doc_comments = self.extra.doc_comments.iter().peekable();\n        for definition in &mut definitions {\n            let (docs_start, docs): (u32, Vec<&str>) = doc_comments_before(\n                &mut doc_comments,\n                &self.extra,\n                definition.location().start,\n                &self.code,\n            );\n            if !docs.is_empty() {\n                let doc = docs.join(\"\\n\").into();\n                definition.put_doc((docs_start, doc));\n            }\n\n            if let DocumentableDefinition::CustomType(CustomType { constructors, .. }) = definition\n            {\n                for constructor in constructors {\n                    let (docs_start, docs): (u32, Vec<&str>) = doc_comments_before(\n                        &mut doc_comments,\n                        &self.extra,\n                        constructor.location.start,\n                        &self.code,\n                    );\n                    if !docs.is_empty() {\n                        let doc = docs.join(\"\\n\").into();\n                        constructor.put_doc((docs_start, doc));\n                    }\n\n                    for argument in constructor.arguments.iter_mut() {\n                        let (docs_start, docs): (u32, Vec<&str>) = doc_comments_before(\n                            &mut doc_comments,\n                            &self.extra,\n                            argument.location.start,\n                            &self.code,\n                        );\n                        if !docs.is_empty() {\n                            let doc = docs.join(\"\\n\").into();\n                            argument.put_doc((docs_start, doc));\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\npub fn module_erlang_name(gleam_name: &EcoString) -> EcoString {\n    gleam_name.replace(\"/\", \"@\")\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub struct UnqualifiedImport<'a> {\n    pub name: &'a EcoString,\n    pub module: &'a EcoString,\n    pub is_type: bool,\n    pub location: &'a SrcSpan,\n}\n\n/// The position of a located expression. Used to determine extra context,\n/// such as whether to provide label completions if the expression is in\n/// argument position.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum ExpressionPosition<'a> {\n    Expression,\n    ArgumentOrLabel {\n        called_function: &'a TypedExpr,\n        function_arguments: &'a [TypedCallArg],\n    },\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Located<'a> {\n    Pattern(&'a TypedPattern),\n    PatternSpread {\n        spread_location: SrcSpan,\n        pattern: &'a TypedPattern,\n    },\n    // A prefix alias or a suffix variable defined in a string prefix pattern:\n    // \"prefix\" as alias <> suffix\n    StringPrefixPatternVariable {\n        location: SrcSpan,\n        name: &'a EcoString,\n    },\n    Statement(&'a TypedStatement),\n    Expression {\n        expression: &'a TypedExpr,\n        position: ExpressionPosition<'a>,\n    },\n    VariantConstructorDefinition(&'a TypedRecordConstructor),\n    FunctionBody(&'a TypedFunction),\n    Arg(&'a TypedArg),\n    Annotation {\n        ast: &'a TypeAst,\n        type_: std::sync::Arc<Type>,\n    },\n    UnqualifiedImport(UnqualifiedImport<'a>),\n    Label(SrcSpan, std::sync::Arc<Type>),\n    ModuleName {\n        location: SrcSpan,\n        module_name: EcoString,\n        module_alias: EcoString,\n        layer: ast::Layer,\n    },\n    Constant(&'a TypedConstant),\n    ClauseGuard(&'a TypedClauseGuard),\n\n    // A module's top level definitions\n    ModuleFunction(&'a TypedFunction),\n    ModuleConstant(&'a TypedModuleConstant),\n    ModuleImport(&'a TypedImport),\n    ModuleCustomType(&'a TypedCustomType),\n    ModuleTypeAlias(&'a TypedTypeAlias),\n}\n\nimpl<'a> Located<'a> {\n    // Looks up the type constructor for the given type and then create the location.\n    fn type_location(\n        &self,\n        importable_modules: &'a im::HashMap<EcoString, type_::ModuleInterface>,\n        type_: std::sync::Arc<Type>,\n    ) -> Option<DefinitionLocation> {\n        type_constructor_from_modules(importable_modules, type_).map(|t| DefinitionLocation {\n            module: Some(t.module.clone()),\n            span: t.origin,\n        })\n    }\n\n    pub fn definition_location(\n        &self,\n        importable_modules: &'a im::HashMap<EcoString, type_::ModuleInterface>,\n    ) -> Option<DefinitionLocation> {\n        match self {\n            Self::PatternSpread { .. } => None,\n            Self::Pattern(pattern) => pattern.definition_location(),\n            Self::StringPrefixPatternVariable { location, .. } => Some(DefinitionLocation {\n                module: None,\n                span: *location,\n            }),\n            Self::Statement(statement) => statement.definition_location(),\n            Self::FunctionBody(statement) => None,\n            Self::Expression { expression, .. } => expression.definition_location(),\n\n            Self::ModuleImport(import) => Some(DefinitionLocation {\n                module: Some(import.module.clone()),\n                span: SrcSpan { start: 0, end: 0 },\n            }),\n            Self::ModuleConstant(constant) => Some(DefinitionLocation {\n                module: None,\n                span: constant.location,\n            }),\n            Self::ModuleCustomType(custom_type) => Some(DefinitionLocation {\n                module: None,\n                span: custom_type.location,\n            }),\n            Self::ModuleFunction(function) => Some(DefinitionLocation {\n                module: None,\n                span: function.location,\n            }),\n            Self::ModuleTypeAlias(type_alias) => Some(DefinitionLocation {\n                module: None,\n                span: type_alias.location,\n            }),\n\n            Self::VariantConstructorDefinition(record) => Some(DefinitionLocation {\n                module: None,\n                span: record.location,\n            }),\n            Self::UnqualifiedImport(UnqualifiedImport {\n                module,\n                name,\n                is_type,\n                ..\n            }) => importable_modules.get(*module).and_then(|m| {\n                if *is_type {\n                    m.types.get(*name).map(|t| DefinitionLocation {\n                        module: Some((*module).clone()),\n                        span: t.origin,\n                    })\n                } else {\n                    m.values.get(*name).map(|v| DefinitionLocation {\n                        module: Some((*module).clone()),\n                        span: v.definition_location().span,\n                    })\n                }\n            }),\n            Self::Arg(_) => None,\n            Self::Annotation { type_, .. } => self.type_location(importable_modules, type_.clone()),\n            Self::Label(_, _) => None,\n            Self::ModuleName { module_name, .. } => Some(DefinitionLocation {\n                module: Some(module_name.clone()),\n                span: SrcSpan::new(0, 0),\n            }),\n            Self::Constant(constant) => constant.definition_location(),\n            Self::ClauseGuard(guard) => guard.definition_location(),\n        }\n    }\n\n    pub(crate) fn type_(&self) -> Option<Arc<Type>> {\n        match self {\n            Located::Pattern(pattern) => Some(pattern.type_()),\n            Located::StringPrefixPatternVariable { .. } => Some(type_::string()),\n            Located::Statement(statement) => Some(statement.type_()),\n            Located::Expression { expression, .. } => Some(expression.type_()),\n            Located::Arg(arg) => Some(arg.type_.clone()),\n            Located::Label(_, type_) | Located::Annotation { type_, .. } => Some(type_.clone()),\n            Located::Constant(constant) => Some(constant.type_()),\n            Located::ClauseGuard(guard) => Some(guard.type_()),\n\n            Located::PatternSpread { .. }\n            | Located::ModuleConstant(_)\n            | Located::ModuleCustomType(_)\n            | Located::ModuleFunction(_)\n            | Located::ModuleImport(_)\n            | Located::ModuleTypeAlias(_)\n            | Located::VariantConstructorDefinition(_)\n            | Located::FunctionBody(_)\n            | Located::UnqualifiedImport(_)\n            | Located::ModuleName { .. } => None,\n        }\n    }\n\n    pub fn type_definition_locations(\n        &self,\n        importable_modules: &im::HashMap<EcoString, type_::ModuleInterface>,\n    ) -> Option<Vec<DefinitionLocation>> {\n        let type_ = self.type_()?;\n        Some(type_to_definition_locations(type_, importable_modules))\n    }\n}\n\n/// Returns the locations of all the types that one could reach starting from\n/// the given type (included). This includes all types that are part of a\n/// tuple/function type or that are used as args in a named type.\n///\n/// For example, given this type `Dict(Int, #(Wibble, Wobble))` all the\n/// \"reachable\" include: `Dict`, `Int`, `Wibble` and `Wobble`.\n///\n/// This is what powers the \"go to type definition\" capability of the language\n/// server.\n///\nfn type_to_definition_locations<'a>(\n    type_: Arc<Type>,\n    importable_modules: &'a im::HashMap<EcoString, type_::ModuleInterface>,\n) -> Vec<DefinitionLocation> {\n    match type_.as_ref() {\n        // For named types we start with the location of the named type itself\n        // followed by the locations of all types they reference in their args.\n        //\n        // For example with a `Dict(Wibble, Wobble)` we'd start with the\n        // definition of `Dict`, followed by the definition of `Wibble` and\n        // `Wobble`.\n        //\n        Type::Named {\n            module,\n            name,\n            arguments,\n            ..\n        } => {\n            let Some(module) = importable_modules.get(module) else {\n                return vec![];\n            };\n\n            let Some(type_) = module.get_public_type(&name) else {\n                return vec![];\n            };\n\n            let mut locations = vec![DefinitionLocation {\n                module: Some(module.name.clone()),\n                span: type_.origin,\n            }];\n            for argument in arguments {\n                locations.extend(type_to_definition_locations(\n                    argument.clone(),\n                    importable_modules,\n                ));\n            }\n            locations\n        }\n\n        // For fn types we just get the locations of their arguments and return\n        // type.\n        //\n        Type::Fn { arguments, return_ } => arguments\n            .iter()\n            .flat_map(|argument| type_to_definition_locations(argument.clone(), importable_modules))\n            .chain(type_to_definition_locations(\n                return_.clone(),\n                importable_modules,\n            ))\n            .collect_vec(),\n\n        // In case of a var we just follow it and get the locations of the type\n        // it points to.\n        //\n        Type::Var { type_ } => match type_.borrow().clone() {\n            type_::TypeVar::Unbound { .. } | type_::TypeVar::Generic { .. } => vec![],\n            type_::TypeVar::Link { type_ } => {\n                type_to_definition_locations(type_, importable_modules)\n            }\n        },\n\n        // In case of tuples we get the locations of the wrapped types.\n        //\n        Type::Tuple { elements } => elements\n            .iter()\n            .flat_map(|element| type_to_definition_locations(element.clone(), importable_modules))\n            .collect_vec(),\n    }\n}\n\n// Looks up the type constructor for the given type\npub fn type_constructor_from_modules(\n    importable_modules: &im::HashMap<EcoString, type_::ModuleInterface>,\n    type_: std::sync::Arc<Type>,\n) -> Option<&type_::TypeConstructor> {\n    let type_ = type_::collapse_links(type_);\n    match type_.as_ref() {\n        Type::Named { name, module, .. } => importable_modules\n            .get(module)\n            .and_then(|i| i.types.get(name)),\n        _ => None,\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Origin {\n    Src,\n    Test,\n    Dev,\n}\n\nimpl Origin {\n    /// Returns `true` if the origin is [`Src`].\n    ///\n    /// [`Src`]: Origin::Src\n    #[must_use]\n    pub fn is_src(&self) -> bool {\n        matches!(self, Self::Src)\n    }\n\n    /// Returns `true` if the origin is [`Test`].\n    ///\n    /// [`Test`]: Origin::Test\n    #[must_use]\n    pub fn is_test(&self) -> bool {\n        matches!(self, Self::Test)\n    }\n\n    /// Returns `true` if the origin is [`Dev`].\n    ///\n    /// [`Dev`]: Origin::Dev\n    #[must_use]\n    pub fn is_dev(&self) -> bool {\n        matches!(self, Self::Dev)\n    }\n\n    /// Name of the folder containing the origin.\n    #[must_use]\n    pub fn folder_name(&self) -> &str {\n        match self {\n            Origin::Src => \"src\",\n            Origin::Test => \"test\",\n            Origin::Dev => \"dev\",\n        }\n    }\n}\n\nfn doc_comments_before<'a>(\n    doc_comments_spans: &mut Peekable<impl Iterator<Item = &'a SrcSpan>>,\n    extra: &ModuleExtra,\n    byte: u32,\n    src: &'a str,\n) -> (u32, Vec<&'a str>) {\n    let mut comments = vec![];\n    let mut comment_start = u32::MAX;\n    while let Some(SrcSpan { start, end }) = doc_comments_spans.peek() {\n        if start > &byte {\n            break;\n        }\n        if extra.has_comment_between(*end, byte) {\n            // We ignore doc comments that come before a regular comment.\n            _ = doc_comments_spans.next();\n            continue;\n        }\n        let comment = doc_comments_spans\n            .next()\n            .expect(\"Comment before accessing next span\");\n\n        if comment.start < comment_start {\n            comment_start = comment.start;\n        }\n\n        comments.push(Comment::from((comment, src)).content)\n    }\n    (comment_start, comments)\n}\n\n#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]\npub struct SourceFingerprint(u64);\n\nimpl SourceFingerprint {\n    pub fn new(source: &str) -> Self {\n        SourceFingerprint(xxhash_rust::xxh3::xxh3_64(source.as_bytes()))\n    }\n\n    pub fn to_numerical_string(&self) -> String {\n        self.0.to_string()\n    }\n}\n\n/// Like a `Result`, but the operation can partially succeed or fail.\n///\n#[derive(Debug)]\npub enum Outcome<T, E> {\n    /// The operation was totally succesful.\n    Ok(T),\n\n    /// The operation was partially successful but there were problems.\n    PartialFailure(T, E),\n\n    /// The operation was entirely unsuccessful.\n    TotalFailure(E),\n}\n\nimpl<T, E> Outcome<T, E>\nwhere\n    E: Debug,\n{\n    #[cfg(test)]\n    /// Panic if there's any errors\n    pub fn unwrap(self) -> T {\n        match self {\n            Outcome::Ok(t) => t,\n            Outcome::PartialFailure(_, errors) => panic!(\"Error: {:?}\", errors),\n            Outcome::TotalFailure(error) => panic!(\"Error: {:?}\", error),\n        }\n    }\n\n    /// Panic if there's any errors\n    pub fn expect(self, e: &'static str) -> T {\n        match self {\n            Outcome::Ok(t) => t,\n            Outcome::PartialFailure(_, errors) => panic!(\"{e}: {:?}\", errors),\n            Outcome::TotalFailure(error) => panic!(\"{e}: {:?}\", error),\n        }\n    }\n\n    pub fn into_result(self) -> Result<T, E> {\n        match self {\n            Outcome::Ok(t) => Ok(t),\n            Outcome::PartialFailure(_, e) | Outcome::TotalFailure(e) => Err(e),\n        }\n    }\n\n    pub fn map<T2>(self, f: impl FnOnce(T) -> T2) -> Outcome<T2, E> {\n        match self {\n            Outcome::Ok(t) => Outcome::Ok(f(t)),\n            Outcome::PartialFailure(t, e) => Outcome::PartialFailure(f(t), e),\n            Outcome::TotalFailure(e) => Outcome::TotalFailure(e),\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/call_graph/into_dependency_order_tests.rs",
    "content": "use super::*;\nuse crate::{\n    ast::{Arg, Function, ModuleConstant, Publicity},\n    type_::{\n        Deprecation,\n        expression::{Implementations, Purity},\n    },\n};\nuse ecow::EcoString;\n\ntype FuncInput = (&'static str, &'static [&'static str], &'static str);\ntype ConstInput = (&'static str, &'static str);\n\nfn parse_and_order(\n    functions: &[FuncInput],\n    constants: &[ConstInput],\n) -> Result<Vec<Vec<EcoString>>, Error> {\n    let functions = functions\n        .iter()\n        .map(|(name, arguments, src)| Function {\n            name: Some((SrcSpan::default(), EcoString::from(*name))),\n            arguments: arguments\n                .iter()\n                .map(|name| Arg {\n                    names: crate::ast::ArgNames::Named {\n                        name: EcoString::from(*name),\n                        location: Default::default(),\n                    },\n                    location: Default::default(),\n                    annotation: None,\n                    type_: (),\n                })\n                .collect_vec(),\n            body: crate::parse::parse_statement_sequence(src)\n                .expect(\"syntax error\")\n                .to_vec(),\n            location: Default::default(),\n            body_start: None,\n            return_annotation: None,\n            publicity: Publicity::Public,\n            deprecation: Deprecation::NotDeprecated,\n            end_position: src.len() as u32,\n            return_type: (),\n            documentation: None,\n            external_erlang: None,\n            external_javascript: None,\n            implementations: Implementations {\n                gleam: true,\n                uses_erlang_externals: true,\n                uses_javascript_externals: false,\n                can_run_on_erlang: true,\n                can_run_on_javascript: true,\n            },\n            purity: Purity::Impure,\n        })\n        .collect_vec();\n    let constants = constants\n        .iter()\n        .map(|(name, value)| {\n            let const_value = crate::parse::parse_const_value(value).expect(\"syntax error\");\n            ModuleConstant {\n                documentation: None,\n                location: Default::default(),\n                publicity: Publicity::Public,\n                name: EcoString::from(*name),\n                name_location: SrcSpan::default(),\n                annotation: None,\n                value: Box::from(const_value),\n                implementations: Implementations {\n                    gleam: true,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                },\n                type_: (),\n                deprecation: Deprecation::NotDeprecated,\n            }\n        })\n        .collect_vec();\n\n    Ok(into_dependency_order(functions, constants)?\n        .into_iter()\n        .map(|level| {\n            level\n                .into_iter()\n                .map(|function| match function {\n                    CallGraphNode::Function(f) => f.name.map(|(_, name)| name).unwrap(),\n                    CallGraphNode::ModuleConstant(c) => c.name,\n                })\n                .collect_vec()\n        })\n        .collect())\n}\n\n#[test]\nfn empty() {\n    let functions = [];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        Vec::<Vec<EcoString>>::new()\n    );\n}\n\n#[test]\nfn no_deps() {\n    let functions = [\n        (\"a\", [].as_slice(), \"1\"),\n        (\"b\", [].as_slice(), r#\"\"ok\"\"#),\n        (\"c\", [].as_slice(), r#\"1\"#),\n        (\"d\", [].as_slice(), r#\"1.0\"#),\n        (\"e\", [].as_slice(), r#\"todo\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"b\"], vec![\"c\"], vec![\"d\"], vec![\"e\"]]\n    );\n}\n\n#[test]\nfn one_dep() {\n    let functions = [\n        (\"a\", [].as_slice(), \"1\"),\n        (\"b\", [].as_slice(), r#\"c\"#),\n        (\"c\", [].as_slice(), r#\"0\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"c\"], vec![\"b\"]]\n    );\n}\n\n#[test]\nfn unknown_vars() {\n    let functions = [\n        (\"a\", [].as_slice(), \"1\"),\n        (\"b\", [].as_slice(), r#\"Nil\"#),\n        (\"c\", [].as_slice(), r#\"Ok\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"b\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn calling_function() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"b()\"#),\n        (\"b\", [].as_slice(), r#\"c(1, 2)\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"c\"], vec![\"b\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn ref_in_call_argument() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"c(1, b())\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn sequence() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"c({ 1 2 b })\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn tuple() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"#(b, c, 1)\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pipeline() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"1 |> b |> c\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn list() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"[b, b, c, 1]\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn list_spread() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"[b, b, ..c]\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn record_access() {\n    let functions = [\n        (\"a\", [].as_slice(), \"1\"),\n        (\"b\", [].as_slice(), r#\"b().wibble\"#),\n        (\"c\", [].as_slice(), r#\"123\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"b\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn binop() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"1 + a() + 2 / b() * 4\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn bit_arrays() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"<<b, c>>\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn tuple_index() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"b.0\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn record_update() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"Wibble(..b, wobble: c())\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn negate() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"!c()\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn use_() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"use x <- c\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn use_shadowing() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"123\"#),\n        (\"b\", [].as_slice(), r#\"{ use c <- a c }\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"b\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn fn_argument_shadowing() {\n    let functions = &[\n        (\"a\", [].as_slice(), r#\"fn(b) { c b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn fn_argument_shadowing_then_not() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ fn(b) { c b } b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn let_var() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let c = b c }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn pattern_int() {\n    let functions = [(\"a\", [].as_slice(), r#\"{ let 1 = x }\"#)];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pattern_float() {\n    let functions = [(\"a\", [].as_slice(), r#\"{ let 1.0 = x }\"#)];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pattern_string() {\n    let functions = [(\"a\", [].as_slice(), r#\"{ let \"1.0\" = x }\"#)];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pattern_underscore() {\n    let functions = [(\"a\", [].as_slice(), r#\"{ let _ = x }\"#)];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pattern_concat() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let \"a\" <> c = b c }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn pattern_tuple() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let #(a, c) = b a c }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn pattern_list() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let [a, c] = b a c }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn pattern_list_spread() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let [a, ..c] = b a c }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn pattern_bit_array_segment_size_var_usage() {\n    let functions = [\n        (\n            \"a\",\n            [].as_slice(),\n            r#\"{ let <<y:size(b), _:unit(3)>> = c y }\"#,\n        ),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pattern_assign() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let 1 as b = c b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn pattern_constructor() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let Ok(b) = c b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn scope_reset() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let x = { let b = 1 b } b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn case_subject() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"case b { _ -> 1 }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn case_subjects() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"case b, c { _, _ -> 1 }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"c\"], vec![\"a\"]]\n    );\n}\n\n#[test]\nfn case_pattern_shadow() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"case 1 { b -> b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"b\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn case_use_in_clause() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"case 1 { _ -> b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn case_clause_doesnt_shadow_later_clauses() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"case 1 { b -> 1 _ -> b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn case_clause_doesnt_shadow_after() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ case 1 { b -> 1 } b }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn guard() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"case 1 { _ if b -> 1 }\"#),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn big_guard() {\n    let functions = [\n        (\n            \"a\",\n            [].as_slice(),\n            r#\"case 1 { _ if 1 == 2 || x != #(Ok(b), 123) -> 1 }\"#,\n        ),\n        (\"b\", [].as_slice(), r#\"123\"#),\n        (\"c\", [].as_slice(), \"1\"),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\"], vec![\"a\"], vec![\"c\"]]\n    );\n}\n\n#[test]\nfn duplicate_external_function_name() {\n    let functions = [(\"c\", [].as_slice(), \"1\"), (\"c\", [].as_slice(), \"1\")];\n    _ = parse_and_order(functions.as_slice(), [].as_slice()).unwrap_err();\n}\n\n#[test]\nfn duplicate_function_name() {\n    let functions = [\n        (\"b\", [].as_slice(), r#\"123456\"#),\n        (\"b\", [].as_slice(), r#\"123456\"#),\n    ];\n    _ = parse_and_order(functions.as_slice(), [].as_slice()).unwrap_err();\n}\n\n#[test]\nfn more_complex_cycle() {\n    let functions = [\n        (\"a1\", [].as_slice(), r#\"{ a2 }\"#),\n        (\"a2\", [].as_slice(), r#\"{ a3 a1 }\"#),\n        (\"a3\", [].as_slice(), r#\"{ a1 }\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a2\", \"a3\", \"a1\"]]\n    );\n}\n\n#[test]\nfn function_argument_shadowing() {\n    let functions = [\n        (\"a\", [\"b\"].as_slice(), r#\"b\"#),\n        (\"b\", [].as_slice(), r#\"Nil\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"b\"]]\n    );\n}\n\n#[test]\nfn constants_and_functions() {\n    let functions = [\n        (\"a\", [\"b\"].as_slice(), r#\"b\"#),\n        (\"b\", [].as_slice(), r#\"c\"#),\n    ];\n    let constants = [(\"d\", r#\"c\"#), (\"c\", r#\"a\"#)];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), constants.as_slice()).unwrap(),\n        vec![vec![\"a\"], vec![\"c\"], vec![\"b\"], vec![\"d\"]]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2275\n#[test]\nfn bug_2275() {\n    let functions = [\n        (\"one\", [].as_slice(), r#\"two one\"#),\n        (\"two\", [].as_slice(), r#\"two\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"two\"], vec![\"one\"]]\n    );\n}\n\n#[test]\nfn let_assert_message() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ let assert True = False as b() }\"#),\n        (\"b\", [].as_slice(), r#\"a()\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\", \"a\"]]\n    );\n}\n\n#[test]\nfn assert_subject() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ assert b() }\"#),\n        (\"b\", [].as_slice(), r#\"a()\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\", \"a\"]]\n    );\n}\n\n#[test]\nfn assert_message() {\n    let functions = [\n        (\"a\", [].as_slice(), r#\"{ assert False as b() }\"#),\n        (\"b\", [].as_slice(), r#\"a()\"#),\n    ];\n    assert_eq!(\n        parse_and_order(functions.as_slice(), [].as_slice()).unwrap(),\n        vec![vec![\"b\", \"a\"]]\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/call_graph.rs",
    "content": "//! Graphs that represent the relationships between entities in a Gleam module,\n//! such as module functions or constants.\n\n#[cfg(test)]\nmod into_dependency_order_tests;\n\nuse crate::{\n    Result,\n    ast::{\n        AssignName, AssignmentKind, BitArrayOption, BitArraySize, ClauseGuard, Constant, Pattern,\n        SrcSpan, Statement, UntypedClauseGuard, UntypedExpr, UntypedFunction,\n        UntypedModuleConstant, UntypedPattern, UntypedStatement,\n    },\n    type_::Error,\n};\nuse itertools::Itertools;\nuse petgraph::stable_graph::NodeIndex;\nuse petgraph::{Directed, stable_graph::StableGraph};\n\n#[derive(Debug, Default)]\nstruct CallGraphBuilder<'a> {\n    names: im::HashMap<&'a str, Option<(NodeIndex, SrcSpan)>>,\n    graph: StableGraph<(), (), Directed>,\n    current_function: NodeIndex,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum CallGraphNode {\n    Function(UntypedFunction),\n\n    ModuleConstant(UntypedModuleConstant),\n}\n\nimpl<'a> CallGraphBuilder<'a> {\n    fn into_graph(self) -> StableGraph<(), (), Directed> {\n        self.graph\n    }\n\n    /// Add each function to the graph, storing the index of the node under the\n    /// name of the function.\n    fn register_module_function_existence(\n        &mut self,\n        function: &'a UntypedFunction,\n    ) -> Result<(), Error> {\n        let (_, name) = function\n            .name\n            .as_ref()\n            .expect(\"A module's function must be named\");\n        let location = function.location;\n\n        let index = self.graph.add_node(());\n        let previous = self.names.insert(name, Some((index, location)));\n\n        if let Some(Some((_, previous_location))) = previous {\n            return Err(Error::DuplicateName {\n                location_a: location,\n                location_b: previous_location,\n                name: name.clone(),\n            });\n        }\n        Ok(())\n    }\n\n    /// Add each constant to the graph, storing the index of the node under the\n    /// name of the constant.\n    fn register_module_const_existence(\n        &mut self,\n        constant: &'a UntypedModuleConstant,\n    ) -> Result<(), Error> {\n        let name = &constant.name;\n        let location = constant.location;\n\n        let index = self.graph.add_node(());\n        let previous = self.names.insert(name, Some((index, location)));\n\n        if let Some(Some((_, previous_location))) = previous {\n            return Err(Error::DuplicateName {\n                location_a: location,\n                location_b: previous_location,\n                name: name.clone(),\n            });\n        }\n        Ok(())\n    }\n\n    fn register_references_constant(&mut self, constant: &'a UntypedModuleConstant) {\n        self.current_function = self\n            .names\n            .get(constant.name.as_str())\n            .expect(\"Constant must already have been registered as existing\")\n            .expect(\"Constant must not be shadowed at module level\")\n            .0;\n        self.constant(&constant.value);\n    }\n\n    fn register_references(&mut self, function: &'a UntypedFunction) {\n        let names = self.names.clone();\n\n        self.current_function = self\n            .names\n            .get(\n                function\n                    .name\n                    .as_ref()\n                    .map(|(_, name)| name.as_str())\n                    .expect(\"A module's function must be named\"),\n            )\n            .expect(\"Function must already have been registered as existing\")\n            .expect(\"Function must not be shadowed at module level\")\n            .0;\n        for name in function\n            .arguments\n            .iter()\n            .flat_map(|a| a.get_variable_name())\n        {\n            self.define(name);\n        }\n\n        self.statements(&function.body);\n\n        self.names = names;\n    }\n\n    fn referenced(&mut self, name: &str) {\n        // If we don't know what the target is then it's either a programmer\n        // error to be detected later, or it's not a module function and as such\n        // is not a value we are tracking.\n        let Some(target) = self.names.get(name) else {\n            return;\n        };\n\n        // If the target is known but registered as None then it's local value\n        // that shadows a module function.\n        let Some((target, _)) = target else { return };\n\n        _ = self.graph.add_edge(self.current_function, *target, ());\n    }\n\n    fn statements(&mut self, statements: &'a [UntypedStatement]) {\n        let names = self.names.clone();\n        for statement in statements {\n            self.statement(statement);\n        }\n        self.names = names;\n    }\n\n    fn statement(&mut self, statement: &'a UntypedStatement) {\n        match statement {\n            Statement::Expression(expression) => {\n                self.expression(expression);\n            }\n            Statement::Assignment(assignment) => {\n                self.expression(&assignment.value);\n                self.pattern(&assignment.pattern);\n                match &assignment.kind {\n                    AssignmentKind::Assert {\n                        message: Some(message),\n                        ..\n                    } => self.expression(message),\n                    AssignmentKind::Let\n                    | AssignmentKind::Generated\n                    | AssignmentKind::Assert { message: None, .. } => {}\n                }\n            }\n            Statement::Use(use_) => {\n                self.expression(&use_.call);\n                for assignment in &use_.assignments {\n                    self.pattern(&assignment.pattern);\n                }\n            }\n            Statement::Assert(assert) => {\n                self.expression(&assert.value);\n                if let Some(message) = &assert.message {\n                    self.expression(message)\n                }\n            }\n        };\n    }\n\n    fn expression(&mut self, expression: &'a UntypedExpr) {\n        match expression {\n            UntypedExpr::Int { .. } | UntypedExpr::Float { .. } | UntypedExpr::String { .. } => (),\n\n            UntypedExpr::Todo { message, .. } => {\n                if let Some(msg_expr) = message {\n                    self.expression(msg_expr)\n                }\n            }\n\n            UntypedExpr::Panic { message, .. } => {\n                if let Some(msg_expr) = message {\n                    self.expression(msg_expr)\n                }\n            }\n\n            UntypedExpr::Echo {\n                expression,\n                location: _,\n                keyword_end: _,\n                message,\n            } => {\n                if let Some(expression) = expression {\n                    self.expression(expression);\n                }\n                if let Some(message) = message {\n                    self.expression(message);\n                }\n            }\n\n            // Aha! A variable is being referenced.\n            UntypedExpr::Var { name, .. } => {\n                self.referenced(name);\n            }\n\n            UntypedExpr::Call { fun, arguments, .. } => {\n                self.expression(fun);\n                for argument in arguments {\n                    self.expression(&argument.value);\n                }\n            }\n\n            UntypedExpr::PipeLine { expressions } => {\n                for expression in expressions {\n                    self.expression(expression);\n                }\n            }\n\n            UntypedExpr::Tuple { elements, .. } => {\n                for expression in elements {\n                    self.expression(expression);\n                }\n            }\n\n            UntypedExpr::Block { statements, .. } => {\n                let names = self.names.clone();\n                self.statements(statements);\n                self.names = names;\n            }\n\n            UntypedExpr::BinOp { left, right, .. } => {\n                self.expression(left);\n                self.expression(right);\n            }\n\n            UntypedExpr::List { elements, tail, .. } => {\n                for element in elements {\n                    self.expression(element);\n                }\n                if let Some(tail) = tail {\n                    self.expression(tail);\n                }\n            }\n\n            UntypedExpr::NegateInt {\n                value: expression, ..\n            }\n            | UntypedExpr::NegateBool {\n                value: expression, ..\n            }\n            | UntypedExpr::TupleIndex {\n                tuple: expression, ..\n            }\n            | UntypedExpr::FieldAccess {\n                container: expression,\n                ..\n            } => {\n                self.expression(expression);\n            }\n\n            UntypedExpr::BitArray { segments, .. } => {\n                for segment in segments {\n                    self.expression(&segment.value);\n                    for option in &segment.options {\n                        if let BitArrayOption::Size { value, .. } = option {\n                            self.expression(value);\n                        }\n                    }\n                }\n            }\n\n            UntypedExpr::RecordUpdate {\n                record, arguments, ..\n            } => {\n                self.expression(&record.base);\n                for argument in arguments {\n                    self.expression(&argument.value);\n                }\n            }\n\n            UntypedExpr::Fn {\n                arguments, body, ..\n            } => {\n                let names = self.names.clone();\n                for argument in arguments {\n                    if let Some(name) = argument.names.get_variable_name() {\n                        self.define(name)\n                    }\n                }\n                self.statements(body);\n                self.names = names;\n            }\n\n            UntypedExpr::Case {\n                subjects, clauses, ..\n            } => {\n                for subject in subjects {\n                    self.expression(subject);\n                }\n                for clause in clauses.as_deref().unwrap_or_default() {\n                    let names = self.names.clone();\n                    for pattern in &clause.pattern {\n                        self.pattern(pattern);\n                    }\n                    if let Some(guard) = &clause.guard {\n                        self.guard(guard);\n                    }\n                    self.expression(&clause.then);\n                    self.names = names;\n                }\n            }\n        }\n    }\n\n    fn pattern(&mut self, pattern: &'a UntypedPattern) {\n        match pattern {\n            Pattern::Discard { .. }\n            | Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::StringPrefix {\n                right_side_assignment: AssignName::Discard(_),\n                ..\n            }\n            | Pattern::Invalid { .. } => (),\n\n            Pattern::StringPrefix {\n                right_side_assignment: AssignName::Variable(name),\n                ..\n            }\n            | Pattern::Variable { name, .. } => {\n                self.define(name);\n            }\n\n            Pattern::Tuple {\n                elements: patterns, ..\n            } => {\n                for pattern in patterns {\n                    self.pattern(pattern);\n                }\n            }\n\n            Pattern::List { elements, tail, .. } => {\n                for element in elements {\n                    self.pattern(element);\n                }\n                if let Some(tail) = tail {\n                    self.pattern(&tail.pattern);\n                }\n            }\n\n            Pattern::BitArraySize(size) => {\n                self.bit_array_size(size);\n            }\n\n            Pattern::Assign { name, pattern, .. } => {\n                self.define(name);\n                self.pattern(pattern);\n            }\n\n            Pattern::Constructor { arguments, .. } => {\n                for argument in arguments {\n                    self.pattern(&argument.value);\n                }\n            }\n\n            Pattern::BitArray { segments, .. } => {\n                for segment in segments {\n                    for option in &segment.options {\n                        self.bit_array_option(option, |s, p| s.pattern(p));\n                    }\n                    self.pattern(&segment.value);\n                }\n            }\n        }\n    }\n\n    fn bit_array_size(&mut self, size: &'a BitArraySize<()>) {\n        match size {\n            BitArraySize::Int { .. } => {}\n            BitArraySize::Variable { name, .. } => self.referenced(name),\n            BitArraySize::BinaryOperator { left, right, .. } => {\n                self.bit_array_size(left);\n                self.bit_array_size(right);\n            }\n            BitArraySize::Block { inner, .. } => self.bit_array_size(inner),\n        }\n    }\n\n    fn define(&mut self, name: &'a str) {\n        _ = self.names.insert(name, None);\n    }\n\n    fn bit_array_option<T>(\n        &mut self,\n        option: &'a BitArrayOption<T>,\n        process: impl Fn(&mut Self, &'a T),\n    ) {\n        match option {\n            BitArrayOption::Big { .. }\n            | BitArrayOption::Bytes { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unit { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf8Codepoint { .. } => (),\n\n            BitArrayOption::Size { value: pattern, .. } => {\n                process(self, pattern);\n            }\n        }\n    }\n\n    fn guard(&mut self, guard: &'a UntypedClauseGuard) {\n        match guard {\n            ClauseGuard::BinaryOperator { left, right, .. } => {\n                self.guard(left);\n                self.guard(right);\n            }\n\n            ClauseGuard::Block { value, .. } => self.guard(value),\n\n            ClauseGuard::Not { expression, .. } => self.guard(expression),\n\n            ClauseGuard::Var { name, .. } => self.referenced(name),\n\n            ClauseGuard::TupleIndex { tuple, .. } => self.guard(tuple),\n\n            ClauseGuard::FieldAccess { container, .. } => self.guard(container),\n\n            ClauseGuard::ModuleSelect { module_name, .. } => self.referenced(module_name),\n\n            ClauseGuard::Constant(constant) => self.constant(constant),\n        }\n    }\n\n    fn constant(&mut self, constant: &'a Constant<(), ()>) {\n        match constant {\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Invalid { .. }\n            | Constant::Var {\n                module: Some(_), ..\n            } => (),\n\n            Constant::List { elements, .. } | Constant::Tuple { elements, .. } => {\n                for element in elements {\n                    self.constant(element);\n                }\n            }\n\n            Constant::Record { arguments, .. } => {\n                for argument in arguments {\n                    self.constant(&argument.value);\n                }\n            }\n\n            Constant::RecordUpdate {\n                record, arguments, ..\n            } => {\n                self.constant(&record.base);\n\n                for argument in arguments {\n                    self.constant(&argument.value);\n                }\n            }\n\n            Constant::Var {\n                module: None, name, ..\n            } => self.referenced(name),\n\n            Constant::BitArray { segments, .. } => {\n                for segment in segments {\n                    for option in &segment.options {\n                        self.bit_array_option(option, |s, c| s.constant(c));\n                    }\n                    self.constant(&segment.value);\n                }\n            }\n\n            Constant::StringConcatenation { left, right, .. } => {\n                self.constant(left);\n                self.constant(right);\n            }\n        }\n    }\n}\n\n/// Determine the order in which functions and constants should be compiled and if any\n/// mutually recursive functions need to be compiled together.\n///\npub fn into_dependency_order(\n    functions: Vec<UntypedFunction>,\n    constants: Vec<UntypedModuleConstant>,\n) -> Result<Vec<Vec<CallGraphNode>>, Error> {\n    let mut grapher = CallGraphBuilder::default();\n\n    for function in &functions {\n        grapher.register_module_function_existence(function)?;\n    }\n\n    for constant in &constants {\n        grapher.register_module_const_existence(constant)?;\n    }\n\n    // Build the call graph between the module functions.\n    for function in &functions {\n        grapher.register_references(function);\n    }\n\n    for constant in &constants {\n        grapher.register_references_constant(constant);\n    }\n\n    // Consume the grapher to get the graph\n    let graph = grapher.into_graph();\n\n    // Determine the order in which the functions should be compiled by looking\n    // at which other functions they depend on.\n    let indices = crate::graph::into_dependency_order(graph);\n\n    // We got node indices back, so we need to map them back to the functions\n    // they represent.\n    // We wrap them each with `Some` so we can use `.take()`.\n    let mut definitions = functions\n        .into_iter()\n        .map(CallGraphNode::Function)\n        .chain(constants.into_iter().map(CallGraphNode::ModuleConstant))\n        .map(Some)\n        .collect_vec();\n\n    let ordered = indices\n        .into_iter()\n        .map(|level| {\n            level\n                .into_iter()\n                .map(|index| {\n                    definitions\n                        .get_mut(index.index())\n                        .expect(\"Index out of bounds\")\n                        .take()\n                        .expect(\"Function already taken\")\n                })\n                .collect_vec()\n        })\n        .collect_vec();\n\n    Ok(ordered)\n}\n"
  },
  {
    "path": "compiler-core/src/codegen.rs",
    "content": "use crate::{\n    Result,\n    build::{\n        ErlangAppCodegenConfiguration, Module, module_erlang_name, package_compiler::StdlibPackage,\n    },\n    config::PackageConfig,\n    erlang,\n    io::FileSystemWriter,\n    javascript::{self, ModuleConfig},\n    line_numbers::LineNumbers,\n};\nuse ecow::EcoString;\nuse erlang::escape_atom_string;\nuse itertools::Itertools;\nuse std::fmt::Debug;\n\nuse camino::Utf8Path;\n\n/// A code generator that creates a .erl Erlang module and record header files\n/// for each Gleam module in the package.\n#[derive(Debug)]\npub struct Erlang<'a> {\n    build_directory: &'a Utf8Path,\n    include_directory: &'a Utf8Path,\n}\n\nimpl<'a> Erlang<'a> {\n    pub fn new(build_directory: &'a Utf8Path, include_directory: &'a Utf8Path) -> Self {\n        Self {\n            build_directory,\n            include_directory,\n        }\n    }\n\n    pub fn render<Writer: FileSystemWriter>(\n        &self,\n        writer: Writer,\n        modules: &[Module],\n        root: &Utf8Path,\n    ) -> Result<()> {\n        for module in modules {\n            let erl_name = module.erlang_name();\n            self.erlang_module(&writer, module, &erl_name, root)?;\n            self.erlang_record_headers(&writer, module, &erl_name)?;\n        }\n        Ok(())\n    }\n\n    fn erlang_module<Writer: FileSystemWriter>(\n        &self,\n        writer: &Writer,\n        module: &Module,\n        erl_name: &str,\n        root: &Utf8Path,\n    ) -> Result<()> {\n        let name = format!(\"{erl_name}.erl\");\n        let path = self.build_directory.join(&name);\n        let line_numbers = LineNumbers::new(&module.code);\n        let output = erlang::module(&module.ast, &line_numbers, root);\n        tracing::debug!(name = ?name, \"Generated Erlang module\");\n        writer.write(&path, &output?)\n    }\n\n    fn erlang_record_headers<Writer: FileSystemWriter>(\n        &self,\n        writer: &Writer,\n        module: &Module,\n        erl_name: &str,\n    ) -> Result<()> {\n        for (name, text) in erlang::records(&module.ast) {\n            let name = format!(\"{erl_name}_{name}.hrl\");\n            tracing::debug!(name = ?name, \"Generated Erlang header\");\n            writer.write(&self.include_directory.join(name), &text)?;\n        }\n        Ok(())\n    }\n}\n\n/// A code generator that creates a .app Erlang application file for the package\n#[derive(Debug)]\npub struct ErlangApp<'a> {\n    output_directory: &'a Utf8Path,\n    config: &'a ErlangAppCodegenConfiguration,\n}\n\nimpl<'a> ErlangApp<'a> {\n    pub fn new(output_directory: &'a Utf8Path, config: &'a ErlangAppCodegenConfiguration) -> Self {\n        Self {\n            output_directory,\n            config,\n        }\n    }\n\n    pub fn render<Writer: FileSystemWriter>(\n        &self,\n        writer: Writer,\n        config: &PackageConfig,\n        modules: &[Module],\n        native_modules: Vec<EcoString>,\n    ) -> Result<()> {\n        fn tuple(key: &str, value: &str) -> String {\n            format!(\"    {{{key}, {value}}},\\n\")\n        }\n\n        let path = self.output_directory.join(format!(\"{}.app\", &config.name));\n\n        let start_module = match config.erlang.application_start_module.as_ref() {\n            None => \"\".into(),\n            Some(module) => {\n                let module = module_erlang_name(module);\n                let argument = match config.erlang.application_start_argument.as_ref() {\n                    Some(argument) => argument.as_str(),\n                    None => \"[]\",\n                };\n                tuple(\"mod\", &format!(\"{{'{module}', {argument}}}\"))\n            }\n        };\n\n        let modules = modules\n            .iter()\n            .map(|m| m.erlang_name())\n            .chain(native_modules)\n            .unique()\n            .sorted()\n            .map(escape_atom_string)\n            .join(\",\\n               \");\n\n        // TODO: When precompiling for production (i.e. as a precompiled hex\n        // package) we will need to exclude the dev deps.\n        let applications = config\n            .dependencies\n            .keys()\n            .chain(\n                config\n                    .dev_dependencies\n                    .keys()\n                    .take_while(|_| self.config.include_dev_deps),\n            )\n            // TODO: test this!\n            .map(|name| self.config.package_name_overrides.get(name).unwrap_or(name))\n            .chain(config.erlang.extra_applications.iter())\n            .sorted()\n            .join(\",\\n                    \");\n\n        let text = format!(\n            r#\"{{application, {package}, [\n{start_module}    {{vsn, \"{version}\"}},\n    {{applications, [{applications}]}},\n    {{description, \"{description}\"}},\n    {{modules, [{modules}]}},\n    {{registered, []}}\n]}}.\n\"#,\n            applications = applications,\n            description = config.description,\n            modules = modules,\n            package = config.name,\n            start_module = start_module,\n            version = config.version,\n        );\n\n        writer.write(&path, &text)\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum TypeScriptDeclarations {\n    None,\n    Emit,\n}\n\n#[derive(Debug)]\npub struct JavaScript<'a> {\n    output_directory: &'a Utf8Path,\n    prelude_location: &'a Utf8Path,\n    project_root: &'a Utf8Path,\n    typescript: TypeScriptDeclarations,\n}\n\nimpl<'a> JavaScript<'a> {\n    pub fn new(\n        output_directory: &'a Utf8Path,\n        typescript: TypeScriptDeclarations,\n        prelude_location: &'a Utf8Path,\n        project_root: &'a Utf8Path,\n    ) -> Self {\n        Self {\n            prelude_location,\n            output_directory,\n            project_root,\n            typescript,\n        }\n    }\n\n    pub fn render(\n        &self,\n        writer: &impl FileSystemWriter,\n        modules: &[Module],\n        stdlib_package: StdlibPackage,\n    ) -> Result<()> {\n        for module in modules {\n            let js_name = module.name.clone();\n            if self.typescript == TypeScriptDeclarations::Emit {\n                self.ts_declaration(writer, module, &js_name)?;\n            }\n            self.js_module(writer, module, &js_name, stdlib_package)?\n        }\n        self.write_prelude(writer)?;\n        Ok(())\n    }\n\n    fn write_prelude(&self, writer: &impl FileSystemWriter) -> Result<()> {\n        let rexport = format!(\"export * from \\\"{}\\\";\\n\", self.prelude_location);\n        let prelude_path = &self.output_directory.join(\"gleam.mjs\");\n\n        // This check skips unnecessary `gleam.mjs` writes which confuse\n        // watchers and HMR build tools\n        if !writer.exists(prelude_path) {\n            writer.write(prelude_path, &rexport)?;\n        }\n\n        if self.typescript == TypeScriptDeclarations::Emit {\n            let rexport = format!(\n                \"export * from \\\"{}\\\";\\nexport type * from \\\"{}\\\";\\n\",\n                self.prelude_location,\n                self.prelude_location.as_str().replace(\".mjs\", \".d.mts\")\n            );\n            let prelude_declaration_path = &self.output_directory.join(\"gleam.d.mts\");\n\n            // Type declaration may trigger badly configured watchers\n            if !writer.exists(prelude_declaration_path) {\n                writer.write(prelude_declaration_path, &rexport)?;\n            }\n        }\n\n        Ok(())\n    }\n\n    fn ts_declaration(\n        &self,\n        writer: &impl FileSystemWriter,\n        module: &Module,\n        js_name: &str,\n    ) -> Result<()> {\n        let name = format!(\"{js_name}.d.mts\");\n        let path = self.output_directory.join(name);\n        let output = javascript::ts_declaration(&module.ast);\n        tracing::debug!(name = ?js_name, \"Generated TS declaration\");\n        writer.write(&path, &output)\n    }\n\n    fn js_module(\n        &self,\n        writer: &impl FileSystemWriter,\n        module: &Module,\n        js_name: &str,\n        stdlib_package: StdlibPackage,\n    ) -> Result<()> {\n        let name = format!(\"{js_name}.mjs\");\n        let path = self.output_directory.join(name);\n        let line_numbers = LineNumbers::new(&module.code);\n        let output = javascript::module(ModuleConfig {\n            module: &module.ast,\n            line_numbers: &line_numbers,\n            path: &module.input_path,\n            project_root: self.project_root,\n            src: &module.code,\n            typescript: self.typescript,\n            stdlib_package,\n        });\n        tracing::debug!(name = ?js_name, \"Generated js module\");\n        writer.write(&path, &output)\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/config/stale_package_remover.rs",
    "content": "use crate::manifest::Manifest;\nuse crate::requirement::Requirement;\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse std::collections::{HashMap, HashSet};\n\n#[derive(Debug)]\npub struct StalePackageRemover<'a> {\n    // These are the packages for which the requirement or their parents\n    // requirement has not changed.\n    fresh: HashSet<&'a str>,\n    locked: HashMap<EcoString, &'a Vec<EcoString>>,\n}\n\nimpl<'a> StalePackageRemover<'a> {\n    pub fn fresh_and_locked(\n        requirements: &'a HashMap<EcoString, Requirement>,\n        manifest: &'a Manifest,\n    ) -> HashMap<EcoString, Version> {\n        let locked = manifest\n            .packages\n            .iter()\n            .map(|p| (p.name.clone(), &p.requirements))\n            .collect();\n        Self {\n            fresh: HashSet::new(),\n            locked,\n        }\n        .run(requirements, manifest)\n    }\n\n    fn run(\n        &mut self,\n        requirements: &'a HashMap<EcoString, Requirement>,\n        manifest: &'a Manifest,\n    ) -> HashMap<EcoString, Version> {\n        // Record all the requirements that have not changed\n        for (name, requirement) in requirements {\n            if manifest.requirements.get(name) != Some(requirement) {\n                continue; // This package has changed, don't record it\n            }\n\n            // Recursively record the package and its deps as being fresh\n            self.record_tree_fresh(name);\n        }\n\n        // Return all the previously resolved packages that have not been\n        // recorded as fresh\n        manifest\n            .packages\n            .iter()\n            .filter(|package| {\n                let new = requirements.contains_key(package.name.as_str())\n                    && !manifest.requirements.contains_key(package.name.as_str());\n                let fresh = self.fresh.contains(package.name.as_str());\n                let locked = !new && fresh;\n                if !locked {\n                    tracing::info!(name = package.name.as_str(), \"unlocking_stale_package\");\n                }\n                locked\n            })\n            .map(|package| (package.name.clone(), package.version.clone()))\n            .collect()\n    }\n\n    fn record_tree_fresh(&mut self, name: &'a str) {\n        // Record the top level package\n        let _ = self.fresh.insert(name);\n\n        let Some(deps) = self.locked.get(name) else {\n            // If the package is not in the manifest then it means that the package is an optional\n            // dependency that has not been included. That or someone has been editing the manifest\n            // and broken it, but let's hope that's not the case.\n            return;\n        };\n\n        // Record each of its deps recursively\n        for package in *deps {\n            self.record_tree_fresh(package);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::manifest::{Base16Checksum, Manifest, ManifestPackage, ManifestPackageSource};\n    use crate::requirement::Requirement;\n    use hexpm::version::{Range, Version};\n    use std::collections::HashMap;\n\n    // https://github.com/gleam-lang/gleam/issues/4152\n    #[test]\n    fn optional_package_not_in_manifest() {\n        let requirements = HashMap::from_iter([(\n            \"required_package\".into(),\n            Requirement::Hex {\n                version: Range::new(\"1.0.0\".into()).unwrap(),\n            },\n        )]);\n        let manifest = Manifest {\n            requirements: requirements.clone(),\n            packages: vec![ManifestPackage {\n                name: \"required_package\".into(),\n                version: Version::new(1, 0, 0),\n                build_tools: vec![\"gleam\".into()],\n                otp_app: None,\n                requirements: vec![\n                    // NOTE: this package isn't in the manifest. This will have been because it is\n                    // an optional dep of `required_package`.\n                    \"optional_package\".into(),\n                ],\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![]),\n                },\n            }],\n        };\n\n        assert_eq!(\n            StalePackageRemover::fresh_and_locked(&requirements, &manifest),\n            HashMap::from_iter([(\"required_package\".into(), Version::new(1, 0, 0))])\n        );\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/config.rs",
    "content": "mod stale_package_remover;\nuse crate::error::{FileIoAction, FileKind};\nuse crate::io::FileSystemReader;\nuse crate::io::ordered_map;\nuse crate::manifest::Manifest;\nuse crate::requirement::Requirement;\nuse crate::version::COMPILER_VERSION;\nuse crate::{Error, Result};\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::EcoString;\nuse globset::{Glob, GlobSetBuilder};\nuse hexpm::version::{self, LowestVersion, Version};\nuse http::Uri;\nuse serde::ser::SerializeSeq;\nuse serde::{Deserialize, Serialize};\nuse std::collections::HashMap;\nuse std::fmt::{self};\nuse std::marker::PhantomData;\n\n#[cfg(test)]\nuse crate::manifest::ManifestPackage;\n\nuse crate::build::{Mode, Runtime, Target};\n\nfn default_version() -> Version {\n    Version::parse(\"0.1.0\").expect(\"default version\")\n}\n\nfn erlang_target() -> Target {\n    Target::Erlang\n}\n\nfn default_javascript_runtime() -> Runtime {\n    Runtime::NodeJs\n}\n\npub type Dependencies = HashMap<EcoString, Requirement>;\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct SpdxLicense {\n    pub licence: String,\n}\n\nimpl ToString for SpdxLicense {\n    fn to_string(&self) -> String {\n        String::from(&self.licence)\n    }\n}\n\nimpl<'de> Deserialize<'de> for SpdxLicense {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        deserializer.deserialize_str(SpdxLicenseVisitor)\n    }\n}\n\nstruct SpdxLicenseVisitor;\n\nimpl<'de> serde::de::Visitor<'de> for SpdxLicenseVisitor {\n    type Value = SpdxLicense;\n\n    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {\n        formatter.write_str(\"a SPDX License ID\")\n    }\n\n    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n    where\n        E: serde::de::Error,\n    {\n        match spdx::license_id(value) {\n            None => Err(serde::de::Error::custom(format!(\n                \"{value} is not a valid SPDX License ID\"\n            ))),\n            Some(_) => Ok(SpdxLicense {\n                licence: value.to_string(),\n            }),\n        }\n    }\n}\n\nimpl Serialize for SpdxLicense {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_str(&self.licence)\n    }\n}\n\nimpl AsRef<str> for SpdxLicense {\n    fn as_ref(&self) -> &str {\n        self.licence.as_str()\n    }\n}\n\n#[derive(Debug, PartialEq, Clone)]\npub struct GleamVersion(version::Range);\nimpl From<version::Range> for GleamVersion {\n    fn from(range: version::Range) -> Self {\n        Self(range)\n    }\n}\n\nimpl From<GleamVersion> for version::Range {\n    fn from(gleam_version: GleamVersion) -> Self {\n        gleam_version.0\n    }\n}\n\nimpl From<GleamVersion> for pubgrub::Range<Version> {\n    fn from(gleam_version: GleamVersion) -> Self {\n        gleam_version.0.into()\n    }\n}\n\nimpl GleamVersion {\n    pub fn from_pubgrub(range: pubgrub::Range<Version>) -> Self {\n        let range: version::Range = range.into();\n        range.into()\n    }\n\n    pub fn as_pubgrub(&self) -> &pubgrub::Range<Version> {\n        self.0.to_pubgrub()\n    }\n\n    pub fn new(spec: String) -> Result<GleamVersion> {\n        let hex =\n            version::Range::new(spec.to_string()).map_err(|e| Error::InvalidVersionFormat {\n                input: spec,\n                error: e.to_string(),\n            })?;\n        Ok(hex.into())\n    }\n\n    pub fn lowest_version(&self) -> Option<Version> {\n        self.as_pubgrub().lowest_version()\n    }\n\n    pub fn hex(&self) -> &version::Range {\n        &self.0\n    }\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]\npub struct PackageConfig {\n    #[serde(deserialize_with = \"package_name::deserialize\")]\n    pub name: EcoString,\n    #[serde(default = \"default_version\")]\n    pub version: Version,\n\n    #[serde(\n        default,\n        rename = \"gleam\",\n        deserialize_with = \"deserialise_gleam_version\",\n        serialize_with = \"serialise_gleam_version\"\n    )]\n    pub gleam_version: Option<GleamVersion>,\n    #[serde(default, alias = \"licenses\")]\n    pub licences: Vec<SpdxLicense>,\n    #[serde(default)]\n    pub description: EcoString,\n    #[serde(default, alias = \"docs\")]\n    pub documentation: Docs,\n    #[serde(default, serialize_with = \"ordered_map\")]\n    pub dependencies: Dependencies,\n    #[serde(default, alias = \"dev-dependencies\", serialize_with = \"ordered_map\")]\n    pub dev_dependencies: Dependencies,\n    #[serde(default)]\n    pub repository: Option<Repository>,\n    #[serde(default)]\n    pub links: Vec<Link>,\n    #[serde(default)]\n    pub erlang: ErlangConfig,\n    #[serde(default)]\n    pub javascript: JavaScriptConfig,\n    #[serde(default = \"erlang_target\")]\n    pub target: Target,\n    #[serde(default)]\n    pub internal_modules: Option<Vec<Glob>>,\n}\n\npub fn serialise_gleam_version<S>(\n    gleam_gersion: &Option<GleamVersion>,\n    serializer: S,\n) -> Result<S::Ok, S::Error>\nwhere\n    S: serde::Serializer,\n{\n    match gleam_gersion {\n        Some(version) => serializer.serialize_str(&version.hex().to_string()),\n        None => serializer.serialize_none(),\n    }\n}\n\npub fn deserialise_gleam_version<'de, D>(deserialiser: D) -> Result<Option<GleamVersion>, D::Error>\nwhere\n    D: serde::Deserializer<'de>,\n{\n    match Deserialize::deserialize(deserialiser)? {\n        Some(range_string) => {\n            let hex = version::Range::new(range_string).map_err(serde::de::Error::custom)?;\n            Ok(Some(hex.into()))\n        }\n        None => Ok(None),\n    }\n}\n\nimpl PackageConfig {\n    pub fn dependencies_for(&self, mode: Mode) -> Result<Dependencies> {\n        match mode {\n            Mode::Dev | Mode::Lsp => self.all_direct_dependencies(),\n            Mode::Prod => Ok(self.dependencies.clone()),\n        }\n    }\n\n    // Return all the dependencies listed in the configuration, that is, all the\n    // direct dependencies, both in the `dependencies` and `dev_dependencies`.\n    pub fn all_direct_dependencies(&self) -> Result<Dependencies> {\n        let mut deps =\n            HashMap::with_capacity(self.dependencies.len() + self.dev_dependencies.len());\n        for (name, requirement) in self.dependencies.iter().chain(&self.dev_dependencies) {\n            let already_inserted = deps.insert(name.clone(), requirement.clone()).is_some();\n            if already_inserted {\n                return Err(Error::DuplicateDependency(name.clone()));\n            }\n        }\n        Ok(deps)\n    }\n\n    pub fn read<FS: FileSystemReader, P: AsRef<Utf8Path>>(\n        path: P,\n        fs: &FS,\n    ) -> Result<PackageConfig, Error> {\n        let toml = fs.read(path.as_ref())?;\n        deserialise_config(path, toml)\n    }\n\n    /// Get the locked packages for the current config and a given (optional)\n    /// manifest of previously locked packages.\n    ///\n    /// If a package is removed or the specified required version range for it\n    /// changes then it is not considered locked. This also goes for any child\n    /// packages of the package which have no other parents.\n    ///\n    /// This function should be used each time resolution is performed so that\n    /// outdated deps are removed from the manifest and not locked to the\n    /// previously selected versions.\n    ///\n    pub fn locked(&self, manifest: Option<&Manifest>) -> Result<HashMap<EcoString, Version>> {\n        match manifest {\n            None => Ok(HashMap::new()),\n            Some(manifest) => {\n                let requirements = self.all_direct_dependencies()?;\n                let fresh_and_locked = stale_package_remover::StalePackageRemover::fresh_and_locked(\n                    &requirements,\n                    manifest,\n                );\n                Ok(fresh_and_locked)\n            }\n        }\n    }\n\n    /// Determines whether the given module should be hidden in the docs or not\n    ///\n    /// The developer can specify a list of glob patterns in the gleam.toml file\n    /// to determine modules that should not be shown in the package's documentation\n    pub fn is_internal_module(&self, module: &str) -> bool {\n        let package = &self.name;\n        match &self.internal_modules {\n            Some(globs) => {\n                let mut builder = GlobSetBuilder::new();\n                for glob in globs {\n                    _ = builder.add(glob.clone());\n                }\n                builder.build()\n            }\n\n            // If no patterns were specified in the config then we use a default value\n            None => GlobSetBuilder::new()\n                .add(Glob::new(&format!(\"{package}/internal\")).expect(\"internal module glob\"))\n                .add(Glob::new(&format!(\"{package}/internal/*\")).expect(\"internal module glob\"))\n                .build(),\n        }\n        .expect(\"internal module globs\")\n        .is_match(module)\n    }\n\n    // Checks to see if the gleam version specified in the config is compatible\n    // with the current compiler version\n    pub fn check_gleam_compatibility(&self) -> Result<(), Error> {\n        if let Some(version) = &self.gleam_version {\n            let range = version.as_pubgrub();\n            let compiler_version =\n                Version::parse(COMPILER_VERSION).expect(\"Parse compiler semantic version\");\n\n            // We ignore the pre-release and build metadata when checking compatibility\n            let mut version_without_pre = compiler_version.clone();\n            version_without_pre.pre = vec![];\n            version_without_pre.build = None;\n            if !range.contains(&version_without_pre) {\n                return Err(Error::IncompatibleCompilerVersion {\n                    package: self.name.to_string(),\n                    required_version: range.to_string(),\n                    gleam_version: COMPILER_VERSION.to_string(),\n                });\n            }\n        }\n        Ok(())\n    }\n\n    pub fn tag_for_version(&self, version: &Version) -> String {\n        let prefix = match self.repository.as_ref() {\n            Some(\n                Repository::GitHub { tag_prefix, .. }\n                | Repository::GitLab { tag_prefix, .. }\n                | Repository::BitBucket { tag_prefix, .. }\n                | Repository::Codeberg { tag_prefix, .. }\n                | Repository::SourceHut { tag_prefix, .. }\n                | Repository::Gitea { tag_prefix, .. }\n                | Repository::Forgejo { tag_prefix, .. }\n                | Repository::Tangled { tag_prefix, .. },\n            ) => tag_prefix.as_ref(),\n\n            Some(Repository::Custom { .. }) | None => None,\n        };\n\n        match prefix {\n            Some(prefix) => format!(\"{prefix}v{version}\"),\n            None => format!(\"v{version}\"),\n        }\n    }\n}\n\nfn deserialise_config<P: AsRef<Utf8Path>>(\n    path: P,\n    toml: String,\n) -> std::result::Result<PackageConfig, Error> {\n    let config: PackageConfig = toml::from_str(&toml).map_err(|e| Error::FileIo {\n        action: FileIoAction::Parse,\n        kind: FileKind::File,\n        path: path.as_ref().to_path_buf(),\n        err: Some(e.to_string()),\n    })?;\n    Ok(config)\n}\n\n// https://github.com/gleam-lang/gleam/issues/4867\n#[test]\nfn deny_extra_deps_properties() {\n    let toml = r#\"\nname = \"wibble\"\nversion = \"1.0.0\"\n\n[dependencies]\naide_generator = { git = \"git@github.com:crowdhailer/aide.git\", ref = \"f559c5bc\", extra = \"idk what this is\" }\n\"#;\n    let error = deserialise_config(\"gleam.toml\", toml.into())\n        .expect_err(\"should fail to deserialise because of additional path\");\n\n    insta::assert_snapshot!(insta::internals::AutoName, error.pretty_string());\n}\n\n#[test]\nfn locked_no_manifest() {\n    let mut config = PackageConfig::default();\n    config.dependencies = [\n        (\"prod1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        (\"prod2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n    ]\n    .into();\n    config.dev_dependencies = [\n        (\"dev1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        (\"dev2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n    ]\n    .into();\n    assert_eq!(config.locked(None).unwrap(), [].into());\n}\n\n#[test]\nfn locked_no_changes() {\n    let mut config = PackageConfig::default();\n    config.dependencies = [\n        (\"prod1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        (\"prod2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n    ]\n    .into();\n    config.dev_dependencies = [\n        (\"dev1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        (\"dev2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n    ]\n    .into();\n    let manifest = Manifest {\n        requirements: config.all_direct_dependencies().unwrap(),\n        packages: vec![\n            manifest_package(\"prod1\", \"1.1.0\", &[]),\n            manifest_package(\"prod2\", \"1.2.0\", &[]),\n            manifest_package(\"dev1\", \"1.1.0\", &[]),\n            manifest_package(\"dev2\", \"1.2.0\", &[]),\n        ],\n    };\n    assert_eq!(\n        config.locked(Some(&manifest)).unwrap(),\n        [\n            locked_version(\"prod1\", \"1.1.0\"),\n            locked_version(\"prod2\", \"1.2.0\"),\n            locked_version(\"dev1\", \"1.1.0\"),\n            locked_version(\"dev2\", \"1.2.0\"),\n        ]\n        .into()\n    );\n}\n\n#[test]\nfn locked_some_removed() {\n    let mut config = PackageConfig::default();\n    config.dependencies = [(\"prod1\".into(), Requirement::hex(\"~> 1.0\").unwrap())].into();\n    config.dev_dependencies = [(\"dev2\".into(), Requirement::hex(\"~> 2.0\").unwrap())].into();\n    let manifest = Manifest {\n        requirements: config.all_direct_dependencies().unwrap(),\n        packages: vec![\n            manifest_package(\"prod1\", \"1.1.0\", &[]),\n            manifest_package(\"prod2\", \"1.2.0\", &[]), // Not in config\n            manifest_package(\"dev1\", \"1.1.0\", &[]),  // Not in config\n            manifest_package(\"dev2\", \"1.2.0\", &[]),\n        ],\n    };\n    assert_eq!(\n        config.locked(Some(&manifest)).unwrap(),\n        [\n            // prod2 removed\n            // dev1 removed\n            locked_version(\"prod1\", \"1.1.0\"),\n            locked_version(\"dev2\", \"1.2.0\"),\n        ]\n        .into()\n    );\n}\n\n#[test]\nfn locked_some_changed() {\n    let mut config = PackageConfig::default();\n    config.dependencies = [\n        (\"prod1\".into(), Requirement::hex(\"~> 3.0\").unwrap()), // Does not match manifest\n        (\"prod2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n    ]\n    .into();\n    config.dev_dependencies = [\n        (\"dev1\".into(), Requirement::hex(\"~> 3.0\").unwrap()), // Does not match manifest\n        (\"dev2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n    ]\n    .into();\n    let manifest = Manifest {\n        requirements: [\n            (\"prod1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n            (\"prod2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n            (\"dev1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n            (\"dev2\".into(), Requirement::hex(\"~> 2.0\").unwrap()),\n        ]\n        .into(),\n        packages: vec![\n            manifest_package(\"prod1\", \"1.1.0\", &[]),\n            manifest_package(\"prod2\", \"1.2.0\", &[]),\n            manifest_package(\"dev1\", \"1.1.0\", &[]),\n            manifest_package(\"dev2\", \"1.2.0\", &[]),\n        ],\n    };\n    assert_eq!(\n        config.locked(Some(&manifest)).unwrap(),\n        [\n            // prod1 removed\n            // dev1 removed\n            locked_version(\"prod2\", \"1.2.0\"),\n            locked_version(\"dev2\", \"1.2.0\"),\n        ]\n        .into()\n    );\n}\n\n#[test]\nfn locked_nested_are_removed_too() {\n    let mut config = PackageConfig::default();\n    config.dependencies = [\n        (\"1\".into(), Requirement::hex(\"~> 2.0\").unwrap()), // Does not match manifest\n        (\"2\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n    ]\n    .into();\n    config.dev_dependencies = [].into();\n    let manifest = Manifest {\n        requirements: [\n            (\"1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n            (\"2\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        ]\n        .into(),\n        packages: vec![\n            manifest_package(\"1\", \"1.1.0\", &[\"1.1\", \"1.2\"]),\n            manifest_package(\"1.1\", \"1.1.0\", &[\"1.1.1\", \"1.1.2\"]),\n            manifest_package(\"1.1.1\", \"1.1.0\", &[\"shared\"]),\n            manifest_package(\"1.1.2\", \"1.1.0\", &[]),\n            manifest_package(\"1.2\", \"1.1.0\", &[\"1.2.1\", \"1.2.2\"]),\n            manifest_package(\"1.2.1\", \"1.1.0\", &[]),\n            manifest_package(\"1.2.2\", \"1.1.0\", &[]),\n            manifest_package(\"2\", \"2.1.0\", &[\"2.1\", \"2.2\"]),\n            manifest_package(\"2.1\", \"2.1.0\", &[\"2.1.1\", \"2.1.2\"]),\n            manifest_package(\"2.1.1\", \"2.1.0\", &[]),\n            manifest_package(\"2.1.2\", \"2.1.0\", &[]),\n            manifest_package(\"2.2\", \"2.1.0\", &[\"2.2.1\", \"2.2.2\", \"shared\"]),\n            manifest_package(\"2.2.1\", \"2.1.0\", &[]),\n            manifest_package(\"2.2.2\", \"2.1.0\", &[]),\n            manifest_package(\"shared\", \"2.1.0\", &[]),\n        ],\n    };\n    assert_eq!(\n        config.locked(Some(&manifest)).unwrap(),\n        [\n            // 1* removed\n            locked_version(\"2\", \"2.1.0\"),\n            locked_version(\"2.1\", \"2.1.0\"),\n            locked_version(\"2.1.1\", \"2.1.0\"),\n            locked_version(\"2.1.2\", \"2.1.0\"),\n            locked_version(\"2.2\", \"2.1.0\"),\n            locked_version(\"2.2.1\", \"2.1.0\"),\n            locked_version(\"2.2.2\", \"2.1.0\"),\n            locked_version(\"shared\", \"2.1.0\"),\n        ]\n        .into()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1754\n#[test]\nfn locked_unlock_new() {\n    let mut config = PackageConfig::default();\n    config.dependencies = [\n        (\"1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        (\"2\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        (\"3\".into(), Requirement::hex(\"~> 3.0\").unwrap()), // Does not match manifest\n    ]\n    .into();\n    config.dev_dependencies = [].into();\n    let manifest = Manifest {\n        requirements: [\n            (\"1\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n            (\"2\".into(), Requirement::hex(\"~> 1.0\").unwrap()),\n        ]\n        .into(),\n        packages: vec![\n            manifest_package(\"1\", \"1.1.0\", &[\"3\"]),\n            manifest_package(\"2\", \"1.1.0\", &[\"3\"]),\n            manifest_package(\"3\", \"1.1.0\", &[]),\n        ],\n    };\n    assert_eq!(\n        config.locked(Some(&manifest)).unwrap(),\n        [locked_version(\"1\", \"1.1.0\"), locked_version(\"2\", \"1.1.0\"),].into()\n    )\n}\n\n#[test]\nfn default_internal_modules() {\n    // When no internal modules are specified then we default to\n    // `[\"$package/internal\", \"$package/internal/*\"]`\n    let mut config = PackageConfig::default();\n    config.name = \"my_package\".into();\n    config.internal_modules = None;\n\n    assert!(config.is_internal_module(\"my_package/internal\"));\n    assert!(config.is_internal_module(\"my_package/internal/wibble\"));\n    assert!(config.is_internal_module(\"my_package/internal/wibble/wobble\"));\n    assert!(!config.is_internal_module(\"my_package/internallll\"));\n    assert!(!config.is_internal_module(\"my_package/other\"));\n    assert!(!config.is_internal_module(\"my_package/other/wibble\"));\n    assert!(!config.is_internal_module(\"other/internal\"));\n}\n\n#[test]\nfn no_internal_modules() {\n    // When no internal modules are specified then we default to\n    // `[\"$package/internal\", \"$package/internal/*\"]`\n    let mut config = PackageConfig::default();\n    config.name = \"my_package\".into();\n    config.internal_modules = Some(vec![]);\n\n    assert!(!config.is_internal_module(\"my_package/internal\"));\n    assert!(!config.is_internal_module(\"my_package/internal/wibble\"));\n    assert!(!config.is_internal_module(\"my_package/internal/wibble/wobble\"));\n    assert!(!config.is_internal_module(\"my_package/internallll\"));\n    assert!(!config.is_internal_module(\"my_package/other\"));\n    assert!(!config.is_internal_module(\"my_package/other/wibble\"));\n    assert!(!config.is_internal_module(\"other/internal\"));\n}\n\n#[test]\nfn hidden_a_directory_from_docs() {\n    let mut config = PackageConfig::default();\n    config.internal_modules = Some(vec![Glob::new(\"package/internal/*\").expect(\"\")]);\n\n    let mod1 = \"package/internal\";\n    let mod2 = \"package/internal/module\";\n\n    assert_eq!(config.is_internal_module(mod1), false);\n    assert_eq!(config.is_internal_module(mod2), true);\n}\n\n#[test]\nfn hidden_two_directories_from_docs() {\n    let mut config = PackageConfig::default();\n    config.internal_modules = Some(vec![\n        Glob::new(\"package/internal1/*\").expect(\"\"),\n        Glob::new(\"package/internal2/*\").expect(\"\"),\n    ]);\n\n    let mod1 = \"package/internal1\";\n    let mod2 = \"package/internal1/module\";\n    let mod3 = \"package/internal2\";\n    let mod4 = \"package/internal2/module\";\n\n    assert_eq!(config.is_internal_module(mod1), false);\n    assert_eq!(config.is_internal_module(mod2), true);\n    assert_eq!(config.is_internal_module(mod3), false);\n    assert_eq!(config.is_internal_module(mod4), true);\n}\n\n#[test]\nfn hidden_a_directory_and_a_file_from_docs() {\n    let mut config = PackageConfig::default();\n    config.internal_modules = Some(vec![\n        Glob::new(\"package/internal1/*\").expect(\"\"),\n        Glob::new(\"package/module\").expect(\"\"),\n    ]);\n\n    let mod1 = \"package/internal1\";\n    let mod2 = \"package/internal1/module\";\n    let mod3 = \"package/module\";\n    let mod4 = \"package/module/inner\";\n\n    assert_eq!(config.is_internal_module(mod1), false);\n    assert_eq!(config.is_internal_module(mod2), true);\n    assert_eq!(config.is_internal_module(mod3), true);\n    assert_eq!(config.is_internal_module(mod4), false);\n}\n\n#[test]\nfn hidden_a_file_in_all_directories_from_docs() {\n    let mut config = PackageConfig::default();\n    config.internal_modules = Some(vec![Glob::new(\"package/*/module1\").expect(\"\")]);\n\n    let mod1 = \"package/internal1/module1\";\n    let mod2 = \"package/internal2/module1\";\n    let mod3 = \"package/internal2/module2\";\n    let mod4 = \"package/module\";\n\n    assert_eq!(config.is_internal_module(mod1), true);\n    assert_eq!(config.is_internal_module(mod2), true);\n    assert_eq!(config.is_internal_module(mod3), false);\n    assert_eq!(config.is_internal_module(mod4), false);\n}\n\n#[cfg(test)]\nfn manifest_package(\n    name: &'static str,\n    version: &'static str,\n    requirements: &'static [&'static str],\n) -> ManifestPackage {\n    use crate::manifest::Base16Checksum;\n\n    ManifestPackage {\n        name: name.into(),\n        version: Version::parse(version).unwrap(),\n        build_tools: vec![],\n        otp_app: None,\n        requirements: requirements\n            .iter()\n            .map(|requirement| (*requirement).into())\n            .collect(),\n        source: crate::manifest::ManifestPackageSource::Hex {\n            outer_checksum: Base16Checksum(vec![]),\n        },\n    }\n}\n\n#[cfg(test)]\nfn locked_version(name: &'static str, version: &'static str) -> (EcoString, Version) {\n    (name.into(), Version::parse(version).unwrap())\n}\n\nimpl Default for PackageConfig {\n    fn default() -> Self {\n        Self {\n            name: Default::default(),\n            version: default_version(),\n            gleam_version: Default::default(),\n            description: Default::default(),\n            documentation: Default::default(),\n            dependencies: Default::default(),\n            erlang: Default::default(),\n            javascript: Default::default(),\n            repository: Default::default(),\n            dev_dependencies: Default::default(),\n            licences: Default::default(),\n            links: Default::default(),\n            internal_modules: Default::default(),\n            target: Target::Erlang,\n        }\n    }\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default, Clone)]\npub struct ErlangConfig {\n    /// An module that can be set in the `.app` file as the entrypoint for a stateful application\n    /// that defines a singleton supervision tree.\n    /// Erlang syntax.\n    #[serde(default)]\n    pub application_start_module: Option<EcoString>,\n    /// The argument for the start module start function. If not set then `[]` is used as the\n    /// default argument.\n    /// Erlang syntax.\n    #[serde(default)]\n    pub application_start_argument: Option<EcoString>,\n    #[serde(default)]\n    pub extra_applications: Vec<EcoString>,\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Default, Clone)]\npub struct JavaScriptConfig {\n    #[serde(default)]\n    pub typescript_declarations: bool,\n    #[serde(default = \"default_javascript_runtime\")]\n    pub runtime: Runtime,\n    #[serde(default, rename = \"deno\")]\n    pub deno: DenoConfig,\n}\n\n#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]\npub enum DenoFlag {\n    AllowAll,\n    Allow(Vec<String>),\n}\n\nimpl Default for DenoFlag {\n    fn default() -> Self {\n        Self::Allow(Vec::new())\n    }\n}\n\nimpl Serialize for DenoFlag {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        match self {\n            DenoFlag::AllowAll => serializer.serialize_bool(true),\n            DenoFlag::Allow(items) => {\n                let mut seq = serializer.serialize_seq(Some(items.len()))?;\n                for e in items {\n                    seq.serialize_element(e)?;\n                }\n                seq.end()\n            }\n        }\n    }\n}\n\nfn bool_or_seq_string_to_deno_flag<'de, D>(deserializer: D) -> Result<DenoFlag, D::Error>\nwhere\n    D: serde::Deserializer<'de>,\n{\n    struct StringOrVec(PhantomData<Vec<String>>);\n\n    impl<'de> serde::de::Visitor<'de> for StringOrVec {\n        type Value = DenoFlag;\n\n        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {\n            formatter.write_str(\"bool or list of strings\")\n        }\n\n        fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>\n        where\n            E: serde::de::Error,\n        {\n            if value {\n                Ok(DenoFlag::AllowAll)\n            } else {\n                Ok(DenoFlag::default())\n            }\n        }\n\n        fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>\n        where\n            S: serde::de::SeqAccess<'de>,\n        {\n            let allow: Vec<String> =\n                Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(visitor))\n                    .unwrap_or_default();\n\n            Ok(DenoFlag::Allow(allow))\n        }\n    }\n\n    deserializer.deserialize_any(StringOrVec(PhantomData))\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default, Clone)]\npub struct DenoConfig {\n    #[serde(default, deserialize_with = \"bool_or_seq_string_to_deno_flag\")]\n    pub allow_env: DenoFlag,\n    #[serde(default)]\n    pub allow_sys: bool,\n    #[serde(default)]\n    pub allow_hrtime: bool,\n    #[serde(default, deserialize_with = \"bool_or_seq_string_to_deno_flag\")]\n    pub allow_net: DenoFlag,\n    #[serde(default)]\n    pub allow_ffi: bool,\n    #[serde(default, deserialize_with = \"bool_or_seq_string_to_deno_flag\")]\n    pub allow_read: DenoFlag,\n    #[serde(default, deserialize_with = \"bool_or_seq_string_to_deno_flag\")]\n    pub allow_run: DenoFlag,\n    #[serde(default, deserialize_with = \"bool_or_seq_string_to_deno_flag\")]\n    pub allow_write: DenoFlag,\n    #[serde(default)]\n    pub allow_all: bool,\n    #[serde(default)]\n    pub unstable: bool,\n    #[serde(\n        default,\n        serialize_with = \"uri_serde::serialize_option\",\n        deserialize_with = \"uri_serde::deserialize_option\"\n    )]\n    pub location: Option<Uri>,\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]\n#[serde(tag = \"type\")]\npub enum Repository {\n    #[serde(rename = \"github\")]\n    GitHub {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n    #[serde(rename = \"gitlab\")]\n    GitLab {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n    #[serde(rename = \"bitbucket\")]\n    BitBucket {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n    #[serde(rename = \"codeberg\")]\n    Codeberg {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n    #[serde(rename = \"gitea\")]\n    Gitea {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n        #[serde(\n            serialize_with = \"uri_serde::serialize\",\n            deserialize_with = \"uri_serde_default_https::deserialize\"\n        )]\n        host: Uri,\n    },\n    #[serde(rename = \"forgejo\")]\n    Forgejo {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n        #[serde(\n            serialize_with = \"uri_serde::serialize\",\n            deserialize_with = \"uri_serde_default_https::deserialize\"\n        )]\n        host: Uri,\n    },\n    #[serde(rename = \"sourcehut\")]\n    SourceHut {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n    #[serde(rename = \"tangled\")]\n    Tangled {\n        user: String,\n        repo: String,\n        path: Option<String>,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n    #[serde(rename = \"custom\")]\n    Custom {\n        url: String,\n        #[serde(alias = \"tag-prefix\")]\n        tag_prefix: Option<String>,\n    },\n}\n\nimpl Repository {\n    pub fn url(&self) -> String {\n        match self {\n            Repository::GitHub { repo, user, .. } => {\n                format!(\"https://github.com/{user}/{repo}\")\n            }\n            Repository::GitLab { repo, user, .. } => {\n                format!(\"https://gitlab.com/{user}/{repo}\")\n            }\n            Repository::BitBucket { repo, user, .. } => {\n                format!(\"https://bitbucket.com/{user}/{repo}\")\n            }\n            Repository::Codeberg { repo, user, .. } => {\n                format!(\"https://codeberg.org/{user}/{repo}\")\n            }\n            Repository::SourceHut { repo, user, .. } => {\n                format!(\"https://git.sr.ht/~{user}/{repo}\")\n            }\n            Repository::Tangled { repo, user, .. } => {\n                format!(\"https://tangled.sh/{user}/{repo}\")\n            }\n            Repository::Gitea {\n                repo, user, host, ..\n            }\n            | Repository::Forgejo {\n                repo, user, host, ..\n            } => {\n                let string_host = host.to_string();\n                let cleaned_host = string_host.trim_end_matches('/');\n                format!(\"{cleaned_host}/{user}/{repo}\")\n            }\n            Repository::Custom { url, .. } => url.clone(),\n        }\n    }\n\n    pub fn path(&self) -> Option<&String> {\n        match self {\n            Repository::GitHub { path, .. }\n            | Repository::GitLab { path, .. }\n            | Repository::BitBucket { path, .. }\n            | Repository::Codeberg { path, .. }\n            | Repository::SourceHut { path, .. }\n            | Repository::Tangled { path, .. }\n            | Repository::Gitea { path, .. }\n            | Repository::Forgejo { path, .. } => path.as_ref(),\n\n            Repository::Custom { .. } => None,\n        }\n    }\n}\n\n#[derive(Deserialize, Serialize, Default, Debug, PartialEq, Eq, Clone)]\npub struct Docs {\n    #[serde(default)]\n    pub pages: Vec<DocsPage>,\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]\npub struct DocsPage {\n    pub title: String,\n    pub path: String,\n    pub source: Utf8PathBuf,\n}\n\n#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]\npub struct Link {\n    pub title: String,\n    #[serde(with = \"uri_serde\")]\n    pub href: Uri,\n}\n\n// Note we don't use http-serde since we also want to validate the scheme and host is set.\nmod uri_serde {\n    use http::uri::InvalidUri;\n    use serde::{Deserialize, Deserializer, de::Error as _};\n\n    pub fn deserialize<'de, D>(deserializer: D) -> Result<http::Uri, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let string = String::deserialize(deserializer)?;\n        let uri: http::Uri = string\n            .parse()\n            .map_err(|err: InvalidUri| D::Error::custom(err.to_string()))?;\n        if uri.scheme().is_none() || uri.host().is_none() {\n            return Err(D::Error::custom(\"uri without scheme\"));\n        }\n        Ok(uri)\n    }\n\n    pub fn deserialize_option<'de, D>(deserializer: D) -> Result<Option<http::Uri>, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let string: Option<String> = Option::deserialize(deserializer)?;\n        match string {\n            Some(s) => {\n                let deserializer = serde::de::value::StringDeserializer::new(s);\n                deserialize(deserializer).map(Some)\n            }\n            None => Ok(None),\n        }\n    }\n\n    pub fn serialize_option<S>(uri: &Option<http::Uri>, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        match uri {\n            Some(uri) => serialize(uri, serializer),\n            None => serializer.serialize_unit(),\n        }\n    }\n\n    pub fn serialize<S>(uri: &http::Uri, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_str(&uri.to_string())\n    }\n}\n\n// This prefixes https as a default in the event no scheme was provided\nmod uri_serde_default_https {\n    use http::uri::InvalidUri;\n    use serde::{Deserialize, Deserializer, de::Error as _};\n\n    pub fn deserialize<'de, D>(deserializer: D) -> Result<http::Uri, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let string = String::deserialize(deserializer)?;\n        let uri: http::Uri = string\n            .parse()\n            .map_err(|err: InvalidUri| D::Error::custom(err.to_string()))?;\n        if uri.host().is_none() {\n            return Err(D::Error::custom(\"uri without host\"));\n        }\n        match uri.scheme().is_none() {\n            true => format!(\"https://{string}\")\n                .parse()\n                .map_err(|err: InvalidUri| D::Error::custom(err.to_string())),\n            false => Ok(uri),\n        }\n    }\n}\n\nmod package_name {\n    use ecow::EcoString;\n    use regex::Regex;\n    use serde::Deserializer;\n    use std::{fmt, sync::OnceLock};\n\n    static PACKAGE_NAME_PATTERN: OnceLock<Regex> = OnceLock::new();\n\n    pub fn deserialize<'de, D>(deserializer: D) -> Result<EcoString, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        deserializer.deserialize_str(NameVisitor)\n    }\n\n    struct NameVisitor;\n\n    impl<'de> serde::de::Visitor<'de> for NameVisitor {\n        type Value = EcoString;\n\n        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {\n            formatter.write_str(\"a package name\")\n        }\n\n        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n        where\n            E: serde::de::Error,\n        {\n            if PACKAGE_NAME_PATTERN\n                .get_or_init(|| Regex::new(\"^[a-z][a-z0-9_]*$\").expect(\"Package name regex\"))\n                .is_match(value)\n            {\n                Ok(value.into())\n            } else {\n                let error =\n                    \"Package names may only contain lowercase letters, numbers, and underscores\";\n                Err(serde::de::Error::custom(error))\n            }\n        }\n    }\n}\n\n#[test]\nfn name_with_dash() {\n    let input = r#\"\nname = \"one-two\"\n\"#;\n\n    insta::assert_snapshot!(\n        insta::internals::AutoName,\n        toml::from_str::<PackageConfig>(input)\n            .unwrap_err()\n            .to_string()\n    );\n}\n\n#[test]\nfn name_with_number_start() {\n    let input = r#\"\nname = \"1\"\n\"#;\n    insta::assert_snapshot!(\n        insta::internals::AutoName,\n        toml::from_str::<PackageConfig>(input)\n            .unwrap_err()\n            .to_string(),\n    )\n}\n\n#[test]\nfn package_config_to_json() {\n    let input = r#\"\nname = \"my_project\"\nversion = \"1.0.0\"\nlicences = [\"Apache-2.0\", \"MIT\"]\ndescription = \"Pretty complex config\"\ntarget = \"erlang\"\nrepository = { type = \"github\", user = \"example\", repo = \"my_dep\" }\nlinks = [{ title = \"Home page\", href = \"https://example.com\" }]\ninternal_modules = [\"my_app/internal\"]\ngleam = \">= 0.30.0\"\n\n[dependencies]\ngleam_stdlib = \">= 0.18.0 and < 2.0.0\"\nmy_other_project = { path = \"../my_other_project\" }\n\n[dev_dependencies]\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n\n[documentation]\npages = [{ title = \"My Page\", path = \"my-page.html\", source = \"./path/to/my-page.md\" }]\n\n[erlang]\napplication_start_module = \"my_app/application\"\nextra_applications = [\"inets\", \"ssl\"]\n\n[javascript]\ntypescript_declarations = true\nruntime = \"node\"\n\n[javascript.deno]\nallow_all = false\nallow_ffi = true\nallow_env = [\"DATABASE_URL\"]\nallow_net = [\"example.com:443\"]\nallow_read = [\"./database.sqlite\"]\n\"#;\n\n    let config = toml::from_str::<PackageConfig>(input).unwrap();\n    let json = serde_json::to_string_pretty(&config).unwrap();\n    let output = format!(\"--- GLEAM.TOML\\n{input}\\n\\n--- EXPORTED JSON\\n\\n{json}\");\n    insta::assert_snapshot!(output);\n\n    let roundtrip = serde_json::from_str::<PackageConfig>(&json).unwrap();\n    assert_eq!(config, roundtrip);\n}\n\n#[test]\nfn barebones_package_config_to_json() {\n    let input = r#\"\nname = \"my_project\"\nversion = \"1.0.0\"\n\"#;\n\n    let config = toml::from_str::<PackageConfig>(input).unwrap();\n    let json = serde_json::to_string_pretty(&config).unwrap();\n    let output = format!(\"--- GLEAM.TOML\\n{input}\\n\\n--- EXPORTED JSON\\n\\n{json}\");\n    insta::assert_snapshot!(output);\n}\n\n#[test]\nfn dev_deps_field_name() {\n    let toml = r#\"\nname = \"wibble\"\nversion = \"1.0.0\"\n\n[dev_dependencies]\nwibble = \">= 1.0.0 and < 2.0.0\"\n\"#;\n    let hyphen_alternative = deserialise_config(\"gleam.toml\", toml.into()).expect(\"valid config\");\n    let toml = r#\"\nname = \"wibble\"\nversion = \"1.0.0\"\n\n[dev_dependencies]\nwibble = \">= 1.0.0 and < 2.0.0\"\n\"#;\n    let canonical = deserialise_config(\"gleam.toml\", toml.into()).expect(\"valid config\");\n    assert_eq!(canonical, hyphen_alternative)\n}\n"
  },
  {
    "path": "compiler-core/src/dep_tree.rs",
    "content": "use ecow::EcoString;\nuse petgraph::{Direction, algo::Cycle, graph::NodeIndex};\nuse std::collections::{HashMap, HashSet};\n\n#[cfg(test)]\nuse pretty_assertions::assert_eq;\n\n/// Take a sequence of values and their deps, and return the values in\n/// order so that deps come before the dependants.\n///\n/// Any deps that are not nodes are ignored and presumed to be nodes\n/// that do not need processing.\n///\n/// Errors if there are duplicate values, unknown deps, or cycles.\n///\npub fn toposort_deps(inputs: Vec<(EcoString, Vec<EcoString>)>) -> Result<Vec<EcoString>, Error> {\n    let mut graph = petgraph::Graph::<(), ()>::with_capacity(inputs.len(), inputs.len() * 5);\n    let mut values = HashMap::with_capacity(inputs.len());\n    let mut indexes = HashMap::with_capacity(inputs.len());\n\n    for (value, _deps) in &inputs {\n        let index = graph.add_node(());\n        let _ = indexes.insert(value.clone(), index);\n        let _ = values.insert(index, value.clone());\n    }\n\n    for (value, deps) in inputs {\n        let &from_index = indexes.get(&value).expect(\"Finding index for value\");\n        for &to_index in deps.into_iter().filter_map(|dep| indexes.get(&dep)) {\n            let _ = graph.add_edge(from_index, to_index, ());\n        }\n    }\n\n    match petgraph::algo::toposort(&graph, None) {\n        Err(e) => Err(Error::Cycle(import_cycle(e, &graph, values))),\n\n        Ok(seq) => Ok(seq\n            .into_iter()\n            .map(|i| values.remove(&i).expect(\"Finding value for index\"))\n            .rev()\n            .collect()),\n    }\n}\n\nfn import_cycle(\n    cycle: Cycle<NodeIndex>,\n    graph: &petgraph::Graph<(), ()>,\n    mut values: HashMap<NodeIndex, EcoString>,\n) -> Vec<EcoString> {\n    let origin = cycle.node_id();\n    let mut path = vec![];\n    let _ = find_cycle(origin, origin, graph, &mut path, &mut HashSet::new());\n    path.iter()\n        .map(|index| {\n            values\n                .remove(index)\n                .expect(\"dep_tree::import_cycle(): cannot find values for index\")\n        })\n        .collect()\n}\n\nfn find_cycle(\n    origin: NodeIndex,\n    parent: NodeIndex,\n    graph: &petgraph::Graph<(), ()>,\n    path: &mut Vec<NodeIndex>,\n    seen: &mut HashSet<NodeIndex>,\n) -> bool {\n    let _ = seen.insert(parent);\n    for node in graph.neighbors_directed(parent, Direction::Outgoing) {\n        if node == origin {\n            path.push(node);\n            return true;\n        }\n        if seen.contains(&node) {\n            continue;\n        }\n        if find_cycle(origin, node, graph, path, seen) {\n            path.push(node);\n            return true;\n        }\n    }\n    false\n}\n\n#[derive(Debug, PartialEq)]\npub enum Error {\n    Cycle(Vec<EcoString>),\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{assert_eq, *};\n\n    #[test]\n    fn toposort_deps_test() {\n        // All deps are nodes\n        assert_eq!(\n            toposort_deps(vec![\n                (\"a\".into(), vec![\"b\".into()]),\n                (\"c\".into(), vec![]),\n                (\"b\".into(), vec![\"c\".into()])\n            ]),\n            Ok(vec![\"c\".into(), \"b\".into(), \"a\".into()])\n        );\n\n        // No deps\n        assert_eq!(\n            toposort_deps(vec![\n                (\"no-deps-1\".into(), vec![]),\n                (\"no-deps-2\".into(), vec![])\n            ]),\n            Ok(vec![\"no-deps-1\".into(), \"no-deps-2\".into(),])\n        );\n\n        // Some deps are not nodes (and thus are ignored)\n        assert_eq!(\n            toposort_deps(vec![\n                (\"a\".into(), vec![\"b\".into(), \"z\".into()]),\n                (\"b\".into(), vec![\"x\".into()])\n            ]),\n            Ok(vec![\"b\".into(), \"a\".into()])\n        );\n    }\n\n    #[test]\n    fn cycle_detection() {\n        // a ---+\n        // ^    |\n        // |    v\n        // +----+\n        assert_eq!(\n            toposort_deps(vec![(\"a\".into(), vec![\"a\".into()])]),\n            Err(Error::Cycle(vec![\"a\".into()]))\n        );\n\n        // a -> b -> c\n        // ^         v\n        // |         |\n        // +---------+\n        assert_eq!(\n            toposort_deps(vec![\n                (\"a\".into(), vec![\"b\".into()]),\n                (\"b\".into(), vec![\"c\".into()]),\n                (\"c\".into(), vec![\"a\".into()]),\n            ]),\n            Err(Error::Cycle(vec![\"c\".into(), \"b\".into(), \"a\".into()]))\n        );\n\n        // a -> b <- e\n        // |    |    ^\n        // v    v    |\n        // f    c -> d\n        assert_eq!(\n            toposort_deps(vec![\n                (\"a\".into(), vec![\"b\".into()]),\n                (\"b\".into(), vec![\"c\".into()]),\n                (\"c\".into(), vec![\"d\".into()]),\n                (\"d\".into(), vec![\"e\".into()]),\n                (\"e\".into(), vec![\"b\".into()]),\n                (\"a\".into(), vec![\"f\".into()]),\n            ]),\n            Err(Error::Cycle(vec![\n                \"e\".into(),\n                \"d\".into(),\n                \"c\".into(),\n                \"b\".into(),\n            ]))\n        );\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/dependency.rs",
    "content": "use std::{cell::RefCell, cmp::Reverse, collections::HashMap, rc::Rc};\n\nuse crate::{Error, Result, manifest};\n\nuse ecow::EcoString;\nuse hexpm::{\n    Dependency, Release,\n    version::{Range, Version},\n};\nuse pubgrub::{Dependencies, Map};\nuse thiserror::Error;\n\npub type PackageVersions = HashMap<String, Version>;\n\ntype PubgrubRange = pubgrub::Range<Version>;\n\npub fn resolve_versions<Requirements>(\n    package_fetcher: &impl PackageFetcher,\n    provided_packages: HashMap<EcoString, hexpm::Package>,\n    root_name: EcoString,\n    dependencies: Requirements,\n    locked: &HashMap<EcoString, Version>,\n) -> Result<PackageVersions>\nwhere\n    Requirements: Iterator<Item = (EcoString, Range)>,\n{\n    tracing::info!(\"resolving_versions\");\n    let root_version = Version::new(0, 0, 0);\n    let requirements = root_dependencies(dependencies, locked)?;\n\n    // Creating a map of all the required packages that have exact versions specified\n    let exact_deps = &requirements\n        .iter()\n        .filter_map(|(name, dep)| parse_exact_version(dep.requirement.as_str()).map(|v| (name, v)))\n        .map(|(name, version)| (name.clone(), version))\n        .collect();\n\n    let root = hexpm::Package {\n        name: root_name.as_str().into(),\n        repository: \"local\".into(),\n        releases: vec![Release {\n            version: root_version.clone(),\n            outer_checksum: vec![],\n            retirement_status: None,\n            requirements,\n            meta: (),\n        }],\n    };\n\n    let packages = pubgrub::resolve(\n        &DependencyProvider::new(package_fetcher, provided_packages, root, locked, exact_deps),\n        root_name.as_str().into(),\n        root_version,\n    )\n    .map_err(|error| Error::dependency_resolution_failed(error, root_name.clone()))?\n    .into_iter()\n    .filter(|(name, _)| name.as_str() != root_name.as_str())\n    .collect();\n\n    Ok(packages)\n}\n\n/**\n* Used to compare 2 versions of a package.\n*/\npub type PackageVersionDiffs = HashMap<String, (Version, Version)>;\n\nfn resolve_versions_diffs(\n    package_fetcher: &impl PackageFetcher,\n    versions: PackageVersions,\n    check_major_versions: bool,\n) -> PackageVersionDiffs {\n    versions\n        .iter()\n        .filter_map(|(package, version)| {\n            let Ok(hex_package) = package_fetcher.get_dependencies(package) else {\n                return None;\n            };\n\n            let latest = hex_package\n                .releases\n                .iter()\n                .map(|release| &release.version)\n                .filter(|version| !version.is_pre())\n                .max()?;\n\n            // If we're checking for major version updates, only include the\n            // package if a new major version is available. Otherwise, include\n            // the package if there is any new version available.\n            match check_major_versions {\n                true => {\n                    if latest.major <= version.major {\n                        return None;\n                    }\n                }\n                false => {\n                    if latest <= version {\n                        return None;\n                    }\n                }\n            }\n\n            Some((package.to_string(), (version.clone(), latest.clone())))\n        })\n        .collect()\n}\n\n/// Check for major version updates for direct dependencies that are being blocked by some version\n/// constraints.\npub fn check_for_major_version_updates(\n    manifest: &manifest::Manifest,\n    package_fetcher: &impl PackageFetcher,\n) -> PackageVersionDiffs {\n    let versions: PackageVersions = manifest\n        .packages\n        .iter()\n        .filter(|manifest_package| {\n            manifest\n                .requirements\n                .iter()\n                .any(|(required_pkg, _)| manifest_package.name == *required_pkg)\n        })\n        .map(|manifest_pkg| (manifest_pkg.name.to_string(), manifest_pkg.version.clone()))\n        .collect();\n\n    resolve_versions_diffs(package_fetcher, versions, true)\n}\n\n/// Check for version updates for direct and transitive dependencies that are being blocked by some version\n/// constraints.\npub fn check_for_version_updates(\n    manifest: &manifest::Manifest,\n    package_fetcher: &impl PackageFetcher,\n) -> PackageVersionDiffs {\n    let versions = manifest\n        .packages\n        .iter()\n        .filter(|manifest_package| {\n            matches!(\n                manifest_package.source,\n                manifest::ManifestPackageSource::Hex { .. }\n            )\n        })\n        .map(|manifest_pkg| (manifest_pkg.name.to_string(), manifest_pkg.version.clone()))\n        .collect();\n\n    resolve_versions_diffs(package_fetcher, versions, false)\n}\n\n// If the string would parse to an exact version then return the version\nfn parse_exact_version(ver: &str) -> Option<Version> {\n    let version = ver.trim();\n    let first_byte = version.as_bytes().first();\n\n    // Version is exact if it starts with an explicit == or a number\n    if version.starts_with(\"==\") || first_byte.is_some_and(|v| v.is_ascii_digit()) {\n        let version = version.replace(\"==\", \"\");\n        let version = version.as_str().trim();\n        Version::parse(version).ok()\n    } else {\n        None\n    }\n}\n\nfn root_dependencies<Requirements>(\n    base_requirements: Requirements,\n    locked: &HashMap<EcoString, Version>,\n) -> Result<HashMap<String, Dependency>, Error>\nwhere\n    Requirements: Iterator<Item = (EcoString, Range)>,\n{\n    // Record all of the already locked versions as hard requirements\n    let mut requirements: HashMap<_, _> = locked\n        .iter()\n        .map(|(name, version)| {\n            (\n                name.to_string(),\n                Dependency {\n                    app: None,\n                    optional: false,\n                    repository: None,\n                    requirement: version.clone().into(),\n                },\n            )\n        })\n        .collect();\n\n    for (name, range) in base_requirements {\n        match locked.get(&name) {\n            // If the package was not already locked then we can use the\n            // specified version requirement without modification.\n            None => {\n                let _ = requirements.insert(\n                    name.into(),\n                    Dependency {\n                        app: None,\n                        optional: false,\n                        repository: None,\n                        requirement: range,\n                    },\n                );\n            }\n\n            // If the version was locked we verify that the requirement is\n            // compatible with the locked version.\n            Some(locked_version) => {\n                let compatible = range.to_pubgrub().contains(locked_version);\n                if !compatible {\n                    return Err(Error::IncompatibleLockedVersion {\n                        error: format!(\n                            \"{name} is specified with the requirement `{range}`, \\\nbut it is locked to {locked_version}, which is incompatible.\",\n                        ),\n                    });\n                }\n            }\n        };\n    }\n\n    Ok(requirements)\n}\n\npub trait PackageFetcher {\n    fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError>;\n}\n\n#[derive(Debug, Error)]\npub enum PackageFetchError {\n    #[error(\"The package {0} was not found in the package repository\")]\n    NotFoundError(String),\n    #[error(\"{0}\")]\n    ApiError(hexpm::ApiError),\n    #[error(\"{0}\")]\n    FetchError(String),\n}\nimpl PackageFetchError {\n    pub fn fetch_error<T: std::error::Error>(err: T) -> Self {\n        Self::FetchError(err.to_string())\n    }\n\n    pub fn from_api_error(api_error: hexpm::ApiError, package: &str) -> Self {\n        match &api_error {\n            hexpm::ApiError::NotFound => Self::NotFoundError(package.to_string()),\n\n            hexpm::ApiError::Json(_)\n            | hexpm::ApiError::IncorrectOneTimePassword\n            | hexpm::ApiError::OAuthRefreshTokenRejected\n            | hexpm::ApiError::OAuthAccessDenied\n            | hexpm::ApiError::OAuthTimeout\n            | hexpm::ApiError::ExpiredToken\n            | hexpm::ApiError::Io(_)\n            | hexpm::ApiError::InvalidProtobuf(_)\n            | hexpm::ApiError::UnexpectedResponse(_, _)\n            | hexpm::ApiError::RateLimited\n            | hexpm::ApiError::InvalidCredentials\n            | hexpm::ApiError::InvalidPackageNameFormat(_)\n            | hexpm::ApiError::IncorrectPayloadSignature\n            | hexpm::ApiError::InvalidVersionFormat(_)\n            | hexpm::ApiError::InvalidVersionRequirementFormat(_)\n            | hexpm::ApiError::IncorrectChecksum\n            | hexpm::ApiError::Forbidden\n            | hexpm::ApiError::NotReplacing\n            | hexpm::ApiError::LateModification => Self::ApiError(api_error),\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct DependencyProvider<'a, T: PackageFetcher> {\n    packages: RefCell<HashMap<EcoString, hexpm::Package>>,\n    remote: &'a T,\n    locked: &'a HashMap<EcoString, Version>,\n    // Map of packages where an exact version was requested\n    // We need this because by default pubgrub checks exact version by checking if a version is between the exact\n    // and the version 1 bump ahead. That default breaks on prerelease builds since a bump includes the whole patch\n    exact_only: &'a HashMap<String, Version>,\n    optional_dependencies: RefCell<HashMap<EcoString, pubgrub::Range<Version>>>,\n}\n\nimpl<'a, T> DependencyProvider<'a, T>\nwhere\n    T: PackageFetcher,\n{\n    fn new(\n        remote: &'a T,\n        mut packages: HashMap<EcoString, hexpm::Package>,\n        root: hexpm::Package,\n        locked: &'a HashMap<EcoString, Version>,\n        exact_only: &'a HashMap<String, Version>,\n    ) -> Self {\n        let _ = packages.insert(root.name.as_str().into(), root);\n        Self {\n            packages: RefCell::new(packages),\n            locked,\n            remote,\n            exact_only,\n            optional_dependencies: RefCell::new(Default::default()),\n        }\n    }\n\n    /// Download information about the package from the registry into the local\n    /// store. Does nothing if the packages are already known.\n    ///\n    /// Package versions are sorted from newest to oldest, with all pre-releases\n    /// at the end to ensure that a non-prerelease version will be picked first\n    /// if there is one.\n    //\n    fn ensure_package_fetched(\n        // We would like to use `&mut self` but the pubgrub library enforces\n        // `&self` with interop mutability.\n        &self,\n        name: &str,\n    ) -> Result<(), PackageFetchError> {\n        let mut packages = self.packages.borrow_mut();\n        if packages.get(name).is_none() {\n            let package = self.remote.get_dependencies(name)?;\n            // mut (therefore clone) is required here in order to sort the releases\n            let mut package = (*package).clone();\n            // Sort the packages from newest to oldest, pres after all others\n            package.releases.sort_by(|a, b| a.version.cmp(&b.version));\n            package.releases.reverse();\n            let (pre, mut norm): (_, Vec<_>) = package\n                .releases\n                .into_iter()\n                .partition(|r| r.version.is_pre());\n            norm.extend(pre);\n            package.releases = norm;\n            let _ = packages.insert(name.into(), package);\n        }\n        Ok(())\n    }\n}\n\ntype PackageName = String;\npub type ResolutionError<'a, T> = pubgrub::PubGrubError<DependencyProvider<'a, T>>;\n\nimpl<T> pubgrub::DependencyProvider for DependencyProvider<'_, T>\nwhere\n    T: PackageFetcher,\n{\n    fn get_dependencies(\n        &self,\n        package: &Self::P,\n        version: &Self::V,\n    ) -> Result<Dependencies<Self::P, Self::VS, Self::M>, Self::Err> {\n        self.ensure_package_fetched(package)?;\n        let packages = self.packages.borrow();\n        let release = match packages\n            .get(package.as_str())\n            .into_iter()\n            .flat_map(|p| p.releases.iter())\n            .find(|r| &r.version == version)\n        {\n            Some(release) => release,\n            None => {\n                return Ok(Dependencies::Unavailable(format!(\n                    \"{package}@{version} is not available\"\n                )));\n            }\n        };\n\n        // Only use retired versions if they have been locked\n        if release.is_retired() && self.locked.get(package.as_str()) != Some(version) {\n            return Ok(Dependencies::Unavailable(format!(\n                \"{package}@{version} is retired\"\n            )));\n        }\n\n        let mut deps: Map<PackageName, PubgrubRange> = Default::default();\n        for (name, d) in &release.requirements {\n            let mut range = d.requirement.to_pubgrub().clone();\n            let mut opt_deps = self.optional_dependencies.borrow_mut();\n            // if it's optional and it was not provided yet, store and skip\n            if d.optional && !packages.contains_key(name.as_str()) {\n                let _ = opt_deps\n                    .entry(name.into())\n                    .and_modify(|stored_range| {\n                        *stored_range = range.intersection(stored_range);\n                    })\n                    .or_insert(range);\n                continue;\n            }\n\n            // if a now required dep was optional before, add back the constraints\n            if let Some(other_range) = opt_deps.remove(name.as_str()) {\n                range = range.intersection(&other_range);\n            }\n\n            let _ = deps.insert(name.clone(), range);\n        }\n        Ok(Dependencies::Available(deps))\n    }\n\n    fn prioritize(\n        &self,\n        package: &Self::P,\n        range: &Self::VS,\n        _package_conflicts_counts: &pubgrub::PackageResolutionStatistics,\n    ) -> Self::Priority {\n        Reverse(\n            self.packages\n                .borrow()\n                .get(package.as_str())\n                .cloned()\n                .into_iter()\n                .flat_map(|p| {\n                    p.releases\n                        .into_iter()\n                        .filter(|r| range.contains(&r.version))\n                })\n                .count(),\n        )\n    }\n\n    fn choose_version(\n        &self,\n        package: &Self::P,\n        range: &Self::VS,\n    ) -> std::result::Result<Option<Self::V>, Self::Err> {\n        self.ensure_package_fetched(package)?;\n\n        let exact_package = self.exact_only.get(package);\n        let potential_versions = self\n            .packages\n            .borrow()\n            .get(package.as_str())\n            .cloned()\n            .into_iter()\n            .flat_map(move |p| {\n                p.releases\n                    .into_iter()\n                    // if an exact version of a package is specified then we only want to allow that version as available\n                    .filter_map(move |release| match exact_package {\n                        Some(ver) => (ver == &release.version).then_some(release.version),\n                        _ => Some(release.version),\n                    })\n            })\n            .filter(|v| range.contains(v));\n        match potential_versions.clone().filter(|v| !v.is_pre()).max() {\n            // Don't resolve to a pre-releaase package unless we *have* to\n            Some(v) => Ok(Some(v)),\n            None => Ok(potential_versions.max()),\n        }\n    }\n\n    type P = PackageName;\n    type V = Version;\n    type VS = PubgrubRange;\n    type Priority = Reverse<usize>;\n    type M = String;\n    type Err = PackageFetchError;\n}\n\n#[cfg(test)]\nmod tests {\n    use hexpm::RetirementStatus;\n\n    use crate::{\n        derivation_tree::DerivationTreePrinter,\n        manifest::{Base16Checksum, ManifestPackage, ManifestPackageSource},\n        requirement,\n    };\n\n    use super::*;\n\n    struct Remote {\n        deps: HashMap<String, Rc<hexpm::Package>>,\n    }\n\n    impl PackageFetcher for Remote {\n        fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError> {\n            self.deps\n                .get(package)\n                .map(Rc::clone)\n                .ok_or(PackageFetchError::NotFoundError(package.to_string()))\n        }\n    }\n\n    fn make_remote() -> Remote {\n        remote(vec![\n            (\n                \"gleam_stdlib\",\n                vec![\n                    release(\"0.1.0\", vec![]),\n                    release(\"0.2.0\", vec![]),\n                    release(\"0.2.2\", vec![]),\n                    release(\"0.3.0\", vec![]),\n                ],\n            ),\n            (\n                \"gleam_otp\",\n                vec![\n                    release(\"0.1.0\", vec![(\"gleam_stdlib\", \">= 0.1.0\")]),\n                    release(\"0.2.0\", vec![(\"gleam_stdlib\", \">= 0.1.0\")]),\n                    release(\"0.3.0-rc1\", vec![(\"gleam_stdlib\", \">= 0.1.0\")]),\n                    release(\"0.3.0-rc2\", vec![(\"gleam_stdlib\", \">= 0.1.0\")]),\n                ],\n            ),\n            (\n                \"package_with_retired\",\n                vec![\n                    release(\"0.1.0\", vec![]),\n                    retired_release(\n                        \"0.2.0\",\n                        vec![],\n                        hexpm::RetirementReason::Security,\n                        \"it's bad\",\n                    ),\n                ],\n            ),\n            (\n                \"package_with_optional\",\n                vec![release_with_optional(\n                    \"0.1.0\",\n                    vec![],\n                    vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")],\n                )],\n            ),\n            (\n                \"direct_pkg_with_major_version\",\n                vec![\n                    release(\"0.1.0\", vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")]),\n                    release(\"1.0.0\", vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")]),\n                    release(\"1.1.0\", vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")]),\n                ],\n            ),\n            (\n                \"depends_on_old_version_of_direct_pkg\",\n                vec![release(\n                    \"0.1.0\",\n                    vec![(\"direct_pkg_with_major_version\", \">= 0.1.0 and < 0.3.0\")],\n                )],\n            ),\n            (\n                \"this_pkg_depends_on_indirect_pkg\",\n                vec![release(\n                    \"0.1.0\",\n                    vec![(\"indirect_pkg_with_major_version\", \">= 0.1.0 and < 1.0.0\")],\n                )],\n            ),\n            (\n                \"indirect_pkg_with_major_version\",\n                vec![\n                    release(\"0.1.0\", vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")]),\n                    release(\"1.0.0\", vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")]),\n                    release(\"1.1.0\", vec![(\"gleam_stdlib\", \">= 0.1.0 and < 0.3.0\")]),\n                ],\n            ),\n        ])\n    }\n\n    #[test]\n    fn resolution_with_locked() {\n        let locked_stdlib = (\"gleam_stdlib\".into(), Version::parse(\"0.1.0\").unwrap());\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_stdlib\".into(), Range::new(\"~> 0.1\".into()).unwrap())].into_iter(),\n            &vec![locked_stdlib].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![(\"gleam_stdlib\".into(), Version::parse(\"0.1.0\").unwrap())]\n                .into_iter()\n                .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_without_deps() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(result, vec![].into_iter().collect())\n    }\n\n    #[test]\n    fn resolution_1_dep() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_stdlib\".into(), Range::new(\"~> 0.1\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![(\"gleam_stdlib\".into(), Version::try_from(\"0.3.0\").unwrap())]\n                .into_iter()\n                .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_with_nested_deps() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_otp\".into(), Range::new(\"~> 0.1\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![\n                (\"gleam_otp\".into(), Version::try_from(\"0.2.0\").unwrap()),\n                (\"gleam_stdlib\".into(), Version::try_from(\"0.3.0\").unwrap())\n            ]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_with_optional_deps() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\n                \"package_with_optional\".into(),\n                Range::new(\"~> 0.1\".into()).unwrap(),\n            )]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![(\n                \"package_with_optional\".into(),\n                Version::try_from(\"0.1.0\").unwrap()\n            )]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_with_optional_deps_explicitly_provided() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![\n                (\n                    \"package_with_optional\".into(),\n                    Range::new(\"~> 0.1\".into()).unwrap(),\n                ),\n                (\"gleam_stdlib\".into(), Range::new(\"~> 0.1\".into()).unwrap()),\n            ]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![\n                (\"gleam_stdlib\".into(), Version::try_from(\"0.2.2\").unwrap()),\n                (\n                    \"package_with_optional\".into(),\n                    Version::try_from(\"0.1.0\").unwrap()\n                ),\n            ]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_with_optional_deps_incompatible() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![\n                (\n                    \"package_with_optional\".into(),\n                    Range::new(\"~> 0.1\".into()).unwrap(),\n                ),\n                (\"gleam_stdlib\".into(), Range::new(\"~> 0.3\".into()).unwrap()),\n            ]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        );\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn resolution_with_optional_deps_required_by_nested_deps() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![\n                (\n                    \"package_with_optional\".into(),\n                    Range::new(\"~> 0.1\".into()).unwrap(),\n                ),\n                (\"gleam_otp\".into(), Range::new(\"~> 0.1\".into()).unwrap()),\n            ]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![\n                (\"gleam_stdlib\".into(), Version::try_from(\"0.2.2\").unwrap()),\n                (\"gleam_otp\".into(), Version::try_from(\"0.2.0\").unwrap()),\n                (\n                    \"package_with_optional\".into(),\n                    Version::try_from(\"0.1.0\").unwrap()\n                ),\n            ]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_with_optional_deps_keep_constraints() {}\n\n    #[test]\n    fn resolution_locked_to_older_version() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_otp\".into(), Range::new(\"~> 0.1.0\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![\n                (\"gleam_otp\".into(), Version::try_from(\"0.1.0\").unwrap()),\n                (\"gleam_stdlib\".into(), Version::try_from(\"0.3.0\").unwrap())\n            ]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_retired_versions_not_used_by_default() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\n                \"package_with_retired\".into(),\n                Range::new(\"> 0.0.0\".into()).unwrap(),\n            )]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![(\n                \"package_with_retired\".into(),\n                // Uses the older version that hasn't been retired\n                Version::try_from(\"0.1.0\").unwrap()\n            ),]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_retired_versions_can_be_used_if_locked() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\n                \"package_with_retired\".into(),\n                Range::new(\"> 0.0.0\".into()).unwrap(),\n            )]\n            .into_iter(),\n            &vec![(\"package_with_retired\".into(), Version::new(0, 2, 0))]\n                .into_iter()\n                .collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![(\n                \"package_with_retired\".into(),\n                // Uses the locked version even though it's retired\n                Version::new(0, 2, 0)\n            ),]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    #[test]\n    fn resolution_prerelease_can_be_selected() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\n                \"gleam_otp\".into(),\n                Range::new(\"~> 0.3.0-rc1\".into()).unwrap(),\n            )]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![\n                (\"gleam_stdlib\".into(), Version::try_from(\"0.3.0\").unwrap()),\n                (\"gleam_otp\".into(), Version::try_from(\"0.3.0-rc2\").unwrap()),\n            ]\n            .into_iter()\n            .collect(),\n        );\n    }\n\n    #[test]\n    fn resolution_exact_prerelease_can_be_selected() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_otp\".into(), Range::new(\"0.3.0-rc1\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![\n                (\"gleam_stdlib\".into(), Version::try_from(\"0.3.0\").unwrap()),\n                (\"gleam_otp\".into(), Version::try_from(\"0.3.0-rc1\").unwrap()),\n            ]\n            .into_iter()\n            .collect(),\n        );\n    }\n\n    #[test]\n    fn resolution_not_found_dep() {\n        let err = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"unknown\".into(), Range::new(\"~> 0.1\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap_err();\n        match err {\n            Error::DependencyResolutionError(error) => assert_eq!(\n                error,\n                \"An error occurred while choosing the version of unknown: The package unknown was not found in the package repository\"\n            ),\n            _ => panic!(\"wrong error: {err}\"),\n        }\n    }\n\n    #[test]\n    fn resolution_no_matching_version() {\n        let _ = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_stdlib\".into(), Range::new(\"~> 99.0\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap_err();\n    }\n\n    #[test]\n    fn resolution_locked_version_doesnt_satisfy_requirements() {\n        let err = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\n                \"gleam_stdlib\".into(),\n                Range::new(\"~> 0.1.0\".into()).unwrap(),\n            )]\n            .into_iter(),\n            &vec![(\"gleam_stdlib\".into(), Version::new(0, 2, 0))]\n                .into_iter()\n                .collect(),\n        )\n        .unwrap_err();\n\n        match err {\n            Error::IncompatibleLockedVersion { error } => assert_eq!(\n                error,\n                \"gleam_stdlib is specified with the requirement `~> 0.1.0`, but it is locked to 0.2.0, which is incompatible.\"\n            ),\n            _ => panic!(\"wrong error: {err}\"),\n        }\n    }\n\n    #[test]\n    fn resolution_with_exact_dep() {\n        let result = resolve_versions(\n            &make_remote(),\n            HashMap::new(),\n            \"app\".into(),\n            vec![(\"gleam_stdlib\".into(), Range::new(\"0.1.0\".into()).unwrap())].into_iter(),\n            &vec![].into_iter().collect(),\n        )\n        .unwrap();\n        assert_eq!(\n            result,\n            vec![(\"gleam_stdlib\".into(), Version::try_from(\"0.1.0\").unwrap())]\n                .into_iter()\n                .collect()\n        );\n    }\n\n    #[test]\n    fn parse_exact_version_test() {\n        assert_eq!(\n            parse_exact_version(\"1.0.0\"),\n            Some(Version::parse(\"1.0.0\").unwrap())\n        );\n        assert_eq!(\n            parse_exact_version(\"==1.0.0\"),\n            Some(Version::parse(\"1.0.0\").unwrap())\n        );\n        assert_eq!(\n            parse_exact_version(\"== 1.0.0\"),\n            Some(Version::parse(\"1.0.0\").unwrap())\n        );\n        assert_eq!(parse_exact_version(\"~> 1.0.0\"), None);\n        assert_eq!(parse_exact_version(\">= 1.0.0\"), None);\n    }\n\n    #[test]\n    fn resolve_major_version_upgrades() {\n        let manifest = manifest::Manifest {\n            requirements: vec![\n                (\n                    EcoString::from(\"package_depends_on_indirect_pkg\"),\n                    requirement::Requirement::Hex {\n                        version: Range::new(\"> 0.1.0 and <= 1.0.0\".into()).unwrap(),\n                    },\n                ),\n                (\n                    EcoString::from(\"direct_pkg_with_major_version\"),\n                    requirement::Requirement::Hex {\n                        version: Range::new(\"> 0.1.0 and <= 2.0.0\".into()).unwrap(),\n                    },\n                ),\n                (\n                    EcoString::from(\"depends_on_old_version_of_direct_pkg\"),\n                    requirement::Requirement::Hex {\n                        version: Range::new(\"> 0.1.0 and <= 1.0.0\".into()).unwrap(),\n                    },\n                ),\n            ]\n            .into_iter()\n            .collect(),\n            packages: vec![\n                ManifestPackage {\n                    name: \"direct_pkg_with_major_version\".into(),\n                    version: Version::parse(\"0.1.0\").unwrap(),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![1, 2, 3]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"depends_on_old_version_of_direct_pkg\".into(),\n                    version: Version::parse(\"0.1.0\").unwrap(),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![\"direct_pkg_with_major_version\".into()],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![1, 2, 3]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"pkg_depends_on_indirect_pkg\".into(),\n                    version: Version::parse(\"0.1.0\").unwrap(),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![\"indirect_pkg_with_major_version\".into()],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![1, 2, 3]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"indirect_pkg_with_major_version\".into(),\n                    version: Version::parse(\"0.1.0\").unwrap(),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![1, 2, 3]),\n                    },\n                },\n            ],\n        };\n        let result = check_for_major_version_updates(&manifest, &make_remote());\n\n        // indirect package with major version will not be in the result even though a major\n        // version of it is available\n        assert_eq!(\n            result,\n            vec![(\n                \"direct_pkg_with_major_version\".into(),\n                (\n                    Version::try_from(\"0.1.0\").unwrap(),\n                    Version::try_from(\"1.1.0\").unwrap()\n                )\n            ),]\n            .into_iter()\n            .collect()\n        );\n    }\n\n    fn retired_release(\n        version: &str,\n        requirements: Vec<(&str, &str)>,\n        reason: hexpm::RetirementReason,\n        message: &str,\n    ) -> Release<()> {\n        Release {\n            retirement_status: Some(RetirementStatus {\n                reason,\n                message: message.into(),\n            }),\n            ..release(version, requirements)\n        }\n    }\n    fn release(version: &str, requirements: Vec<(&str, &str)>) -> Release<()> {\n        release_with_optional(version, requirements, vec![])\n    }\n\n    fn release_with_optional(\n        version: &str,\n        requirements: Vec<(&str, &str)>,\n        optional_requirements: Vec<(&str, &str)>,\n    ) -> Release<()> {\n        let mut all_requirements = HashMap::new();\n\n        for (name, range) in requirements {\n            let requirement = Range::new(range.to_string()).unwrap();\n            let dependency = Dependency {\n                requirement,\n                optional: false,\n                app: None,\n                repository: None,\n            };\n            let _ = all_requirements.insert(name.to_string(), dependency);\n        }\n\n        for (name, range) in optional_requirements {\n            let requirement = Range::new(range.to_string()).unwrap();\n            let dependency = Dependency {\n                requirement,\n                optional: true,\n                app: None,\n                repository: None,\n            };\n            let _ = all_requirements.insert(name.to_string(), dependency);\n        }\n\n        Release {\n            version: Version::try_from(version).unwrap(),\n            requirements: all_requirements,\n            retirement_status: None,\n            outer_checksum: vec![1, 2, 3],\n            meta: (),\n        }\n    }\n\n    fn remote(dependencies: Vec<(&str, Vec<Release<()>>)>) -> Remote {\n        let mut deps = HashMap::new();\n        for (package, releases) in dependencies {\n            let _ = deps.insert(\n                package.into(),\n                Rc::new(hexpm::Package {\n                    name: package.into(),\n                    repository: \"hexpm\".into(),\n                    releases,\n                }),\n            );\n        }\n        Remote { deps }\n    }\n\n    #[test]\n    fn resolution_error_message() {\n        let remote = remote(vec![\n            (\n                \"wibble\",\n                vec![\n                    release(\"1.2.0\", vec![(\"wobble\", \">= 1.0.0 and < 2.0.0\")]),\n                    release(\"1.3.0\", vec![(\"wobble\", \">= 2.0.0 and < 3.0.0\")]),\n                ],\n            ),\n            (\n                \"wobble\",\n                vec![\n                    release(\"1.1.0\", vec![(\"woo\", \">= 1.0.0 and < 2.0.0\")]),\n                    release(\"2.0.0\", vec![(\"waa\", \">= 1.0.0 and < 2.0.0\")]),\n                ],\n            ),\n            (\n                \"woo\",\n                vec![release(\"1.0.0\", vec![]), release(\"2.0.0\", vec![])],\n            ),\n            (\n                \"waa\",\n                vec![release(\"1.0.0\", vec![]), release(\"2.0.0\", vec![])],\n            ),\n        ]);\n\n        let result = resolve_versions(\n            &remote,\n            HashMap::new(),\n            \"app\".into(),\n            vec![\n                (\n                    \"wibble\".into(),\n                    Range::new(\">= 1.0.0 and < 2.0.0\".into()).unwrap(),\n                ),\n                (\n                    \"woo\".into(),\n                    Range::new(\">= 2.0.0 and < 3.0.0\".into()).unwrap(),\n                ),\n                (\n                    \"waa\".into(),\n                    Range::new(\">= 2.0.0 and < 3.0.0\".into()).unwrap(),\n                ),\n            ]\n            .into_iter(),\n            &vec![].into_iter().collect(),\n        );\n\n        if let Err(Error::DependencyResolutionNoSolution {\n            root_package_name,\n            derivation_tree,\n        }) = result\n        {\n            let message = crate::error::wrap(\n                &DerivationTreePrinter::new(root_package_name, derivation_tree.0).print(),\n            );\n            insta::assert_snapshot!(message)\n        } else {\n            panic!(\"expected a resolution error message\")\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/derivation_tree.rs",
    "content": "use crate::error::wrap;\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse im::HashSet;\nuse itertools::Itertools;\nuse petgraph::Direction;\nuse petgraph::algo::all_simple_paths;\nuse petgraph::graph::NodeIndex;\nuse petgraph::prelude::StableGraph;\nuse pubgrub::External;\nuse pubgrub::{DerivationTree, Derived, Ranges};\nuse std::collections::HashMap;\nuse std::hash::RandomState;\nuse std::ops::Bound::{Excluded, Included, Unbounded};\nuse std::sync::Arc;\n\nmacro_rules! wrap_format {\n    ($($tts:tt)*) => {\n        wrap(&format!($($tts)*))\n    }\n}\n\n/// Makes a best effort at turning a derivation tree into a nice readable error\n/// message.\n///\npub struct DerivationTreePrinter {\n    derivation_tree: DerivationTree<String, Ranges<Version>, String>,\n\n    /// The name of the root package for which we're trying to add new\n    /// dependencies. This is the starting point we use to find and report\n    /// dependency conflicts!\n    root_package_name: EcoString,\n\n    /// The graph of dependencies built from the derivation tree. The nodes are\n    /// packages and the arcs connecting them represent a dependency:\n    ///\n    /// ```txt\n    /// wibble ---- (range1, range2) ---> wobble\n    /// ```\n    ///\n    /// Means \"package wibble with version `range1` requires package wobble\n    /// with version `range2`\".\n    ///\n    dependencies: StableGraph<String, (Ranges<Version>, Ranges<Version>)>,\n\n    /// A map going from package name to its index in the dependencies graph.\n    ///\n    nodes: HashMap<String, NodeIndex>,\n}\n\nimpl DerivationTreePrinter {\n    pub fn new(\n        root_package_name: EcoString,\n        mut derivation_tree: DerivationTree<String, Ranges<Version>, String>,\n    ) -> Self {\n        // We start by trying to simplify the derivation tree as much as\n        // possible.\n        derivation_tree.collapse_no_versions();\n        simplify_derivation_tree(&mut derivation_tree);\n\n        let mut dependencies = StableGraph::new();\n        let mut nodes = HashMap::new();\n        build_dependencies_graph(&derivation_tree, &mut dependencies, &mut nodes);\n\n        DerivationTreePrinter {\n            root_package_name,\n            derivation_tree,\n            dependencies,\n            nodes,\n        }\n    }\n\n    pub fn print(&self) -> String {\n        self.pretty_explanation()\n            .unwrap_or_else(|| self.fallback_explanation())\n    }\n\n    /// Tries and print a pretty explanation for the given resolution tree.\n    /// If for some reason our heuristic to produce a nice error message fails\n    /// we return `None` so we can still produce a good enough error message!\n    ///\n    fn pretty_explanation(&self) -> Option<String> {\n        let root_package_index = self.nodes.get(self.root_package_name.as_str())?;\n        let unresolvable_nodes = self.find_unresolvable_nodes();\n        if unresolvable_nodes.is_empty() {\n            return None;\n        }\n\n        let mut unresolvable = vec![];\n        for unresolvable_node in unresolvable_nodes {\n            let paths = all_simple_paths::<Vec<_>, _, RandomState>(\n                &self.dependencies,\n                *root_package_index,\n                unresolvable_node,\n                0,\n                None,\n            );\n\n            let package = self\n                .dependencies\n                .node_weight(unresolvable_node)\n                .expect(\"package is in the graph\");\n\n            let heading = format!(\"There's no compatible version of `{package}`:\");\n            let explanation = paths.sorted().map(|path| self.pretty_path(path)).join(\"\\n\");\n            unresolvable.push(format!(\"{heading}\\n{explanation}\"));\n        }\n        Some(unresolvable.join(\"\\n\\n\"))\n    }\n\n    fn pretty_path(&self, path: Vec<NodeIndex>) -> String {\n        let (you, dependee, rest) = match path.as_slice() {\n            [you, dependee, rest @ ..] => (you, dependee, rest),\n            _ => panic!(\"path with less than two nodes\"),\n        };\n\n        let dependee_name = self\n            .dependencies\n            .node_weight(*dependee)\n            .expect(\"path node is in the graph\");\n        let (_, dependee_range) = self\n            .ranges_between(you, dependee)\n            .expect(\"path edge is in the graph\");\n\n        let mut message = format!(\n            \"  - You require {dependee_name} {}\",\n            pretty_range(dependee_range)\n        );\n\n        let mut previous = dependee;\n        for next in rest {\n            let previous_name = self\n                .dependencies\n                .node_weight(*previous)\n                .expect(\"path node is in the graph\");\n            let next_name = self\n                .dependencies\n                .node_weight(*next)\n                .expect(\"path node is in the graph\");\n            let (_, next_range) = self\n                .ranges_between(previous, next)\n                .expect(\"path edge is in the graph\");\n\n            message.push_str(&format!(\n                \"\\n    - {previous_name} requires {next_name} {}\",\n                pretty_range(next_range)\n            ));\n            previous = next;\n        }\n        message\n    }\n\n    fn find_unresolvable_nodes(&self) -> Vec<NodeIndex> {\n        self.dependencies\n            .node_indices()\n            .filter(|node_index| {\n                self.dependencies\n                    .neighbors_directed(*node_index, Direction::Incoming)\n                    .count()\n                    > 1\n            })\n            .sorted()\n            .collect_vec()\n    }\n\n    fn ranges_between(\n        &self,\n        one: &NodeIndex,\n        other: &NodeIndex,\n    ) -> Option<(&Ranges<Version>, &Ranges<Version>)> {\n        let edge = self.dependencies.find_edge(*one, *other)?;\n        self.dependencies\n            .edge_weight(edge)\n            .map(|(one, other)| (one, other))\n    }\n\n    /// A good enough explanation in case we're not able to produce anything\n    /// nicer.\n    fn fallback_explanation(&self) -> String {\n        let mut conflicting_packages = HashSet::new();\n        collect_conflicting_packages(&self.derivation_tree, &mut conflicting_packages);\n\n        wrap_format!(\n            \"Unable to find compatible versions for \\\nthe version constraints in your gleam.toml. \\\nThe conflicting packages are:\n\n{}\n\",\n            conflicting_packages\n                .into_iter()\n                .map(|s| format!(\"- {s}\"))\n                .join(\"\\n\")\n        )\n    }\n}\n\nfn build_dependencies_graph(\n    derivation_tree: &DerivationTree<String, Ranges<Version>, String>,\n    graph: &mut StableGraph<String, (Ranges<Version>, Ranges<Version>)>,\n    nodes: &mut HashMap<String, NodeIndex<u32>>,\n) {\n    match derivation_tree {\n        DerivationTree::External(External::FromDependencyOf(\n            one,\n            range_one,\n            other,\n            range_other,\n        )) => {\n            let one_index = match nodes.get(one) {\n                Some(index) => *index,\n                None => {\n                    let index = graph.add_node(one.clone());\n                    let _ = nodes.insert(one.clone(), index);\n                    index\n                }\n            };\n\n            let other_index = match nodes.get(other) {\n                Some(index) => *index,\n                None => {\n                    let index = graph.add_node(other.clone());\n                    let _ = nodes.insert(other.clone(), index);\n                    index\n                }\n            };\n\n            let edges = graph.edges_connecting(one_index, other_index);\n            let edge_weight = match edges.peekable().peek() {\n                Some(edge) => {\n                    let (old_range_one, old_range_other) = edge.weight();\n                    (\n                        range_one.union(old_range_one),\n                        range_other.union(old_range_other),\n                    )\n                }\n                None => (range_one.clone(), range_other.clone()),\n            };\n\n            let _ = graph.update_edge(one_index, other_index, edge_weight);\n        }\n        DerivationTree::External(_) => (),\n        DerivationTree::Derived(Derived { cause1, cause2, .. }) => {\n            build_dependencies_graph(cause1, graph, nodes);\n            build_dependencies_graph(cause2, graph, nodes);\n        }\n    }\n}\n\n/// This function collapses adjacent levels of a derivation tree that are all\n/// relative to the same dependency.\n///\n/// By default a derivation tree might have many nodes for a specific package,\n/// each node referring to a specific version range. For example:\n///\n///   - package_wibble `>= 1.0.0 and < 1.1.0` requires package_wobble `>= 1.1.0`\n///   - package_wibble `>= 1.1.0 and < 1.2.0` requires package_wobble `>= 1.2.0`\n///   - package_wibble `1.1.0` requires package_wobble `>= 1.1.0`\n///\n/// This level of fine-grained detail would be quite overwhelming in the vast\n/// majority of cases so we're fine with collapsing all these details into a\n/// single node taking the union of all the ranges that are there:\n///\n///   - package_wibble `>= 1.0.0 and < 1.2.0` requires package_wobble `>= 1.1.0`\n///\n/// This way we can print an error message that is way more concise and still\n/// informative about what went wrong, at the cost of\n///\nfn simplify_derivation_tree(derivation_tree: &mut DerivationTree<String, Ranges<Version>, String>) {\n    match derivation_tree {\n        DerivationTree::External(_) => {}\n        DerivationTree::Derived(derived) => {\n            simplify_derivation_tree(Arc::make_mut(&mut derived.cause1));\n            simplify_derivation_tree(Arc::make_mut(&mut derived.cause2));\n            simplify_derivation_tree_outer(derivation_tree);\n        }\n    }\n}\n\nfn simplify_derivation_tree_outer(\n    derivation_tree: &mut DerivationTree<String, Ranges<Version>, String>,\n) {\n    match derivation_tree {\n        DerivationTree::External(_) => {}\n        DerivationTree::Derived(derived) => {\n            match (\n                Arc::make_mut(&mut derived.cause1),\n                Arc::make_mut(&mut derived.cause2),\n            ) {\n                (\n                    DerivationTree::External(External::FromDependencyOf(\n                        package,\n                        package_range,\n                        required_package,\n                        required_package_range,\n                    )),\n                    DerivationTree::External(External::FromDependencyOf(\n                        maybe_package,\n                        other_package_range,\n                        maybe_required_package,\n                        other_required_package_range,\n                    )),\n                ) if package == maybe_package && required_package == maybe_required_package => {\n                    *derivation_tree = DerivationTree::External(External::FromDependencyOf(\n                        package.clone(),\n                        package_range.union(other_package_range),\n                        required_package.clone(),\n                        required_package_range.union(other_required_package_range),\n                    ))\n                }\n\n                _ => {}\n            }\n        }\n    }\n}\n\nfn collect_conflicting_packages<'dt>(\n    derivation_tree: &'dt DerivationTree<String, Ranges<Version>, String>,\n    conflicting_packages: &mut HashSet<&'dt String>,\n) {\n    match derivation_tree {\n        DerivationTree::External(external) => match external {\n            External::NotRoot(package, _)\n            | External::NoVersions(package, _)\n            | External::Custom(package, _, _) => {\n                let _ = conflicting_packages.insert(package);\n            }\n            External::FromDependencyOf(package, _, dep_package, _) => {\n                let _ = conflicting_packages.insert(package);\n                let _ = conflicting_packages.insert(dep_package);\n            }\n        },\n        DerivationTree::Derived(derived) => {\n            collect_conflicting_packages(&derived.cause1, conflicting_packages);\n            collect_conflicting_packages(&derived.cause2, conflicting_packages);\n        }\n    }\n}\n\nfn pretty_range(range: &Ranges<Version>) -> String {\n    range\n        .iter()\n        .map(|(lower, upper)| match (lower, upper) {\n            (Included(lower), Included(upper)) if lower == upper => format!(\"{lower}\"),\n            (Included(lower), Included(upper)) => format!(\">= {lower} and <= {upper}\"),\n            (Included(lower), Excluded(upper)) => format!(\">= {lower} and < {upper}\"),\n            (Excluded(lower), Included(upper)) => format!(\"> {lower} and <= {upper}\"),\n            (Excluded(lower), Excluded(upper)) => format!(\"> {lower} and < {upper}\"),\n\n            (Included(version), Unbounded) => format!(\">= {version}\"),\n            (Excluded(version), Unbounded) => format!(\"> {version}\"),\n            (Unbounded, Included(version)) => format!(\"<= {version}\"),\n            (Unbounded, Excluded(version)) => format!(\"< {version}\"),\n\n            (Unbounded, Unbounded) => \"\".into(),\n        })\n        .join(\" or \")\n}\n"
  },
  {
    "path": "compiler-core/src/diagnostic.rs",
    "content": "use std::collections::HashMap;\n\nuse camino::Utf8PathBuf;\n\npub use codespan_reporting::diagnostic::{LabelStyle, Severity};\nuse codespan_reporting::{diagnostic::Label as CodespanLabel, files::SimpleFiles};\nuse ecow::EcoString;\nuse termcolor::Buffer;\n\nuse crate::ast::SrcSpan;\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Level {\n    Error,\n    Warning,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Label {\n    pub text: Option<String>,\n    pub span: SrcSpan,\n}\n\nimpl Label {\n    fn to_codespan_label(&self, fileid: usize, style: LabelStyle) -> CodespanLabel<usize> {\n        let label = CodespanLabel::new(\n            style,\n            fileid,\n            (self.span.start as usize)..(self.span.end as usize),\n        );\n        match &self.text {\n            None => label,\n            Some(text) => label.with_message(text.clone()),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ExtraLabel {\n    pub src_info: Option<(EcoString, Utf8PathBuf)>,\n    pub label: Label,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Location {\n    pub src: EcoString,\n    pub path: Utf8PathBuf,\n    pub label: Label,\n    pub extra_labels: Vec<ExtraLabel>,\n}\n\n// TODO: split this into locationed diagnostics and locationless diagnostics\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Diagnostic {\n    pub title: String,\n    pub text: String,\n    pub level: Level,\n    pub location: Option<Location>,\n    pub hint: Option<String>,\n}\n\nimpl Diagnostic {\n    pub fn write(&self, buffer: &mut Buffer) {\n        use std::io::Write;\n        match &self.location {\n            Some(location) => self.write_span(location, buffer),\n            None => self.write_title(buffer),\n        };\n\n        if !self.text.is_empty() {\n            writeln!(buffer, \"{}\", self.text).expect(\"write text\");\n        }\n\n        if let Some(hint) = &self.hint {\n            writeln!(buffer, \"Hint: {hint}\").expect(\"write hint\");\n        }\n    }\n\n    fn write_span(&self, location: &Location, buffer: &mut Buffer) {\n        let mut file_map = HashMap::new();\n        let mut files = SimpleFiles::new();\n\n        let main_location_path = location.path.as_str();\n        let main_location_src = location.src.as_str();\n        let main_file_id = files.add(main_location_path, main_location_src);\n        let _ = file_map.insert(main_location_path, main_file_id);\n\n        let mut labels = vec![\n            location\n                .label\n                .to_codespan_label(main_file_id, LabelStyle::Primary),\n        ];\n\n        location\n            .extra_labels\n            .iter()\n            .map(|label| {\n                let (location_src, location_path) = match &label.src_info {\n                    Some(info) => (info.0.as_str(), info.1.as_str()),\n                    _ => (main_location_src, main_location_path),\n                };\n                match file_map.get(location_path) {\n                    None => {\n                        let file_id = files.add(location_path, location_src);\n                        let _ = file_map.insert(location_path, file_id);\n                        label\n                            .label\n                            .to_codespan_label(file_id, LabelStyle::Secondary)\n                    }\n                    Some(i) => label.label.to_codespan_label(*i, LabelStyle::Secondary),\n                }\n            })\n            .for_each(|label| labels.push(label));\n\n        let severity = match self.level {\n            Level::Error => Severity::Error,\n            Level::Warning => Severity::Warning,\n        };\n\n        let diagnostic = codespan_reporting::diagnostic::Diagnostic::new(severity)\n            .with_message(&self.title)\n            .with_labels(labels);\n        let config = codespan_reporting::term::Config::default();\n        codespan_reporting::term::emit(buffer, &config, &files, &diagnostic)\n            .expect(\"write_diagnostic\");\n    }\n\n    fn write_title(&self, buffer: &mut Buffer) {\n        use std::io::Write;\n        use termcolor::{Color, ColorSpec, WriteColor};\n        let (kind, colour) = match self.level {\n            Level::Error => (\"error\", Color::Red),\n            Level::Warning => (\"warning\", Color::Yellow),\n        };\n        buffer\n            .set_color(ColorSpec::new().set_bold(true).set_fg(Some(colour)))\n            .expect(\"write_title_color1\");\n        write!(buffer, \"{kind}\").expect(\"write_title_kind\");\n        buffer\n            .set_color(ColorSpec::new().set_bold(true))\n            .expect(\"write_title_color2\");\n        write!(buffer, \": {}\\n\\n\", self.title).expect(\"write_title_title\");\n        buffer\n            .set_color(&ColorSpec::new())\n            .expect(\"write_title_reset\");\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/docs/printer.rs",
    "content": "use std::{\n    collections::{HashMap, HashSet},\n    ops::Deref,\n};\n\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\n\nuse crate::{\n    ast::{\n        ArgNames, CustomType, Function, Publicity, RecordConstructorArg, SrcSpan, TypeAlias,\n        TypedArg, TypedDefinitions, TypedModuleConstant, TypedRecordConstructor,\n    },\n    docvec,\n    pretty::{Document, Documentable, break_, join, line, nil, zero_width_string},\n    type_::{\n        Deprecation, PRELUDE_MODULE_NAME, PRELUDE_PACKAGE_NAME, Type, TypeVar,\n        printer::{Names, PrintMode},\n    },\n};\n\nuse super::{\n    Dependency, DependencyKind, DocsValues, TypeConstructor, TypeConstructorArg, TypeDefinition,\n    markdown_documentation, source_links::SourceLinker, text_documentation,\n};\n\n#[derive(Clone, Copy)]\npub struct PrintOptions {\n    pub print_highlighting: bool,\n    pub print_html: bool,\n}\n\nimpl PrintOptions {\n    pub fn all() -> Self {\n        Self {\n            print_highlighting: true,\n            print_html: true,\n        }\n    }\n}\n\npub struct Printer<'a> {\n    options: PrintOptions,\n    names: &'a Names,\n\n    package: EcoString,\n    module: EcoString,\n\n    /// Type variables which don't have annotated names and we have generated\n    /// names for.\n    printed_type_variables: HashMap<u64, EcoString>,\n    /// Names of type variables that we have generated or printed in a given\n    /// definition. This ensures that we have no duplicate generated names.\n    printed_type_variable_names: HashSet<EcoString>,\n    /// An incrementing number used to generate the next type variable name.\n    /// `0` becomes `a`, `1` becomes `b`, etc.\n    next_type_variable_id: u64,\n\n    dependencies: &'a HashMap<EcoString, Dependency>,\n}\n\nimpl Printer<'_> {\n    pub fn new<'a>(\n        package: EcoString,\n        module: EcoString,\n        names: &'a Names,\n        dependencies: &'a HashMap<EcoString, Dependency>,\n    ) -> Printer<'a> {\n        Printer {\n            options: PrintOptions::all(),\n            names,\n            package,\n            module,\n            printed_type_variables: HashMap::new(),\n            printed_type_variable_names: HashSet::new(),\n            next_type_variable_id: 0,\n            dependencies,\n        }\n    }\n\n    // This is currently only used in the tests, though it might be useful in\n    // application code in future. If it is needed, simply remove this attribute.\n    #[cfg(test)]\n    pub fn set_options(&mut self, options: PrintOptions) {\n        self.options = options;\n    }\n\n    pub fn type_definitions<'a>(\n        &mut self,\n        source_links: &SourceLinker,\n        definitions: &'a TypedDefinitions,\n    ) -> Vec<TypeDefinition<'a>> {\n        let mut type_definitions = vec![];\n\n        for CustomType {\n            location,\n            name,\n            publicity,\n            constructors,\n            documentation,\n            deprecation,\n            opaque,\n            parameters,\n            ..\n        } in &definitions.custom_types\n        {\n            if !publicity.is_public() {\n                continue;\n            }\n\n            type_definitions.push(TypeDefinition {\n                name,\n                definition: print(self.custom_type(name, parameters, constructors, *opaque)),\n                raw_definition: self\n                    .raw(|this| this.custom_type(name, parameters, constructors, *opaque)),\n                documentation: markdown_documentation(documentation),\n                text_documentation: text_documentation(documentation),\n                deprecation_message: match deprecation {\n                    Deprecation::NotDeprecated => \"\".to_string(),\n                    Deprecation::Deprecated { message } => message.to_string(),\n                },\n                constructors: if *opaque {\n                    Vec::new()\n                } else {\n                    constructors\n                        .iter()\n                        .map(|constructor| TypeConstructor {\n                            definition: print(self.record_constructor(constructor)),\n                            raw_definition: self.raw(|this| this.record_constructor(constructor)),\n                            documentation: markdown_documentation(&constructor.documentation),\n                            text_documentation: text_documentation(&constructor.documentation),\n                            arguments: constructor\n                                .arguments\n                                .iter()\n                                .filter_map(|arg| arg.label.as_ref().map(|(_, label)| (arg, label)))\n                                .map(|(argument, label)| TypeConstructorArg {\n                                    name: label.trim_end().to_string(),\n                                    doc: markdown_documentation(&argument.doc),\n                                    text_documentation: text_documentation(&argument.doc),\n                                })\n                                .filter(|arg| !arg.doc.is_empty())\n                                .collect(),\n                        })\n                        .collect()\n                },\n                source_url: source_links.url(*location),\n                opaque: *opaque,\n            })\n        }\n\n        for TypeAlias {\n            location,\n            alias: name,\n            parameters,\n            type_,\n            publicity,\n            documentation,\n            deprecation,\n            ..\n        } in &definitions.type_aliases\n        {\n            if !publicity.is_public() {\n                continue;\n            }\n            type_definitions.push(TypeDefinition {\n                name,\n                definition: print(self.type_alias(name, type_, parameters).group()),\n                raw_definition: self.raw(|this| this.type_alias(name, type_, parameters).group()),\n                documentation: markdown_documentation(documentation),\n                text_documentation: text_documentation(documentation),\n                constructors: vec![],\n                source_url: source_links.url(*location),\n                deprecation_message: match deprecation {\n                    Deprecation::NotDeprecated => \"\".to_string(),\n                    Deprecation::Deprecated { message } => message.to_string(),\n                },\n                opaque: false,\n            })\n        }\n\n        type_definitions.sort();\n        type_definitions\n    }\n\n    /// Print a definition without HTML highlighting, such as for search data\n    fn raw<'a, F>(&mut self, definition: F) -> String\n    where\n        F: FnOnce(&mut Self) -> Document<'a>,\n    {\n        let options = self.options;\n        // Turn off highlighting for this definition\n        self.options = PrintOptions {\n            print_highlighting: false,\n            print_html: false,\n        };\n        let result = print(definition(self));\n        // Restore previous options\n        self.options = options;\n        format!(\"```\\n{result}\\n```\")\n    }\n\n    pub fn value_definitions<'a>(\n        &mut self,\n        source_links: &SourceLinker,\n        definitions: &'a TypedDefinitions,\n    ) -> Vec<DocsValues<'a>> {\n        let mut value_definitions = vec![];\n\n        for Function {\n            location,\n            name,\n            arguments,\n            publicity,\n            deprecation,\n            return_type,\n            documentation,\n            ..\n        } in &definitions.functions\n        {\n            let Some((_, name)) = name else { continue };\n            if !publicity.is_public() {\n                continue;\n            }\n\n            // Ensure that any type variables we printed in previous definitions don't\n            // affect our printing of this definition. Two type variables in different\n            // definitions can have the same name without clashing.\n            self.printed_type_variable_names.clear();\n            self.next_type_variable_id = 0;\n\n            value_definitions.push(DocsValues {\n                name,\n                definition: print(self.function_signature(name, arguments, return_type)),\n                raw_definition: self\n                    .raw(|this| this.function_signature(name, arguments, return_type)),\n                documentation: markdown_documentation(documentation),\n                text_documentation: text_documentation(documentation),\n                source_url: source_links.url(*location),\n                deprecation_message: match deprecation {\n                    Deprecation::NotDeprecated => \"\".to_string(),\n                    Deprecation::Deprecated { message } => message.to_string(),\n                },\n            })\n        }\n\n        for TypedModuleConstant {\n            documentation,\n            location,\n            publicity,\n            name,\n            type_,\n            deprecation,\n            ..\n        } in &definitions.constants\n        {\n            if !publicity.is_public() {\n                continue;\n            }\n\n            value_definitions.push(DocsValues {\n                name,\n                definition: print(self.constant(name, type_)),\n                raw_definition: self.raw(|this| this.constant(name, type_)),\n                documentation: markdown_documentation(documentation),\n                text_documentation: text_documentation(documentation),\n                source_url: source_links.url(*location),\n                deprecation_message: match deprecation {\n                    Deprecation::NotDeprecated => \"\".to_string(),\n                    Deprecation::Deprecated { message } => message.to_string(),\n                },\n            })\n        }\n\n        value_definitions.sort();\n        value_definitions\n    }\n\n    fn custom_type<'a>(\n        &mut self,\n        name: &'a str,\n        parameters: &'a [(SrcSpan, EcoString)],\n        constructors: &'a [TypedRecordConstructor],\n        opaque: bool,\n    ) -> Document<'a> {\n        let arguments = if parameters.is_empty() {\n            nil()\n        } else {\n            Self::wrap_arguments(\n                parameters\n                    .iter()\n                    .map(|(_, parameter)| self.variable(parameter)),\n            )\n        };\n\n        let keywords = if opaque {\n            \"pub opaque type \"\n        } else {\n            \"pub type \"\n        };\n\n        let type_head = docvec![self.keyword(keywords), self.title(name), arguments];\n\n        if constructors.is_empty() || opaque {\n            return type_head;\n        }\n\n        let constructors = constructors\n            .iter()\n            .map(|constructor| {\n                line()\n                    .append(self.record_constructor(constructor))\n                    .nest(INDENT)\n            })\n            .collect_vec();\n\n        docvec![type_head, \" {\", constructors, line(), \"}\"]\n    }\n\n    pub fn record_constructor<'a>(\n        &mut self,\n        constructor: &'a TypedRecordConstructor,\n    ) -> Document<'a> {\n        if constructor.arguments.is_empty() {\n            return self.title(&constructor.name);\n        }\n\n        let arguments = constructor.arguments.iter().map(\n            |RecordConstructorArg { label, type_, .. }| match label {\n                Some((_, label)) => self\n                    .variable(label)\n                    .append(\": \")\n                    .append(self.type_(type_, PrintMode::Normal)),\n                None => self.type_(type_, PrintMode::Normal),\n            },\n        );\n\n        let arguments = Self::wrap_arguments(arguments);\n\n        docvec![self.title(&constructor.name), arguments].group()\n    }\n\n    fn type_alias<'a>(\n        &mut self,\n        name: &'a str,\n        type_: &Type,\n        parameters: &[(SrcSpan, EcoString)],\n    ) -> Document<'a> {\n        let parameters = if parameters.is_empty() {\n            nil()\n        } else {\n            let arguments = parameters\n                .iter()\n                .map(|(_, parameter)| self.variable(parameter));\n            Self::wrap_arguments(arguments)\n        };\n\n        docvec![\n            self.keyword(\"pub type \"),\n            self.title(name),\n            parameters,\n            \" =\",\n            line()\n                .append(self.type_(type_, PrintMode::ExpandAliases))\n                .nest(INDENT)\n        ]\n    }\n\n    fn constant<'a>(&mut self, name: &'a str, type_: &Type) -> Document<'a> {\n        self.register_local_type_variable_names(type_);\n\n        docvec![\n            self.keyword(\"pub const \"),\n            self.title(name),\n            \": \",\n            self.type_(type_, PrintMode::Normal)\n        ]\n    }\n\n    fn function_signature<'a>(\n        &mut self,\n        name: &'a str,\n        arguments: &'a [TypedArg],\n        return_type: &Type,\n    ) -> Document<'a> {\n        for argument in arguments {\n            self.register_local_type_variable_names(&argument.type_);\n        }\n        self.register_local_type_variable_names(return_type);\n\n        let arguments = if arguments.is_empty() {\n            \"()\".to_doc()\n        } else {\n            Self::wrap_arguments(arguments.iter().map(|argument| {\n                let name = self.variable(self.argument_name(argument));\n                docvec![name, \": \", self.type_(&argument.type_, PrintMode::Normal)].group()\n            }))\n        };\n\n        docvec![\n            self.keyword(\"pub fn \"),\n            self.title(name),\n            arguments,\n            \" -> \",\n            self.type_(return_type, PrintMode::Normal)\n        ]\n        .group()\n    }\n\n    fn argument_name<'a>(&self, arg: &'a TypedArg) -> Document<'a> {\n        match &arg.names {\n            ArgNames::Named { name, .. } => name.to_doc(),\n            ArgNames::NamedLabelled { label, name, .. } => docvec![label, \" \", name],\n            // We remove the underscore from discarded function arguments since we don't want to\n            // expose this kind of detail: https://github.com/gleam-lang/gleam/issues/2561\n            ArgNames::Discard { name, .. } => match name.strip_prefix('_').unwrap_or(name) {\n                \"\" => \"arg\".to_doc(),\n                name => name.to_doc(),\n            },\n            ArgNames::LabelledDiscard { label, name, .. } => {\n                docvec![label, \" \", name.strip_prefix('_').unwrap_or(name).to_doc()]\n            }\n        }\n    }\n\n    fn wrap_arguments<'a>(arguments: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {\n        break_(\"(\", \"(\")\n            .append(join(arguments, break_(\",\", \", \")))\n            .nest_if_broken(INDENT)\n            .append(break_(\",\", \"\"))\n            .append(\")\")\n    }\n\n    fn type_arguments<'a>(arguments: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {\n        break_(\"\", \"\")\n            .append(join(arguments, break_(\",\", \", \")))\n            .nest_if_broken(INDENT)\n            .append(break_(\",\", \"\"))\n            .group()\n            .surround(\"(\", \")\")\n    }\n\n    fn type_(&mut self, type_: &Type, print_mode: PrintMode) -> Document<'static> {\n        match type_ {\n            Type::Named {\n                package,\n                module,\n                name,\n                arguments,\n                publicity,\n                ..\n            } => {\n                let name = match print_mode {\n                    // If we are printing a type for a type alias, and the alias\n                    // is reexporting an internal type, we want to show that it\n                    // is aliasing that internal type, rather than showing it as\n                    // aliasing itself.\n                    PrintMode::ExpandAliases if *package == self.package => {\n                        self.named_type_name(publicity, package, module, name)\n                    }\n                    // If we are printing a type alias which aliases an internal\n                    // type from a different package, we still want to print the\n                    // public name for that type. If we are not printing a type\n                    // alias at all, we also want to use the public name.\n                    PrintMode::ExpandAliases | PrintMode::Normal => {\n                        // If we are using a reexported internal type, we want to\n                        // print it public name, whether it is from this package\n                        // or otherwise.\n                        if let Some((module, alias)) =\n                            self.names.reexport_alias(module.clone(), name.clone())\n                        {\n                            self.named_type_name(&Publicity::Public, package, module, alias)\n                        } else {\n                            self.named_type_name(publicity, package, module, name)\n                        }\n                    }\n                };\n\n                if arguments.is_empty() {\n                    name\n                } else {\n                    name.append(Self::type_arguments(\n                        arguments\n                            .iter()\n                            .map(|argument| self.type_(argument, PrintMode::Normal)),\n                    ))\n                }\n            }\n            Type::Fn { arguments, return_ } => docvec![\n                self.keyword(\"fn\"),\n                Self::type_arguments(\n                    arguments\n                        .iter()\n                        .map(|argument| self.type_(argument, PrintMode::Normal))\n                ),\n                \" -> \",\n                self.type_(return_, PrintMode::Normal)\n            ],\n            Type::Tuple { elements } => docvec![\n                \"#\",\n                Self::type_arguments(\n                    elements\n                        .iter()\n                        .map(|element| self.type_(element, PrintMode::Normal))\n                ),\n            ],\n            Type::Var { type_ } => match type_.as_ref().borrow().deref() {\n                TypeVar::Link { type_ } => self.type_(type_, PrintMode::Normal),\n\n                TypeVar::Unbound { id } | TypeVar::Generic { id } => {\n                    let name = self.type_variable(*id);\n                    self.variable(name)\n                }\n            },\n        }\n    }\n\n    fn type_variable(&mut self, id: u64) -> EcoString {\n        if let Some(name) = self.names.get_type_variable(id) {\n            return name.clone();\n        }\n\n        if let Some(name) = self.printed_type_variables.get(&id) {\n            return name.clone();\n        }\n\n        loop {\n            let name = self.next_letter();\n            if !self.printed_type_variable_names.contains(&name) {\n                _ = self.printed_type_variable_names.insert(name.clone());\n                _ = self.printed_type_variables.insert(id, name.clone());\n                return name;\n            }\n        }\n    }\n\n    // Copied from the `next_letter` method of the `type_::printer`.\n    fn next_letter(&mut self) -> EcoString {\n        let alphabet_length = 26;\n        let char_offset = b'a';\n        let mut chars = vec![];\n        let mut n;\n        let mut rest = self.next_type_variable_id;\n\n        loop {\n            n = rest % alphabet_length;\n            rest = rest / alphabet_length;\n            chars.push((n as u8 + char_offset) as char);\n\n            if rest == 0 {\n                break;\n            }\n            rest -= 1\n        }\n\n        self.next_type_variable_id += 1;\n        chars.into_iter().rev().collect()\n    }\n\n    fn named_type_name(\n        &self,\n        publicity: &Publicity,\n        package: &str,\n        module: &str,\n        name: &EcoString,\n    ) -> Document<'static> {\n        // There's no documentation page for the prelude\n        if package == PRELUDE_PACKAGE_NAME && module == PRELUDE_MODULE_NAME {\n            return self.title(name);\n        }\n\n        // Internal types don't get linked\n        if !publicity.is_public() {\n            return docvec![self.comment(\"@internal \".to_doc()), self.title(name)];\n        }\n\n        // Linking to a type within the same page\n        if package == self.package && module == self.module {\n            return self.link(eco_format!(\"#{name}\"), self.title(name), None);\n        }\n\n        // Linking to a module within the package\n        if package == self.package {\n            // If we are linking to the current package, we might be viewing the\n            // documentation locally and so we need to generate a relative link.\n\n            let mut module_path = module.split('/').peekable();\n            let mut current_module = self.module.split('/');\n\n            // The documentation page for the final segment of the module is just\n            // an html file by itself, so it doesn't form part of the path and doesn't\n            // need to be backtracked using `..`.\n            let module_name = module_path.next_back().unwrap_or(module);\n            _ = current_module.next_back();\n\n            // The two modules might have some sharer part of the path, which we\n            // don't need to traverse back through. However, if the two modules are\n            // something like `gleam/a/wibble/wobble` and `gleam/b/wibble/wobble`,\n            // the `wibble` folders are two different folders despite being at the\n            // same position with the same name.\n            let mut encountered_different_path = false;\n            let mut path = Vec::new();\n\n            // Calculate how far backwards in the directory tree we need to walk\n            for segment in current_module {\n                // If this is still part of the shared path, we can just skip it:\n                // no need to go back and forth through the same directory in the\n                // path!\n                if !encountered_different_path && module_path.peek() == Some(&segment) {\n                    _ = module_path.next();\n                } else {\n                    encountered_different_path = true;\n                    path.push(\"..\");\n                }\n            }\n\n            // Once we have walked backwards, we walk forwards again to the correct\n            // page.\n            path.extend(module_path);\n            path.push(module_name);\n\n            let qualified_name = docvec![\n                self.variable(EcoString::from(module_name)),\n                \".\",\n                self.title(name)\n            ];\n\n            let title = eco_format!(\"{module}.{{type {name}}}\");\n\n            return self.link(\n                eco_format!(\"{path}.html#{name}\", path = path.join(\"/\")),\n                qualified_name,\n                Some(title),\n            );\n        }\n\n        let module_name = module.split('/').next_back().unwrap_or(module);\n        let qualified_name = docvec![\n            self.variable(EcoString::from(module_name)),\n            \".\",\n            self.title(name)\n        ];\n        let title = eco_format!(\"{module}.{{type {name}}}\");\n\n        // We can't reliably link to documentation if the type is from a path\n        // or git dependency\n        match self.dependencies.get(package) {\n            Some(Dependency {\n                kind: DependencyKind::Hex,\n                version,\n            }) => self.link(\n                eco_format!(\"https://hexdocs.pm/{package}/{version}/{module}.html#{name}\"),\n                qualified_name,\n                Some(title),\n            ),\n            Some(_) | None => self.span_with_title(qualified_name, title),\n        }\n    }\n\n    /// Walk a type and register all the type variable names which occur within\n    /// it. This is to ensure that when generating type variable names for\n    /// unannotated arguments, we don't print any that clash with existing names.\n    ///\n    /// We preregister all names before actually printing anything, because we\n    /// could run into code like this:\n    ///\n    /// ```gleam\n    /// pub fn wibble(_, _: a) -> b {}\n    /// ```\n    ///\n    /// If we did not preregister the type variables in this case, we would end\n    /// up printing `fn wibble(_: a, _: a) -> b` which is not correct.\n    ///\n    fn register_local_type_variable_names(&mut self, type_: &Type) {\n        match type_ {\n            Type::Named { arguments, .. } => {\n                for argument in arguments {\n                    self.register_local_type_variable_names(argument);\n                }\n            }\n            Type::Fn { arguments, return_ } => {\n                for argument in arguments {\n                    self.register_local_type_variable_names(argument);\n                }\n                self.register_local_type_variable_names(return_);\n            }\n            Type::Var { type_ } => match type_.borrow().deref() {\n                TypeVar::Link { type_ } => self.register_local_type_variable_names(type_),\n                TypeVar::Unbound { id } | TypeVar::Generic { id } => {\n                    if let Some(name) = self.names.get_type_variable(*id) {\n                        _ = self.printed_type_variable_names.insert(name.clone());\n                    }\n                }\n            },\n            Type::Tuple { elements } => {\n                for element in elements {\n                    self.register_local_type_variable_names(element);\n                }\n            }\n        }\n    }\n\n    fn keyword<'a>(&self, keyword: impl Documentable<'a>) -> Document<'a> {\n        self.colour_span(keyword, \"keyword\")\n    }\n\n    fn comment<'a>(&self, name: impl Documentable<'a>) -> Document<'a> {\n        self.colour_span(name, \"comment\")\n    }\n\n    fn title<'a>(&self, name: impl Documentable<'a>) -> Document<'a> {\n        self.colour_span(name, \"title\")\n    }\n\n    fn variable<'a>(&self, name: impl Documentable<'a>) -> Document<'a> {\n        self.colour_span(name, \"variable\")\n    }\n\n    fn colour_span<'a>(\n        &self,\n        name: impl Documentable<'a>,\n        colour_class: &'static str,\n    ) -> Document<'a> {\n        if !self.options.print_highlighting {\n            return name.to_doc();\n        }\n\n        name.to_doc().surround(\n            zero_width_string(eco_format!(r#\"<span class=\"hljs-{colour_class}\">\"#)),\n            zero_width_string(\"</span>\".into()),\n        )\n    }\n\n    fn link<'a>(\n        &self,\n        href: EcoString,\n        name: impl Documentable<'a>,\n        title: Option<EcoString>,\n    ) -> Document<'a> {\n        if !self.options.print_html {\n            return name.to_doc();\n        }\n\n        let opening_tag = if let Some(title) = title {\n            eco_format!(r#\"<a href=\"{href}\" title=\"{title}\">\"#)\n        } else {\n            eco_format!(r#\"<a href=\"{href}\">\"#)\n        };\n\n        name.to_doc().surround(\n            zero_width_string(opening_tag),\n            zero_width_string(\"</a>\".into()),\n        )\n    }\n\n    fn span_with_title<'a>(&self, name: impl Documentable<'a>, title: EcoString) -> Document<'a> {\n        if !self.options.print_html {\n            return name.to_doc();\n        }\n\n        name.to_doc().surround(\n            zero_width_string(eco_format!(r#\"<span title=\"{title}\">\"#)),\n            zero_width_string(\"</span>\".into()),\n        )\n    }\n}\n\nconst MAX_COLUMNS: isize = 65;\nconst INDENT: isize = 2;\n\nfn print(doc: Document<'_>) -> String {\n    doc.to_pretty_string(MAX_COLUMNS)\n}\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__canonical_link.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile_with_markdown_pages(config, modules, pages,\\nCompileWithMarkdownPagesOpts::default())\"\n---\n//// LICENSE.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>LICENSE · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/LICENSE.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"./LICENSE.html\">LICENSE</a></li>\n        \n        </ul>\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n          <li><a href=\"./gleam/otp/actor.html\" class=\"module-link\">gleam<wbr />/otp<wbr />/actor</a></li>\n        \n        </ul>\n\n        \n      </nav>\n\n      <main class=\"content\">\n        \n<h1>LICENSE</h1>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"./LICENSE.html\">LICENSE</a></li>\n        \n        </ul>\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n          <li><a href=\"./gleam/otp/actor.html\" class=\"module-link\">gleam<wbr />/otp<wbr />/actor</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>() -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Here is some documentation</p>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n\n//// gleam/otp/actor.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>gleam/otp/actor · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"../../css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"../../docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"../../css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/gleam/otp/actor.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '../..';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"../../\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"../../LICENSE.html\">LICENSE</a></li>\n        \n        </ul>\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"../../app.html\" class=\"module-link\">app</a></li>\n        \n          <li><a href=\"../../gleam/otp/actor.html\" class=\"module-link\">gleam<wbr />/otp<wbr />/actor</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">gleam/otp/actor</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>() -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Here is some documentation</p>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"../../js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"../../js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/index.js?v=0\"></script>\n    <script>\n      fetch(\"../../search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__constructor_with_long_types_and_many_fields.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- option.gleam\npub type Option(a)\n\n-- main.gleam\n\nimport option\n\npub type Uri {\n    Uri(\n        scheme: option.Option(String),\n        userinfo: option.Option(String),\n        host: option.Option(String),\n        port: option.Option(Int),\n        path: String,\n        query: option.Option(String),\n        fragment: option.Option(String)\n    )\n}\n\n\n---- TYPES\n\n--- Uri\n<pre><code>pub type Uri {\n  Uri(\n    scheme: option.Option(String),\n    userinfo: option.Option(String),\n    host: option.Option(String),\n    port: option.Option(Int),\n    path: String,\n    query: option.Option(String),\n    fragment: option.Option(String),\n  )\n}</code></pre>\n\n-- CONSTRUCTORS\n\n<pre><code>Uri(\n  scheme: option.Option(String),\n  userinfo: option.Option(String),\n  host: option.Option(String),\n  port: option.Option(Int),\n  path: String,\n  query: option.Option(String),\n  fragment: option.Option(String),\n)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__constructor_with_long_types_and_many_fields_that_need_splitting.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- option.gleam\npub type Option(a)\n\n-- main.gleam\n\nimport option\n\npub type TypeWithAVeryLoooooooooooooooooooongName\n\npub type Wibble {\n    Wibble(\n        wibble: #(TypeWithAVeryLoooooooooooooooooooongName, TypeWithAVeryLoooooooooooooooooooongName),\n        wobble: option.Option(String),\n    )\n}\n\n\n---- TYPES\n\n--- TypeWithAVeryLoooooooooooooooooooongName\n<pre><code>pub type TypeWithAVeryLoooooooooooooooooooongName</code></pre>\n\n--- Wibble\n<pre><code>pub type Wibble {\n  Wibble(\n    wibble: #(\n      TypeWithAVeryLoooooooooooooooooooongName,\n      TypeWithAVeryLoooooooooooooooooooongName,\n    ),\n    wobble: option.Option(String),\n  )\n}</code></pre>\n\n-- CONSTRUCTORS\n\n<pre><code>Wibble(\n  wibble: #(\n    TypeWithAVeryLoooooooooooooooooooongName,\n    TypeWithAVeryLoooooooooooooooooooongName,\n  ),\n  wobble: option.Option(String),\n)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__discarded_arguments_are_not_shown.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#discard\">discard</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"discard\">\n        <a href=\"#discard\">\n          discard\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">discard</span>(<span class=\"hljs-variable\">discarded</span>: <span class=\"hljs-variable\">a</span>) -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"></div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__docs_of_a_type_constructor_are_not_used_by_the_following_function.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n<h2>Types</h2>\n<ul>\n  \n  <li><a href=\"#Wibble\">Wibble</a></li>\n  \n</ul>\n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#main\">main</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-types\" class=\"module-member-kind\">\n    <a href=\"#module-types\">Types</a>\n    <svg class=\"icon icon-gleam-chasse-2\"><use xlink:href=\"#icon-gleam-chasse-2\"></use></svg>\n  </h1>\n\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"Wibble\">\n        <a href=\"#Wibble\">\n          Wibble\n        </a>\n      </h2>\n      \n    </div>\n    \n    <div class=\"custom-type-constructors\">\n      <div class=\"rendered-markdown\"></div>\n      <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub type </span><span class=\"hljs-title\">Wibble</span> {\n  <span class=\"hljs-title\">Wobble</span>(<span class=\"hljs-variable\">wabble</span>: <span class=\"hljs-title\">Int</span>)\n}</code></pre>\n      \n      <h3>\n        Constructors\n      </h3>\n      <ul class=\"constructor-list\">\n        \n        <li class=\"constructor-item\">\n          <div class=\"constructor-row\">\n            <svg class=\"icon icon-star\"><use xlink:href=\"#icon-star\"></use></svg>\n            <pre class=\"constructor-name\"><code class=\"hljs hljs-ignore\"><span class=\"hljs-title\">Wobble</span>(<span class=\"hljs-variable\">wabble</span>: <span class=\"hljs-title\">Int</span>)</code></pre>\n          </div>\n\n          <div class=\"constructor-item-docs\">\n            \n\n            \n            <h4>\n              Arguments\n            </h4>\n\n            <dl class=\"constructor-argument-list\">\n            \n              <dt class=\"constructor-argument-label\">\n                wabble\n              </dt>\n              <dd class=\"constructor-argument-doc\">\n                <p>Documentation!!</p>\n\n              </dd>\n            \n            </dl>\n            \n          </div>\n        </li>\n        \n      </ul>\n      \n    </div>\n  </div>\n  \n</section>\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"main\">\n        <a href=\"#main\">\n          main\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">main</span>() -> <span class=\"hljs-variable\">a</span></code></pre>\n    \n    <div class=\"rendered-markdown\"></div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__function_uses_reexport_of_internal_type.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- thepackage/internal.gleam\npub type Internal\n\n-- main.gleam\n\nimport thepackage/internal\n\npub type External = internal.Internal\n\npub fn do_thing(value: internal.Internal) -> External {\n  value\n}\n\n\n---- TYPES\n\n--- External\n<pre><code>pub type External =\n  @internal Internal</code></pre>\n\n---- VALUES\n\n--- do_thing\n<pre><code>pub fn do_thing(value: <a href=\"#External\">External</a>) -> <a href=\"#External\">External</a></code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__function_uses_reexport_of_internal_type_in_other_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- thepackage/internal.gleam\npub type Internal\n\n-- thepackage/something.gleam\n\nimport thepackage/internal\n\npub type External = internal.Internal\n\n\n-- main.gleam\n\nimport thepackage/something\n\npub fn do_thing(value: something.External) {\n  value\n}\n\n\n---- VALUES\n\n--- do_thing\n<pre><code>pub fn do_thing(value: <a href=\"thepackage/something.html#External\" title=\"thepackage/something.{type External}\">something.External</a>) -> <a href=\"thepackage/something.html#External\" title=\"thepackage/something.{type External}\">something.External</a></code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__generated_type_variables.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn wibble(_a, _b, _c, _d) {\n  todo\n}\n\n\n---- VALUES\n\n--- wibble\n<pre><code>pub fn wibble(a: a, b: b, c: c, d: d) -> e</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__generated_type_variables_do_not_take_into_account_other_definitions.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn wibble(_a: a, _b: b, _c: c) -> d {\n  todo\n}\n\npub fn identity(x) { x }\n\n\n---- VALUES\n\n--- identity\n<pre><code>pub fn identity(x: a) -> a</code></pre>\n\n--- wibble\n<pre><code>pub fn wibble(a: a, b: b, c: c) -> d</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__generated_type_variables_mixed_with_existing_variables.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn wibble(_a: b, _b: a, _c, _d) {\n  todo\n}\n\n\n---- VALUES\n\n--- wibble\n<pre><code>pub fn wibble(a: b, b: a, c: c, d: d) -> e</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__generated_type_variables_with_existing_variables_coming_afterwards.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn wibble(_a, _b, _c: b, _d: a) {\n  todo\n}\n\n\n---- VALUES\n\n--- wibble\n<pre><code>pub fn wibble(a: c, b: d, c: b, d: a) -> e</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__hello_docs.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>() -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Here is some documentation</p>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__highlight_constant_definition.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub const x = 22\n\n\n---- VALUES\n\n--- x\n<pre><code><span class=\"hljs-keyword\">pub const </span><span class=\"hljs-title\">x</span>: <span class=\"hljs-title\">Int</span></code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__highlight_custom_type.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub type Wibble(a, b) {\n  Wibble(a, i: Int)\n  Wobble(b: b, c: String)\n}\n\n\n---- TYPES\n\n--- Wibble\n<pre><code><span class=\"hljs-keyword\">pub type </span><span class=\"hljs-title\">Wibble</span>(<span class=\"hljs-variable\">a</span>, <span class=\"hljs-variable\">b</span>) {\n  <span class=\"hljs-title\">Wibble</span>(<span class=\"hljs-variable\">a</span>, <span class=\"hljs-variable\">i</span>: <span class=\"hljs-title\">Int</span>)\n  <span class=\"hljs-title\">Wobble</span>(<span class=\"hljs-variable\">b</span>: <span class=\"hljs-variable\">b</span>, <span class=\"hljs-variable\">c</span>: <span class=\"hljs-title\">String</span>)\n}</code></pre>\n\n-- CONSTRUCTORS\n\n<pre><code><span class=\"hljs-title\">Wibble</span>(<span class=\"hljs-variable\">a</span>, <span class=\"hljs-variable\">i</span>: <span class=\"hljs-title\">Int</span>)</code></pre>\n\n<pre><code><span class=\"hljs-title\">Wobble</span>(<span class=\"hljs-variable\">b</span>: <span class=\"hljs-variable\">b</span>, <span class=\"hljs-variable\">c</span>: <span class=\"hljs-title\">String</span>)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__highlight_function_definition.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn wibble(list: List(Int), generic: a, function: fn(a) -> b) -> #(a, b) { todo }\n\n\n---- VALUES\n\n--- wibble\n<pre><code><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">wibble</span>(\n  <span class=\"hljs-variable\">list</span>: <span class=\"hljs-title\">List</span>(<span class=\"hljs-title\">Int</span>),\n  <span class=\"hljs-variable\">generic</span>: <span class=\"hljs-variable\">a</span>,\n  <span class=\"hljs-variable\">function</span>: <span class=\"hljs-keyword\">fn</span>(<span class=\"hljs-variable\">a</span>) -> <span class=\"hljs-variable\">b</span>,\n) -> #(<span class=\"hljs-variable\">a</span>, <span class=\"hljs-variable\">b</span>)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__highlight_opaque_custom_type.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub opaque type Wibble(a, b) {\n  Wibble(a, i: Int)\n  Wobble(b: b, c: String)\n}\n\n\n---- TYPES\n\n--- Wibble\n<pre><code><span class=\"hljs-keyword\">pub opaque type </span><span class=\"hljs-title\">Wibble</span>(<span class=\"hljs-variable\">a</span>, <span class=\"hljs-variable\">b</span>)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__highlight_type_alias.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub type Option(a) = Result(a, Nil)\n\n\n---- TYPES\n\n--- Option\n<pre><code><span class=\"hljs-keyword\">pub type </span><span class=\"hljs-title\">Option</span>(<span class=\"hljs-variable\">a</span>) =\n  <span class=\"hljs-title\">Result</span>(<span class=\"hljs-variable\">a</span>, <span class=\"hljs-title\">Nil</span>)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__ignored_argument_is_called_arg.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>(<span class=\"hljs-variable\">arg</span>: <span class=\"hljs-variable\">a</span>) -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"></div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__internal_definitions_are_not_included.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__internal_type_reexport_in_different_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nassertion_line: 1097\nexpression: output\nsnapshot_kind: text\n---\n---- SOURCE CODE\n-- other.gleam\n@internal pub type Internal\n\n-- main.gleam\n\nimport other\n\npub type External =\n  other.Internal\n\n\n---- TYPES\n\n--- External\n<pre><code>pub type External =\n  @internal Internal</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__internal_type_reexport_in_same_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nassertion_line: 1083\nexpression: output\nsnapshot_kind: text\n---\n---- SOURCE CODE\n-- main.gleam\n\n@internal\npub type Internal\n\npub type External =\n  Internal\n\n\n---- TYPES\n\n--- External\n<pre><code>pub type External =\n  @internal Internal</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__internal_type_reexport_in_same_module_as_parameter.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nassertion_line: 1056\nexpression: output\nsnapshot_kind: text\n---\n---- SOURCE CODE\n-- main.gleam\n\n@internal\npub type Internal\n\npub type External =\n  List(Internal)\n\n\n---- TYPES\n\n--- External\n<pre><code>pub type External =\n  List(@internal Internal)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__internal_type_reexport_in_same_module_as_parameter_colours.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nassertion_line: 1070\nexpression: output\nsnapshot_kind: text\n---\n---- SOURCE CODE\n-- main.gleam\n\n@internal\npub type Internal\n\npub type External =\n  List(Internal)\n\n\n---- TYPES\n\n--- External\n<pre><code><span class=\"hljs-keyword\">pub type </span><span class=\"hljs-title\">External</span> =\n  <span class=\"hljs-title\">List</span>(<span class=\"hljs-comment\">@internal </span><span class=\"hljs-title\">Internal</span>)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__link_to_type_in_different_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/dict.gleam\npub type Dict(a, b)\n\n-- main.gleam\n\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\n\n---- VALUES\n\n--- make_dict\n<pre><code>pub fn make_dict() -> <a href=\"gleam/dict.html#Dict\" title=\"gleam/dict.{type Dict}\">dict.Dict</a>(a, b)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__link_to_type_in_different_module_from_nested_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/dict.gleam\npub type Dict(a, b)\n\n-- gleam/dynamic/decode.gleam\n\nimport gleam/dict\n\npub fn decode_dict() -> dict.Dict(a, b) { todo }\n\n\n---- VALUES\n\n--- decode_dict\n<pre><code>pub fn decode_dict() -> <a href=\"../dict.html#Dict\" title=\"gleam/dict.{type Dict}\">dict.Dict</a>(a, b)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__link_to_type_in_different_module_from_nested_module_with_shared_path.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/dynamic.gleam\npub type Dynamic\n\n-- gleam/dynamic/decode.gleam\n\nimport gleam/dynamic\n\npub type Dynamic = dynamic.Dynamic\n\n\n---- TYPES\n\n--- Dynamic\n<pre><code>pub type Dynamic =\n  <a href=\"../dynamic.html#Dynamic\" title=\"gleam/dynamic.{type Dynamic}\">dynamic.Dynamic</a></code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__link_to_type_in_different_package.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/dict.gleam\npub type Dict(a, b)\n\n-- main.gleam\n\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\n\n---- VALUES\n\n--- make_dict\n<pre><code>pub fn make_dict() -> <a href=\"https://hexdocs.pm/gleam_stdlib/1.0.0/gleam/dict.html#Dict\" title=\"gleam/dict.{type Dict}\">dict.Dict</a>(a, b)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__link_to_type_in_same_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub type Dict(a, b)\n\npub fn new() -> Dict(a, b) { todo }\n\n\n---- TYPES\n\n--- Dict\n<pre><code>pub type Dict(a, b)</code></pre>\n\n---- VALUES\n\n--- new\n<pre><code>pub fn new() -> <a href=\"#Dict\">Dict</a>(a, b)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__long_function_with_no_arguments_parentheses_are_not_split.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn aaaaaaaaaaaaaaaaaaaaaaaaaaaa() -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {\n  todo\n}\n\n\n---- VALUES\n\n--- aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n<pre><code>pub fn aaaaaaaaaaaaaaaaaaaaaaaaaaaa() -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__long_function_wrapping.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n<h2>Types</h2>\n<ul>\n  \n  <li><a href=\"#Option\">Option</a></li>\n  \n</ul>\n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#lazy_or\">lazy_or</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-types\" class=\"module-member-kind\">\n    <a href=\"#module-types\">Types</a>\n    <svg class=\"icon icon-gleam-chasse-2\"><use xlink:href=\"#icon-gleam-chasse-2\"></use></svg>\n  </h1>\n\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"Option\">\n        <a href=\"#Option\">\n          Option\n        </a>\n      </h2>\n      \n    </div>\n    \n    <div class=\"custom-type-constructors\">\n      <div class=\"rendered-markdown\"></div>\n      <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub type </span><span class=\"hljs-title\">Option</span>(<span class=\"hljs-variable\">t</span>) {\n  <span class=\"hljs-title\">Some</span>(<span class=\"hljs-variable\">t</span>)\n  <span class=\"hljs-title\">None</span>\n}</code></pre>\n      \n      <h3>\n        Constructors\n      </h3>\n      <ul class=\"constructor-list\">\n        \n        <li class=\"constructor-item\">\n          <div class=\"constructor-row\">\n            <svg class=\"icon icon-star\"><use xlink:href=\"#icon-star\"></use></svg>\n            <pre class=\"constructor-name\"><code class=\"hljs hljs-ignore\"><span class=\"hljs-title\">Some</span>(<span class=\"hljs-variable\">t</span>)</code></pre>\n          </div>\n\n          <div class=\"constructor-item-docs\">\n            \n\n            \n          </div>\n        </li>\n        \n        <li class=\"constructor-item\">\n          <div class=\"constructor-row\">\n            <svg class=\"icon icon-star\"><use xlink:href=\"#icon-star\"></use></svg>\n            <pre class=\"constructor-name\"><code class=\"hljs hljs-ignore\"><span class=\"hljs-title\">None</span></code></pre>\n          </div>\n\n          <div class=\"constructor-item-docs\">\n            \n\n            \n          </div>\n        </li>\n        \n      </ul>\n      \n    </div>\n  </div>\n  \n</section>\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"lazy_or\">\n        <a href=\"#lazy_or\">\n          lazy_or\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">lazy_or</span>(\n  <span class=\"hljs-variable\">first</span>: <a href=\"#Option\"><span class=\"hljs-title\">Option</span></a>(<span class=\"hljs-variable\">a</span>),\n  <span class=\"hljs-variable\">second</span>: <span class=\"hljs-keyword\">fn</span>() -> <a href=\"#Option\"><span class=\"hljs-title\">Option</span></a>(<span class=\"hljs-variable\">a</span>),\n) -> <a href=\"#Option\"><span class=\"hljs-title\">Option</span></a>(<span class=\"hljs-variable\">a</span>)</code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Returns the first value if it is <code>Some</code>, otherwise evaluates the given\nfunction for a fallback value.</p>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__markdown_code_from_function_comment_is_trimmed.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#indentation_test\">indentation_test</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"indentation_test\">\n        <a href=\"#indentation_test\">\n          indentation_test\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">indentation_test</span>() -> <span class=\"hljs-variable\">a</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Here’s an example code snippet:</p>\n<pre><code>wibble\n  |&gt; wobble\n</code></pre>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__markdown_code_from_module_comment_is_trimmed.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n<p>Here’s an example code snippet:</p>\n<pre><code>wibble\n  |&gt; wobble\n</code></pre>\n\n\n\n\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__markdown_code_from_standalone_pages_is_not_trimmed.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile_with_markdown_pages(config, vec![], pages,\\nCompileWithMarkdownPagesOpts::default())\"\n---\n//// one.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>one · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/one.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"./one.html\">one</a></li>\n        \n        </ul>\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n        </ul>\n\n        \n      </nav>\n\n      <main class=\"content\">\n        \n<p>This is an example code snippet that should be indented</p>\n<pre><code class=\"language-gleam\">pub fn indentation_test() {\n  todo as \"This line should be indented by two spaces\"\n}\n</code></pre>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__no_hex_publish.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile_with_markdown_pages(config, modules, pages,\\nCompileWithMarkdownPagesOpts { hex_publish: Some(DocContext::Build) })\"\n---\n//// LICENSE.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>LICENSE · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    \n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"./LICENSE.html\">LICENSE</a></li>\n        \n        </ul>\n        \n\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n          <li><a href=\"./gleam/otp/actor.html\" class=\"module-link\">gleam<wbr />/otp<wbr />/actor</a></li>\n        \n        </ul>\n\n        \n      </nav>\n\n      <main class=\"content\">\n        \n<h1>LICENSE</h1>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    \n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"./LICENSE.html\">LICENSE</a></li>\n        \n        </ul>\n        \n\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n          <li><a href=\"./gleam/otp/actor.html\" class=\"module-link\">gleam<wbr />/otp<wbr />/actor</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>() -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Here is some documentation</p>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n\n//// gleam/otp/actor.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>gleam/otp/actor · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"../../css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"../../docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"../../css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    \n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '../..';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"../../\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n        <h2>Pages</h2>\n        <ul>\n        \n          <li><a href=\"../../LICENSE.html\">LICENSE</a></li>\n        \n        </ul>\n        \n\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"../../app.html\" class=\"module-link\">app</a></li>\n        \n          <li><a href=\"../../gleam/otp/actor.html\" class=\"module-link\">gleam<wbr />/otp<wbr />/actor</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">gleam/otp/actor</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>() -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><p>Here is some documentation</p>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"../../js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"../../js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"../../js/index.js?v=0\"></script>\n    <script>\n      fetch(\"../../search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__no_link_to_type_in_git_dependency.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/dict.gleam\npub type Dict(a, b)\n\n-- main.gleam\n\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\n\n---- VALUES\n\n--- make_dict\n<pre><code>pub fn make_dict() -> <span title=\"gleam/dict.{type Dict}\">dict.Dict</span>(a, b)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__no_link_to_type_in_path_dependency.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/dict.gleam\npub type Dict(a, b)\n\n-- main.gleam\n\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\n\n---- VALUES\n\n--- make_dict\n<pre><code>pub fn make_dict() -> <span title=\"gleam/dict.{type Dict}\">dict.Dict</span>(a, b)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__no_links_to_prelude_types.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub fn int_to_string(i: Int) -> String { todo }\n\n\n---- VALUES\n\n--- int_to_string\n<pre><code>pub fn int_to_string(i: Int) -> String</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__output_of_search_data_json.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: json\n---\n{\"items\":[{\"type\":\"module\",\"parentTitle\":\"gleam/option\",\"title\":\"gleam/option\",\"doc\":\"\",\"ref\":\"gleam/option.html\"},{\"type\":\"type\",\"parentTitle\":\"gleam/option\",\"title\":\"Option\",\"doc\":\"`Option` represents a value that may be present or not. `Some` means the value is present, `None` means the value is not.\",\"ref\":\"gleam/option.html#Option\"},{\"type\":\"value\",\"parentTitle\":\"gleam/option\",\"title\":\"unwrap\",\"doc\":\"Extracts the value from an `Option`, returning a default value if there is none.\",\"ref\":\"gleam/option.html#unwrap\"},{\"type\":\"value\",\"parentTitle\":\"gleam/dynamic/decode\",\"title\":\"bool\",\"doc\":\"A decoder that decodes `Bool` values.\\n\\n # Examples\\n\\n \\n let result = decode.run(dynamic.from(True), decode.bool)\\n assert result == Ok(True)\\n \\n\",\"ref\":\"gleam/dynamic/decode.html#bool\"}],\"proglang\":\"gleam\"}\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__print_qualified_names_from_other_modules.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- gleam/option.gleam\n\npub type Option(t) {\n  Some(t)\n  None\n}\n\n\n-- main.gleam\n\nimport gleam/option.{type Option, Some, None}\n\npub fn from_option(o: Option(t), e: e) -> Result(t, e) {\n  case o {\n    Some(t) -> Ok(t)\n    None -> Error(e)\n  }\n}\n\n\n---- VALUES\n\n--- from_option\n<pre><code>pub fn from_option(o: option.Option(t), e: e) -> Result(t, e)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__print_type_variables_in_function_signatures.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- main.gleam\n\npub type Dict(key, value)\n\npub fn insert(dict: Dict(key, value), key: key, value: value) -> Dict(key, value) {\n  dict\n}\n\n\n---- TYPES\n\n--- Dict\n<pre><code>pub type Dict(key, value)</code></pre>\n\n---- VALUES\n\n--- insert\n<pre><code>pub fn insert(\n  dict: Dict(key, value),\n  key: key,\n  value: value,\n) -> Dict(key, value)</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__public_type_reexport_in_different_internal_module.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nassertion_line: 1111\nexpression: output\nsnapshot_kind: text\n---\n---- SOURCE CODE\n-- thepackage/internal/other.gleam\npub type Internal\n\n-- main.gleam\n\nimport thepackage/internal/other\n\npub type External =\n  other.Internal\n\n\n---- TYPES\n\n--- External\n<pre><code>pub type External =\n  @internal Internal</code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__search_item_for_constant.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n------ SOURCE CODE\n\n/// Reverses a `List`, and returns the list in reverse.\n/// ```\n/// reverse([1, 2, 3])\n/// // [3, 2, 1]\n/// ```\npub fn reverse(list: List(a), out: List(a)) -> List(a) {\n  case list {\n    [] -> out\n    [first, ..rest] -> reverse(rest, [first, ..out])\n  }\n}\n\n------------------------------------\n\nTITLE:         main\nPARENT TITLE:  main\nTYPE:          Module\nREFERENCE:     main.html\nCONTENT:\n\n------------------------------------\nTITLE:         reverse\nPARENT TITLE:  module\nTYPE:          Value\nREFERENCE:     module.html#reverse\nCONTENT:\n```\npub fn reverse(list: List(a), out: List(a)) -> List(a)\n```\n Reverses a `List`, and returns the list in reverse.\n \n reverse([1, 2, 3])\n // [3, 2, 1]\n \n\nSynonyms:\nmodule.reverse\nmodule reverse\n------------------------------------\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__search_item_for_custom_type.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n------ SOURCE CODE\n\n/// # The `Option` type\n/// Represents an optional value, either `Some` or `None`.\n/// If it is None, the value is absent\n/// [Read more](https://example.com)\npub type Option(inner) {\n  /// Here is some\n  /// documentation for the `Some` constructor\n  Some(\n    /// And even documentation on a **field**!\n    value: inner\n  )\n  None\n}\n\n------------------------------------\n\nTITLE:         main\nPARENT TITLE:  main\nTYPE:          Module\nREFERENCE:     main.html\nCONTENT:\n\n------------------------------------\nTITLE:         Option\nPARENT TITLE:  module\nTYPE:          Type\nREFERENCE:     module.html#Option\nCONTENT:\n```\npub type Option(inner) {\n  Some(value: inner)\n  None\n}\n```\n # The `Option` type\n Represents an optional value, either `Some` or `None`.\n If it is None, the value is absent\n [Read more](https://example.com)\n\n```\nSome(value: inner)\n```\n Here is some\n documentation for the `Some` constructor\n\nvalue\n And even documentation on a **field**!\n\n```\nNone\n```\n\n\nSynonyms:\nmodule.Option\nmodule Option\n------------------------------------\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__search_item_for_function.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n------ SOURCE CODE\n\n/// Pi is the ration between a circle's **radius** and its\n/// *circumference*. Pretty cool!\npub const pi = 3.14\n\n------------------------------------\n\nTITLE:         main\nPARENT TITLE:  main\nTYPE:          Module\nREFERENCE:     main.html\nCONTENT:\n\n------------------------------------\nTITLE:         pi\nPARENT TITLE:  module\nTYPE:          Value\nREFERENCE:     module.html#pi\nCONTENT:\n```\npub const pi: Float\n```\n Pi is the ration between a circle's **radius** and its\n *circumference*. Pretty cool!\n\nSynonyms:\nmodule.pi\nmodule pi\n------------------------------------\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__search_item_for_type_alias.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n------ SOURCE CODE\n\n/// This is a type alias to a list\n/// of integer values.\n/// ## Examples\n/// ```\n/// // Examples\n/// ```\npub type IntList = List(Int)\n\n------------------------------------\n\nTITLE:         main\nPARENT TITLE:  main\nTYPE:          Module\nREFERENCE:     main.html\nCONTENT:\n\n------------------------------------\nTITLE:         IntList\nPARENT TITLE:  module\nTYPE:          Type\nREFERENCE:     module.html#IntList\nCONTENT:\n```\npub type IntList =\n  List(Int)\n```\n This is a type alias to a list\n of integer values.\n ## Examples\n \n // Examples\n \n\n\nSynonyms:\nmodule.IntList\nmodule IntList\n------------------------------------\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__tables.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: \"compile(config, modules)\"\n---\n//// app.html\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>app · test_project_name · v0.1.0</title>\n    <meta name=\"description\" content=\"\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"./css/index.css?v=GLEAM_VERSION_HERE\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"./docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"./css/atom-one-light.min.css?v=GLEAM_VERSION_HERE\"/>\n    <link rel=\"canonical\" href=\"https://hexdocs.pm/test_project_name/app.html\" />\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '.';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"./\">test_project_name</a>\n        <span id=\"project-version\">\n          <span> - v0.1.0 </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v0.1.0\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search test_project_name\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        \n\n        \n        <h2>Links</h2>\n        <ul>\n        \n          <li><a href=\"https://hex.pm/packages/test_project_name\">Hex</a></li>\n        \n        </ul>\n        \n\n        <h2>Modules</h2>\n        <ul>\n        \n          <li><a href=\"./app.html\" class=\"module-link\">app</a></li>\n        \n        </ul>\n\n        \n\n\n\n<h2>Values</h2>\n<ul>\n  \n  <li><a href=\"#one\">one</a></li>\n  \n</ul>\n\n\n      </nav>\n\n      <main class=\"content\">\n        \n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">app</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n\n\n\n\n\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  \n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"one\">\n        <a href=\"#one\">\n          one\n        </a>\n      </h2>\n      \n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\"><span class=\"hljs-keyword\">pub fn </span><span class=\"hljs-title\">one</span>() -> <span class=\"hljs-title\">Int</span></code></pre>\n    \n    <div class=\"rendered-markdown\"><table><thead><tr><th>heading 1</th><th>heading 2</th></tr></thead><tbody>\n<tr><td>row 1 cell 1</td><td>row 1 cell 2</td></tr>\n<tr><td>row 2 cell 1</td><td>row 2 cell 2</td></tr>\n</tbody></table>\n</div>\n  </div>\n  \n</section>\n\n\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"./js/highlight.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-gleam.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-erlang.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-elixir.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-javascript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/highlightjs-typescript.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"./js/lunr.min.js?v=GLEAM_VERSION_HERE\"></script>\n    <script src=\"./js/index.js?v=0\"></script>\n    <script>\n      fetch(\"./search-data.json?v=0\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/src/docs/snapshots/gleam_core__docs__tests__use_reexport_from_other_package.snap",
    "content": "---\nsource: compiler-core/src/docs/tests.rs\nexpression: output\n---\n---- SOURCE CODE\n-- some_package/internal.gleam\npub type Internal\n\n-- some_package/api.gleam\n\nimport some_package/internal\npub type External = internal.Internal\n\n\n-- main.gleam\n\nimport some_package/api\n\npub fn do_thing(value: api.External) {\n  value\n}\n\n\n---- VALUES\n\n--- do_thing\n<pre><code>pub fn do_thing(value: <a href=\"https://hexdocs.pm/some_package/1.0.0/some_package/api.html#External\" title=\"some_package/api.{type External}\">api.External</a>) -> <a href=\"https://hexdocs.pm/some_package/1.0.0/some_package/api.html#External\" title=\"some_package/api.{type External}\">api.External</a></code></pre>\n"
  },
  {
    "path": "compiler-core/src/docs/source_links.rs",
    "content": "use crate::{\n    ast::SrcSpan,\n    build,\n    config::{PackageConfig, Repository},\n    line_numbers::LineNumbers,\n    paths::ProjectPaths,\n};\n\nuse camino::{Utf8Component, Utf8Path, Utf8PathBuf};\n\npub struct SourceLinker {\n    line_numbers: LineNumbers,\n    url_pattern: Option<(String, String)>,\n}\n\nimpl SourceLinker {\n    pub fn new(\n        paths: &ProjectPaths,\n        project_config: &PackageConfig,\n        module: &build::Module,\n    ) -> Self {\n        let path = paths\n            .src_directory()\n            .join(module.name.as_str())\n            .strip_prefix(paths.root())\n            .expect(\"path is not in root\")\n            .with_extension(\"gleam\");\n\n        let path_in_repo = match project_config\n            .repository\n            .as_ref()\n            .map(|r| r.path())\n            .unwrap_or_default()\n        {\n            Some(repo_path) => to_url_path(&Utf8PathBuf::from(repo_path).join(path)),\n            _ => to_url_path(&path),\n        }\n        .unwrap_or_default();\n\n        let tag = project_config.tag_for_version(&project_config.version);\n\n        let url_pattern = project_config\n            .repository\n            .as_ref()\n            .map(|r| match r {\n                Repository::GitHub { user, repo, .. } => Some((\n                    format!(\"https://github.com/{user}/{repo}/blob/{tag}/{path_in_repo}#L\"),\n                    \"-L\".into(),\n                )),\n                Repository::GitLab { user, repo, .. } => Some((\n                    format!(\"https://gitlab.com/{user}/{repo}/-/blob/{tag}/{path_in_repo}#L\"),\n                    \"-\".into(),\n                )),\n                Repository::BitBucket { user, repo, .. } => Some((\n                    format!(\"https://bitbucket.com/{user}/{repo}/src/{tag}/{path_in_repo}#lines-\"),\n                    \":\".into(),\n                )),\n                Repository::Codeberg { user, repo, .. } => Some((\n                    format!(\"https://codeberg.org/{user}/{repo}/src/tag/{tag}/{path_in_repo}#L\"),\n                    \"-\".into(),\n                )),\n                Repository::SourceHut { user, repo, .. } => Some((\n                    format!(\"https://git.sr.ht/~{user}/{repo}/tree/{tag}/item/{path_in_repo}#L\"),\n                    \"-\".into(),\n                )),\n                Repository::Tangled { user, repo, .. } => Some((\n                    format!(\"https://tangled.sh/{user}/{repo}/tree/{tag}/{path_in_repo}#L\"),\n                    \"-\".into(),\n                )),\n                Repository::Gitea {\n                    user, repo, host, ..\n                }\n                | Repository::Forgejo {\n                    user, repo, host, ..\n                } => {\n                    let string_host = host.to_string();\n                    let cleaned_host = string_host.trim_end_matches('/');\n                    Some((\n                        format!(\"{cleaned_host}/{user}/{repo}/src/tag/{tag}/{path_in_repo}#L\",),\n                        \"-L\".into(),\n                    ))\n                }\n                Repository::Custom { .. } => None,\n            })\n            .unwrap_or_default();\n\n        SourceLinker {\n            line_numbers: LineNumbers::new(&module.code),\n            url_pattern,\n        }\n    }\n\n    pub fn url(&self, span: SrcSpan) -> String {\n        match &self.url_pattern {\n            Some((base, line_sep)) => {\n                let start_line = self.line_numbers.line_number(span.start);\n                let end_line = self.line_numbers.line_number(span.end);\n                if start_line == end_line {\n                    format!(\"{base}{start_line}\")\n                } else {\n                    format!(\"{base}{start_line}{line_sep}{end_line}\")\n                }\n            }\n\n            None => \"\".into(),\n        }\n    }\n}\n\nfn to_url_path(path: &Utf8Path) -> Option<String> {\n    let mut buf = String::new();\n    for c in path.components() {\n        if let Utf8Component::Normal(s) = c {\n            buf.push_str(s);\n        }\n        buf.push('/');\n    }\n\n    let _ = buf.pop();\n\n    Some(buf)\n}\n"
  },
  {
    "path": "compiler-core/src/docs/tests.rs",
    "content": "use std::{\n    collections::{HashMap, HashSet},\n    time::SystemTime,\n};\n\nuse super::{\n    Dependency, DependencyKind, DocumentationConfig, SearchData, SearchItem, SearchItemType,\n    SearchProgrammingLanguage,\n    printer::{PrintOptions, Printer},\n    source_links::SourceLinker,\n};\nuse crate::{\n    build::{\n        self, Mode, NullTelemetry, Origin, PackageCompiler, StaleTracker,\n        TargetCodegenConfiguration,\n    },\n    config::{DocsPage, PackageConfig, Repository},\n    docs::{DocContext, search_item_for_module, search_item_for_type, search_item_for_value},\n    io::{FileSystemWriter, memory::InMemoryFileSystem},\n    paths::ProjectPaths,\n    type_,\n    uid::UniqueIdGenerator,\n    version::COMPILER_VERSION,\n    warning::WarningEmitter,\n};\nuse camino::Utf8PathBuf;\nuse ecow::{EcoString, eco_format};\nuse hexpm::version::Version;\nuse http::Uri;\nuse itertools::Itertools;\nuse serde_json::to_string as serde_to_string;\n\n#[derive(Default)]\nstruct CompileWithMarkdownPagesOpts {\n    hex_publish: Option<DocContext>,\n}\n\nfn compile_with_markdown_pages(\n    config: PackageConfig,\n    modules: Vec<(&str, &str)>,\n    markdown_pages: Vec<(&str, &str)>,\n    opts: CompileWithMarkdownPagesOpts,\n) -> EcoString {\n    let fs = InMemoryFileSystem::new();\n    for (name, src) in modules {\n        fs.write(&Utf8PathBuf::from(format!(\"/src/{name}\")), src)\n            .unwrap();\n    }\n\n    // We're saving the pages under a different `InMemoryFileSystem` for these\n    // tests so we don't have to juggle with borrows and lifetimes.\n    // The package compiler is going to take ownership of `fs` but later\n    // `generate_html` also needs a `FileSystemReader` to go and read the\n    // markdown pages' content.\n    let pages_fs = InMemoryFileSystem::new();\n    for (title, src) in markdown_pages.iter() {\n        pages_fs\n            .write(&Utf8PathBuf::from(format!(\"{title}.md\")), src)\n            .unwrap();\n    }\n\n    let ids = UniqueIdGenerator::new();\n    let mut type_manifests = im::HashMap::new();\n    let mut defined_modules = im::HashMap::new();\n    let warnings = WarningEmitter::null();\n    let target = TargetCodegenConfiguration::Erlang { app_file: None };\n\n    let root = Utf8PathBuf::from(\"/\");\n    let build = root.join(\"build\");\n    let lib = root.join(\"lib\");\n    let paths = ProjectPaths::new(root.clone());\n    let mut compiler =\n        PackageCompiler::new(&config, Mode::Dev, &root, &build, &lib, &target, ids, fs);\n    compiler.write_entrypoint = false;\n    compiler.write_metadata = false;\n    compiler.compile_beam_bytecode = true;\n    let mut modules = compiler\n        .compile(\n            &warnings,\n            &mut type_manifests,\n            &mut defined_modules,\n            &mut StaleTracker::default(),\n            &mut HashSet::new(),\n            &NullTelemetry,\n        )\n        .unwrap()\n        .modules;\n\n    for module in &mut modules {\n        module.attach_doc_and_module_comments();\n    }\n\n    let docs_pages = markdown_pages\n        .into_iter()\n        .map(|(title, _)| DocsPage {\n            title: (*title).into(),\n            path: format!(\"{title}.html\"),\n            source: format!(\"{title}.md\").into(),\n        })\n        .collect_vec();\n\n    super::generate_html(\n        &paths,\n        DocumentationConfig {\n            package_config: &config,\n            dependencies: HashMap::new(),\n            analysed: &modules,\n            docs_pages: &docs_pages,\n            rendering_timestamp: SystemTime::UNIX_EPOCH,\n            context: if let Some(doc_context) = opts.hex_publish {\n                doc_context\n            } else {\n                DocContext::HexPublish\n            },\n        },\n        pages_fs,\n    )\n    .into_iter()\n    .filter(|file| file.path.extension() == Some(\"html\"))\n    .sorted_by(|a, b| a.path.cmp(&b.path))\n    .flat_map(|file| {\n        Some(format!(\n            \"//// {}\\n\\n{}\\n\\n\",\n            file.path.as_str(),\n            file.content\n                .text()?\n                .replace(COMPILER_VERSION, \"GLEAM_VERSION_HERE\")\n        ))\n    })\n    .collect::<String>()\n    .chars()\n    .collect()\n}\n\npub fn compile(config: PackageConfig, modules: Vec<(&str, &str)>) -> EcoString {\n    compile_with_markdown_pages(\n        config,\n        modules,\n        vec![],\n        CompileWithMarkdownPagesOpts::default(),\n    )\n}\n\nfn compile_documentation(\n    module_name: &str,\n    module_src: &str,\n    modules: Vec<(&str, &str, &str)>,\n    dependency_kind: DependencyKind,\n    options: PrintOptions,\n) -> EcoString {\n    let module = type_::tests::compile_module(module_name, module_src, None, modules.clone())\n        .expect(\"Module should compile successfully\");\n\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n    let paths = ProjectPaths::new(\"/\".into());\n    let build_module = build::Module {\n        name: \"main\".into(),\n        code: module_src.into(),\n        mtime: SystemTime::now(),\n        input_path: \"/\".into(),\n        origin: Origin::Src,\n        ast: module,\n        extra: Default::default(),\n        dependencies: Default::default(),\n    };\n\n    let source_links = SourceLinker::new(&paths, &config, &build_module);\n\n    let module = build_module.ast;\n    let dependencies = modules\n        .iter()\n        .map(|(package, _, _)| {\n            (\n                EcoString::from(*package),\n                Dependency {\n                    version: Version::new(1, 0, 0),\n                    kind: dependency_kind,\n                },\n            )\n        })\n        .collect();\n\n    let mut printer = Printer::new(\n        module.type_info.package.clone(),\n        module.name.clone(),\n        &module.names,\n        &dependencies,\n    );\n    printer.set_options(options);\n\n    let types = printer.type_definitions(&source_links, &module.definitions);\n    let values = printer.value_definitions(&source_links, &module.definitions);\n\n    let mut output = EcoString::new();\n\n    output.push_str(\"---- SOURCE CODE\\n\");\n    for (_package, name, src) in modules {\n        output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n    }\n    output.push_str(\"-- \");\n    output.push_str(module_name);\n    output.push_str(\".gleam\\n\");\n    output.push_str(module_src);\n\n    if !types.is_empty() {\n        output.push_str(\"\\n\\n---- TYPES\");\n    }\n    for type_ in types {\n        output.push_str(\"\\n\\n--- \");\n        output.push_str(type_.name);\n        if !type_.documentation.is_empty() {\n            output.push('\\n');\n            output.push_str(&type_.documentation);\n        }\n        output.push_str(\"\\n<pre><code>\");\n        output.push_str(&type_.definition);\n        output.push_str(\"</code></pre>\");\n\n        if !type_.constructors.is_empty() {\n            output.push_str(\"\\n\\n-- CONSTRUCTORS\");\n        }\n        for constructor in type_.constructors {\n            output.push_str(\"\\n\\n\");\n            if !constructor.documentation.is_empty() {\n                output.push_str(&constructor.documentation);\n                output.push('\\n');\n            }\n            output.push_str(\"<pre><code>\");\n            output.push_str(&constructor.definition);\n            output.push_str(\"</code></pre>\");\n        }\n    }\n\n    if !values.is_empty() {\n        output.push_str(\"\\n\\n---- VALUES\");\n    }\n    for value in values {\n        output.push_str(\"\\n\\n--- \");\n        output.push_str(value.name);\n        if !value.documentation.is_empty() {\n            output.push('\\n');\n            output.push_str(&value.documentation);\n        }\n        output.push_str(\"\\n<pre><code>\");\n        output.push_str(&value.definition);\n        output.push_str(\"</code></pre>\");\n    }\n\n    output\n}\n\nmacro_rules! assert_documentation {\n    ($src:literal $(,)?) => {\n        assert_documentation!($src, PrintOptions::all());\n    };\n\n    ($src:literal, $options:expr $(,)?) => {\n        let output = compile_documentation(\"main\", $src, Vec::new(), DependencyKind::Hex, $options);\n        insta::assert_snapshot!(output);\n    };\n\n    ($(($name:expr, $module_src:literal)),+, $src:literal $(,)?) => {\n        let output = compile_documentation(\n            \"main\",\n            $src,\n            vec![$((\"thepackage\", $name, $module_src)),*],\n            DependencyKind::Hex,\n            PrintOptions::all(),\n        );\n        insta::assert_snapshot!(output);\n    };\n\n    ($(($name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => {\n        let output = compile_documentation(\n            \"main\",\n            $src,\n            vec![$((\"thepackage\", $name, $module_src)),*],\n            DependencyKind::Hex,\n            $options,\n        );\n        insta::assert_snapshot!(output);\n    };\n\n    ($(($name:expr, $module_src:literal)),+, $main_module:literal, $src:literal, $options:expr $(,)?) => {\n        let output = compile_documentation(\n            $main_module,\n            $src,\n            vec![$((\"thepackage\", $name, $module_src)),*],\n            DependencyKind::Hex,\n            $options,\n        );\n        insta::assert_snapshot!(output);\n    };\n\n    ($(($package:expr, $name:expr, $module_src:literal)),+, $src:literal $(,)?) => {\n        let output = compile_documentation(\n            \"main\",\n            $src,\n            vec![$(($package, $name, $module_src)),*],\n            DependencyKind::Hex,\n            PrintOptions::all(),\n        );\n        insta::assert_snapshot!(output);\n    };\n\n    ($(($package:expr, $name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => {\n        let output = compile_documentation(\n            \"main\",\n            $src,\n            vec![$(($package, $name, $module_src)),*],\n            DependencyKind::Hex,\n            $options,\n        );\n        insta::assert_snapshot!(output);\n    };\n\n    (git: $(($package:expr, $name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => {\n        let output = compile_documentation(\n            \"main\",\n            $src,\n            vec![$(($package, $name, $module_src)),*],\n            DependencyKind::Git,\n            $options,\n        );\n        insta::assert_snapshot!(output);\n    };\n\n    (path: $(($package:expr, $name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => {\n        let output = compile_documentation(\n            \"main\",\n            $src,\n            vec![$(($package, $name, $module_src)),*],\n            DependencyKind::Path,\n            $options,\n        );\n        insta::assert_snapshot!(output);\n    };\n}\n\n#[test]\nfn hello_docs() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        r#\"\n/// Here is some documentation\npub fn one() {\n  1\n}\n\"#,\n    )];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n#[test]\nfn ignored_argument_is_called_arg() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\"app.gleam\", \"pub fn one(_) { 1 }\")];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n// https://github.com/gleam-lang/gleam/issues/2347\n#[test]\nfn tables() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        r#\"\n/// | heading 1    | heading 2    |\n/// |--------------|--------------|\n/// | row 1 cell 1 | row 1 cell 2 |\n/// | row 2 cell 1 | row 2 cell 2 |\n///\npub fn one() {\n  1\n}\n\"#,\n    )];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n// https://github.com/gleam-lang/gleam/issues/2202\n#[test]\nfn long_function_wrapping() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        r#\"\npub type Option(t) {\n  Some(t)\n  None\n}\n\n/// Returns the first value if it is `Some`, otherwise evaluates the given\n/// function for a fallback value.\n///\npub fn lazy_or(first: Option(a), second: fn() -> Option(a)) -> Option(a) {\n  case first {\n    Some(_) -> first\n    None -> second()\n  }\n}\n\"#,\n    )];\n\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n#[test]\nfn internal_definitions_are_not_included() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        r#\"\n@internal\npub const wibble = 1\n\n@internal\npub type Wibble = Int\n\n@internal\npub type Wobble { Wobble }\n\n@internal\npub fn one() { 1 }\n\"#,\n    )];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n// https://github.com/gleam-lang/gleam/issues/2561\n#[test]\nfn discarded_arguments_are_not_shown() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\"app.gleam\", \"pub fn discard(_discarded: a) -> Int { 1 }\")];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n// https://github.com/gleam-lang/gleam/issues/2631\n#[test]\nfn docs_of_a_type_constructor_are_not_used_by_the_following_function() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        r#\"\npub type Wibble {\n  Wobble(\n    /// Documentation!!\n    wabble: Int,\n  )\n}\n\npub fn main() { todo }\n\"#,\n    )];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n#[test]\nfn markdown_code_from_standalone_pages_is_not_trimmed() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let pages = vec![(\n        \"one\",\n        \"\nThis is an example code snippet that should be indented\n```gleam\npub fn indentation_test() {\n  todo as \\\"This line should be indented by two spaces\\\"\n}\n```\",\n    )];\n    insta::assert_snapshot!(compile_with_markdown_pages(\n        config,\n        vec![],\n        pages,\n        CompileWithMarkdownPagesOpts::default()\n    ));\n}\n\n#[test]\nfn markdown_code_from_function_comment_is_trimmed() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        \"\n/// Here's an example code snippet:\n/// ```\n/// wibble\n///   |> wobble\n/// ```\n///\npub fn indentation_test() {\n  todo\n}\n\",\n    )];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n#[test]\nfn markdown_code_from_module_comment_is_trimmed() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        \"\n//// Here's an example code snippet:\n//// ```\n//// wibble\n////   |> wobble\n//// ```\n////\n\",\n    )];\n    insta::assert_snapshot!(compile(config, modules));\n}\n\n#[test]\nfn doc_for_commented_definitions_is_not_included_in_next_constant() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        \"\n/// Not included!\n// pub fn wibble() {}\n\n/// Included!\npub const wobble = 1\n\",\n    )];\n    assert!(!compile(config, modules).contains(\"Not included!\"));\n}\n\n#[test]\nfn doc_for_commented_definitions_is_not_included_in_next_type() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        \"\n/// Not included!\n// pub fn wibble() {}\n\n/// Included!\npub type Wibble {\n  /// Wobble!\n  Wobble\n}\n\",\n    )];\n    assert!(!compile(config, modules).contains(\"Not included!\"));\n}\n\n#[test]\nfn doc_for_commented_definitions_is_not_included_in_next_function() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        \"\n/// Not included!\n// pub fn wibble() {}\n\n/// Included!\npub fn wobble(arg) {}\n\",\n    )];\n    assert!(!compile(config, modules).contains(\"Not included!\"));\n}\n\n#[test]\nfn doc_for_commented_definitions_is_not_included_in_next_type_alias() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![(\n        \"app.gleam\",\n        \"\n/// Not included!\n// pub fn wibble() {}\n\n/// Included!\npub type Wibble = Int\n\",\n    )];\n    assert!(!compile(config, modules).contains(\"Not included!\"));\n}\n\n#[test]\nfn source_link_for_github_repository() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    config.repository = Some(Repository::GitHub {\n        user: \"wibble\".to_string(),\n        repo: \"wobble\".to_string(),\n        path: None,\n        tag_prefix: None,\n    });\n\n    let modules = vec![(\"app.gleam\", \"pub type Wibble = Int\")];\n    assert!(\n        compile(config, modules)\n            .contains(\"https://github.com/wibble/wobble/blob/v0.1.0/src/app.gleam#L1\")\n    );\n}\n\n#[test]\nfn source_link_for_github_repository_with_path_and_tag_prefix() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    config.repository = Some(Repository::GitHub {\n        user: \"wibble\".to_string(),\n        repo: \"wobble\".to_string(),\n        path: Some(\"path/to/package\".to_string()),\n        tag_prefix: Some(\"subdir-\".into()),\n    });\n\n    let modules = vec![(\"app.gleam\", \"pub type Wibble = Int\")];\n    assert!(compile(config, modules).contains(\n        \"https://github.com/wibble/wobble/blob/subdir-v0.1.0/path/to/package/src/app.gleam#L1\"\n    ));\n}\n\n#[test]\nfn canonical_link() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![\n        (\n            \"app.gleam\",\n            r#\"\n/// Here is some documentation\npub fn one() {\n  1\n}\n\"#,\n        ),\n        (\n            \"gleam/otp/actor.gleam\",\n            r#\"\n/// Here is some documentation\npub fn one() {\n  1\n}\n\"#,\n        ),\n    ];\n\n    let pages = vec![(\n        \"LICENSE\",\n        r#\"\n# LICENSE\n    \"#,\n    )];\n    insta::assert_snapshot!(compile_with_markdown_pages(\n        config,\n        modules,\n        pages,\n        CompileWithMarkdownPagesOpts::default()\n    ));\n}\n\n#[test]\nfn no_hex_publish() {\n    let mut config = PackageConfig::default();\n    config.name = EcoString::from(\"test_project_name\");\n    let modules = vec![\n        (\n            \"app.gleam\",\n            r#\"\n/// Here is some documentation\npub fn one() {\n  1\n}\n\"#,\n        ),\n        (\n            \"gleam/otp/actor.gleam\",\n            r#\"\n/// Here is some documentation\npub fn one() {\n  1\n}\n\"#,\n        ),\n    ];\n\n    let pages = vec![(\n        \"LICENSE\",\n        r#\"\n# LICENSE\n    \"#,\n    )];\n    insta::assert_snapshot!(compile_with_markdown_pages(\n        config,\n        modules,\n        pages,\n        CompileWithMarkdownPagesOpts {\n            hex_publish: Some(DocContext::Build)\n        }\n    ));\n}\n\nfn create_sample_search_data() -> SearchData {\n    SearchData {\n        items: vec![\n            SearchItem {\n                type_: SearchItemType::Module,\n                parent_title: \"gleam/option\".to_string(),\n                title: \"gleam/option\".to_string(),\n                content: \"\".to_string(),\n                reference: \"gleam/option.html\".to_string(),\n            },\n            SearchItem {\n                type_: SearchItemType::Type,\n                parent_title: \"gleam/option\".to_string(),\n                title: \"Option\".to_string(),\n                content: \"`Option` represents a value that may be present or not. `Some` means the value is present, `None` means the value is not.\".to_string(),\n                reference: \"gleam/option.html#Option\".to_string(),\n            },\n            SearchItem {\n                type_: SearchItemType::Value,\n                parent_title: \"gleam/option\".to_string(),\n                title: \"unwrap\".to_string(),\n                content: \"Extracts the value from an `Option`, returning a default value if there is none.\".to_string(),\n                reference: \"gleam/option.html#unwrap\".to_string(),\n            },\n            SearchItem {\n                type_: SearchItemType::Value,\n                parent_title: \"gleam/dynamic/decode\".to_string(),\n                title: \"bool\".to_string(),\n                content: \"A decoder that decodes `Bool` values.\\n\\n # Examples\\n\\n \\n let result = decode.run(dynamic.from(True), decode.bool)\\n assert result == Ok(True)\\n \\n\".to_string(),\n                reference: \"gleam/dynamic/decode.html#bool\".to_string(),\n            },\n        ],\n        programming_language: SearchProgrammingLanguage::Gleam,\n    }\n}\n\n#[test]\nfn ensure_search_data_matches_exdocs_search_data_model_specification() {\n    let data = create_sample_search_data();\n    let json = serde_to_string(&data).unwrap();\n\n    let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();\n\n    // Ensure output of SearchData matches specification\n    assert!(parsed.is_object());\n    let obj = parsed.as_object().unwrap();\n    assert!(obj.contains_key(\"items\"));\n    assert!(obj.contains_key(\"proglang\"));\n\n    // Ensure output of SearchItem matches specification\n    let items = obj.get(\"items\").unwrap().as_array().unwrap();\n    for item in items {\n        let item = item.as_object().unwrap();\n        assert!(item.contains_key(\"type\"));\n        assert!(item.contains_key(\"parentTitle\"));\n        assert!(item.contains_key(\"title\"));\n        assert!(item.contains_key(\"doc\"));\n        assert!(item.contains_key(\"ref\"));\n    }\n}\n\n#[test]\nfn output_of_search_data_json() {\n    let data = create_sample_search_data();\n    let json = serde_to_string(&data).unwrap();\n    insta::assert_snapshot!(json);\n}\n\nconst ONLY_LINKS: PrintOptions = PrintOptions {\n    print_highlighting: false,\n    print_html: true,\n};\nconst NONE: PrintOptions = PrintOptions {\n    print_highlighting: false,\n    print_html: false,\n};\n\n#[test]\nfn highlight_function_definition() {\n    assert_documentation!(\n        \"\npub fn wibble(list: List(Int), generic: a, function: fn(a) -> b) -> #(a, b) { todo }\n\"\n    );\n}\n\n#[test]\nfn highlight_constant_definition() {\n    assert_documentation!(\n        \"\npub const x = 22\n\"\n    );\n}\n\n#[test]\nfn highlight_type_alias() {\n    assert_documentation!(\n        \"\npub type Option(a) = Result(a, Nil)\n\"\n    );\n}\n\n#[test]\nfn highlight_custom_type() {\n    assert_documentation!(\n        \"\npub type Wibble(a, b) {\n  Wibble(a, i: Int)\n  Wobble(b: b, c: String)\n}\n\"\n    );\n}\n\n#[test]\nfn highlight_opaque_custom_type() {\n    assert_documentation!(\n        \"\npub opaque type Wibble(a, b) {\n  Wibble(a, i: Int)\n  Wobble(b: b, c: String)\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2629\n#[test]\nfn print_type_variables_in_function_signatures() {\n    assert_documentation!(\n        \"\npub type Dict(key, value)\n\npub fn insert(dict: Dict(key, value), key: key, value: value) -> Dict(key, value) {\n  dict\n}\n\",\n        NONE\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/828\n#[test]\nfn print_qualified_names_from_other_modules() {\n    assert_documentation!(\n        (\n            \"gleam/option\",\n            \"\npub type Option(t) {\n  Some(t)\n  None\n}\n\"\n        ),\n        \"\nimport gleam/option.{type Option, Some, None}\n\npub fn from_option(o: Option(t), e: e) -> Result(t, e) {\n  case o {\n    Some(t) -> Ok(t)\n    None -> Error(e)\n  }\n}\n\",\n        NONE\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3461\n#[test]\nfn link_to_type_in_same_module() {\n    assert_documentation!(\n        \"\npub type Dict(a, b)\n\npub fn new() -> Dict(a, b) { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3461\n#[test]\nfn link_to_type_in_different_module() {\n    assert_documentation!(\n        (\"gleam/dict\", \"pub type Dict(a, b)\"),\n        \"\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn link_to_type_in_different_module_from_nested_module() {\n    assert_documentation!(\n        (\"gleam/dict\", \"pub type Dict(a, b)\"),\n        \"gleam/dynamic/decode\",\n        \"\nimport gleam/dict\n\npub fn decode_dict() -> dict.Dict(a, b) { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn link_to_type_in_different_module_from_nested_module_with_shared_path() {\n    assert_documentation!(\n        (\"gleam/dynamic\", \"pub type Dynamic\"),\n        \"gleam/dynamic/decode\",\n        \"\nimport gleam/dynamic\n\npub type Dynamic = dynamic.Dynamic\n\",\n        ONLY_LINKS\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3461\n#[test]\nfn link_to_type_in_different_package() {\n    assert_documentation!(\n        (\"gleam_stdlib\", \"gleam/dict\", \"pub type Dict(a, b)\"),\n        \"\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn no_link_to_type_in_git_dependency() {\n    assert_documentation!(\n        git: (\"gleam_stdlib\", \"gleam/dict\", \"pub type Dict(a, b)\"),\n        \"\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn no_link_to_type_in_path_dependency() {\n    assert_documentation!(\n        path: (\"gleam_stdlib\", \"gleam/dict\", \"pub type Dict(a, b)\"),\n        \"\nimport gleam/dict\n\npub fn make_dict() -> dict.Dict(a, b) { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn no_links_to_prelude_types() {\n    assert_documentation!(\n        \"\npub fn int_to_string(i: Int) -> String { todo }\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn generated_type_variables() {\n    assert_documentation!(\n        \"\npub fn wibble(_a, _b, _c, _d) {\n  todo\n}\n\",\n        NONE\n    );\n}\n\n#[test]\nfn generated_type_variables_mixed_with_existing_variables() {\n    assert_documentation!(\n        \"\npub fn wibble(_a: b, _b: a, _c, _d) {\n  todo\n}\n\",\n        NONE\n    );\n}\n\n#[test]\nfn generated_type_variables_with_existing_variables_coming_afterwards() {\n    assert_documentation!(\n        \"\npub fn wibble(_a, _b, _c: b, _d: a) {\n  todo\n}\n\",\n        NONE\n    );\n}\n\n#[test]\nfn generated_type_variables_do_not_take_into_account_other_definitions() {\n    assert_documentation!(\n        \"\npub fn wibble(_a: a, _b: b, _c: c) -> d {\n  todo\n}\n\npub fn identity(x) { x }\n\",\n        NONE\n    );\n}\n\n#[test]\nfn internal_type_reexport_in_same_module_as_parameter() {\n    assert_documentation!(\n        \"\n@internal\npub type Internal\n\npub type External =\n  List(Internal)\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn internal_type_reexport_in_same_module_as_parameter_colours() {\n    assert_documentation!(\n        \"\n@internal\npub type Internal\n\npub type External =\n  List(Internal)\n\",\n    );\n}\n\n#[test]\nfn internal_type_reexport_in_same_module() {\n    assert_documentation!(\n        \"\n@internal\npub type Internal\n\npub type External =\n  Internal\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn internal_type_reexport_in_different_module() {\n    assert_documentation!(\n        (\"other\", \"@internal pub type Internal\"),\n        \"\nimport other\n\npub type External =\n  other.Internal\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn public_type_reexport_in_different_internal_module() {\n    assert_documentation!(\n        (\"thepackage/internal/other\", \"pub type Internal\"),\n        \"\nimport thepackage/internal/other\n\npub type External =\n  other.Internal\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn use_reexport_from_other_package() {\n    assert_documentation!(\n        (\"some_package\", \"some_package/internal\", \"pub type Internal\"),\n        (\n            \"some_package\",\n            \"some_package/api\",\n            \"\nimport some_package/internal\npub type External = internal.Internal\n\"\n        ),\n        \"\nimport some_package/api\n\npub fn do_thing(value: api.External) {\n  value\n}\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn function_uses_reexport_of_internal_type() {\n    assert_documentation!(\n        (\"thepackage/internal\", \"pub type Internal\"),\n        \"\nimport thepackage/internal\n\npub type External = internal.Internal\n\npub fn do_thing(value: internal.Internal) -> External {\n  value\n}\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn function_uses_reexport_of_internal_type_in_other_module() {\n    assert_documentation!(\n        (\"thepackage/internal\", \"pub type Internal\"),\n        (\n            \"thepackage/something\",\n            \"\nimport thepackage/internal\n\npub type External = internal.Internal\n\"\n        ),\n        \"\nimport thepackage/something\n\npub fn do_thing(value: something.External) {\n  value\n}\n\",\n        ONLY_LINKS\n    );\n}\n\n#[test]\nfn constructor_with_long_types_and_many_fields() {\n    assert_documentation!(\n        (\"option\", \"pub type Option(a)\"),\n        \"\nimport option\n\npub type Uri {\n    Uri(\n        scheme: option.Option(String),\n        userinfo: option.Option(String),\n        host: option.Option(String),\n        port: option.Option(Int),\n        path: String,\n        query: option.Option(String),\n        fragment: option.Option(String)\n    )\n}\n\",\n        NONE\n    );\n}\n\n#[test]\nfn constructor_with_long_types_and_many_fields_that_need_splitting() {\n    assert_documentation!(\n        (\"option\", \"pub type Option(a)\"),\n        \"\nimport option\n\npub type TypeWithAVeryLoooooooooooooooooooongName\n\npub type Wibble {\n    Wibble(\n        wibble: #(TypeWithAVeryLoooooooooooooooooooongName, TypeWithAVeryLoooooooooooooooooooongName),\n        wobble: option.Option(String),\n    )\n}\n\",\n        NONE\n    );\n}\n\n#[test]\nfn gitea_repository_url_has_no_double_slash() {\n    let repo = Repository::Forgejo {\n        host: \"https://code.example.org/\".parse::<Uri>().unwrap(),\n        user: \"person\".into(),\n        repo: \"forgejo_bug\".into(),\n        path: None,\n        tag_prefix: None,\n    };\n\n    assert_eq!(repo.url(), \"https://code.example.org/person/forgejo_bug\");\n}\n\n#[test]\nfn long_function_with_no_arguments_parentheses_are_not_split() {\n    assert_documentation!(\n        \"\npub fn aaaaaaaaaaaaaaaaaaaaaaaaaaaa() -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {\n  todo\n}\n\",\n        NONE\n    );\n}\n\n#[test]\nfn forgejo_single_line_definition() {\n    let mut config = PackageConfig::default();\n    let repo = Repository::Forgejo {\n        host: \"https://code.example.org/\".parse::<Uri>().unwrap(),\n        user: \"wibble\".into(),\n        repo: \"wobble\".into(),\n        path: None,\n        tag_prefix: None,\n    };\n\n    config.name = EcoString::from(\"test_project_name\");\n    config.repository = Some(repo);\n\n    let modules = vec![(\"app.gleam\", \"pub type Wibble = Int\")];\n    let html = compile(config, modules);\n\n    assert!(\n        html.contains(\"https://code.example.org/wibble/wobble/src/tag/v0.1.0/src/app.gleam#L1\")\n    );\n}\n\n#[test]\nfn forgejo_multiple_line_definition() {\n    let mut config = PackageConfig::default();\n    let repo = Repository::Forgejo {\n        host: \"https://code.example.org/\".parse::<Uri>().unwrap(),\n        user: \"wibble\".into(),\n        repo: \"wobble\".into(),\n        path: None,\n        tag_prefix: None,\n    };\n\n    config.name = EcoString::from(\"test_project_name\");\n    config.repository = Some(repo);\n\n    let modules = vec![(\"app.gleam\", \"pub type Wibble \\n\\n= Int\")];\n    let html = compile(config, modules);\n\n    assert!(\n        html.contains(\"https://code.example.org/wibble/wobble/src/tag/v0.1.0/src/app.gleam#L1-L3\")\n    );\n}\n\nfn generate_search_data(module_name: &str, module_src: &str) -> EcoString {\n    let module = type_::tests::compile_module(module_name, module_src, None, Vec::new())\n        .expect(\"Module should compile successfully\");\n\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n    let paths = ProjectPaths::new(\"/\".into());\n    let build_module = build::Module {\n        name: \"main\".into(),\n        code: module_src.into(),\n        mtime: SystemTime::now(),\n        input_path: \"/\".into(),\n        origin: Origin::Src,\n        ast: module,\n        extra: Default::default(),\n        dependencies: Default::default(),\n    };\n\n    let source_links = SourceLinker::new(&paths, &config, &build_module);\n\n    let module = &build_module.ast;\n\n    let dependencies = HashMap::new();\n    let mut printer = Printer::new(\n        module.type_info.package.clone(),\n        module.name.clone(),\n        &module.names,\n        &dependencies,\n    );\n\n    let mut search_items = Vec::new();\n\n    let types = printer.type_definitions(&source_links, &module.definitions);\n    let values = printer.value_definitions(&source_links, &module.definitions);\n\n    search_items.push(search_item_for_module(&build_module));\n\n    for type_ in types {\n        search_items.push(search_item_for_type(module_name, &type_));\n    }\n    for value in values {\n        search_items.push(search_item_for_value(module_name, &value));\n    }\n\n    let mut output = EcoString::new();\n\n    output.push_str(\"------ SOURCE CODE\\n\");\n    output.push_str(module_src);\n    output.push_str(\"\\n------------------------------------\\n\\n\");\n\n    for item in search_items {\n        let SearchItem {\n            type_,\n            parent_title,\n            title,\n            content,\n            reference,\n        } = item;\n\n        let type_ = match type_ {\n            SearchItemType::Value => \"Value\",\n            SearchItemType::Module => \"Module\",\n            SearchItemType::Page => \"Page\",\n            SearchItemType::Type => \"Type\",\n        };\n\n        output.push_str(&eco_format!(\n            \"TITLE:         {title}\nPARENT TITLE:  {parent_title}\nTYPE:          {type_}\nREFERENCE:     {reference}\nCONTENT:\n{content}\n------------------------------------\n\"\n        ));\n    }\n\n    output\n}\n\n#[test]\nfn search_item_for_custom_type() {\n    let output = generate_search_data(\n        \"module\",\n        \"\n/// # The `Option` type\n/// Represents an optional value, either `Some` or `None`.\n/// If it is None, the value is absent\n/// [Read more](https://example.com)\npub type Option(inner) {\n  /// Here is some\n  /// documentation for the `Some` constructor\n  Some(\n    /// And even documentation on a **field**!\n    value: inner\n  )\n  None\n}\n\",\n    );\n    insta::assert_snapshot!(output);\n}\n\n#[test]\nfn search_item_for_type_alias() {\n    let output = generate_search_data(\n        \"module\",\n        \"\n/// This is a type alias to a list\n/// of integer values.\n/// ## Examples\n/// ```\n/// // Examples\n/// ```\npub type IntList = List(Int)\n\",\n    );\n    insta::assert_snapshot!(output);\n}\n\n#[test]\nfn search_item_for_function() {\n    let output = generate_search_data(\n        \"module\",\n        \"\n/// Pi is the ration between a circle's **radius** and its\n/// *circumference*. Pretty cool!\npub const pi = 3.14\n\",\n    );\n    insta::assert_snapshot!(output);\n}\n\n#[test]\nfn search_item_for_constant() {\n    let output = generate_search_data(\n        \"module\",\n        \"\n/// Reverses a `List`, and returns the list in reverse.\n/// ```\n/// reverse([1, 2, 3])\n/// // [3, 2, 1]\n/// ```\npub fn reverse(list: List(a), out: List(a)) -> List(a) {\n  case list {\n    [] -> out\n    [first, ..rest] -> reverse(rest, [first, ..out])\n  }\n}\n\",\n    );\n    insta::assert_snapshot!(output);\n}\n"
  },
  {
    "path": "compiler-core/src/docs.rs",
    "content": "mod printer;\nmod source_links;\n#[cfg(test)]\nmod tests;\n\nuse std::{collections::HashMap, time::SystemTime};\n\nuse camino::Utf8PathBuf;\nuse hexpm::version::Version;\nuse printer::Printer;\n\nuse crate::{\n    build::{Module, Package},\n    config::{DocsPage, PackageConfig},\n    docs::source_links::SourceLinker,\n    io::{Content, FileSystemReader, OutputFile},\n    package_interface::PackageInterface,\n    paths::ProjectPaths,\n    type_::{self},\n    version::COMPILER_VERSION,\n};\nuse askama::Template;\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse serde::{Deserialize, Serialize};\nuse serde_json::to_string as serde_to_string;\n\n#[derive(PartialEq, Eq, Copy, Clone, Debug)]\npub enum DocContext {\n    HexPublish,\n    Build,\n}\n\n#[derive(PartialEq, Debug, Serialize, Deserialize)]\npub struct PackageInformation {\n    #[serde(rename = \"gleam.toml\")]\n    package_config: PackageConfig,\n}\n\n/// Like `ManifestPackage`, but lighter and cheaper to clone as it is all that\n/// we need for printing documentation.\n#[derive(Debug, Clone)]\npub struct Dependency {\n    pub version: Version,\n    pub kind: DependencyKind,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum DependencyKind {\n    Hex,\n    Path,\n    Git,\n}\n\n#[derive(Debug)]\npub struct DocumentationConfig<'a> {\n    pub package_config: &'a PackageConfig,\n    pub dependencies: HashMap<EcoString, Dependency>,\n    pub analysed: &'a [Module],\n    pub docs_pages: &'a [DocsPage],\n    pub rendering_timestamp: SystemTime,\n    pub context: DocContext,\n}\n\npub fn generate_html<IO: FileSystemReader>(\n    paths: &ProjectPaths,\n    config: DocumentationConfig<'_>,\n    fs: IO,\n) -> Vec<OutputFile> {\n    let DocumentationConfig {\n        package_config: config,\n        dependencies,\n        analysed,\n        docs_pages,\n        rendering_timestamp,\n        context: is_hex_publish,\n    } = config;\n\n    let modules = analysed\n        .iter()\n        .filter(|module| module.origin.is_src())\n        .filter(|module| !config.is_internal_module(&module.name));\n\n    let rendering_timestamp = rendering_timestamp\n        .duration_since(SystemTime::UNIX_EPOCH)\n        .expect(\"get current timestamp\")\n        .as_secs()\n        .to_string();\n\n    // Define user-supplied (or README) pages\n    let pages: Vec<_> = docs_pages\n        .iter()\n        .map(|page| Link {\n            name: page.title.to_string(),\n            path: page.path.to_string(),\n        })\n        .collect();\n\n    let doc_links = config.links.iter().map(|doc_link| Link {\n        name: doc_link.title.to_string(),\n        path: doc_link.href.to_string(),\n    });\n\n    let repo_link = config\n        .repository\n        .as_ref()\n        .map(|r| r.url())\n        .map(|path| Link {\n            name: \"Repository\".into(),\n            path,\n        });\n\n    let host = if is_hex_publish == DocContext::HexPublish {\n        \"https://hexdocs.pm\"\n    } else {\n        \"\"\n    };\n\n    // https://github.com/gleam-lang/gleam/issues/3020\n    let links: Vec<_> = match is_hex_publish {\n        DocContext::HexPublish => doc_links\n            .chain(repo_link)\n            .chain([Link {\n                name: \"Hex\".into(),\n                path: format!(\"https://hex.pm/packages/{0}\", config.name).to_string(),\n            }])\n            .collect(),\n        DocContext::Build => doc_links.chain(repo_link).collect(),\n    };\n\n    let mut files = vec![];\n\n    let mut search_items = vec![];\n\n    let modules_links: Vec<_> = modules\n        .clone()\n        .map(|m| {\n            let path = [&m.name, \".html\"].concat();\n            Link {\n                path,\n                name: m.name.split('/').join(\"<wbr />/\"),\n            }\n        })\n        .sorted()\n        .collect();\n\n    // Generate user-supplied (or README) pages\n    for page in docs_pages {\n        let content = fs.read(&page.source).unwrap_or_default();\n        let rendered_content = render_markdown(&content, MarkdownSource::Standalone);\n        let unnest = page_unnest(&page.path);\n\n        let page_path_without_ext = page.path.split('.').next().unwrap_or(\"\");\n        let page_title = match page_path_without_ext {\n            // The index page, such as README, should not push it's page title\n            \"index\" => format!(\"{} · v{}\", config.name, config.version),\n            // Other page title's should say so\n            _other => format!(\"{} · {} · v{}\", page.title, config.name, config.version),\n        };\n        let page_meta_description = match page_path_without_ext {\n            \"index\" => config.description.to_string().clone(),\n            _other => \"\".to_owned(),\n        };\n        let path = Utf8PathBuf::from(&page.path);\n\n        let temp = PageTemplate {\n            gleam_version: COMPILER_VERSION,\n            links: &links,\n            pages: &pages,\n            modules: &modules_links,\n            project_name: &config.name,\n            page_title: &page_title,\n            page_meta_description: &page_meta_description,\n            file_path: &path.clone(),\n            project_version: &config.version.to_string(),\n            content: rendered_content,\n            rendering_timestamp: &rendering_timestamp,\n            host,\n            unnest: &unnest,\n        };\n\n        files.push(OutputFile {\n            path,\n            content: Content::Text(temp.render().expect(\"Page template rendering\")),\n        });\n\n        search_items.push(search_item_for_page(&config.name, &page.path, content))\n    }\n\n    // Generate module documentation pages\n    for module in modules {\n        let name = module.name.clone();\n        let unnest = page_unnest(&module.name);\n\n        // Read module src & create line number lookup structure\n        let source_links = SourceLinker::new(paths, config, module);\n\n        let documentation_content = module.ast.documentation.iter().join(\"\\n\");\n        let rendered_documentation =\n            render_markdown(&documentation_content, MarkdownSource::Comment);\n\n        let mut printer = Printer::new(\n            module.ast.type_info.package.clone(),\n            module.name.clone(),\n            &module.ast.names,\n            &dependencies,\n        );\n\n        let types = printer.type_definitions(&source_links, &module.ast.definitions);\n        let values = printer.value_definitions(&source_links, &module.ast.definitions);\n\n        types\n            .iter()\n            .for_each(|type_| search_items.push(search_item_for_type(&module.name, type_)));\n        values\n            .iter()\n            .for_each(|value| search_items.push(search_item_for_value(&module.name, value)));\n\n        search_items.push(search_item_for_module(module));\n\n        let page_title = format!(\"{} · {} · v{}\", name, config.name, config.version);\n        let page_meta_description = \"\";\n        let path = Utf8PathBuf::from(format!(\"{}.html\", module.name));\n\n        let template = ModuleTemplate {\n            gleam_version: COMPILER_VERSION,\n            host,\n            unnest,\n            links: &links,\n            pages: &pages,\n            documentation: rendered_documentation,\n            modules: &modules_links,\n            project_name: &config.name,\n            page_title: &page_title,\n            page_meta_description,\n            module_name: EcoString::from(&name),\n            file_path: &path.clone(),\n            project_version: &config.version.to_string(),\n            types,\n            values,\n            rendering_timestamp: &rendering_timestamp,\n        };\n\n        files.push(OutputFile {\n            path,\n            content: Content::Text(\n                template\n                    .render()\n                    .expect(\"Module documentation template rendering\"),\n            ),\n        });\n    }\n\n    // Render static assets\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"css/atom-one-light.min.css\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-css/atom-one-light.min.css\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"css/atom-one-dark.min.css\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-css/atom-one-dark.min.css\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"css/index.css\"),\n        content: Content::Text(std::include_str!(\"../templates/docs-css/index.css\").to_string()),\n    });\n\n    // highlightjs:\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/highlight.min.js\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-js/highlight.min.js\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/highlightjs-gleam.js\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-js/highlightjs-gleam.js\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/highlightjs-erlang.min.js\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-js/highlightjs-erlang.min.js\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/highlightjs-elixir.min.js\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-js/highlightjs-elixir.min.js\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/highlightjs-javascript.min.js\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-js/highlightjs-javascript.min.js\").to_string(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/highlightjs-typescript.min.js\"),\n        content: Content::Text(\n            std::include_str!(\"../templates/docs-js/highlightjs-typescript.min.js\").to_string(),\n        ),\n    });\n\n    // lunr.min.js, search-data.json and index.js\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/lunr.min.js\"),\n        content: Content::Text(std::include_str!(\"../templates/docs-js/lunr.min.js\").to_string()),\n    });\n\n    let search_data_json = serde_to_string(&SearchData {\n        items: search_items,\n        programming_language: SearchProgrammingLanguage::Gleam,\n    })\n    .expect(\"search index serialization\");\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"search-data.json\"),\n        content: Content::Text(search_data_json.to_string()),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"js/index.js\"),\n        content: Content::Text(std::include_str!(\"../templates/docs-js/index.js\").to_string()),\n    });\n\n    // web fonts:\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/karla-v23-regular-latin-ext.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/karla-v23-regular-latin-ext.woff2\").to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/karla-v23-regular-latin.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/karla-v23-regular-latin.woff2\").to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/karla-v23-bold-latin-ext.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/karla-v23-bold-latin-ext.woff2\").to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/karla-v23-bold-latin.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/karla-v23-bold-latin.woff2\").to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/ubuntu-mono-v15-regular-cyrillic-ext.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/ubuntu-mono-v15-regular-cyrillic-ext.woff2\")\n                .to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/ubuntu-mono-v15-regular-cyrillic.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/ubuntu-mono-v15-regular-cyrillic.woff2\")\n                .to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/ubuntu-mono-v15-regular-greek-ext.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/ubuntu-mono-v15-regular-greek-ext.woff2\")\n                .to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/ubuntu-mono-v15-regular-greek.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/ubuntu-mono-v15-regular-greek.woff2\").to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/ubuntu-mono-v15-regular-latin-ext.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/ubuntu-mono-v15-regular-latin-ext.woff2\")\n                .to_vec(),\n        ),\n    });\n\n    files.push(OutputFile {\n        path: Utf8PathBuf::from(\"fonts/ubuntu-mono-v15-regular-latin.woff2\"),\n        content: Content::Binary(\n            include_bytes!(\"../templates/docs-fonts/ubuntu-mono-v15-regular-latin.woff2\").to_vec(),\n        ),\n    });\n\n    files\n}\n\nfn search_item_for_page(package: &str, path: &str, content: String) -> SearchItem {\n    SearchItem {\n        type_: SearchItemType::Page,\n        parent_title: package.to_string(),\n        title: package.to_string(),\n        content,\n        reference: path.to_string(),\n    }\n}\n\nfn search_item_for_type(module: &str, type_: &TypeDefinition<'_>) -> SearchItem {\n    let constructors = type_\n        .constructors\n        .iter()\n        .map(|constructor| {\n            let arguments = constructor\n                .arguments\n                .iter()\n                .map(|argument| format!(\"{}\\n{}\", argument.name, argument.text_documentation))\n                .join(\"\\n\");\n\n            format!(\n                \"{}\\n{}\\n{}\",\n                constructor.raw_definition, constructor.text_documentation, arguments\n            )\n        })\n        .join(\"\\n\");\n\n    SearchItem {\n        type_: SearchItemType::Type,\n        parent_title: module.to_string(),\n        title: type_.name.to_string(),\n        content: format!(\n            \"{}\\n{}\\n{}\\n{}\",\n            type_.raw_definition,\n            type_.text_documentation,\n            constructors,\n            import_synonyms(module, type_.name)\n        ),\n        reference: format!(\"{}.html#{}\", module, type_.name),\n    }\n}\n\nfn search_item_for_value(module: &str, value: &DocsValues<'_>) -> SearchItem {\n    SearchItem {\n        type_: SearchItemType::Value,\n        parent_title: module.to_string(),\n        title: value.name.to_string(),\n        content: format!(\n            \"{}\\n{}\\n{}\",\n            value.raw_definition,\n            value.text_documentation,\n            import_synonyms(module, value.name)\n        ),\n        reference: format!(\"{}.html#{}\", module, value.name),\n    }\n}\n\nfn search_item_for_module(module: &Module) -> SearchItem {\n    SearchItem {\n        type_: SearchItemType::Module,\n        parent_title: module.name.to_string(),\n        title: module.name.to_string(),\n        content: module.ast.documentation.iter().join(\"\\n\"),\n        reference: format!(\"{}.html\", module.name),\n    }\n}\n\npub fn generate_json_package_interface(\n    path: Utf8PathBuf,\n    package: &Package,\n    cached_modules: &im::HashMap<EcoString, type_::ModuleInterface>,\n) -> OutputFile {\n    OutputFile {\n        path,\n        content: Content::Text(\n            serde_json::to_string(&PackageInterface::from_package(package, cached_modules))\n                .expect(\"JSON module interface serialisation\"),\n        ),\n    }\n}\n\npub fn generate_json_package_information(path: Utf8PathBuf, config: PackageConfig) -> OutputFile {\n    OutputFile {\n        path,\n        content: Content::Text(package_information_as_json(config)),\n    }\n}\n\nfn package_information_as_json(config: PackageConfig) -> String {\n    let info = PackageInformation {\n        package_config: config,\n    };\n    serde_json::to_string_pretty(&info).expect(\"JSON module information serialisation\")\n}\n\nfn page_unnest(path: &str) -> String {\n    let unnest = path\n        .strip_prefix('/')\n        .unwrap_or(path)\n        .split('/')\n        .skip(1)\n        .map(|_| \"..\")\n        .join(\"/\");\n    if unnest.is_empty() {\n        \".\".into()\n    } else {\n        unnest\n    }\n}\n\n#[test]\nfn page_unnest_test() {\n    // Pages\n    assert_eq!(page_unnest(\"wibble.html\"), \".\");\n    assert_eq!(page_unnest(\"/wibble.html\"), \".\");\n    assert_eq!(page_unnest(\"/wibble/woo.html\"), \"..\");\n    assert_eq!(page_unnest(\"/wibble/wobble/woo.html\"), \"../..\");\n\n    // Modules\n    assert_eq!(page_unnest(\"string\"), \".\");\n    assert_eq!(page_unnest(\"gleam/string\"), \"..\");\n    assert_eq!(page_unnest(\"gleam/string/inspect\"), \"../..\");\n}\n\nfn import_synonyms(parent: &str, child: &str) -> String {\n    format!(\"Synonyms:\\n{parent}.{child}\\n{parent} {child}\")\n}\n\nfn text_documentation(doc: &Option<(u32, EcoString)>) -> String {\n    let raw_text = doc\n        .as_ref()\n        .map(|(_, it)| it.to_string())\n        .unwrap_or_else(|| \"\".into());\n\n    // TODO: parse markdown properly and extract the text nodes\n    raw_text.replace(\"```gleam\", \"\").replace(\"```\", \"\")\n}\n\nfn markdown_documentation(doc: &Option<(u32, EcoString)>) -> String {\n    doc.as_ref()\n        .map(|(_, doc)| render_markdown(doc, MarkdownSource::Comment))\n        .unwrap_or_default()\n}\n\n/// An enum to represent the source of a Markdown string to render.\nenum MarkdownSource {\n    /// A Markdown string that comes from the documentation of a\n    /// definition/module. This means that each line is going to be preceded by\n    /// a whitespace.\n    Comment,\n    /// A Markdown string coming from a standalone file like a README.md.\n    Standalone,\n}\n\nfn render_markdown(text: &str, source: MarkdownSource) -> String {\n    let text = match source {\n        MarkdownSource::Standalone => text.into(),\n        // Doc comments start with \"///\\s\", which can confuse the markdown parser\n        // and prevent tables from rendering correctly, so remove that first space.\n        MarkdownSource::Comment => text\n            .split('\\n')\n            .map(|s| s.strip_prefix(' ').unwrap_or(s))\n            .join(\"\\n\"),\n    };\n\n    let mut s = String::with_capacity(text.len() * 3 / 2);\n    let p = pulldown_cmark::Parser::new_ext(&text, pulldown_cmark::Options::all());\n    pulldown_cmark::html::push_html(&mut s, p);\n    s\n}\n\n#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]\nstruct Link {\n    name: String,\n    path: String,\n}\n\n#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]\nstruct TypeConstructor {\n    definition: String,\n    raw_definition: String,\n    documentation: String,\n    text_documentation: String,\n    arguments: Vec<TypeConstructorArg>,\n}\n\n#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]\nstruct TypeConstructorArg {\n    name: String,\n    doc: String,\n    text_documentation: String,\n}\n\n#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]\nstruct TypeDefinition<'a> {\n    name: &'a str,\n    definition: String,\n    raw_definition: String,\n    documentation: String,\n    constructors: Vec<TypeConstructor>,\n    text_documentation: String,\n    source_url: String,\n    deprecation_message: String,\n    opaque: bool,\n}\n\n#[derive(PartialEq, Eq, PartialOrd, Ord)]\nstruct DocsValues<'a> {\n    name: &'a str,\n    definition: String,\n    raw_definition: String,\n    documentation: String,\n    text_documentation: String,\n    source_url: String,\n    deprecation_message: String,\n}\n\n#[derive(Template)]\n#[template(path = \"documentation_page.html\")]\nstruct PageTemplate<'a> {\n    gleam_version: &'a str,\n    unnest: &'a str,\n    host: &'a str,\n    page_title: &'a str,\n    page_meta_description: &'a str,\n    file_path: &'a Utf8PathBuf,\n    project_name: &'a str,\n    project_version: &'a str,\n    pages: &'a [Link],\n    links: &'a [Link],\n    modules: &'a [Link],\n    content: String,\n    rendering_timestamp: &'a str,\n}\n\n#[derive(Template)]\n#[template(path = \"documentation_module.html\")]\nstruct ModuleTemplate<'a> {\n    gleam_version: &'a str,\n    unnest: String,\n    host: &'a str,\n    page_title: &'a str,\n    page_meta_description: &'a str,\n    file_path: &'a Utf8PathBuf,\n    module_name: EcoString,\n    project_name: &'a str,\n    project_version: &'a str,\n    pages: &'a [Link],\n    links: &'a [Link],\n    modules: &'a [Link],\n    types: Vec<TypeDefinition<'a>>,\n    values: Vec<DocsValues<'a>>,\n    documentation: String,\n    rendering_timestamp: &'a str,\n}\n\n/// Search data for use by Hexdocs search, as well as the search built-in to\n/// generated documentation\n#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]\nstruct SearchData {\n    items: Vec<SearchItem>,\n    #[serde(rename = \"proglang\")]\n    programming_language: SearchProgrammingLanguage,\n}\n\n/// A single item that can appear as a search result\n#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]\nstruct SearchItem {\n    /// The type of item this is: Value, Type, Module, or other Page\n    #[serde(rename = \"type\")]\n    type_: SearchItemType,\n    /// The title of the module or package containing this search item\n    #[serde(rename = \"parentTitle\")]\n    parent_title: String,\n    /// The title of this item\n    title: String,\n    /// Markdown text which describes this item, containing documentation from\n    /// doc comments, as well as rendered definitions of types and values.\n    #[serde(rename = \"doc\")]\n    content: String,\n    /// The relative URL to the documentation for this search item, for example\n    /// `gleam/option.html#Option`\n    #[serde(rename = \"ref\")]\n    reference: String,\n}\n\n#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]\n#[serde(rename_all = \"lowercase\")]\nenum SearchItemType {\n    Value,\n    Module,\n    Page,\n    Type,\n}\n\n#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]\n#[serde(rename_all = \"lowercase\")]\nenum SearchProgrammingLanguage {\n    // Elixir,\n    // Erlang,\n    Gleam,\n}\n\n#[test]\nfn package_config_to_json() {\n    let input = r#\"\nname = \"my_project\"\nversion = \"1.0.0\"\nlicences = [\"Apache-2.0\", \"MIT\"]\ndescription = \"Pretty complex config\"\ntarget = \"erlang\"\nrepository = { type = \"github\", user = \"example\", repo = \"my_dep\" }\nlinks = [{ title = \"Home page\", href = \"https://example.com\" }]\ninternal_modules = [\"my_app/internal\"]\ngleam = \">= 0.30.0\"\n\n[dependencies]\ngleam_stdlib = \">= 0.18.0 and < 2.0.0\"\nmy_other_project = { path = \"../my_other_project\" }\n\n[dev_dependencies]\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n\n[documentation]\npages = [{ title = \"My Page\", path = \"my-page.html\", source = \"./path/to/my-page.md\" }]\n\n[erlang]\napplication_start_module = \"my_app/application\"\nextra_applications = [\"inets\", \"ssl\"]\n\n[javascript]\ntypescript_declarations = true\nruntime = \"node\"\n\n[javascript.deno]\nallow_all = false\nallow_ffi = true\nallow_env = [\"DATABASE_URL\"]\nallow_net = [\"example.com:443\"]\nallow_read = [\"./database.sqlite\"]\n\"#;\n\n    let config = toml::from_str::<PackageConfig>(input).unwrap();\n    let info = PackageInformation {\n        package_config: config.clone(),\n    };\n    let json = package_information_as_json(config);\n    let output = format!(\"--- GLEAM.TOML\\n{input}\\n\\n--- EXPORTED JSON\\n\\n{json}\");\n    insta::assert_snapshot!(output);\n\n    let roundtrip: PackageInformation = serde_json::from_str(&json).unwrap();\n    assert_eq!(info, roundtrip);\n}\n\n#[test]\nfn barebones_package_config_to_json() {\n    let input = r#\"\nname = \"my_project\"\nversion = \"1.0.0\"\n\"#;\n\n    let config = toml::from_str::<PackageConfig>(input).unwrap();\n    let json = package_information_as_json(config);\n    let output = format!(\"--- GLEAM.TOML\\n{input}\\n\\n--- EXPORTED JSON\\n\\n{json}\");\n    insta::assert_snapshot!(output);\n}\n"
  },
  {
    "path": "compiler-core/src/encryption.rs",
    "content": "use thiserror::Error;\n\npub fn encrypt_with_passphrase(\n    message: &[u8],\n    passphrase: &str,\n) -> Result<String, age::EncryptError> {\n    let passphrase = age::secrecy::SecretString::from(passphrase);\n    let recipient = age::scrypt::Recipient::new(passphrase.clone());\n\n    let encrypted = age::encrypt_and_armor(&recipient, message)?;\n\n    Ok(encrypted)\n}\n\n// the function `decrypt_with_passphrase` has two possible failure cases:\n// - when decryption fails\n// - when the data was decrypted succesfully but the result is not UTF-8 valid\n#[derive(Error, Debug)]\npub enum DecryptError {\n    #[error(\"unable to decrypt message: {0}\")]\n    Decrypt(#[from] age::DecryptError),\n    #[error(\"decrypted message is not UTF-8 valid: {0}\")]\n    Io(#[from] std::string::FromUtf8Error),\n}\n\npub fn decrypt_with_passphrase(\n    encrypted_message: &[u8],\n    passphrase: &str,\n) -> Result<String, DecryptError> {\n    let passphrase = age::secrecy::SecretString::from(passphrase);\n    let identity = age::scrypt::Identity::new(passphrase);\n\n    let decrypted = age::decrypt(&identity, encrypted_message)?;\n    let decrypted = String::from_utf8(decrypted)?;\n\n    Ok(decrypted)\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/pattern.rs",
    "content": "use ecow::eco_format;\n\nuse crate::analyse::Inferred;\n\nuse super::*;\n\npub(super) struct PatternPrinter<'a, 'env> {\n    pub environment: &'env mut Env<'a>,\n    pub variables: Vec<&'a str>,\n    pub guards: Vec<Document<'a>>,\n    /// In case we're dealing with string patterns, we might have something like\n    /// this: `\"a\" as letter <> rest`. In this case we want to compile it to\n    /// `<<\"a\"/utf8, rest/binary>>` and then bind a variable to `\"a\"`.\n    /// This way it's easier for the erlang compiler to optimise the pattern\n    /// matching.\n    ///\n    /// Here we store a list of gleam variable name to its name used in the\n    /// Erlang code and its literal value.\n    pub assignments: Vec<StringPatternAssignment<'a>>,\n}\n\n/// This is used to hold data about string patterns with an alias like:\n/// `\"a\" as letter <> _`\npub struct StringPatternAssignment<'a> {\n    /// The name assigned to the pattern in the Gleam code:\n    ///\n    /// ```gleam\n    /// \"a\" as letter <> _\n    /// //     ^^^^^^ This one\n    /// ```\n    ///\n    pub gleam_name: EcoString,\n    /// The name we're using for that same variable in the generated Erlang\n    /// code, could have numbers added to it to make sure it's unique, like\n    /// `Letter@1`.\n    ///\n    pub erlang_name: Document<'a>,\n    /// The document representing the literal value of that variable. For\n    /// example, if we had this pattern `\"a\" <> letter` it's literal value in\n    /// Erlang is going to be a document with the following string\n    /// `<<\"a\"/utf8>>`.\n    ///\n    pub literal_value: Document<'a>,\n}\n\nimpl<'a> StringPatternAssignment<'a> {\n    pub fn to_assignment_doc(&self) -> Document<'a> {\n        docvec![self.erlang_name.clone(), \" = \", self.literal_value.clone()]\n    }\n}\n\nimpl<'a, 'env> PatternPrinter<'a, 'env> {\n    pub(super) fn new(environment: &'env mut Env<'a>) -> Self {\n        Self {\n            environment,\n            variables: vec![],\n            guards: vec![],\n            assignments: vec![],\n        }\n    }\n\n    pub(super) fn reset_variables(&mut self) {\n        self.variables = vec![];\n    }\n\n    pub(super) fn print(&mut self, pattern: &'a TypedPattern) -> Document<'a> {\n        match pattern {\n            Pattern::Assign { name, pattern, .. } => {\n                self.variables.push(name);\n                self.print(pattern)\n                    .append(\" = \")\n                    .append(self.environment.next_local_var_name(name))\n            }\n\n            Pattern::List { elements, tail, .. } => self.pattern_list(elements, tail.as_deref()),\n\n            Pattern::Discard { .. } => \"_\".to_doc(),\n\n            Pattern::BitArraySize(size) => match size {\n                BitArraySize::Int { .. }\n                | BitArraySize::Variable { .. }\n                | BitArraySize::Block { .. } => self.bit_array_size(size),\n                BitArraySize::BinaryOperator { .. } => self.bit_array_size(size).surround(\"(\", \")\"),\n            },\n\n            Pattern::Variable { name, .. } => {\n                self.variables.push(name);\n                self.environment.next_local_var_name(name)\n            }\n\n            Pattern::Int { value, .. } => int(value),\n            Pattern::Float { value, .. } => float(value),\n            Pattern::String { value, .. } => string(value),\n\n            Pattern::Constructor {\n                arguments,\n                constructor: Inferred::Known(PatternConstructor { name, .. }),\n                ..\n            } => self.tag_tuple_pattern(name, arguments),\n\n            Pattern::Constructor {\n                constructor: Inferred::Unknown,\n                ..\n            } => {\n                panic!(\"Erlang generation performed with uninferred pattern constructor\")\n            }\n\n            Pattern::Tuple { elements, .. } => {\n                tuple(elements.iter().map(|pattern| self.print(pattern)))\n            }\n\n            Pattern::BitArray { segments, .. } => bit_array(\n                segments\n                    .iter()\n                    .map(|s| self.pattern_segment(&s.value, &s.options)),\n            ),\n\n            Pattern::StringPrefix {\n                left_side_string,\n                right_side_assignment,\n                left_side_assignment,\n                ..\n            } => {\n                let right = match right_side_assignment {\n                    AssignName::Variable(right) => {\n                        self.variables.push(right);\n                        self.environment.next_local_var_name(right)\n                    }\n                    AssignName::Discard(_) => \"_\".to_doc(),\n                };\n\n                if let Some((left_name, _)) = left_side_assignment {\n                    // \"wibble\" as prefix <> rest\n                    //             ^^^^^^^^^ In case the left prefix of the pattern matching is given an alias\n                    //                       we bind it to a local variable so that it can be correctly\n                    //                       referenced inside the case branch.\n                    //\n                    // So we will end up with something that looks like this:\n                    //\n                    // <<\"wibble\"/binary, Rest/binary>> ->\n                    //     Prefix = \"wibble\",\n                    //     ...\n                    //\n                    self.variables.push(left_name);\n\n                    self.assignments.push(StringPatternAssignment {\n                        gleam_name: left_name.clone(),\n                        erlang_name: self.environment.next_local_var_name(left_name),\n                        literal_value: string(left_side_string),\n                    });\n                }\n\n                docvec![\n                    \"<<\\\"\",\n                    string_inner(left_side_string),\n                    \"\\\"/utf8\",\n                    \", \",\n                    right,\n                    \"/binary>>\"\n                ]\n            }\n\n            Pattern::Invalid { .. } => panic!(\"invalid patterns should not reach code generation\"),\n        }\n    }\n\n    fn bit_array_size(&mut self, size: &'a TypedBitArraySize) -> Document<'a> {\n        match size {\n            BitArraySize::Int { value, .. } => int(value),\n            BitArraySize::Block { inner, .. } => self.bit_array_size(inner).surround(\"(\", \")\"),\n            BitArraySize::Variable {\n                name, constructor, ..\n            } => {\n                let variant = &constructor\n                    .as_ref()\n                    .expect(\"Constructor not found for variable usage\")\n                    .variant;\n                match variant {\n                    ValueConstructorVariant::ModuleConstant { literal, .. } => {\n                        const_inline(literal, self.environment)\n                    }\n                    ValueConstructorVariant::LocalVariable { .. }\n                    | ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::Record { .. } => {\n                        self.environment.local_var_name(name)\n                    }\n                }\n            }\n            BitArraySize::BinaryOperator {\n                operator,\n                left,\n                right,\n                ..\n            } => {\n                let operator = match operator {\n                    IntOperator::Add => \" + \",\n                    IntOperator::Subtract => \" - \",\n                    IntOperator::Multiply => \" * \",\n                    IntOperator::Divide => {\n                        return self.bit_array_size_divide(left, right, \"div\");\n                    }\n                    IntOperator::Remainder => {\n                        return self.bit_array_size_divide(left, right, \"rem\");\n                    }\n                };\n\n                docvec![\n                    self.bit_array_size(left),\n                    operator,\n                    self.bit_array_size(right)\n                ]\n            }\n        }\n    }\n\n    fn bit_array_size_divide(\n        &mut self,\n        left: &'a TypedBitArraySize,\n        right: &'a TypedBitArraySize,\n        operator: &'static str,\n    ) -> Document<'a> {\n        if right.non_zero_compile_time_number() {\n            return self.bit_array_size_operator(left, operator, right);\n        }\n\n        let left = self.bit_array_size(left);\n        let right = self.bit_array_size(right);\n        let denominator = self.environment.next_local_var_name(\"gleam@denominator\");\n        let clauses = docvec![\n            line(),\n            \"0 -> 0;\",\n            line(),\n            denominator.clone(),\n            \" -> \",\n            binop_documents(left, operator, denominator)\n        ];\n        docvec![\"case \", right, \" of\", clauses.nest(INDENT), line(), \"end\"]\n    }\n\n    fn bit_array_size_operator(\n        &mut self,\n        left: &'a TypedBitArraySize,\n        operator: &'static str,\n        right: &'a TypedBitArraySize,\n    ) -> Document<'a> {\n        let left = if let BitArraySize::BinaryOperator { .. } = left {\n            self.bit_array_size(left).surround(\"(\", \")\")\n        } else {\n            self.bit_array_size(left)\n        };\n        let right = if let BitArraySize::BinaryOperator { .. } = right {\n            self.bit_array_size(right).surround(\"(\", \")\")\n        } else {\n            self.bit_array_size(right)\n        };\n        binop_documents(left, operator, right)\n    }\n\n    fn tag_tuple_pattern(\n        &mut self,\n        name: &'a str,\n        arguments: &'a [CallArg<TypedPattern>],\n    ) -> Document<'a> {\n        if arguments.is_empty() {\n            atom_string(to_snake_case(name))\n        } else {\n            tuple(\n                [atom_string(to_snake_case(name))]\n                    .into_iter()\n                    .chain(arguments.iter().map(|argument| self.print(&argument.value))),\n            )\n        }\n    }\n\n    fn pattern_list(\n        &mut self,\n        elements: &'a [TypedPattern],\n        tail: Option<&'a TypedTailPattern>,\n    ) -> Document<'a> {\n        let elements = join(\n            elements.iter().map(|element| self.print(element)),\n            break_(\",\", \", \"),\n        );\n        let tail = tail.map(|tail| self.print(&tail.pattern));\n        list(elements, tail)\n    }\n\n    fn pattern_segment(\n        &mut self,\n        value: &'a TypedPattern,\n        options: &'a [BitArrayOption<TypedPattern>],\n    ) -> Document<'a> {\n        let pattern_is_a_string_literal = matches!(value, Pattern::String { .. });\n        let pattern_is_a_discard = matches!(value, Pattern::Discard { .. });\n\n        let create_document = |this: &mut PatternPrinter<'a, 'env>| match value {\n            Pattern::String { value, .. } => string_inner(value).surround(\"\\\"\", \"\\\"\"),\n            Pattern::Discard { .. }\n            | Pattern::Variable { .. }\n            | Pattern::Int { .. }\n            | Pattern::Float { .. } => this.print(value),\n\n            Pattern::Assign { name, pattern, .. } => {\n                this.variables.push(name);\n                let variable_name = this.environment.next_local_var_name(name);\n\n                match pattern.as_ref() {\n                    // In Erlang, assignment patterns inside bit arrays are not allowed. So instead of\n                    // generating `<<1 = A>>`, we  use guards, and generate `<<A>> when A =:= 1`.\n                    Pattern::Int { value, .. } => {\n                        this.guards\n                            .push(docvec![variable_name.clone(), \" =:= \", int(value)]);\n                        variable_name\n                    }\n                    Pattern::Float { value, .. } => {\n                        this.guards\n                            .push(docvec![variable_name.clone(), \" =:= \", float(value)]);\n                        variable_name\n                    }\n\n                    // Here we do the same as for floats and ints, but we must calculate the size of\n                    // the string first, so we can correctly match the bit array segment then compare\n                    // it afterwards.\n                    Pattern::String { value, .. } => {\n                        this.guards\n                            .push(docvec![variable_name.clone(), \" =:= \", string(value)]);\n                        docvec![variable_name, \":\", string_length_utf8_bytes(value)]\n                    }\n\n                    // Doing a pattern such as `<<_ as a>>` is the same as just `<<a>>`, so we treat it\n                    // as such.\n                    Pattern::Discard { .. } => variable_name,\n\n                    // Any other pattern is invalid as a bit array segment. We already handle the case\n                    // of `<<a as b>>` in the type-checker, and assignment patterns cannot be nested.\n                    Pattern::Variable { .. }\n                    | Pattern::BitArraySize(_)\n                    | Pattern::Assign { .. }\n                    | Pattern::List { .. }\n                    | Pattern::Constructor { .. }\n                    | Pattern::Tuple { .. }\n                    | Pattern::BitArray { .. }\n                    | Pattern::StringPrefix { .. }\n                    | Pattern::Invalid { .. } => panic!(\"Pattern segment match not recognised\"),\n                }\n            }\n\n            Pattern::BitArraySize(_)\n            | Pattern::List { .. }\n            | Pattern::Constructor { .. }\n            | Pattern::Tuple { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => panic!(\"Pattern segment match not recognised\"),\n        };\n\n        let size = |value: &'a TypedPattern, this: &mut PatternPrinter<'a, 'env>| {\n            Some(\":\".to_doc().append(this.print(value)))\n        };\n\n        let unit = |value: &'a u8| Some(eco_format!(\"unit:{value}\").to_doc());\n\n        bit_array_segment(\n            create_document,\n            options,\n            size,\n            unit,\n            pattern_is_a_string_literal,\n            pattern_is_a_discard,\n            self,\n        )\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__allowed_string_escapes.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn a() { \\\"\\\\n\\\" \\\"\\\\r\\\" \\\"\\\\t\\\" \\\"\\\\\\\\\\\" \\\"\\\\\\\"\\\" \\\"\\\\\\\\^\\\" }\"\n---\n----- SOURCE CODE\npub fn a() { \"\\n\" \"\\r\" \"\\t\" \"\\\\\" \"\\\"\" \"\\\\^\" }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a() -> binary().\na() ->\n    <<\"\\n\"/utf8>>,\n    <<\"\\r\"/utf8>>,\n    <<\"\\t\"/utf8>>,\n    <<\"\\\\\"/utf8>>,\n    <<\"\\\"\"/utf8>>,\n    <<\"\\\\^\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__binop_parens.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n    let a = 2 * {3 + 1} / 2\\n    let b = 5 + 3 / 3 * 2 - 6 * 4\\n    b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let a = 2 * {3 + 1} / 2\n    let b = 5 + 3 / 3 * 2 - 6 * 4\n    b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    A = (2 * (3 + 1)) div 2,\n    B = (5 + ((3 div 3) * 2)) - (6 * 4),\n    B.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__bit_pattern_shadowing.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n  let code = <<\\\"hello world\\\":utf8>>\\n  let pre = 1\\n  case code {\\n    <<pre:bytes-size(pre), _:bytes>> -> pre\\n    _ -> panic\\n  }\\n}        \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let code = <<\"hello world\":utf8>>\n  let pre = 1\n  case code {\n    <<pre:bytes-size(pre), _:bytes>> -> pre\n    _ -> panic\n  }\n}        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    Code = <<\"hello world\"/utf8>>,\n    Pre = 1,\n    case Code of\n        <<Pre@1:Pre/binary, _/binary>> ->\n            Pre@1;\n\n        _ ->\n            erlang:error(#{gleam_error => panic,\n                    message => <<\"`panic` expression evaluated.\"/utf8>>,\n                    file => <<?FILEPATH/utf8>>,\n                    module => <<\"my/mod\"/utf8>>,\n                    function => <<\"main\"/utf8>>,\n                    line => 7})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__block_assignment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n  let x = {\\n    1\\n    2\\n  }\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = {\n    1\n    2\n  }\n  x\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = begin\n        1,\n        2\n    end,\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub const module_info = 1\\n\\npub fn main() {\\n    module_info\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const module_info = 1\n\npub fn main() {\n    module_info\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module\\n\\npub fn main() {\\n    some_module.module_info\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module\n\npub fn main() {\n    some_module.module_info\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported_qualified.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module.{module_info}\\n\\npub fn main() {\\n    module_info\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module.{module_info}\n\npub fn main() {\n    module_info\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn function() {\\n    1\\n}\\n\\npub const module_info = function\\n\\npub fn main() {\\n    module_info()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn function() {\n    1\n}\n\npub const module_info = function\n\npub fn main() {\n    module_info()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([function/0, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec function() -> integer().\nfunction() ->\n    1.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main() -> integer().\nmain() ->\n    function().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module\\n\\npub fn main() {\\n    some_module.module_info()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module\n\npub fn main() {\n    some_module.module_info()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    fun some_module:function/0().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported_qualified.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module.{module_info}\\n\\npub fn main() {\\n    module_info()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module.{module_info}\n\npub fn main() {\n    module_info()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    some_module:function().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__discard_in_assert.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn x(y) {\\n  let assert Ok(_) = y\\n  1\\n}\"\n---\n----- SOURCE CODE\npub fn x(y) {\n  let assert Ok(_) = y\n  1\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x({ok, any()} | {error, any()}) -> integer().\nx(Y) ->\n    case Y of\n        {ok, _} -> nil;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"x\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 36,\n                        pattern_start => 27,\n                        pattern_end => 32})\n    end,\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__dynamic.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: pub type Dynamic\n---\n----- SOURCE CODE\npub type Dynamic\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([dynamic_/0]).\n\n-type dynamic_() :: any().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub type FnBox {\\n  FnBox(f: fn(Int) -> Int)\\n}\\n\\npub fn main() {\\n    let b = FnBox(f: fn(x) { x })\\n    b.f(5)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type FnBox {\n  FnBox(f: fn(Int) -> Int)\n}\n\npub fn main() {\n    let b = FnBox(f: fn(x) { x })\n    b.f(5)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([fn_box/0]).\n\n-type fn_box() :: {fn_box, fun((integer()) -> integer())}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    B = {fn_box, fun(X) -> X end},\n    (erlang:element(2, B))(5).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n    let t = #(fn(x) { x })\\n\\n    t.0(5)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let t = #(fn(x) { x })\n\n    t.0(5)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    T = {fun(X) -> X end},\n    (erlang:element(1, T))(5).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_non_zero.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n  1.0 /. 2.0\\n}        \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1.0 /. 2.0\n}        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> float().\nmain() ->\n    1.0 / 2.0.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_zero.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n  1.0 /. 0.0\\n}        \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1.0 /. 0.0\n}        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> float().\nmain() ->\n    +0.0.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_argument_shadowing.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn main(a) {\\n  Box\\n}\\n\\npub type Box {\\n  Box(Int)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(a) {\n  Box\n}\n\npub type Box {\n  Box(Int)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n-export_type([box/0]).\n\n-type box() :: {box, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main(any()) -> fun((integer()) -> box()).\nmain(A) ->\n    fun(Field@0) -> {box, Field@0} end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn module_info() {\\n    1\\n}\\n\\npub fn main() {\\n    module_info()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn module_info() {\n    1\n}\n\npub fn main() {\n    module_info()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export(['moduleInfo'/0, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec 'moduleInfo'() -> integer().\n'moduleInfo'() ->\n    1.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    'moduleInfo'().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module\\n\\npub fn main() {\\n    some_module.module_info()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module\n\npub fn main() {\n    some_module.module_info()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    some_module:'moduleInfo'().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported_qualified.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module.{module_info}\\n\\npub fn main() {\\n    module_info()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module.{module_info}\n\npub fn main() {\n    module_info()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    some_module:'moduleInfo'().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn module_info() {\\n    1\\n}\\n\\npub const constant = module_info\\n\\npub fn main() {\\n    constant()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn module_info() {\n    1\n}\n\npub const constant = module_info\n\npub fn main() {\n    constant()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export(['moduleInfo'/0, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec 'moduleInfo'() -> integer().\n'moduleInfo'() ->\n    1.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main() -> integer().\nmain() ->\n    'moduleInfo'().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module\\n\\npub fn main() {\\n    some_module.constant()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module\n\npub fn main() {\n    some_module.constant()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    fun some_module:'moduleInfo'/0().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported_qualified.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nimport some_module.{constant}\\n\\npub fn main() {\\n    constant()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some_module.{constant}\n\npub fn main() {\n    constant()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    some_module:'moduleInfo'().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__guard_variable_rewriting.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn main() {\\n  case 1.0 {\\n    a if a <. 0.0 -> {\\n      let a = a\\n      a\\n    }\\n    _ -> 0.0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  case 1.0 {\n    a if a <. 0.0 -> {\n      let a = a\n      a\n    }\n    _ -> 0.0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main() -> float().\nmain() ->\n    case 1.0 of\n        A when A < +0.0 ->\n            A@1 = A,\n            A@1;\n\n        _ ->\n            +0.0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__inline_const_pattern_option.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn main() {\\n            let fifteen = 15\\n            let x = <<5:size(sixteen)>>\\n            case x {\\n              <<5:size(sixteen)>> -> <<5:size(sixteen)>>\\n              <<6:size(fifteen)>> -> <<5:size(fifteen)>>\\n              _ -> <<>>\\n            }\\n          }\\n\\n          pub const sixteen = 16\"\n---\n----- SOURCE CODE\npub fn main() {\n            let fifteen = 15\n            let x = <<5:size(sixteen)>>\n            case x {\n              <<5:size(sixteen)>> -> <<5:size(sixteen)>>\n              <<6:size(fifteen)>> -> <<5:size(fifteen)>>\n              _ -> <<>>\n            }\n          }\n\n          pub const sixteen = 16\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main() -> bitstring().\nmain() ->\n    Fifteen = 15,\n    X = <<5:(lists:max([(16), 0]))>>,\n    case X of\n        <<5:16>> ->\n            <<5:(lists:max([(16), 0]))>>;\n\n        <<6:Fifteen>> ->\n            <<5:(lists:max([(Fifteen), 0]))>>;\n\n        _ ->\n            <<>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn go() {\\nlet x = #(100000000000000000, #(2000000000, 3000000000000, 40000000000), 50000, 6000000000)\\n  x\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\nlet x = #(100000000000000000, #(2000000000, 3000000000000, 40000000000), 50000, 6000000000)\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> {integer(),\n    {integer(), integer(), integer()},\n    integer(),\n    integer()}.\ngo() ->\n    X = {100000000000000000,\n        {2000000000, 3000000000000, 40000000000},\n        50000,\n        6000000000},\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn go() {\\n  let y = 1\\n  let y = 2\\n  y\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let y = 1\n  let y = 2\n  y\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    Y = 1,\n    Y@1 = 2,\n    Y@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn go() {\\n    let fifteen = 0xF\\n    let nine = 0o11\\n    let ten = 0b1010\\n  fifteen\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n    let fifteen = 0xF\n    let nine = 0o11\n    let ten = 0b1010\n  fifteen\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    Fifteen = 16#F,\n    Nine = 8#11,\n    Ten = 2#1010,\n    Fifteen.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn go() {\\n  let y = 1\\n  let y = 2\\n  y\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let y = 1\n  let y = 2\n  y\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    Y = 1,\n    Y@1 = 2,\n    Y@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn t() { True }\"\n---\n----- SOURCE CODE\npub fn t() { True }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([t/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec t() -> boolean().\nt() ->\n    true.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test10.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type Null { Null }\\npub fn x() { Null }\"\n---\n----- SOURCE CODE\npub type Null { Null }\npub fn x() { Null }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n-export_type([null/0]).\n\n-type null() :: null.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec x() -> null().\nx() ->\n    null.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test11.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type Point { Point(x: Int, y: Int) }\\npub fn x() { Point(x: 4, y: 6) Point(y: 1, x: 9) }\"\n---\n----- SOURCE CODE\npub type Point { Point(x: Int, y: Int) }\npub fn x() { Point(x: 4, y: 6) Point(y: 1, x: 9) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n-export_type([point/0]).\n\n-type point() :: {point, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec x() -> point().\nx() ->\n    {point, 4, 6},\n    {point, 9, 1}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test12.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type Point { Point(x: Int, y: Int) }\\npub fn x(y) { let Point(a, b) = y a }\"\n---\n----- SOURCE CODE\npub type Point { Point(x: Int, y: Int) }\npub fn x(y) { let Point(a, b) = y a }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/1]).\n-export_type([point/0]).\n\n-type point() :: {point, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec x(point()) -> integer().\nx(Y) ->\n    {point, A, B} = Y,\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test13.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type State{ Start(Int) End(Int) }\\n            pub fn build(constructor : fn(Int) -> a) -> a { constructor(1) }\\n            pub fn main() { build(End) }\"\n---\n----- SOURCE CODE\npub type State{ Start(Int) End(Int) }\n            pub fn build(constructor : fn(Int) -> a) -> a { constructor(1) }\n            pub fn main() { build(End) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([build/1, main/0]).\n-export_type([state/0]).\n\n-type state() :: {start, integer()} | {'end', integer()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec build(fun((integer()) -> I)) -> I.\nbuild(Constructor) ->\n    Constructor(1).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> state().\nmain() ->\n    build(fun(Field@0) -> {'end', Field@0} end).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test16.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"fn go(x xx, y yy) { xx }\\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\"\n---\n----- SOURCE CODE\nfn go(x xx, y yy) { xx }\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go(I, any()) -> I.\ngo(Xx, Yy) ->\n    Xx.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec x() -> integer().\nx() ->\n    go(1, 2),\n    go(4, 3).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test17.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub type User { User(id: Int, name: String, age: Int) }\\npub fn create_user(user_id) { User(age: 22, id: user_id, name: \\\"\\\") }\\n\"\n---\n----- SOURCE CODE\n\npub type User { User(id: Int, name: String, age: Int) }\npub fn create_user(user_id) { User(age: 22, id: user_id, name: \"\") }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([create_user/1]).\n-export_type([user/0]).\n\n-type user() :: {user, integer(), binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec create_user(integer()) -> user().\ncreate_user(User_id) ->\n    {user, User_id, <<\"\"/utf8>>, 22}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test18.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn run() { case 1, 2 { a, b -> a } }\"\n---\n----- SOURCE CODE\npub fn run() { case 1, 2 { a, b -> a } }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([run/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec run() -> integer().\nrun() ->\n    case {1, 2} of\n        {A, B} ->\n            A\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test19.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type X { X(x: Int, y: Float) }\\npub fn x() { X(x: 1, y: 2.) X(y: 3., x: 4) }\"\n---\n----- SOURCE CODE\npub type X { X(x: Int, y: Float) }\npub fn x() { X(x: 1, y: 2.) X(y: 3., x: 4) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n-export_type([x/0]).\n\n-type x() :: {x, integer(), float()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec x() -> x().\nx() ->\n    {x, 1, 2.0},\n    {x, 4, 3.0}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type Money { Pound(Int) }\\npub fn pound(x) { Pound(x) }\"\n---\n----- SOURCE CODE\npub type Money { Pound(Int) }\npub fn pound(x) { Pound(x) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([pound/1]).\n-export_type([money/0]).\n\n-type money() :: {pound, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec pound(integer()) -> money().\npound(X) ->\n    {pound, X}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn loop() { loop() }\"\n---\n----- SOURCE CODE\npub fn loop() { loop() }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([loop/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec loop() -> any().\nloop() ->\n    loop().\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_4.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"fn inc(x) { x + 1 }\\n                    pub fn go() { 1 |> inc |> inc |> inc }\"\n---\n----- SOURCE CODE\nfn inc(x) { x + 1 }\n                    pub fn go() { 1 |> inc |> inc |> inc }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec inc(integer()) -> integer().\ninc(X) ->\n    X + 1.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go() -> integer().\ngo() ->\n    _pipe = 1,\n    _pipe@1 = inc(_pipe),\n    _pipe@2 = inc(_pipe@1),\n    inc(_pipe@2).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_5.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"fn add(x, y) { x + y }\\n                    pub fn go() { 1 |> add(_, 1) |> add(2, _) |> add(_, 3) }\"\n---\n----- SOURCE CODE\nfn add(x, y) { x + y }\n                    pub fn go() { 1 |> add(_, 1) |> add(2, _) |> add(_, 3) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec add(integer(), integer()) -> integer().\nadd(X, Y) ->\n    X + Y.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go() -> integer().\ngo() ->\n    _pipe = 1,\n    _pipe@1 = add(_pipe, 1),\n    _pipe@2 = add(2, _pipe@1),\n    add(_pipe@2, 3).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_6.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn and(x, y) { x && y }\\npub fn or(x, y) { x || y }\\npub fn remainder(x, y) { x % y }\\npub fn fdiv(x, y) { x /. y }\\n            \"\n---\n----- SOURCE CODE\npub fn and(x, y) { x && y }\npub fn or(x, y) { x || y }\npub fn remainder(x, y) { x % y }\npub fn fdiv(x, y) { x /. y }\n            \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export(['and'/2, 'or'/2, remainder/2, fdiv/2]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec 'and'(boolean(), boolean()) -> boolean().\n'and'(X, Y) ->\n    X andalso Y.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec 'or'(boolean(), boolean()) -> boolean().\n'or'(X, Y) ->\n    X orelse Y.\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec remainder(integer(), integer()) -> integer().\nremainder(X, Y) ->\n    case Y of\n        0 -> 0;\n        Gleam@denominator -> X rem Gleam@denominator\n    end.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec fdiv(float(), float()) -> float().\nfdiv(X, Y) ->\n    case Y of\n        +0.0 -> +0.0;\n        -0.0 -> -0.0;\n        Gleam@denominator -> X / Gleam@denominator\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn second(list) { case list { [x, y] -> y z -> 1 } }\\npub fn tail(list) { case list { [x, ..xs] -> xs z -> list } }\\n            \"\n---\n----- SOURCE CODE\npub fn second(list) { case list { [x, y] -> y z -> 1 } }\npub fn tail(list) { case list { [x, ..xs] -> xs z -> list } }\n            \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([second/1, tail/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec second(list(integer())) -> integer().\nsecond(List) ->\n    case List of\n        [X, Y] ->\n            Y;\n\n        Z ->\n            1\n    end.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec tail(list(P)) -> list(P).\ntail(List) ->\n    case List of\n        [X | Xs] ->\n            Xs;\n\n        Z ->\n            List\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test20.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn go(a) {\\n  let a = a + 1\\n  a\\n}\\n\\n                    \"\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  let a = a + 1\n  a\n}\n\n                    \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(integer()) -> integer().\ngo(A) ->\n    A@1 = A + 1,\n    A@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test21.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn go(a) {\\n  let a = 1\\n  a\\n}\\n\\n                    \"\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  let a = 1\n  a\n}\n\n                    \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(any()) -> integer().\ngo(A) ->\n    A@1 = 1,\n    A@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test22.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn factory(f, i) {\\n  f(i)\\n}\\n\\npub type Box {\\n  Box(i: Int)\\n}\\n\\npub fn main() {\\n  factory(Box, 0)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn factory(f, i) {\n  f(i)\n}\n\npub type Box {\n  Box(i: Int)\n}\n\npub fn main() {\n  factory(Box, 0)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([factory/2, main/0]).\n-export_type([box/0]).\n\n-type box() :: {box, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec factory(fun((J) -> N), J) -> N.\nfactory(F, I) ->\n    F(I).\n\n-file(\"project/test/my/mod.gleam\", 10).\n-spec main() -> box().\nmain() ->\n    factory(fun(Field@0) -> {box, Field@0} end, 0).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test23.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main(args) {\\n  case args {\\n    _ -> {\\n      let a = 1\\n      a\\n    }\\n  }\\n  let a = 2\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(args) {\n  case args {\n    _ -> {\n      let a = 1\n      a\n    }\n  }\n  let a = 2\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(any()) -> integer().\nmain(Args) ->\n    case Args of\n        _ ->\n            A = 1,\n            A\n    end,\n    A@1 = 2,\n    A@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type Point { Point(x: Int, y: Int) }\\npub fn y() { fn() { Point }()(4, 6) }\"\n---\n----- SOURCE CODE\npub type Point { Point(x: Int, y: Int) }\npub fn y() { fn() { Point }()(4, 6) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([y/0]).\n-export_type([point/0]).\n\n-type point() :: {point, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec y() -> point().\ny() ->\n    {point, 4, 6}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test5.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn tail(list) {\\n  case list {\\n    [x, ..] -> x\\n    _ -> 0\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn tail(list) {\n  case list {\n    [x, ..] -> x\n    _ -> 0\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([tail/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec tail(list(integer())) -> integer().\ntail(List) ->\n    case List of\n        [X | _] ->\n            X;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test6.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn x() { let x = 1 let x = x + 1 x }\"\n---\n----- SOURCE CODE\npub fn x() { let x = 1 let x = x + 1 x }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x() -> integer().\nx() ->\n    X = 1,\n    X@1 = X + 1,\n    X@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test8.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn x() { 1. <. 2.3 }\"\n---\n----- SOURCE CODE\npub fn x() { 1. <. 2.3 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x() -> boolean().\nx() ->\n    1.0 < 2.3.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test9.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type Pair(x, y) { Pair(x: x, y: y) } pub fn x() { Pair(1, 2) Pair(3., 4.) }\"\n---\n----- SOURCE CODE\npub type Pair(x, y) { Pair(x: x, y: y) } pub fn x() { Pair(1, 2) Pair(3., 4.) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n-export_type([pair/2]).\n\n-type pair(I, J) :: {pair, I, J}.\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x() -> pair(float(), float()).\nx() ->\n    {pair, 1, 2},\n    {pair, 3.0, 4.0}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type X { Div }\"\n---\n----- SOURCE CODE\npub type X { Div }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([x/0]).\n\n-type x() :: 'div'.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub type X { Fun(Int) }\"\n---\n----- SOURCE CODE\npub type X { Fun(Int) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([x/0]).\n\n-type x() :: {'fun', integer()}.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn negate(x) {\\n  !x\\n}\"\n---\n----- SOURCE CODE\npub fn negate(x) {\n  !x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([negate/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec negate(boolean()) -> boolean().\nnegate(X) ->\n    not X.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn negate(x) {\\n  !{\\n    123\\n    x\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn negate(x) {\n  !{\n    123\n    x\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([negate/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec negate(boolean()) -> boolean().\nnegate(X) ->\n    not begin\n        123,\n        X\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__operator_pipe_right_hand_side.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"fn id(x) {\\n  x\\n}\\n\\npub fn bool_expr(x, y) {\\n  y || x |> id\\n}\"\n---\n----- SOURCE CODE\nfn id(x) {\n  x\n}\n\npub fn bool_expr(x, y) {\n  y || x |> id\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([bool_expr/2]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec id(I) -> I.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec bool_expr(boolean(), boolean()) -> boolean().\nbool_expr(X, Y) ->\n    Y orelse begin\n        _pipe = X,\n        id(_pipe)\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__positive_zero.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n  0.0\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0.0\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> float().\nmain() ->\n    +0.0.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__recursive_type.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\nfn id(x) {\\n  x\\n}\\n\\npub fn main() {\\n  id(id)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn id(x) {\n  x\n}\n\npub fn main() {\n  id(id)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec id(I) -> I.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> fun((M) -> M).\nmain() ->\n    id(fun id/1).\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__scientific_notation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n  1.0e6\\n  1.e6\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1.0e6\n  1.e6\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> float().\nmain() ->\n    1.0e6,\n    1.0e6.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tail_maybe_expr_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn a() {\\n  let fake_tap = fn(x) { x }\\n  let b = [99]\\n  [\\n    1,\\n    2,\\n    ..b\\n    |> fake_tap\\n  ]\\n}\\n\"\n---\n----- SOURCE CODE\npub fn a() {\n  let fake_tap = fn(x) { x }\n  let b = [99]\n  [\n    1,\n    2,\n    ..b\n    |> fake_tap\n  ]\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a() -> list(integer()).\na() ->\n    Fake_tap = fun(X) -> X end,\n    B = [99],\n    [1,\n        2 |\n        begin\n            _pipe = B,\n            Fake_tap(_pipe)\n        end].\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tuple_access_in_guard.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub fn main() {\\n    let key = 10\\n    let x = [#(10, 2), #(1, 2)]\\n    case x {\\n        [first, ..rest] if first.0 == key -> \\\"ok\\\"\\n        _ -> \\\"ko\\\"\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let key = 10\n    let x = [#(10, 2), #(1, 2)]\n    case x {\n        [first, ..rest] if first.0 == key -> \"ok\"\n        _ -> \"ko\"\n    }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> binary().\nmain() ->\n    Key = 10,\n    X = [{10, 2}, {1, 2}],\n    case X of\n        [First | Rest] when erlang:element(1, First) =:= Key ->\n            <<\"ok\"/utf8>>;\n\n        _ ->\n            <<\"ko\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_else.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub type Else {\\n  Else\\n}\\n\\npub fn main() {\\n  Else\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Else {\n  Else\n}\n\npub fn main() {\n  Else\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type(['else'/0]).\n\n-type 'else'() :: 'else'.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> 'else'().\nmain() ->\n    'else'.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_module_info.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"\\npub type ModuleInfo {\\n    ModuleInfo\\n}\\n\\npub fn main() {\\n    ModuleInfo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type ModuleInfo {\n    ModuleInfo\n}\n\npub fn main() {\n    ModuleInfo\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([module_info/0]).\n\n-type module_info() :: module_info.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> module_info().\nmain() ->\n    module_info.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__variable_name_underscores_preserved.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn a(name_: String) -> String {\\n    let name__ = name_\\n    let name = name__\\n    let one_1 = 1\\n    let one1 = one_1\\n    name\\n}\"\n---\n----- SOURCE CODE\npub fn a(name_: String) -> String {\n    let name__ = name_\n    let name = name__\n    let one_1 = 1\n    let one1 = one_1\n    name\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a(binary()) -> binary().\na(Name_) ->\n    Name__ = Name_,\n    Name = Name__,\n    One_1 = 1,\n    One1 = One_1,\n    Name.\n"
  },
  {
    "path": "compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__windows_file_escaping_bug.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests.rs\nexpression: \"pub fn main() { Nil }\"\n---\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"C:\\\\root\\\\project\\\\test\\\\my\\\\mod.gleam\").\n-export([main/0]).\n\n-file(\"C:\\\\root\\\\project\\\\test\\\\my\\\\mod.gleam\", 1).\n-spec main() -> nil.\nmain() ->\n    nil.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/assert.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn assert_variable() {\n    assert_erl!(\n        \"\npub fn main() {\n  let x = True\n  assert x\n}\n\"\n    );\n}\n\n#[test]\nfn assert_literal() {\n    assert_erl!(\n        \"\npub fn main() {\n  assert False\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operation() {\n    assert_erl!(\n        \"\npub fn main() {\n  let x = True\n  assert x || False\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operation2() {\n    assert_erl!(\n        \"\npub fn eq(a, b) {\n  assert a == b\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operation3() {\n    assert_erl!(\n        \"\npub fn assert_answer(x) {\n  assert x == 42\n}\n\"\n    );\n}\n\n#[test]\nfn assert_function_call() {\n    assert_erl!(\n        \"\nfn bool() {\n  True\n}\n\npub fn main() {\n  assert bool()\n}\n\"\n    );\n}\n\n#[test]\nfn assert_function_call2() {\n    assert_erl!(\n        \"\nfn and(a, b) {\n  a && b\n}\n\npub fn go(x) {\n  assert and(True, x)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_nested_function_call() {\n    assert_erl!(\n        \"\nfn and(x, y) {\n  x && y\n}\n\npub fn main() {\n  assert and(and(True, False), True)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operator_with_side_effects() {\n    assert_erl!(\n        \"\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert True && wibble(1, 4)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operator_with_side_effects2() {\n    assert_erl!(\n        \"\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert wibble(5, 5) && wibble(4, 6)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_with_message() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  assert True as \"This shouldn't fail\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_with_block_message() {\n    assert_erl!(\n        r#\"\nfn identity(a) {\n  a\n}\n\npub fn main() {\n  assert identity(True) as {\n    let message = identity(\"This shouldn't fail\")\n    message\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/bit_arrays.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn bit_array() {\n    assert_erl!(\n        r#\"pub fn main() {\n  let a = 1\n  let simple = <<1, a>>\n  let complex = <<4:int-big, 5.0:little-float, 6:native-int>>\n  let assert <<7:2, 8:size(3), b:bytes-size(4)>> = <<1>>\n  let assert <<c:8-unit(1), d:bytes-size(2)-unit(2)>> = <<1>>\n\n  simple\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_float() {\n    assert_erl!(\n        r#\"pub fn main() {\n  let b = 16\n  let floats = <<1.0:16-float, 5.0:float-32, 6.0:float-64-little, 1.0:float-size(b)>>\n  let assert <<1.0:16-float, 5.0:float-32, 6.0:float-64-little, 1.0:float-size(b)>> = floats\n}\"#\n    );\n}\n\n#[test]\nfn bit_array1() {\n    assert_erl!(\n        r#\"pub fn x() { 2 }\npub fn main() {\n  let a = -1\n  let b = <<a:unit(2)-size(a * 2), a:size(3 + x())-unit(1)>>\n\n  b\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array2() {\n    assert_erl!(\n        r#\"pub fn main() {\n  let a = 1\n  let assert <<b, 1>> = <<1, a>>\n  b\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array3() {\n    assert_erl!(\n        r#\"pub fn main() {\n  let a = <<\"test\":utf8>>\n  let assert <<b:utf8_codepoint, \"st\":utf8>> = a\n  b\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array4() {\n    assert_erl!(\n        r#\"fn x() { 1 }\npub fn main() {\n  let a = <<x():int>>\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array5() {\n    assert_erl!(\n        r#\"const bit_size = 8\npub fn main() {\n  let a = <<10:size(bit_size)>>\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_discard() {\n    // https://github.com/gleam-lang/gleam/issues/704\n\n    assert_erl!(\n        r#\"\npub fn bit_array_discard(x) -> Bool {\n case x {\n  <<_:utf8, rest:bytes>> -> True\n   _ -> False\n }\n}\n                    \"#\n    );\n}\n\n#[test]\nfn bit_array_discard1() {\n    assert_erl!(\n        r#\"\npub fn bit_array_discard(x) -> Bool {\n case x {\n  <<_discardme:utf8, rest:bytes>> -> True\n   _ -> False\n }\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_declare_and_use_var() {\n    assert_erl!(\n        r#\"pub fn go(x) {\n  let assert <<name_size:8, name:bytes-size(name_size)>> = x\n  name\n}\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3050\n#[test]\nfn unicode_bit_array_1() {\n    assert_erl!(\n        r#\"\n    pub fn main() {\n        let emoji = \"\\u{1F600}\"\n        let arr = <<emoji:utf8>>\n}\"#\n    );\n}\n\n#[test]\nfn unicode_bit_array_2() {\n    assert_erl!(\n        r#\"\n    pub fn main() {\n        let arr = <<\"\\u{1F600}\":utf8>>\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_literal_string_constant_is_treated_as_utf8() {\n    assert_erl!(\n        r#\"\nconst a = <<\"hello\", \" \", \"world\">>\npub fn main() { a }\n\"#\n    );\n}\n\n#[test]\nfn bit_array_literal_string_is_treated_as_utf8() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  <<\"hello\", \" \", \"world\">>\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_literal_string_pattern_is_treated_as_utf8() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case <<>> {\n    <<\"a\", \"b\", _:bits>> -> 1\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn discard_utf8_pattern() {\n    assert_erl!(\n        r#\"\npub fn main() {\n    let assert <<_:utf8, rest:bits>> = <<>>\n}\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3944\n#[test]\nfn pipe_size_segment() {\n    assert_erl!(\n        \"\npub fn main() {\n  <<0xAE:size(5 |> identity)>>\n}\n\nfn identity(x) {\n  x\n}\n\"\n    );\n}\n\n#[test]\nfn utf16_codepoint_little_endian() {\n    assert_erl!(\n        \"\npub fn go(codepoint) {\n  <<codepoint:utf16_codepoint-little>>\n}\n\"\n    );\n}\n\n#[test]\nfn utf32_codepoint_little_endian() {\n    assert_erl!(\n        \"\npub fn go(codepoint) {\n  <<codepoint:utf32_codepoint-little>>\n}\n\"\n    );\n}\n\n#[test]\nfn pattern_match_utf16_codepoint_little_endian() {\n    assert_erl!(\n        \"\npub fn go(x) {\n  let assert <<codepoint:utf16_codepoint-little>> = x\n  codepoint\n}\n\"\n    );\n}\n\n#[test]\nfn pattern_match_utf32_codepoint_little_endian() {\n    assert_erl!(\n        \"\npub fn go(x) {\n  let assert <<codepoint:utf32_codepoint-little>> = x\n  codepoint\n}\n\"\n    );\n}\n\n#[test]\nfn operator_in_pattern_size() {\n    assert_erl!(\n        \"\npub fn main() {\n  let assert <<len, payload:size(len * 8 - 8)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn operator_in_pattern_size2() {\n    assert_erl!(\n        \"\npub fn main() {\n  let assert <<len, payload:size(len / 8 - 1)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn operator_in_pattern_size3() {\n    assert_erl!(\n        \"\npub fn main() {\n  let additional = 10\n  let assert <<len, payload:size(len + additional * 8)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn block_in_pattern_size() {\n    assert_erl!(\n        \"\npub fn main() {\n  let assert <<len, payload:size({ len - 1 } * 8)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn non_byte_aligned_size_calculation() {\n    assert_erl!(\n        \"\npub fn main() {\n  case <<>> {\n    <<a:1, b:3, c:size(b - 2)>> -> c + b\n    _ -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unicode_character_encoding_in_bit_array_pattern_segment() {\n    assert_erl!(\n        r#\"\npub fn main() -> Nil {\n  let wibble = <<\"\\u{00A9}wibble\":utf8>>\n  let _bits = case wibble {\n    <<\"\\u{00A9}\":utf8, rest: bits>> -> rest\n    _ -> wibble\n  }\n  Nil\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/case.rs",
    "content": "use crate::assert_erl;\n\n// https://github.com/gleam-lang/gleam/issues/1675\n#[test]\nfn alternative_pattern_variable_rewriting() {\n    assert_erl!(\n        \"\npub fn myfun(mt) {\n  case mt {\n    1 | _ ->\n      1\n      |> Ok\n  }\n  1\n  |> Ok\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2349\n#[test]\nfn positive_zero_pattern() {\n    assert_erl!(\n        \"\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    _ -> 2\n  }\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2349\n#[test]\nfn negative_zero_pattern() {\n    assert_erl!(\n        \"\npub fn main(x) {\n  case x {\n    -0.0 -> 1\n    _ -> 2\n  }\n}\n\"\n    )\n}\n\n#[test]\nfn not() {\n    assert_erl!(\n        r#\"pub fn main(x, y) {\n  case x {\n    _ if !y -> 0\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn not_two() {\n    assert_erl!(\n        r#\"pub fn main(x, y) {\n  case x {\n    _ if !y && !x -> 0\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2657\n#[test]\nfn spread_empty_list() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case [] {\n    [..] -> 1\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2657\n#[test]\nfn spread_empty_list_assigning() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case [] {\n    [..rest] -> rest\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5055\n#[test]\nfn alternative_patter_with_string_alias() {\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  case x {\n    \"a\" as letter <> _ | \"b\" as letter <> _ -> letter\n    _ -> \"wibble\"\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5115\n#[test]\nfn aliased_string_prefix_pattern_referenced_in_guard() {\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  case x {\n    \"a\" as letter <> _ if letter == x -> letter\n    _ -> \"wibble\"\n  }\n}\n\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/conditional_compilation.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn excluded_attribute_syntax() {\n    assert_erl!(\n        \"@target(javascript)\n  pub fn main() { 1 }\n\"\n    );\n}\n\n#[test]\nfn included_attribute_syntax() {\n    assert_erl!(\n        \"@target(erlang)\n  pub fn main() { 1 }\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/consts.rs",
    "content": "use crate::assert_erl;\n\n// https://github.com/gleam-lang/gleam/issues/2163\n#[test]\nfn record_constructor() {\n    assert_erl!(\n        r#\"\npub type X {\n  X(Int)\n}\n\npub const z = X\n\npub fn main() {\n  z\n}\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2163\n#[test]\nfn record_constructor_in_tuple() {\n    assert_erl!(\n        r#\"\npub type X {\n  X(Int)\n}\n\npub const z = #(X)\n\npub fn main() {\n  z\n}\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2179\n#[test]\nfn const_type_variable() {\n    assert_erl!(\n        r#\"\nfn identity(a: a) -> a {\n  a\n}\n\nconst id: fn(a) -> a = identity\n\"#\n    );\n}\n\n#[test]\nfn const_generalise() {\n    assert_erl!(\n        r#\"\nfn identity(a: a) -> a {\na\n}\n\nconst id  = identity\n\npub fn main(){\n  let num  = id(1)\n  let word = id(\"Word\")\n}\"#\n    );\n}\n\n#[test]\nfn pub_const_equal_to_private_function() {\n    assert_erl!(\n        r#\"\n          fn identity(a) {\n            a\n          }\n\n          pub const id = identity\n        \"#\n    );\n}\n\n#[test]\nfn pub_const_equal_to_record_with_private_function_field() {\n    assert_erl!(\n        r#\"\n          fn identity(a) {\n            a\n          }\n\n          pub type Mapper(b) {\n            Mapper(fn(b) -> b)\n          }\n\n          pub const id_mapper = Mapper(identity)\n        \"#\n    );\n}\n\n#[test]\nfn pub_const_equal_to_record_with_nested_private_function_field() {\n    assert_erl!(\n        r#\"\n          fn identity(a) {\n            a\n          }\n\n          pub type Mapper(b) {\n            Mapper(fn(b) -> b)\n          }\n\n          pub type Funcs(b) {\n            Funcs(mapper: Mapper(b))\n          }\n\n          pub const id_mapper = Funcs(Mapper(identity))\n        \"#\n    );\n}\n\n#[test]\nfn use_unqualified_pub_const_equal_to_private_function() {\n    assert_erl!(\n        r#\"\n              fn identity(a) {\n                a\n              }\n\n              pub const id = identity\n        \"#\n    );\n}\n\n#[test]\nfn use_unqualified_pub_const_equal_to_record_with_private_function_field() {\n    assert_erl!(\n        r#\"\n              fn identity(a) {\n                a\n              }\n\n              pub type Mapper(b) {\n                Mapper(fn(b) -> b)\n              }\n\n              pub const id_mapper = Mapper(identity)\n        \"#\n    );\n}\n\n#[test]\nfn use_qualified_pub_const_equal_to_record_with_private_function_field() {\n    assert_erl!(\n        r#\"\n              fn identity(a) {\n                a\n              }\n\n              pub type Mapper(b) {\n                Mapper(fn(b) -> b)\n              }\n\n              pub const id_mapper = Mapper(identity)\n        \"#\n    );\n}\n\n#[test]\nfn use_private_in_internal() {\n    assert_erl!(\n        r#\"\n              fn identity(a) {\n                a\n              }\n\n              pub type Mapper(b) {\n                Mapper(fn(b) -> b)\n              }\n\n              @internal\n              pub const id_mapper = Mapper(identity)\n        \"#\n    );\n}\n\n#[test]\nfn use_private_in_list() {\n    assert_erl!(\n        r#\"\n          fn identity(a) {\n            a\n          }\n\n          pub const funcs = [identity]\n        \"#\n    )\n}\n\n#[test]\nfn use_private_in_tuple() {\n    assert_erl!(\n        r#\"\n          fn identity(a) {\n            a\n          }\n\n          pub const funcs = #(identity)\n        \"#\n    )\n}\n\n#[test]\nfn list_prepend() {\n    assert_erl!(\n        \"\nconst wibble = [2, 3, 4]\npub const wobble = [0, 1, ..wibble]\n\npub fn main() {\n  wobble\n}\n\"\n    );\n}\n\n#[test]\nfn list_prepend_from_other_module() {\n    assert_erl!(\n        (\"thepackage\", \"mod\", \"pub const wibble = [2, 3, 4]\"),\n        \"\nimport mod\n\npub const wobble = [0, 1, ..mod.wibble]\n\npub fn main() {\n  wobble\n}\n\"\n    );\n}\n\n#[test]\nfn list_prepend_literal() {\n    assert_erl!(\n        \"\npub const wibble = [0, 1, ..[2, 3, 4]]\n\npub fn main() {\n  wibble\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/custom_types.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn phantom() {\n    assert_erl!(\"pub type Map(k, v)\");\n}\n\n#[test]\nfn annotated_external_type() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"gleam_stdlib\", \"dict\")\npub type Dict(key, value)\n\"#\n    );\n}\n\n#[test]\nfn annotated_external_type_used_in_function() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"gleam_stdlib\", \"dict\")\npub type Dict(key, value)\n\n@external(erlang, \"maps\", \"get\")\npub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5127\n#[test]\nfn unused_opaque_constructor_is_generated_correctly() {\n    assert_erl!(\n        \"\ntype Wibble {\n  Wibble\n}\n\npub opaque type Wobble {\n  Wobble(Wibble)\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/documentation.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn function_with_documentation() {\n    assert_erl!(\n        r#\"\n/// Function doc!\npub fn documented() { 1 }\"#\n    );\n}\n\n#[test]\nfn function_with_multiline_documentation() {\n    assert_erl!(\n        r#\"\n/// Function doc!\n/// Hello!!\n///\npub fn documented() { 1 }\"#\n    );\n}\n\n#[test]\nfn quotes_in_documentation_are_escaped() {\n    assert_erl!(\n        r#\"\n/// \"hello\"\npub fn documented() { 1 }\"#\n    );\n}\n\n#[test]\nfn backslashes_in_documentation_are_escaped() {\n    assert_erl!(\n        r#\"\n/// \\hello\\\npub fn documented() { 1 }\"#\n    );\n}\n\n#[test]\nfn single_line_module_comment() {\n    assert_erl!(\n        r#\"\n//// Hello! This is a single line module comment.\n\npub fn main() { 1 }\"#\n    );\n}\n\n#[test]\nfn multi_line_module_comment() {\n    assert_erl!(\n        r#\"\n//// Hello! This is a multi-\n//// line module comment.\n////\n\npub fn main() { 1 }\"#\n    );\n}\n\n#[test]\nfn double_quotes_are_escaped_in_module_comment() {\n    assert_erl!(\n        r#\"\n//// \"quotes!\"\n\npub fn main() { 1 }\"#\n    );\n}\n\n#[test]\nfn backslashes_are_escaped_in_module_comment() {\n    assert_erl!(\n        r#\"\n//// \\backslashes!\\\n\npub fn main() { 1 }\"#\n    );\n}\n\n#[test]\nfn internal_function_has_no_documentation() {\n    assert_erl!(\n        r#\"\n/// hidden!\n@internal\npub fn main() { 1 }\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/echo.rs",
    "content": "use crate::assert_erl;\n\n#[test]\npub fn echo_with_a_simple_expression() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo 1\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_simple_expression_and_a_message() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo 1 as \"hello!\"\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_complex_expression_as_a_message() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo 1 as case name() {\n    \"Giacomo\" -> \"hello Jak!\"\n    _ -> \"hello!\"\n  }\n}\n\nfn name() { \"Giacomo\" }\n\"#\n    );\n}\n\n#[test]\npub fn multiple_echos_inside_expression() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo 1\n  echo 2\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_case_expression() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo case 1 {\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_panic() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo panic\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_function_call() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo wibble(1, 2)\n}\n\nfn wibble(n: Int, m: Int) { n + m }\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_function_call_and_a_message() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo wibble(1, 2) as message()\n}\n\nfn wibble(n: Int, m: Int) { n + m }\nfn message() { \"Hello!\" }\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_block() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo {\n    Nil\n    1\n  }\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_in_a_pipeline() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn echo_in_a_pipeline_with_message() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo as \"message!!\"\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn multiple_echos_in_a_pipeline() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n  |> echo\n  |> wibble\n  |> echo\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn pipeline_printed_by_echo_is_wrapped_in_begin_end_block() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  echo\n    123\n    |> wibble\n    |> wibble\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn record_update_printed_by_echo_is_wrapped_in_begin_end_block() {\n    assert_erl!(\n        r#\"\npub type Wobble { Wobble(id: Int, name: String) }\n\npub fn main() {\n  let wobble = Wobble(1, \"wobble\")\n  echo Wobble(..wobble, id: 1)\n}\n\"#\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/external_fn.rs",
    "content": "use crate::{assert_erl, assert_js_module_error, assert_module_error};\n\n#[test]\nfn integration_test1_3() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"Elixir.MyApp\", \"run\")\npub fn run() -> Int\n\"#\n    );\n}\n\n#[test]\nfn integration_test7() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"try\", \"and\")\npub fn receive() -> Int\npub fn catch(x) { receive() }\n\"#\n    );\n}\n\n#[test]\nfn private_external_function_calls() {\n    // Private external function calls are inlined\n    assert_erl!(\n        r#\"\n@external(erlang, \"m\", \"f\")\nfn go(x x: Int, y y: Int) -> Int\n\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\"#\n    );\n}\n\n#[test]\nfn public_local_function_calls() {\n    // Public external function calls are inlined but the wrapper function is\n    // also printed in the erlang output and exported\n    assert_erl!(\n        r#\"\n@external(erlang, \"m\", \"f\")\npub fn go(x x: Int, y y: Int) -> Int\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\n\"#\n    );\n}\n\n#[test]\nfn private_local_function_references() {\n    // Private external function references are inlined\n    assert_erl!(\n        r#\"\n@external(erlang, \"m\", \"f\")\nfn go(x: Int, y: Int) -> Int\npub fn x() { go }\n\"#\n    );\n}\n\n#[test]\nfn inlining_external_functions_from_another_module() {\n    assert_erl!(\n        (\n            \"lib\",\n            \"atom\",\n            r#\"\npub type Atom\n\n@external(erlang, \"erlang\", \"binary_to_atom\")\npub fn make(x: String) -> Atom\n\"#\n        ),\n        r#\"import atom\npub fn main() {\n  atom.make(\"ok\")\n}\n\"#\n    );\n}\n\n#[test]\nfn unqualified_inlining_external_functions_from_another_module() {\n    assert_erl!(\n        (\n            \"lib\",\n            \"atom\",\n            r#\"\npub type Atom\n\n@external(erlang, \"erlang\", \"binary_to_atom\")\npub fn make(x: String) -> Atom\n\"#\n        ),\n        \"import atom.{make}\npub fn main() {\n  make(\\\"ok\\\")\n}\n\"\n    );\n}\n\n#[test]\nfn reference_to_imported_elixir_external_fn() {\n    assert_erl!(\n        (\n            \"lib\",\n            \"my_app\",\n            r#\"\n@external(erlang, \"Elixir.MyApp\", \"run\")\npub fn run() -> Int\n\"#\n        ),\n        r#\"import my_app\npub fn main() {\n  let x = my_app.run\n  id(my_app.run)\n}\nfn id(x) { x }\n\"#\n    );\n}\n\n#[test]\nfn unqualified_reference_to_imported_elixir_external_fn() {\n    assert_erl!(\n        (\n            \"lib\",\n            \"my_app\",\n            r#\"\n@external(erlang, \"Elixir.MyApp\", \"run\")\npub fn run() -> Int\n\"#\n        ),\n        r#\"import my_app.{run}\npub fn main() {\n  let x = run\n  id(run)\n}\nfn id(x) { x }\n\"#\n    );\n}\n\n#[test]\nfn attribute_erlang() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn attribute_javascript() {\n    assert_erl!(\n        r#\"\n@external(javascript, \"./one.mjs\", \"one\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn erlang_and_javascript() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"one\", \"one\")\n@external(javascript, \"./one.mjs\", \"one\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn no_type_annotation_for_parameter() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int, y) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn no_type_annotation_for_return() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int) {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn hole_parameter_erlang() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"one\", \"one\")\npub fn one(x: List(_)) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn hole_return_erlang() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"one\", \"one\")\npub fn one(x: List(Int)) -> List(_) {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn hole_parameter_javascript() {\n    assert_module_error!(\n        r#\"\n@external(javascript, \"one\", \"one\")\npub fn one(x: List(_)) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn hole_return_javascript() {\n    assert_module_error!(\n        r#\"\n@external(javascript, \"one\", \"one\")\npub fn one(x: List(Int)) -> List(_) {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn no_body() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn no_body_or_implementation() {\n    assert_module_error!(\n        r#\"\npub fn one(x: Int) -> Float\n\"#\n    );\n}\n\n#[test]\nfn private() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  do()\n}\n\n@external(erlang, \"library\", \"main\")\nfn do() -> Int\n\"#\n    );\n}\n\n#[test]\nfn elixir() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  #(do, do())\n}\n\n@external(erlang, \"Elixir.String\", \"main\")\nfn do() -> Int\n\"#\n    );\n}\n\n#[test]\nfn public_elixir() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"Elixir.String\", \"main\")\npub fn do() -> Int\n\"#\n    );\n}\n\n#[test]\nfn javascript_only() {\n    assert_erl!(\n        r#\"\npub fn should_be_generated(x: Int) -> Int {\n  x\n}\n\n@external(javascript, \"one\", \"one\")\npub fn should_not_be_generated(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn javascript_only_indirect() {\n    assert_erl!(\n        r#\"\npub fn should_be_generated(x: Int) -> Int {\n  x\n}\n\n@external(javascript, \"one\", \"one\")\npub fn should_not_be_generated(x: Int) -> Int\n\npub fn also_should_not_be_generated() {\n  should_not_be_generated(1)\n  |> should_be_generated\n}\n\"#\n    );\n}\n\n#[test]\nfn both_externals_no_valid_impl() {\n    assert_erl!(\n        r#\"\n@external(javascript, \"one\", \"one\")\npub fn js() -> Nil\n\n@external(erlang, \"one\", \"one\")\npub fn erl() -> Nil\n\npub fn should_not_be_generated() {\n  js()\n  erl()\n}\n\"#\n    );\n}\n\n#[test]\nfn no_gleam_impl_no_annotations_function_fault_tolerance() {\n    // A function not having annotations when required does not stop analysis.\n    assert_module_error!(\n        r#\"\n@external(erlang, \"one\", \"two\")\npub fn no_impl()\n\npub type X = UnknownType\n\"#\n    );\n}\n\n#[test]\nfn no_target_supported_function_fault_tolerance() {\n    // A function not supporting the current target does not stop analysis.\n    assert_js_module_error!(\n        r#\"\n// This will error for having no support on this platform\n@external(erlang, \"one\", \"two\")\npub fn no_impl() -> Int\n\npub fn main() {\n  // This will due to no_impl not having an appropriate implementation for the\n  // target, NOT because it doesn't exist. The analyser should still know about\n  // it, even though it is invalid.\n  no_impl()\n}\n\"#\n    );\n}\n\n#[test]\nfn discarded_arg_in_external_are_passed_correctly() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\npub fn woo(_a: a) -> Nil\n\"#\n    );\n}\n\n#[test]\nfn multiple_discarded_args_in_external_are_passed_correctly() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\npub fn woo(_: a, _: b) -> Nil\n\"#\n    );\n}\n\n#[test]\nfn multiple_discarded_args_in_external_are_passed_correctly_2() {\n    assert_erl!(\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\npub fn woo(__: a, _two: b) -> Nil\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/functions.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn function_as_value() {\n    assert_erl!(\n        r#\"\nfn other() {\n  Nil\n}\n\npub fn main() {\n  other\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_imported_function_as_value() {\n    assert_erl!(\n        (\"package\", \"some/other\", \"pub fn wibble() { Nil }\"),\n        r#\"\nimport some/other\n\npub fn main() {\n  other.wibble\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_unqualified_imported_function_as_value() {\n    assert_erl!(\n        (\"package\", \"some/other\", \"pub fn wibble() { Nil }\"),\n        r#\"\nimport some/other.{wibble}\n\npub fn main() {\n  wibble\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_aliased_imported_function_as_value() {\n    assert_erl!(\n        (\"package\", \"some/other\", \"pub fn wibble() { Nil }\"),\n        r#\"\nimport some/other.{wibble as wobble}\n\npub fn main() {\n  wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn function_called() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  main()\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_imported_function_called() {\n    assert_erl!(\n        (\"package\", \"some/other\", \"pub fn wibble() { Nil }\"),\n        r#\"\nimport some/other\n\npub fn main() {\n  other.wibble()\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_unqualified_imported_function_called() {\n    assert_erl!(\n        (\"package\", \"some/other\", \"pub fn wibble() { Nil }\"),\n        r#\"\nimport some/other.{wibble}\n\npub fn main() {\n  wibble()\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_aliased_imported_function_called() {\n    assert_erl!(\n        (\"package\", \"some/other\", \"pub fn wibble() { Nil }\"),\n        r#\"\nimport some/other.{wibble as wobble}\n\npub fn main() {\n  wobble()\n}\n\"#\n    );\n}\n\n#[test]\nfn labelled_argument_ordering() {\n    // https://github.com/gleam-lang/gleam/issues/3671\n    assert_erl!(\n        \"\ntype A { A }\ntype B { B }\ntype C { C }\ntype D { D }\n\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\n  Nil\n}\n\npub fn main() {\n  wibble(A, C, D, b: B)\n  wibble(A, C, D, b: B)\n  wibble(B, C, D, a: A)\n  wibble(B, C, a: A, d: D)\n  wibble(B, C, d: D, a: A)\n  wibble(B, D, a: A, c: C)\n  wibble(B, D, c: C, a: A)\n  wibble(C, D, b: B, a: A)\n}\n\"\n    );\n}\n\n#[test]\nfn unused_private_functions() {\n    assert_erl!(\n        r#\"\npub fn main() -> Int {\n  used()\n}\n\nfn used() -> Int {\n  123\n}\n\nfn unused1() -> Int {\n  unused2()\n}\n\nfn unused2() -> Int {\n  used()\n}\n\nfn unused3() -> Int {\n  used()\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/guards.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn clause_guards() {\n    // Clause guards\n    assert_erl!(\n        r#\"\npub fn main(args) {\n  case args {\n    x if x == args -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_1() {\n    assert_erl!(\n        r#\"\npub fn main(args) {\n  case args {\n    x if {x != x} == {args == args} -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_2() {\n    assert_erl!(\n        r#\"\npub fn main(args) {\n  case args {\n    x if x && x || x == x && x -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_3() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 1, 0 {\n    x, y if x > y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_4() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 1, 0 {\n    x, y if x >= y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_5() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 1, 0 {\n    x, y if x < y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_6() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 1, 0 {\n    x, y if x <= y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_7() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 1.0, 0.1 {\n    x, y if x >. y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_8() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 1.0, 0.1 {\n    x, y if x >=. y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_9() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = 0.123\n  case x {\n    99.9854 -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards_10() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = 0.123\n  case x {\n    _ if x == 3.14 -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards20() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = 0.123\n  case x {\n    _ if 0.123 <. x -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards21() {\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  case x {\n    _ if x == [1, 2, 3] -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards22() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = 0\n  case x {\n    0 -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards23() {\n    // Tuple literals in guards\n\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = #(1, 2, 3)\n  case x {\n    _ if x == #(1, 2, 3) -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards24() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = #(1, 2, 3)\n  case x {\n    _ if x == #(1, 2, 3) -> 1\n    _ if x == #(2, 3, 4) -> 2\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards25() {\n    // Int literals in guards\n\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = 0\n  case x {\n    _ if x == 0 -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards26() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = 0\n  case x {\n    _ if 0 < x -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards27() {\n    // String literals in guards\n\n    assert_erl!(\n        r#\"\npub fn main() {\n  case \"test\" {\n    x if x == \"test\" -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards28() {\n    // Record literals in guards\n\n    assert_erl!(\n        r#\"\n    type Test { Test(x: Int, y: Float) }\n    pub fn main() {\n      let x = Test(1, 3.0)\n      case x {\n        _ if x == Test(1, 1.0) -> 1\n        _ if x == Test(y: 2.0, x: 2) -> 2\n        _ if x != Test(2, 3.0) -> 2\n        _ -> 0\n      }\n    }\n\"#\n    );\n}\n\n#[test]\nfn clause_guards29() {\n    // Float vars in guards\n\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 0.1, 1.0 {\n    x, y if x <. y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards30() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  case 0.1, 1.0 {\n    x, y if x <=. y -> 1\n    _, _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards31() {\n    assert_erl!(\n        r#\"\npub fn main(args) {\n  case args {\n    [x] | [x, _] if x -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn clause_guards32() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let wibble = \"wobble\"\n  case wibble {\n    x if x == \"wob\" <> \"ble\" -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn constants_in_guards() {\n    assert_erl!(\n        r#\"\npub const string_value = \"constant value\"\npub const float_value = 3.14\npub const int_value = 42\npub const tuple_value = #(1, 2.0, \"3\")\npub const list_value = [1, 2, 3]\n\npub fn main(arg) {\n  let _ = list_value\n  case arg {\n    #(w, x, y, z) if w == tuple_value && x == string_value && y >. float_value && z == int_value -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn constants_in_guards1() {\n    assert_erl!(\n        r#\"\npub const list = [1, 2, 3]\n\npub fn main(arg) {\n  case arg {\n    _ if arg == list -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn only_guards() {\n    assert_erl!(\n        r#\"\npub const string_value = \"constant value\"\n\npub fn main(arg) {\n  case arg {\n    _ if arg == string_value -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn only_guards1() {\n    assert_erl!(\n        r#\"\npub const bits = <<1, \"ok\":utf8, 3, 4:50>>\n\npub fn main(arg) {\n  case arg {\n    _ if arg == bits -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn only_guards2() {\n    assert_erl!(\n        r#\"\npub const constant = #(1, 2.0)\n\npub fn main(arg) {\n  case arg {\n    _ if arg == constant -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn only_guards3() {\n    assert_erl!(\n        r#\"\npub const float_value = 3.14\n\npub fn main(arg) {\n  case arg {\n    _ if arg >. float_value -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn field_access() {\n    assert_erl!(\n        r#\"\n        pub type Person {\n          Person(username: String, name: String, age: Int)\n        }\n        \n        pub fn main() {\n          let given_name = \"jack\"\n          let raiden = Person(\"raiden\", \"jack\", 31)\n        \n          case given_name {\n            name if name == raiden.name -> \"It's jack\"\n            _ -> \"It's not jack\"\n          }\n        }\n        \"#\n    )\n}\n\n#[test]\nfn nested_record_access() {\n    assert_erl!(\n        r#\"\npub type A {\n  A(b: B)\n}\n\npub type B {\n  B(c: C)\n}\n\npub type C {\n  C(d: Bool)\n}\n\npub fn a(a: A) {\n  case a {\n    _ if a.b.c.d -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn module_string_access() {\n    assert_erl!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub const ironman = \"Tony Stark\"\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_list_access() {\n    assert_erl!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub const heroes = [\"Tony Stark\", \"Bruce Wayne\"]\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let names = [\"Tony Stark\", \"Bruce Wayne\"]\n            case names {\n              n if n == hero.heroes -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_tuple_access() {\n    assert_erl!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub const hero = #(\"ironman\", \"Tony Stark\")\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.hero.1 -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_access() {\n    assert_erl!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub type Hero {\n                Hero(name: String)\n              }\n              pub const ironman = Hero(\"Tony Stark\")\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman.name -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_nested_access() {\n    assert_erl!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub type Person {\n                Person(name: String)\n              }\n              pub type Hero {\n                Hero(secret_identity: Person)\n              }\n              const bruce = Person(\"Bruce Wayne\")\n              pub const batman = Hero(bruce)\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Bruce Wayne\"\n            case name {\n              n if n == hero.batman.secret_identity.name -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/inlining.rs",
    "content": "use crate::assert_erl;\n\nconst BOOL_MODULE: &str = \"\npub fn guard(\n  when condition: Bool,\n  return value: a,\n  otherwise callback: fn() -> a,\n) -> a {\n  case condition {\n    True -> value\n    False -> callback()\n  }\n}\n\npub fn lazy_guard(\n  when condition: Bool,\n  return consequence: fn() -> a,\n  otherwise alternative: fn() -> a,\n) -> a {\n  case condition {\n    True -> consequence()\n    False -> alternative()\n  }\n}\n\";\n\nconst RESULT_MODULE: &str = \"\npub fn try(result: Result(a, e), apply f: fn(a) -> Result(b, e)) -> Result(b, e) {\n  case result {\n    Ok(value) -> f(value)\n    Error(error) -> Error(error)\n  }\n}\n\npub fn map(over result: Result(a, e), with f: fn(a) -> b) -> Result(b, e) {\n  case result {\n    Ok(value) -> Ok(f(value))\n    Error(error) -> Error(error)\n  }\n}\n\";\n\n#[test]\nfn inline_higher_order_function() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn main() {\n  result.map(over: Ok(10), with: double)\n}\n\nfn double(x) { x + x }\n\"\n    );\n}\n\n#[test]\nfn inline_higher_order_function_with_capture() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), divide(_, 2))\n}\n\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inline_higher_order_function_anonymous() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), fn(value) {\n    Ok({ value + 2 } * 4)\n  })\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_which_calls_other_function() {\n    // This function calls `result.try`, meaning this must be inlined twice to\n    // achieve the desired result.\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        (\n            \"gleam_stdlib\",\n            \"testing\",\n            \"\nimport gleam/result.{try}\n\npub fn always_inline(result, f) -> Result(b, e) {\n  try(result, f)\n}\n\"\n        ),\n        \"\nimport testing\n\npub fn main() {\n  testing.always_inline(Ok(10), Error)\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_with_use() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/bool\", BOOL_MODULE),\n        \"\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.guard(when: b == 0, return: 0)\n  a / b\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_with_use_and_anonymous() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/bool\", BOOL_MODULE),\n        r#\"\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.lazy_guard(b == 0, fn() { panic as \"Cannot divide by 0\" })\n  a / b\n}\n\"#\n    );\n}\n\n#[test]\nfn inline_function_with_use_becomes_tail_recursive() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/bool\", BOOL_MODULE),\n        \"\nimport gleam/bool\n\npub fn count(from: Int, to: Int) -> Int {\n  use <- bool.guard(when: from >= to, return: from)\n  echo from\n  count(from + 1, to)\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_inline_parameters_used_more_than_once() {\n    // Since the `something` parameter is used more than once in the body of the\n    // function, it should not be inlined, and should be assigned once at the\n    // beginning of the function.\n    assert_erl!(\n        (\n            \"gleam_stdlib\",\n            \"testing\",\n            \"\npub fn always_inline(something) {\n  case something {\n    True -> something\n    False -> False\n  }\n}\n\"\n        ),\n        \"\nimport testing\n\npub fn main() {\n  testing.always_inline(True)\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_inline_parameters_that_have_side_effects() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        r#\"\nimport gleam/result\n\npub fn main() {\n  result.map(Ok(10), do_side_effects())\n}\n\nfn do_side_effects() {\n  let function = fn(x) { x + 1 }\n  panic as \"Side effects\"\n  function\n}\n\"#\n    );\n}\n\n#[test]\nfn inline_anonymous_function_call() {\n    assert_erl!(\n        \"\npub fn main() {\n  fn(a, b) { #(a, b) }(42, False)\n}\n\"\n    );\n}\n\n#[test]\nfn inline_anonymous_function_in_pipe() {\n    assert_erl!(\n        \"\npub fn main() {\n  1 |> fn(x) { x + 1 } |> fn(y) { y * y }\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_capture_in_pipe() {\n    // The function capture is desugared to an anonymous function, so it should\n    // be turned into a direct call to `add`\n    assert_erl!(\n        \"\npub fn main() {\n  1 |> add(4, _)\n}\n\nfn add(a, b) { a + b }\n\"\n    );\n}\n\n#[test]\nfn inlining_works_through_blocks() {\n    assert_erl!(\n        \"\npub fn main() {\n    { fn(x) { Ok(x + 1) } }(41)\n}\n\"\n    );\n}\n\n#[test]\nfn blocks_get_preserved_when_needed() {\n    assert_erl!(\n        \"\npub fn main() {\n    { 4 |> make_adder }(6)\n}\n\nfn make_adder(a) {\n  fn(b) { a + b }\n}\n\"\n    );\n}\n\n#[test]\nfn blocks_get_preserved_when_needed2() {\n    assert_erl!(\n        \"\npub fn main() {\n    fn(x) { 1 + x }(2) * 3\n}\n\"\n    );\n}\n\n#[test]\nfn parameters_from_nested_functions_are_correctly_inlined() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn halve_all(a, b, c) {\n  use x <- result.try(divide(a, 2))\n  use y <- result.try(divide(b, 2))\n  use z <- result.map(divide(c, 2))\n\n  #(x, y, z)\n}\n\nfn divide(a, b) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4852\n#[test]\nfn inlining_works_properly_with_record_updates() {\n    assert_erl!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let w = Wibble(1, 2)\n  use b <- result.map(Ok(3))\n  Wibble(..w, b:)\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4877\n#[test]\nfn inline_shadowed_variable() {\n    assert_erl!(\n        \"\npub fn main() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn inline_variable_shadowing_parameter() {\n    assert_erl!(\n        \"\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn inline_shadowed_variable_nested() {\n    assert_erl!(\n        \"\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    fn(y) {\n      let a = 10\n      y - a\n    }(x + a)\n\n    a\n  }(a + b)\n\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn inline_variable_shadowed_in_case_pattern() {\n    assert_erl!(\n        \"\npub fn sum() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    case 7, 8 {\n      a, b -> a + b + x\n    }\n  }(a + b)\n\n  a + b\n}\n\"\n    );\n}\n\n#[test]\nfn inline_variable_shadowing_case_pattern() {\n    assert_erl!(\n        \"\npub fn sum() {\n  case 1, 2 {\n    a, b -> fn(x) {\n      let a = 7\n      x + a\n    }(a + b)\n  }\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/let_assert.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn one_var() {\n    // One var\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert Ok(y) = Ok(1)\n  y\n}\"#\n    );\n}\n\n#[test]\nfn more_than_one_var() {\n    // More vars\n    assert_erl!(\n        r#\"pub fn go(x) {\n  let assert [1, a, b, c] = x\n  [a, b, c]\n}\"#\n    );\n}\n\n#[test]\nfn pattern_let() {\n    // Pattern::Let\n    assert_erl!(\n        r#\"pub fn go(x) {\n  let assert [1 as a, b, c] = x\n  [a, b, c]\n}\"#\n    );\n}\n\n#[test]\nfn variable_rewrites() {\n    // Following asserts use appropriate variable rewrites\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert Ok(y) = Ok(1)\n  let assert Ok(y) = Ok(1)\n  y\n}\"#\n    );\n}\n\n#[test]\nfn message() {\n    assert_erl!(\n        r#\"\npub fn unwrap_or_panic(value) {\n  let assert Ok(inner) = value as \"Oops, there was an error\"\n  inner\n}\n\"#\n    );\n}\n\n#[test]\nfn variable_message() {\n    assert_erl!(\n        r#\"\npub fn expect(value, message) {\n  let assert Ok(inner) = value as message\n  inner\n}\n\"#\n    );\n}\n\n#[test]\nfn just_variable() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert x = Ok(1)\n  x\n}\"#\n    );\n}\n\n#[test]\nfn tuple_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert #(a, b, c) = #(1, 2, 3)\n  a + b + c\n}\"#\n    );\n}\n\n#[test]\nfn int_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert 1 = 2\n}\"#\n    );\n}\n\n#[test]\nfn float_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert 1.5 = 5.1\n}\"#\n    );\n}\n\n#[test]\nfn string_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert \"Hello!\" = \"Hel\" <> \"lo!\"\n}\"#\n    );\n}\n\n#[test]\nfn assignment_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert 123 as x = 123\n  x\n}\"#\n    );\n}\n\n#[test]\nfn discard_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert _ = 123\n}\"#\n    );\n}\n\n#[test]\nfn list_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert [1, x, 3] = [1, 2, 3]\n  x\n}\"#\n    );\n}\n\n#[test]\nfn list_pattern_with_multiple_variables() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert [a, b, c] = [1, 2, 3]\n  a + b + c\n}\"#\n    );\n}\n\n#[test]\nfn constructor_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert Ok(x) = Error(Nil)\n  x\n}\"#\n    );\n}\n\n#[test]\nfn constructor_pattern_with_multiple_variables() {\n    assert_erl!(\n        r#\"\npub type Wibble {\n  Wibble(Int, Float)\n}\n\npub fn go() {\n  let assert Wibble(x, 2.0 as y) = Wibble(1, 2.0)\n  x\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert <<a:2, b:3, c:3>> = <<123>>\n  a + b + c\n}\"#\n    );\n}\n\n#[test]\nfn string_prefix_pattern() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert \"Hello \" <> name = \"Hello John\"\n  name\n}\"#\n    );\n}\n\n#[test]\nfn string_prefix_pattern_with_prefix_binding() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let assert \"Hello \" as greeting <> name = \"Hello John\"\n  #(greeting, name)\n}\"#\n    );\n}\n\n#[test]\nfn let_assert_at_end_of_block() {\n    assert_erl!(\n        r#\"\npub fn go() {\n  let result = Ok(10)\n  let x = {\n    let assert Ok(_) = result\n  }\n  x\n}\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4145\n#[test]\nfn reference_earlier_segment() {\n    assert_erl!(\n        \"\npub fn main() {\n  let assert <<length, bytes:size(length)-unit(8)>> = <<3, 1, 2, 3>>\n  bytes\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_int() {\n    assert_erl!(\n        \"\npub fn main() {\n  let assert <<1 as a>> = <<1>>\n  a\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_float() {\n    assert_erl!(\n        \"\npub fn main() {\n  let assert <<3.14 as pi:float>> = <<3.14>>\n  pi\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_string() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let assert <<\"Hello, world!\" as message:utf8>> = <<\"Hello, world!\">>\n  message\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_discard() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let assert <<_ as number>> = <<10>>\n  number\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4924\n#[test]\nfn let_assert_should_not_use_redefined_variable() {\n    assert_erl!(\n        r#\"\nfn split_once(x: String, y: String) -> Result(#(String, String), String) {\n    Ok(#(x, y))\n}\n\npub fn main() {\n    let string = \"Hello, world!\"\n    let assert Ok(#(prefix, string)) = split_once(string, \"\\n\")\n    as { \"Failed to split: \" <> string }\n}\n        \"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/numbers.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn numbers_with_underscores() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  100_000\n  100_000.00101\n}\n\"#\n    );\n}\n\n#[test]\nfn numbers_with_underscores1() {\n    assert_erl!(\n        r#\"\nconst i = 100_000\nconst f = 100_000.00101\npub fn main() {\n  i\n  f\n}\n\"#\n    );\n}\n\n#[test]\nfn numbers_with_underscores2() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let assert 100_000 = 1\n  let assert 100_000.00101 = 1.\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn numbers_with_scientific_notation() {\n    assert_erl!(\n        r#\"\nconst i = 100.001e223\nconst j = -100.001e-223\n\npub fn main() {\n  i\n  j\n}\n\"#\n    );\n}\n\n#[test]\nfn int_negation() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let a = 3\n  let b = -a\n}\n\"#\n    );\n}\n\n#[test]\nfn repeated_int_negation() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let a = 3\n  let b = --a\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2356\n#[test]\nfn zero_b_in_hex() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  0xffe0bb\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/panic.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn panic_as() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  panic as \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn plain() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  panic\n}\n\"#\n    );\n}\n\n#[test]\nfn panic_as_function() {\n    assert_erl!(\n        r#\"\npub fn retstring() {\n  \"wibble\"\n}\npub fn main() {\n  panic as { retstring() <> \"wobble\" }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2176\n#[test]\nfn piped() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  \"lets\"\n  |> panic\n}\n    \"#\n    );\n}\n\n#[test]\nfn piped_chain() {\n    assert_erl!(\n        r#\"\n     pub fn main() {\n      \"lets\"\n      |> panic as \"pipe\"\n      |> panic as \"other panic\"\n    }\n    \"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/patterns.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn alternative_patterns() {\n    // reassigning name in alternative patterns\n    assert_erl!(\n        r#\"\npub fn main() {\n  let duplicate_name = 1\n\n  case 1 {\n    1 | 2 -> {\n      let duplicate_name = duplicate_name + 1\n      duplicate_name\n    }\n    _ -> 0\n  }\n}\"#\n    );\n}\n\n#[test]\nfn alternative_patterns1() {\n    // Alternative patterns with a clause containing vars\n    assert_erl!(\n        r#\"\npub fn main() {\n  case Ok(1) {\n    Ok(duplicate_name) | Error(duplicate_name) -> duplicate_name\n  }\n}\"#\n    );\n}\n\n#[test]\nfn alternative_patterns2() {\n    // Alternative patterns with a guard clause containing vars\n    assert_erl!(\n        r#\"\npub fn main() {\n    let duplicate_name = 1\n\n    case 1 {\n        1 | 2 if duplicate_name == 1 -> duplicate_name\n        _ -> 0\n    }\n}\"#\n    );\n}\n\n#[test]\nfn alternative_patterns3() {\n    assert_erl!(\n        r#\"\npub const constant = Ok(1)\n\npub fn main(arg) {\n  let _ = constant\n  case arg {\n    _ if arg == constant -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_as() {\n    assert_erl!(\n        \"pub fn a(x) {\n  case x {\n    Ok(1 as y) -> 1\n    _ -> 0\n  }\n}\"\n    );\n}\n\n#[test]\nfn string_prefix_as_pattern_with_multiple_subjects() {\n    assert_erl!(\n        \"pub fn a(x) {\n  case x, x {\n    _, \\\"a\\\" as a <> _  -> a\n    _, _ -> \\\"a\\\"\n  }\n}\"\n    );\n}\n\n#[test]\nfn string_prefix_as_pattern_with_multiple_subjects_and_guard() {\n    assert_erl!(\n        \"pub fn a(x) {\n  case x, x {\n    _, \\\"a\\\" as a <> rest if rest == \\\"a\\\" -> a\n    _, _ -> \\\"a\\\"\n  }\n}\"\n    );\n}\n\n#[test]\nfn string_prefix_as_pattern_with_list() {\n    assert_erl!(\n        \"pub fn a(x) {\n  case x {\n    [\\\"a\\\" as a <> _, \\\"b\\\" as b <> _] -> a <> b\n    _ -> \\\"\\\"\n  }\n}\"\n    );\n}\n\n#[test]\nfn string_prefix_as_pattern_with_assertion() {\n    assert_erl!(\n        \"pub fn a(x) {\n  let assert \\\"a\\\" as a <> rest = \\\"wibble\\\"\n  a\n}\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/pipes.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn clever_pipe_rewriting() {\n    // a |> b\n    assert_erl!(\n        r#\"\npub fn apply(f: fn(a) -> b, a: a) { a |> f }\n\"#\n    );\n}\n\n#[test]\nfn clever_pipe_rewriting1() {\n    // a |> b(c)\n    assert_erl!(\n        r#\"\npub fn apply(f: fn(a, Int) -> b, a: a) { a |> f(1) }\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/952\n#[test]\nfn block_expr_into_pipe() {\n    assert_erl!(\n        r#\"fn id(a) { a }\npub fn main() {\n  {\n    let x = 1\n    x\n  }\n  |> id\n}\"#\n    );\n}\n\n#[test]\nfn pipe_in_list() {\n    assert_erl!(\n        \"pub fn x(f) {\n  [\n    1 |> f\n  ]\n}\"\n    );\n}\n\n#[test]\nfn pipe_in_tuple() {\n    assert_erl!(\n        \"pub fn x(f) {\n  #(\n    1 |> f\n  )\n}\"\n    );\n}\n\n#[test]\nfn pipe_in_case_subject() {\n    assert_erl!(\n        \"pub fn x(f) {\n  case 1 |> f {\n    x -> x\n  }\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1379\n#[test]\nfn pipe_in_record_update() {\n    assert_erl!(\n        \"pub type X {\n  X(a: Int, b: Int)\n}\n\nfn id(x) {\n  x\n}\n\npub fn main(x) {\n  X(..x, a: 1 |> id)\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1385\n#[test]\nfn pipe_in_eq() {\n    assert_erl!(\n        \"fn id(x) {\n  x\n}\n\npub fn main() {\n    1 == 1 |> id\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1863\n#[test]\nfn call_pipeline_result() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  { 1 |> add }(1)\n}\n\npub fn add(x) {\n  fn(y) { x + y }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1931\n#[test]\nfn pipe_in_call() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  123\n  |> two(\n    1 |> two(2),\n    _,\n  )\n}\n\npub fn two(a, b) {\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_pipes() {\n    assert_erl!(\n        \"\npub fn main() {\n  1 |> x |> x\n  2 |> x |> x\n}\n\nfn x(x) { x }\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/prelude.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn qualified_prelude() {\n    assert_erl!(\n        \"import gleam\npub type X { X(gleam.Int) }\n\"\n    );\n\n    assert_erl!(\n        \"import gleam\npub fn x() { gleam.Ok(1) }\n\"\n    );\n}\n\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/records.rs",
    "content": "use crate::assert_erl;\nuse crate::erlang::*;\nuse crate::type_;\n\n#[test]\nfn basic() {\n    insta::assert_snapshot!(record_definition(\n        \"PetCat\",\n        &[\n            (\"name\", type_::tuple(vec![])),\n            (\"is_cute\", type_::tuple(vec![]))\n        ]\n    ));\n}\n\n#[test]\nfn reserve_words() {\n    // Reserved words are escaped in record names and fields\n    insta::assert_snapshot!(record_definition(\n        \"div\",\n        &[\n            (\"receive\", type_::int()),\n            (\"catch\", type_::tuple(vec![])),\n            (\"unreserved\", type_::tuple(vec![]))\n        ]\n    ));\n}\n\n#[test]\nfn type_vars() {\n    // Type vars are printed as `any()` because records don't support generics\n    insta::assert_snapshot!(record_definition(\n        \"PetCat\",\n        &[\n            (\"name\", type_::generic_var(1)),\n            (\"is_cute\", type_::unbound_var(1)),\n            (\"linked\", type_::link(type_::int()))\n        ]\n    ));\n}\n\n#[test]\nfn module_types() {\n    // Types are printed with module qualifiers\n    let module_name = \"name\".into();\n    insta::assert_snapshot!(record_definition(\n        \"PetCat\",\n        &[(\n            \"name\",\n            Arc::new(Type::Named {\n                publicity: Publicity::Public,\n                package: \"package\".into(),\n                module: module_name,\n                name: \"my_type\".into(),\n                arguments: vec![],\n                inferred_variant: None,\n            })\n        )]\n    ));\n}\n\n#[test]\nfn long_definition_formatting() {\n    // Long definition formatting\n    insta::assert_snapshot!(record_definition(\n        \"PetCat\",\n        &[\n            (\"name\", type_::generic_var(1)),\n            (\"is_cute\", type_::unbound_var(1)),\n            (\"linked\", type_::link(type_::int())),\n            (\n                \"whatever\",\n                type_::list(type_::tuple(vec![\n                    type_::nil(),\n                    type_::list(type_::tuple(vec![type_::nil(), type_::nil(), type_::nil()])),\n                    type_::nil(),\n                    type_::list(type_::tuple(vec![type_::nil(), type_::nil(), type_::nil()])),\n                    type_::nil(),\n                    type_::list(type_::tuple(vec![type_::nil(), type_::nil(), type_::nil()])),\n                ]))\n            ),\n        ]\n    ));\n}\n\n#[test]\nfn record_accessors() {\n    // We can use record accessors for types with only one constructor\n    assert_erl!(\n        r#\"\npub type Person { Person(name: String, age: Int) }\npub fn get_age(person: Person) { person.age }\npub fn get_name(person: Person) { person.name }\n\"#\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants() {\n    // We can access fields on custom types with multiple variants\n    assert_erl!(\n        \"\npub type Person {\n    Teacher(name: String, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\"\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants_positions_other_than_first() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_erl!(\n        \"\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants_parameterised_types() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_erl!(\n        \"\npub type Person {\n    Teacher(name: String, age: List(Int), title: String)\n    Student(name: String, age: List(Int))\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn record_accessor_multiple_with_first_position_different_types() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_erl!(\n        \"\npub type Person {\n    Teacher(name: Nil, age: Int)\n    Student(name: String, age: Int)\n}\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn record_spread() {\n    // Test binding to a record field with the spread operator\n    assert_erl!(\n        r#\"\npub type Triple {\n    Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  let Triple(the_a, ..) = triple\n  the_a\n}\n\"#\n    );\n}\n\n#[test]\nfn record_spread1() {\n    // Test binding to a record field with the spread operator\n    // Test binding to a record field with the spread operator and a labelled argument\n    assert_erl!(\n        r#\"\npub type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  let Triple(b: the_b, ..) = triple\n  the_b\n}\n\"#\n    );\n}\n\n#[test]\nfn record_spread2() {\n    // Test binding to a record field with the spread operator with both a labelled argument and a positional argument\n    assert_erl!(\n        r#\"\npub type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  let Triple(the_a, c: the_c, ..) = triple\n  the_c\n}\n\"#\n    );\n}\n\n#[test]\nfn record_spread3() {\n    // Test binding to a record field with the spread operator in a match\n    assert_erl!(\n        r#\"\npub type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  case triple {\n    Triple(b: the_b, ..) -> the_b\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn record_updates() {\n    // Record updates\n    assert_erl!(\n        r#\"\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let p = Person(\"Quinn\", 27)\n    let new_p = Person(..p, age: 28)\n    new_p\n}\n\"#\n    );\n}\n\n#[test]\nfn record_updates1() {\n    // Record updates with field accesses\n    assert_erl!(\n        r#\"\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let p = Person(\"Quinn\", 27)\n    let new_p = Person(..p, age: p.age + 1)\n    new_p\n}\n\"#\n    );\n}\n\n#[test]\nfn record_updates2() {\n    // Record updates with multiple fields\n    assert_erl!(\n        r#\"\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let p = Person(\"Quinn\", 27)\n    let new_p = Person(..p, age: 28, name: \"Riley\")\n    new_p\n}\n\"#\n    );\n}\n\n#[test]\nfn record_updates3() {\n    // Record updates when record is returned from function\n    assert_erl!(\n        r#\"\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let new_p = Person(..return_person(), age: 28)\n    new_p\n}\n\nfn return_person() {\n    Person(\"Quinn\", 27)\n}\n\"#\n    );\n}\n\n#[test]\nfn record_updates4() {\n    // Record updates when record is field on another record\n    assert_erl!(\n        r#\"\npub type Car { Car(make: String, model: String, driver: Person) }\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let car = Car(make: \"Amphicar\", model: \"Model 770\", driver: Person(name: \"John Doe\", age: 27))\n    let new_p = Person(..car.driver, age: 28)\n    new_p\n}\n\"#\n    );\n}\n\n#[test]\nfn record_constants() {\n    assert_erl!(\n        \"pub type Test { A }\nconst some_test = A\npub fn a() { A }\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1698\n#[test]\nfn pipe_update_subject() {\n    assert_erl!(\n        \"pub type Thing {\n  Thing(a: Int, b: Int)\n}\n\npub fn identity(x) { x }\n\npub fn main() {\n  let thing = Thing(1, 2)\n  Thing(..thing |> identity, b: 1000)\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1698\n#[test]\nfn record_access_block() {\n    assert_erl!(\n        \"pub type Thing {\n  Thing(a: Int, b: Int)\n}\n\npub fn main() {\n  {\n    let thing = Thing(1, 2)\n    thing\n  }.a\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1981\n#[test]\nfn imported_qualified_constructor_as_fn_name_escape() {\n    assert_erl!(\n        (\"other_package\", \"other_module\", \"pub type Let { Let(Int) }\"),\n        \"import other_module\n\npub fn main() {\n  other_module.Let\n}\"\n    );\n}\n\n#[test]\nfn nested_record_update() {\n    assert_erl!(\n        \"pub type Wibble {\n  Wibble(a: Int, b: Wobble, c: Int)\n}\n\npub type Wobble {\n  Wobble(a: Int, b: Int)\n}\n\npub fn main() {\n  let base = Wibble(1, Wobble(2, 3), 4)\n  Wibble(..base, b: Wobble(..base.b, b: 5))\n}\"\n    );\n}\n\n#[test]\nfn nested_record_update_with_blocks() {\n    assert_erl!(\n        \"pub type A { A(b: B) }\npub type B { B(c: C) }\npub type C { C(val: Int) }\n\npub fn main(a: A) {\n    A(..a, b: {\n        B(..a.b, c: {\n            C(..a.b.c, val: 0)\n        })\n    })\n}\"\n    )\n}\n\n#[test]\nfn private_unused_records() {\n    assert_erl!(\n        \"type A { A(inner: Int) }\ntype B { B(String) }\ntype C { C(Int) }\n\npub fn main(x: Int) -> Int {\n  let a = A(x)\n  a.inner\n}\n\"\n    )\n}\n\n#[test]\nfn const_record_update_generic_respecialization() {\n    assert_erl!(\n        \"\npub type Box(a) {\n  Box(name: String, value: a)\n}\n\npub const base = Box(\\\"score\\\", 50)\npub const updated = Box(..base, value: \\\"Hello\\\")\n\npub fn main() {\n  #(base, updated)\n}\n\",\n    );\n}\n\n#[test]\nfn record_update_with_unlabelled_fields() {\n    assert_erl!(\n        r#\"\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub fn main() {\n  let record = Wibble(1, 3.14, True, \"Hello\")\n  Wibble(..record, b: False)\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_record_update_with_unlabelled_fields() {\n    assert_erl!(\n        r#\"\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub const record = Wibble(1, 3.14, True, \"Hello\")\npub const updated = Wibble(..record, b: False)\n\npub fn main() {\n  updated\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/reserved.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn build_in_erlang_type_escaping() {\n    assert_erl!(\"pub type Map\");\n}\n\n#[test]\nfn escape_erlang_reserved_keywords_in_type_names() {\n    // list of all reserved words in erlang\n    // http://erlang.org/documentation/doc-5.8/doc/reference_manual/introduction.html\n    assert_erl!(\n        r#\"pub type After { TestAfter }\npub type And { TestAnd }\npub type Andalso { TestAndAlso }\npub type Band { TestBAnd }\npub type Begin { TestBegin }\npub type Bnot { TestBNot }\npub type Bor { TestBOr }\npub type Bsl { TestBsl }\npub type Bsr { TestBsr }\npub type Bxor { TestBXor }\npub type Case { TestCase }\npub type Catch { TestCatch }\npub type Cond { TestCond }\npub type Div { TestDiv }\npub type End { TestEnd }\npub type Fun { TestFun }\npub type If { TestIf }\npub type Let { TestLet }\npub type Maybe { TestMaybe }\npub type Not { TestNot }\npub type Of { TestOf }\npub type Or { TestOr }\npub type Orelse { TestOrElse }\npub type Query { TestQuery }\npub type Receive { TestReceive }\npub type Rem { TestRem }\npub type Try { TestTry }\npub type When { TestWhen }\npub type Xor { TestXor }\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  let x = True\\n  assert x || False\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = True\n  assert x || False\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> nil.\nmain() ->\n    X = true,\n    case X orelse false of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 4,\n                kind => binary_operator,\n                operator => '||',\n                left => #{kind => expression,\n                    value => false,\n                    start => 41,\n                    'end' => 42\n                    },\n                right => #{kind => literal,\n                    value => false,\n                    start => 46,\n                    'end' => 51\n                    },\n                start => 34,\n                'end' => 51,\n                expression_start => 41})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\npub fn eq(a, b) {\\n  assert a == b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn eq(a, b) {\n  assert a == b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([eq/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec eq(J, J) -> nil.\neq(A, B) ->\n    case A =:= B of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"eq\"/utf8>>,\n                line => 3,\n                kind => binary_operator,\n                operator => '==',\n                left => #{kind => expression,\n                    value => A,\n                    start => 28,\n                    'end' => 29\n                    },\n                right => #{kind => expression,\n                    value => B,\n                    start => 33,\n                    'end' => 34\n                    },\n                start => 21,\n                'end' => 34,\n                expression_start => 28})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\npub fn assert_answer(x) {\\n  assert x == 42\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn assert_answer(x) {\n  assert x == 42\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([assert_answer/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec assert_answer(integer()) -> nil.\nassert_answer(X) ->\n    _assert_subject = 42,\n    case X =:= _assert_subject of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"assert_answer\"/utf8>>,\n                line => 3,\n                kind => binary_operator,\n                operator => '==',\n                left => #{kind => expression,\n                    value => X,\n                    start => 36,\n                    'end' => 37\n                    },\n                right => #{kind => literal,\n                    value => _assert_subject,\n                    start => 41,\n                    'end' => 43\n                    },\n                start => 29,\n                'end' => 43,\n                expression_start => 36})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\nfn wibble(a, b) {\\n  let result = a + b\\n  result == 10\\n}\\n\\npub fn go(x) {\\n  assert True && wibble(1, 4)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert True && wibble(1, 4)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec wibble(integer(), integer()) -> boolean().\nwibble(A, B) ->\n    Result = A + B,\n    Result =:= 10.\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec go(any()) -> nil.\ngo(X) ->\n    case true of\n        true -> case wibble(1, 4) of\n                true -> nil;\n                false -> erlang:error(#{gleam_error => assert,\n                        message => <<\"Assertion failed.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 8,\n                        kind => binary_operator,\n                        operator => '&&',\n                        left => #{kind => literal,\n                            value => true,\n                            start => 82,\n                            'end' => 86\n                            },\n                        right => #{kind => expression,\n                            value => false,\n                            start => 90,\n                            'end' => 102\n                            },\n                        start => 75,\n                        'end' => 102,\n                        expression_start => 82})\n            end;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"go\"/utf8>>,\n                line => 8,\n                kind => binary_operator,\n                operator => '&&',\n                left => #{kind => literal,\n                    value => false,\n                    start => 82,\n                    'end' => 86\n                    },\n                right => #{kind => unevaluated,\n                    start => 90,\n                    'end' => 102\n                    },\n                start => 75,\n                'end' => 102,\n                expression_start => 82})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\nfn wibble(a, b) {\\n  let result = a + b\\n  result == 10\\n}\\n\\npub fn go(x) {\\n  assert wibble(5, 5) && wibble(4, 6)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert wibble(5, 5) && wibble(4, 6)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec wibble(integer(), integer()) -> boolean().\nwibble(A, B) ->\n    Result = A + B,\n    Result =:= 10.\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec go(any()) -> nil.\ngo(X) ->\n    case wibble(5, 5) of\n        true -> case wibble(4, 6) of\n                true -> nil;\n                false -> erlang:error(#{gleam_error => assert,\n                        message => <<\"Assertion failed.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 8,\n                        kind => binary_operator,\n                        operator => '&&',\n                        left => #{kind => expression,\n                            value => true,\n                            start => 82,\n                            'end' => 94\n                            },\n                        right => #{kind => expression,\n                            value => false,\n                            start => 98,\n                            'end' => 110\n                            },\n                        start => 75,\n                        'end' => 110,\n                        expression_start => 82})\n            end;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"go\"/utf8>>,\n                line => 8,\n                kind => binary_operator,\n                operator => '&&',\n                left => #{kind => expression,\n                    value => false,\n                    start => 82,\n                    'end' => 94\n                    },\n                right => #{kind => unevaluated,\n                    start => 98,\n                    'end' => 110\n                    },\n                start => 75,\n                'end' => 110,\n                expression_start => 82})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\nfn bool() {\\n  True\\n}\\n\\npub fn main() {\\n  assert bool()\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn bool() {\n  True\n}\n\npub fn main() {\n  assert bool()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec bool() -> boolean().\nbool() ->\n    true.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> nil.\nmain() ->\n    case bool() of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 7,\n                kind => function_call,\n                arguments => [],\n                start => 41,\n                'end' => 54,\n                expression_start => 48})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\nfn and(a, b) {\\n  a && b\\n}\\n\\npub fn go(x) {\\n  assert and(True, x)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn and(a, b) {\n  a && b\n}\n\npub fn go(x) {\n  assert and(True, x)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec 'and'(boolean(), boolean()) -> boolean().\n'and'(A, B) ->\n    A andalso B.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec go(boolean()) -> nil.\ngo(X) ->\n    case 'and'(true, X) of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"go\"/utf8>>,\n                line => 7,\n                kind => function_call,\n                arguments => [#{kind => literal,\n                        value => true,\n                        start => 56,\n                        'end' => 60\n                        }, #{kind => expression,\n                        value => X,\n                        start => 62,\n                        'end' => 63\n                        }],\n                start => 45,\n                'end' => 64,\n                expression_start => 52})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_literal.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert False\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert False\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> nil.\nmain() ->\n    case false of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 3,\n                kind => expression,\n                expression => #{kind => literal,\n                    value => false,\n                    start => 26,\n                    'end' => 31\n                    },\n                start => 19,\n                'end' => 31,\n                expression_start => 26})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_nested_function_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\nfn and(x, y) {\\n  x && y\\n}\\n\\npub fn main() {\\n  assert and(and(True, False), True)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn and(x, y) {\n  x && y\n}\n\npub fn main() {\n  assert and(and(True, False), True)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec 'and'(boolean(), boolean()) -> boolean().\n'and'(X, Y) ->\n    X andalso Y.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> nil.\nmain() ->\n    _assert_subject = 'and'(true, false),\n    case 'and'(_assert_subject, true) of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 7,\n                kind => function_call,\n                arguments => [#{kind => expression,\n                        value => _assert_subject,\n                        start => 57,\n                        'end' => 73\n                        }, #{kind => literal,\n                        value => true,\n                        start => 75,\n                        'end' => 79\n                        }],\n                start => 46,\n                'end' => 80,\n                expression_start => 53})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_variable.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  let x = True\\n  assert x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = True\n  assert x\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> nil.\nmain() ->\n    X = true,\n    case X of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"Assertion failed.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 4,\n                kind => expression,\n                expression => #{kind => expression,\n                    value => false,\n                    start => 41,\n                    'end' => 42\n                    },\n                start => 34,\n                'end' => 42,\n                expression_start => 41})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_block_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\nfn identity(a) {\\n  a\\n}\\n\\npub fn main() {\\n  assert identity(True) as {\\n    let message = identity(\\\"This shouldn't fail\\\")\\n    message\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn identity(a) {\n  a\n}\n\npub fn main() {\n  assert identity(True) as {\n    let message = identity(\"This shouldn't fail\")\n    message\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(I) -> I.\nidentity(A) ->\n    A.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> nil.\nmain() ->\n    case identity(true) of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => begin\n                    Message = identity(<<\"This shouldn't fail\"/utf8>>),\n                    Message\n                end,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 7,\n                kind => function_call,\n                arguments => [#{kind => literal,\n                        value => true,\n                        start => 59,\n                        'end' => 63\n                        }],\n                start => 43,\n                'end' => 64,\n                expression_start => 50})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True as \\\"This shouldn't fail\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True as \"This shouldn't fail\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> nil.\nmain() ->\n    case true of\n        true -> nil;\n        false -> erlang:error(#{gleam_error => assert,\n                message => <<\"This shouldn't fail\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 3,\n                kind => expression,\n                expression => #{kind => literal,\n                    value => false,\n                    start => 26,\n                    'end' => 30\n                    },\n                start => 19,\n                'end' => 30,\n                expression_start => 26})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"pub fn main() {\\n  let a = 1\\n  let simple = <<1, a>>\\n  let complex = <<4:int-big, 5.0:little-float, 6:native-int>>\\n  let assert <<7:2, 8:size(3), b:bytes-size(4)>> = <<1>>\\n  let assert <<c:8-unit(1), d:bytes-size(2)-unit(2)>> = <<1>>\\n\\n  simple\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a = 1\n  let simple = <<1, a>>\n  let complex = <<4:int-big, 5.0:little-float, 6:native-int>>\n  let assert <<7:2, 8:size(3), b:bytes-size(4)>> = <<1>>\n  let assert <<c:8-unit(1), d:bytes-size(2)-unit(2)>> = <<1>>\n\n  simple\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main() -> bitstring().\nmain() ->\n    A = 1,\n    Simple = <<1, A>>,\n    Complex = <<4/integer-big, 5.0/little-float, 6/native-integer>>,\n    B@1 = case <<1>> of\n        <<7:2, 8:3, B:4/binary>> -> B;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 5,\n                        value => _assert_fail,\n                        start => 116,\n                        'end' => 170,\n                        pattern_start => 127,\n                        pattern_end => 162})\n    end,\n    {C@1, D@1} = case <<1>> of\n        <<C:8/unit:1, D:2/binary-unit:2>> -> {C, D};\n        _assert_fail@1 ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 6,\n                        value => _assert_fail@1,\n                        start => 173,\n                        'end' => 232,\n                        pattern_start => 184,\n                        pattern_end => 224})\n    end,\n    Simple.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"pub fn x() { 2 }\\npub fn main() {\\n  let a = -1\\n  let b = <<a:unit(2)-size(a * 2), a:size(3 + x())-unit(1)>>\\n\\n  b\\n}\\n\"\n---\n----- SOURCE CODE\npub fn x() { 2 }\npub fn main() {\n  let a = -1\n  let b = <<a:unit(2)-size(a * 2), a:size(3 + x())-unit(1)>>\n\n  b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x() -> integer().\nx() ->\n    2.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    A = -1,\n    B = <<A:(lists:max([(A * 2), 0]))/unit:2,\n        A:(lists:max([(3 + x()), 0]))/unit:1>>,\n    B.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"pub fn main() {\\n  let a = 1\\n  let assert <<b, 1>> = <<1, a>>\\n  b\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a = 1\n  let assert <<b, 1>> = <<1, a>>\n  b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main() -> integer().\nmain() ->\n    A = 1,\n    B@1 = case <<1, A>> of\n        <<B, 1>> -> B;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 30,\n                        'end' => 60,\n                        pattern_start => 41,\n                        pattern_end => 49})\n    end,\n    B@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"pub fn main() {\\n  let a = <<\\\"test\\\":utf8>>\\n  let assert <<b:utf8_codepoint, \\\"st\\\":utf8>> = a\\n  b\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a = <<\"test\":utf8>>\n  let assert <<b:utf8_codepoint, \"st\":utf8>> = a\n  b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main() -> integer().\nmain() ->\n    A = <<\"test\"/utf8>>,\n    B@1 = case A of\n        <<B/utf8, \"st\"/utf8>> -> B;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 44,\n                        'end' => 90,\n                        pattern_start => 55,\n                        pattern_end => 86})\n    end,\n    B@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array4.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"fn x() { 1 }\\npub fn main() {\\n  let a = <<x():int>>\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\nfn x() { 1 }\npub fn main() {\n  let a = <<x():int>>\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x() -> integer().\nx() ->\n    1.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    A = <<(x())/integer>>,\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array5.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"const bit_size = 8\\npub fn main() {\\n  let a = <<10:size(bit_size)>>\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\nconst bit_size = 8\npub fn main() {\n  let a = <<10:size(bit_size)>>\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    A = <<10:(lists:max([(8), 0]))>>,\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_declare_and_use_var.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"pub fn go(x) {\\n  let assert <<name_size:8, name:bytes-size(name_size)>> = x\\n  name\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n  let assert <<name_size:8, name:bytes-size(name_size)>> = x\n  name\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go(bitstring()) -> bitstring().\ngo(X) ->\n    {Name_size@1, Name@1} = case X of\n        <<Name_size:8, Name:Name_size/binary>> -> {Name_size, Name};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 17,\n                        'end' => 75,\n                        pattern_start => 28,\n                        pattern_end => 71})\n    end,\n    Name@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn bit_array_discard(x) -> Bool {\\n case x {\\n  <<_:utf8, rest:bytes>> -> True\\n   _ -> False\\n }\\n}\\n                    \"\n---\n----- SOURCE CODE\n\npub fn bit_array_discard(x) -> Bool {\n case x {\n  <<_:utf8, rest:bytes>> -> True\n   _ -> False\n }\n}\n                    \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([bit_array_discard/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec bit_array_discard(bitstring()) -> boolean().\nbit_array_discard(X) ->\n    case X of\n        <<_/utf8, Rest/binary>> ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn bit_array_discard(x) -> Bool {\\n case x {\\n  <<_discardme:utf8, rest:bytes>> -> True\\n   _ -> False\\n }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn bit_array_discard(x) -> Bool {\n case x {\n  <<_discardme:utf8, rest:bytes>> -> True\n   _ -> False\n }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([bit_array_discard/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec bit_array_discard(bitstring()) -> boolean().\nbit_array_discard(X) ->\n    case X of\n        <<_/utf8, Rest/binary>> ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_float.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"pub fn main() {\\n  let b = 16\\n  let floats = <<1.0:16-float, 5.0:float-32, 6.0:float-64-little, 1.0:float-size(b)>>\\n  let assert <<1.0:16-float, 5.0:float-32, 6.0:float-64-little, 1.0:float-size(b)>> = floats\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let b = 16\n  let floats = <<1.0:16-float, 5.0:float-32, 6.0:float-64-little, 1.0:float-size(b)>>\n  let assert <<1.0:16-float, 5.0:float-32, 6.0:float-64-little, 1.0:float-size(b)>> = floats\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main() -> bitstring().\nmain() ->\n    B = 16,\n    Floats = <<1.0:16/float,\n        5.0:32/float,\n        6.0:64/float-little,\n        1.0:(lists:max([(B), 0]))/float>>,\n    case Floats of\n        <<1.0:16/float, 5.0:32/float, 6.0:64/float-little, 1.0:B/float>> -> Floats;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 4,\n                        value => _assert_fail,\n                        start => 117,\n                        'end' => 207,\n                        pattern_start => 128,\n                        pattern_end => 198})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_constant_is_treated_as_utf8.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\nconst a = <<\\\"hello\\\", \\\" \\\", \\\"world\\\">>\\npub fn main() { a }\\n\"\n---\n----- SOURCE CODE\n\nconst a = <<\"hello\", \" \", \"world\">>\npub fn main() { a }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> bitstring().\nmain() ->\n    <<\"hello\"/utf8, \" \"/utf8, \"world\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_is_treated_as_utf8.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"hello\\\", \\\" \\\", \\\"world\\\">>\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"hello\", \" \", \"world\">>\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    <<\"hello\"/utf8, \" \"/utf8, \"world\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_pattern_is_treated_as_utf8.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  case <<>> {\\n    <<\\\"a\\\", \\\"b\\\", _:bits>> -> 1\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case <<>> {\n    <<\"a\", \"b\", _:bits>> -> 1\n    _ -> 2\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case <<>> of\n        <<\"a\"/utf8, \"b\"/utf8, _/bitstring>> ->\n            1;\n\n        _ ->\n            2\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__block_in_pattern_size.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<len, payload:size({ len - 1 } * 8)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<len, payload:size({ len - 1 } * 8)>> = <<>>\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    _assert_subject = <<>>,\n    case _assert_subject of\n        <<Len, Payload:((Len - 1) * 8)>> -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 75,\n                        pattern_start => 30,\n                        pattern_end => 68})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__discard_utf8_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n    let assert <<_:utf8, rest:bits>> = <<>>\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let assert <<_:utf8, rest:bits>> = <<>>\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    _assert_subject = <<>>,\n    case _assert_subject of\n        <<_/utf8, Rest/bitstring>> -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 21,\n                        'end' => 60,\n                        pattern_start => 32,\n                        pattern_end => 53})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__non_byte_aligned_size_calculation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  case <<>> {\\n    <<a:1, b:3, c:size(b - 2)>> -> c + b\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case <<>> {\n    <<a:1, b:3, c:size(b - 2)>> -> c + b\n    _ -> 1\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case <<>> of\n        <<A:1, B:3, C:(B - 2)>> ->\n            C + B;\n\n        _ ->\n            1\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<len, payload:size(len * 8 - 8)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<len, payload:size(len * 8 - 8)>> = <<>>\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    _assert_subject = <<>>,\n    case _assert_subject of\n        <<Len, Payload:(Len * 8 - 8)>> -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 71,\n                        pattern_start => 30,\n                        pattern_end => 64})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<len, payload:size(len / 8 - 1)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<len, payload:size(len / 8 - 1)>> = <<>>\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    _assert_subject = <<>>,\n    case _assert_subject of\n        <<Len, Payload:(Len div 8 - 1)>> -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 71,\n                        pattern_start => 30,\n                        pattern_end => 64})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let additional = 10\\n  let assert <<len, payload:size(len + additional * 8)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let additional = 10\n  let assert <<len, payload:size(len + additional * 8)>> = <<>>\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    Additional = 10,\n    _assert_subject = <<>>,\n    case _assert_subject of\n        <<Len, Payload:(Len + Additional * 8)>> -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 4,\n                        value => _assert_fail,\n                        start => 41,\n                        'end' => 102,\n                        pattern_start => 52,\n                        pattern_end => 95})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf16_codepoint_little_endian.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<codepoint:utf16_codepoint-little>> = x\\n  codepoint\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<codepoint:utf16_codepoint-little>> = x\n  codepoint\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(bitstring()) -> integer().\ngo(X) ->\n    Codepoint@1 = case X of\n        <<Codepoint/utf16-little>> -> Codepoint;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 18,\n                        'end' => 69,\n                        pattern_start => 29,\n                        pattern_end => 65})\n    end,\n    Codepoint@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf32_codepoint_little_endian.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<codepoint:utf32_codepoint-little>> = x\\n  codepoint\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<codepoint:utf32_codepoint-little>> = x\n  codepoint\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(bitstring()) -> integer().\ngo(X) ->\n    Codepoint@1 = case X of\n        <<Codepoint/utf32-little>> -> Codepoint;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 18,\n                        'end' => 69,\n                        pattern_start => 29,\n                        pattern_end => 65})\n    end,\n    Codepoint@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pipe_size_segment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<0xAE:size(5 |> identity)>>\\n}\\n\\nfn identity(x) {\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<0xAE:size(5 |> identity)>>\n}\n\nfn identity(x) {\n  x\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec identity(J) -> J.\nidentity(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    <<16#AE:(lists:max([(begin\n            _pipe = 5,\n            identity(_pipe)\n        end), 0]))>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\n    pub fn main() {\\n        let emoji = \\\"\\\\u{1F600}\\\"\\n        let arr = <<emoji:utf8>>\\n}\"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        let emoji = \"\\u{1F600}\"\n        let arr = <<emoji:utf8>>\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    Emoji = <<\"\\x{1F600}\"/utf8>>,\n    Arr = <<Emoji/binary>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\n    pub fn main() {\\n        let arr = <<\\\"\\\\u{1F600}\\\":utf8>>\\n}\"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        let arr = <<\"\\u{1F600}\":utf8>>\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> bitstring().\nmain() ->\n    Arr = <<\"\\x{1F600}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_character_encoding_in_bit_array_pattern_segment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn main() -> Nil {\\n  let wibble = <<\\\"\\\\u{00A9}wibble\\\":utf8>>\\n  let _bits = case wibble {\\n    <<\\\"\\\\u{00A9}\\\":utf8, rest: bits>> -> rest\\n    _ -> wibble\\n  }\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Nil {\n  let wibble = <<\"\\u{00A9}wibble\":utf8>>\n  let _bits = case wibble {\n    <<\"\\u{00A9}\":utf8, rest: bits>> -> rest\n    _ -> wibble\n  }\n  Nil\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> nil.\nmain() ->\n    Wibble = <<\"\\x{00A9}wibble\"/utf8>>,\n    _ = case Wibble of\n        <<\"\\x{00A9}\"/utf8, Rest/bitstring>> ->\n            Rest;\n\n        _ ->\n            Wibble\n    end,\n    nil.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf16_codepoint_little_endian.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn go(codepoint) {\\n  <<codepoint:utf16_codepoint-little>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(codepoint) {\n  <<codepoint:utf16_codepoint-little>>\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(integer()) -> bitstring().\ngo(Codepoint) ->\n    <<Codepoint/utf16-little>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf32_codepoint_little_endian.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/bit_arrays.rs\nexpression: \"\\npub fn go(codepoint) {\\n  <<codepoint:utf32_codepoint-little>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(codepoint) {\n  <<codepoint:utf32_codepoint-little>>\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(integer()) -> bitstring().\ngo(Codepoint) ->\n    <<Codepoint/utf32-little>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__aliased_string_prefix_pattern_referenced_in_guard.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    \\\"a\\\" as letter <> _ if letter == x -> letter\\n    _ -> \\\"wibble\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    \"a\" as letter <> _ if letter == x -> letter\n    _ -> \"wibble\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    case X of\n        <<\"a\"/utf8, _/binary>> when <<\"a\"/utf8>> =:= X ->\n            Letter = <<\"a\"/utf8>>,\n            Letter;\n\n        _ ->\n            <<\"wibble\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_patter_with_string_alias.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    \\\"a\\\" as letter <> _ | \\\"b\\\" as letter <> _ -> letter\\n    _ -> \\\"wibble\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    \"a\" as letter <> _ | \"b\" as letter <> _ -> letter\n    _ -> \"wibble\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    case X of\n        <<\"a\"/utf8, _/binary>> ->\n            Letter = <<\"a\"/utf8>>,\n            Letter;\n\n        <<\"b\"/utf8, _/binary>> ->\n            Letter = <<\"b\"/utf8>>,\n            Letter;\n\n        _ ->\n            <<\"wibble\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_pattern_variable_rewriting.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn myfun(mt) {\\n  case mt {\\n    1 | _ ->\\n      1\\n      |> Ok\\n  }\\n  1\\n  |> Ok\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn myfun(mt) {\n  case mt {\n    1 | _ ->\n      1\n      |> Ok\n  }\n  1\n  |> Ok\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([myfun/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec myfun(integer()) -> {ok, integer()} | {error, any()}.\nmyfun(Mt) ->\n    case Mt of\n        1 ->\n            _pipe = 1,\n            {ok, _pipe};\n\n        _ ->\n            _pipe = 1,\n            {ok, _pipe}\n    end,\n    _pipe@1 = 1,\n    {ok, _pipe@1}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__negative_zero_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    -0.0 -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    -0.0 -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(float()) -> integer().\nmain(X) ->\n    case X of\n        -0.0 ->\n            1;\n\n        _ ->\n            2\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"pub fn main(x, y) {\\n  case x {\\n    _ if !y -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x, y) {\n  case x {\n    _ if !y -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/2]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main(any(), boolean()) -> integer().\nmain(X, Y) ->\n    case X of\n        _ when not Y ->\n            0;\n\n        _ ->\n            1\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not_two.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"pub fn main(x, y) {\\n  case x {\\n    _ if !y && !x -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x, y) {\n  case x {\n    _ if !y && !x -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/2]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main(boolean(), boolean()) -> integer().\nmain(X, Y) ->\n    case X of\n        _ when not Y andalso not X ->\n            0;\n\n        _ ->\n            1\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__positive_zero_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0.0 -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(float()) -> integer().\nmain(X) ->\n    case X of\n        +0.0 ->\n            1;\n\n        _ ->\n            2\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn main() {\\n  case [] {\\n    [..] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case [] {\n    [..] -> 1\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case [] of\n        _ ->\n            1\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list_assigning.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/case.rs\nexpression: \"\\npub fn main() {\\n  case [] {\\n    [..rest] -> rest\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case [] {\n    [..rest] -> rest\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> list(any()).\nmain() ->\n    case [] of\n        Rest ->\n            Rest\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__excluded_attribute_syntax.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/conditional_compilation.rs\nexpression: \"@target(javascript)\\n  pub fn main() { 1 }\\n\"\n---\n----- SOURCE CODE\n@target(javascript)\n  pub fn main() { 1 }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__included_attribute_syntax.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/conditional_compilation.rs\nexpression: \"@target(erlang)\\n  pub fn main() { 1 }\\n\"\n---\n----- SOURCE CODE\n@target(erlang)\n  pub fn main() { 1 }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_generalise.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\nfn identity(a: a) -> a {\\na\\n}\\n\\nconst id  = identity\\n\\npub fn main(){\\n  let num  = id(1)\\n  let word = id(\\\"Word\\\")\\n}\"\n---\n----- SOURCE CODE\n\nfn identity(a: a) -> a {\na\n}\n\nconst id  = identity\n\npub fn main(){\n  let num  = id(1)\n  let word = id(\"Word\")\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(I) -> I.\nidentity(A) ->\n    A.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main() -> binary().\nmain() ->\n    Num = identity(1),\n    Word = identity(<<\"Word\"/utf8>>).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_type_variable.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\nfn identity(a: a) -> a {\\n  a\\n}\\n\\nconst id: fn(a) -> a = identity\\n\"\n---\n----- SOURCE CODE\n\nfn identity(a: a) -> a {\n  a\n}\n\nconst id: fn(a) -> a = identity\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\nconst wibble = [2, 3, 4]\\npub const wobble = [0, 1, ..wibble]\\n\\npub fn main() {\\n  wobble\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [2, 3, 4]\npub const wobble = [0, 1, ..wibble]\n\npub fn main() {\n  wobble\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> list(integer()).\nmain() ->\n    [0, 1, 2, 3, 4].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_from_other_module.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\nimport mod\\n\\npub const wobble = [0, 1, ..mod.wibble]\\n\\npub fn main() {\\n  wobble\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport mod\n\npub const wobble = [0, 1, ..mod.wibble]\n\npub fn main() {\n  wobble\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> list(integer()).\nmain() ->\n    [0, 1, 2, 3, 4].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_literal.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\npub const wibble = [0, 1, ..[2, 3, 4]]\\n\\npub fn main() {\\n  wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const wibble = [0, 1, ..[2, 3, 4]]\n\npub fn main() {\n  wibble\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> list(integer()).\nmain() ->\n    [0, 1, 2, 3, 4].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_private_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n          fn identity(a) {\\n            a\\n          }\\n\\n          pub const id = identity\\n        \"\n---\n----- SOURCE CODE\n\n          fn identity(a) {\n            a\n          }\n\n          pub const id = identity\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(I) -> I.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_nested_private_function_field.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n          fn identity(a) {\\n            a\\n          }\\n\\n          pub type Mapper(b) {\\n            Mapper(fn(b) -> b)\\n          }\\n\\n          pub type Funcs(b) {\\n            Funcs(mapper: Mapper(b))\\n          }\\n\\n          pub const id_mapper = Funcs(Mapper(identity))\\n        \"\n---\n----- SOURCE CODE\n\n          fn identity(a) {\n            a\n          }\n\n          pub type Mapper(b) {\n            Mapper(fn(b) -> b)\n          }\n\n          pub type Funcs(b) {\n            Funcs(mapper: Mapper(b))\n          }\n\n          pub const id_mapper = Funcs(Mapper(identity))\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n-export_type([mapper/1, funcs/1]).\n\n-type mapper(I) :: {mapper, fun((I) -> I)}.\n\n-type funcs(J) :: {funcs, mapper(J)}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(K) -> K.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_private_function_field.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n          fn identity(a) {\\n            a\\n          }\\n\\n          pub type Mapper(b) {\\n            Mapper(fn(b) -> b)\\n          }\\n\\n          pub const id_mapper = Mapper(identity)\\n        \"\n---\n----- SOURCE CODE\n\n          fn identity(a) {\n            a\n          }\n\n          pub type Mapper(b) {\n            Mapper(fn(b) -> b)\n          }\n\n          pub const id_mapper = Mapper(identity)\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n-export_type([mapper/1]).\n\n-type mapper(I) :: {mapper, fun((I) -> I)}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(J) -> J.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\npub type X {\\n  X(Int)\\n}\\n\\npub const z = X\\n\\npub fn main() {\\n  z\\n}\"\n---\n----- SOURCE CODE\n\npub type X {\n  X(Int)\n}\n\npub const z = X\n\npub fn main() {\n  z\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([x/0]).\n\n-type x() :: {x, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main() -> fun((integer()) -> x()).\nmain() ->\n    fun(Field@0) -> {x, Field@0} end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor_in_tuple.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\npub type X {\\n  X(Int)\\n}\\n\\npub const z = #(X)\\n\\npub fn main() {\\n  z\\n}\"\n---\n----- SOURCE CODE\n\npub type X {\n  X(Int)\n}\n\npub const z = #(X)\n\npub fn main() {\n  z\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([x/0]).\n\n-type x() :: {x, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main() -> {fun((integer()) -> x())}.\nmain() ->\n    {fun(Field@0) -> {x, Field@0} end}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_internal.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n              fn identity(a) {\\n                a\\n              }\\n\\n              pub type Mapper(b) {\\n                Mapper(fn(b) -> b)\\n              }\\n\\n              @internal\\n              pub const id_mapper = Mapper(identity)\\n        \"\n---\n----- SOURCE CODE\n\n              fn identity(a) {\n                a\n              }\n\n              pub type Mapper(b) {\n                Mapper(fn(b) -> b)\n              }\n\n              @internal\n              pub const id_mapper = Mapper(identity)\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n-export_type([mapper/1]).\n\n-type mapper(I) :: {mapper, fun((I) -> I)}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(J) -> J.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_list.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n          fn identity(a) {\\n            a\\n          }\\n\\n          pub const funcs = [identity]\\n        \"\n---\n----- SOURCE CODE\n\n          fn identity(a) {\n            a\n          }\n\n          pub const funcs = [identity]\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(I) -> I.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_tuple.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n          fn identity(a) {\\n            a\\n          }\\n\\n          pub const funcs = #(identity)\\n        \"\n---\n----- SOURCE CODE\n\n          fn identity(a) {\n            a\n          }\n\n          pub const funcs = #(identity)\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(I) -> I.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_qualified_pub_const_equal_to_record_with_private_function_field.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n              fn identity(a) {\\n                a\\n              }\\n\\n              pub type Mapper(b) {\\n                Mapper(fn(b) -> b)\\n              }\\n\\n              pub const id_mapper = Mapper(identity)\\n        \"\n---\n----- SOURCE CODE\n\n              fn identity(a) {\n                a\n              }\n\n              pub type Mapper(b) {\n                Mapper(fn(b) -> b)\n              }\n\n              pub const id_mapper = Mapper(identity)\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n-export_type([mapper/1]).\n\n-type mapper(I) :: {mapper, fun((I) -> I)}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(J) -> J.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_private_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n              fn identity(a) {\\n                a\\n              }\\n\\n              pub const id = identity\\n        \"\n---\n----- SOURCE CODE\n\n              fn identity(a) {\n                a\n              }\n\n              pub const id = identity\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(I) -> I.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_record_with_private_function_field.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/consts.rs\nexpression: \"\\n              fn identity(a) {\\n                a\\n              }\\n\\n              pub type Mapper(b) {\\n                Mapper(fn(b) -> b)\\n              }\\n\\n              pub const id_mapper = Mapper(identity)\\n        \"\n---\n----- SOURCE CODE\n\n              fn identity(a) {\n                a\n              }\n\n              pub type Mapper(b) {\n                Mapper(fn(b) -> b)\n              }\n\n              pub const id_mapper = Mapper(identity)\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1]).\n-export_type([mapper/1]).\n\n-type mapper(I) :: {mapper, fun((I) -> I)}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec identity(J) -> J.\nidentity(A) ->\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/custom_types.rs\nexpression: \"\\n@external(erlang, \\\"gleam_stdlib\\\", \\\"dict\\\")\\npub type Dict(key, value)\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"gleam_stdlib\", \"dict\")\npub type Dict(key, value)\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([dict/2]).\n\n-type dict(I, J) :: gleam_stdlib:dict(I, J).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type_used_in_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/custom_types.rs\nexpression: \"\\n@external(erlang, \\\"gleam_stdlib\\\", \\\"dict\\\")\\npub type Dict(key, value)\\n\\n@external(erlang, \\\"maps\\\", \\\"get\\\")\\npub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"gleam_stdlib\", \"dict\")\npub type Dict(key, value)\n\n@external(erlang, \"maps\", \"get\")\npub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([get/2]).\n-export_type([dict/2]).\n\n-type dict(I, J) :: gleam_stdlib:dict(I, J).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec get(dict(K, L), K) -> {ok, L} | {error, nil}.\nget(Dict, Key) ->\n    maps:get(Dict, Key).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__phantom.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/custom_types.rs\nexpression: \"pub type Map(k, v)\"\n---\n----- SOURCE CODE\npub type Map(k, v)\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([map_/2]).\n\n-type map_(I, J) :: any() | {gleam_phantom, I, J}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__unused_opaque_constructor_is_generated_correctly.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/custom_types.rs\nexpression: \"\\ntype Wibble {\\n  Wibble\\n}\\n\\npub opaque type Wobble {\\n  Wobble(Wibble)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble\n}\n\npub opaque type Wobble {\n  Wobble(Wibble)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([wibble/0, wobble/0]).\n\n-type wibble() :: wibble.\n\n-opaque wobble() :: {wobble, wibble()}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_are_escaped_in_module_comment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n//// \\\\backslashes!\\\\\\n\\npub fn main() { 1 }\"\n---\n----- SOURCE CODE\n\n//// \\backslashes!\\\n\npub fn main() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n?MODULEDOC(\" \\\\backslashes!\\\\\\n\").\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_in_documentation_are_escaped.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n/// \\\\hello\\\\\\npub fn documented() { 1 }\"\n---\n----- SOURCE CODE\n\n/// \\hello\\\npub fn documented() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([documented/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"project/test/my/mod.gleam\", 3).\n?DOC(\" \\\\hello\\\\\\n\").\n-spec documented() -> integer().\ndocumented() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__double_quotes_are_escaped_in_module_comment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n//// \\\"quotes!\\\"\\n\\npub fn main() { 1 }\"\n---\n----- SOURCE CODE\n\n//// \"quotes!\"\n\npub fn main() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n?MODULEDOC(\" \\\"quotes!\\\"\\n\").\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_documentation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n/// Function doc!\\npub fn documented() { 1 }\"\n---\n----- SOURCE CODE\n\n/// Function doc!\npub fn documented() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([documented/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"project/test/my/mod.gleam\", 3).\n?DOC(\" Function doc!\\n\").\n-spec documented() -> integer().\ndocumented() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_multiline_documentation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n/// Function doc!\\n/// Hello!!\\n///\\npub fn documented() { 1 }\"\n---\n----- SOURCE CODE\n\n/// Function doc!\n/// Hello!!\n///\npub fn documented() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([documented/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"project/test/my/mod.gleam\", 5).\n?DOC(\n    \" Function doc!\\n\"\n    \" Hello!!\\n\"\n).\n-spec documented() -> integer().\ndocumented() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__internal_function_has_no_documentation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n/// hidden!\\n@internal\\npub fn main() { 1 }\"\n---\n----- SOURCE CODE\n\n/// hidden!\n@internal\npub fn main() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"project/test/my/mod.gleam\", 4).\n?DOC(false).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__multi_line_module_comment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n//// Hello! This is a multi-\\n//// line module comment.\\n////\\n\\npub fn main() { 1 }\"\n---\n----- SOURCE CODE\n\n//// Hello! This is a multi-\n//// line module comment.\n////\n\npub fn main() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n?MODULEDOC(\n    \" Hello! This is a multi-\\n\"\n    \" line module comment.\\n\"\n    \"\\n\"\n).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__quotes_in_documentation_are_escaped.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n/// \\\"hello\\\"\\npub fn documented() { 1 }\"\n---\n----- SOURCE CODE\n\n/// \"hello\"\npub fn documented() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([documented/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"project/test/my/mod.gleam\", 3).\n?DOC(\" \\\"hello\\\"\\n\").\n-spec documented() -> integer().\ndocumented() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__single_line_module_comment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/documentation.rs\nexpression: \"\\n//// Hello! This is a single line module comment.\\n\\npub fn main() { 1 }\"\n---\n----- SOURCE CODE\n\n//// Hello! This is a single line module comment.\n\npub fn main() { 1 }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n?MODULEDOC(\" Hello! This is a single line module comment.\\n\").\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> integer().\nmain() ->\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> echo\\n  |> wibble\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/1, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec wibble(J) -> J.\nwibble(N) ->\n    N.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> list(integer()).\nmain() ->\n    _pipe = [1, 2, 3],\n    echo(_pipe, nil, 4),\n    wibble(_pipe).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline_with_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> echo as \\\"message!!\\\"\\n  |> wibble\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, 2, 3]\n  |> echo as \"message!!\"\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/1, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec wibble(J) -> J.\nwibble(N) ->\n    N.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> list(integer()).\nmain() ->\n    _pipe = [1, 2, 3],\n    echo(_pipe, <<\"message!!\"/utf8>>, 4),\n    wibble(_pipe).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo {\\n    Nil\\n    1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo {\n    Nil\n    1\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(\n        begin\n            nil,\n            1\n        end,\n        nil,\n        3\n    ).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_case_expression.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo case 1 {\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo case 1 {\n    _ -> 2\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(case 1 of\n            _ ->\n                2\n        end, nil, 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo wibble(1, 2)\\n}\\n\\nfn wibble(n: Int, m: Int) { n + m }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo wibble(1, 2)\n}\n\nfn wibble(n: Int, m: Int) { n + m }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec wibble(integer(), integer()) -> integer().\nwibble(N, M) ->\n    N + M.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(wibble(1, 2), nil, 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call_and_a_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo wibble(1, 2) as message()\\n}\\n\\nfn wibble(n: Int, m: Int) { n + m }\\nfn message() { \\\"Hello!\\\" }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo wibble(1, 2) as message()\n}\n\nfn wibble(n: Int, m: Int) { n + m }\nfn message() { \"Hello!\" }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec wibble(integer(), integer()) -> integer().\nwibble(N, M) ->\n    N + M.\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec message() -> binary().\nmessage() ->\n    <<\"Hello!\"/utf8>>.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(wibble(1, 2), message(), 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_panic.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo panic\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo panic\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    echo(erlang:error(#{gleam_error => panic,\n                message => <<\"`panic` expression evaluated.\"/utf8>>,\n                file => <<?FILEPATH/utf8>>,\n                module => <<\"my/mod\"/utf8>>,\n                function => <<\"main\"/utf8>>,\n                line => 3}), nil, 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(1, nil, 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression_and_a_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1 as \\\"hello!\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1 as \"hello!\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(1, <<\"hello!\"/utf8>>, 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_complex_expression_as_a_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1 as case name() {\\n    \\\"Giacomo\\\" -> \\\"hello Jak!\\\"\\n    _ -> \\\"hello!\\\"\\n  }\\n}\\n\\nfn name() { \\\"Giacomo\\\" }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1 as case name() {\n    \"Giacomo\" -> \"hello Jak!\"\n    _ -> \"hello!\"\n  }\n}\n\nfn name() { \"Giacomo\" }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec name() -> binary().\nname() ->\n    <<\"Giacomo\"/utf8>>.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(1, case name() of\n            <<\"Giacomo\"/utf8>> ->\n                <<\"hello Jak!\"/utf8>>;\n\n            _ ->\n                <<\"hello!\"/utf8>>\n        end, 3).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_in_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> echo\\n  |> wibble\\n  |> echo\\n  |> wibble\\n  |> echo\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n  |> echo\n  |> wibble\n  |> echo\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/1, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 11).\n-spec wibble(J) -> J.\nwibble(N) ->\n    N.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> list(integer()).\nmain() ->\n    _pipe = [1, 2, 3],\n    echo(_pipe, nil, 4),\n    _pipe@1 = wibble(_pipe),\n    echo(_pipe@1, nil, 6),\n    _pipe@2 = wibble(_pipe@1),\n    echo(_pipe@2, nil, 8).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_inside_expression.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1\\n  echo 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1\n  echo 2\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(1, nil, 3),\n    echo(2, nil, 4).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__pipeline_printed_by_echo_is_wrapped_in_begin_end_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo\\n    123\\n    |> wibble\\n    |> wibble\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo\n    123\n    |> wibble\n    |> wibble\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/1, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec wibble(J) -> J.\nwibble(N) ->\n    N.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    echo(\n        begin\n            _pipe = 123,\n            _pipe@1 = wibble(_pipe),\n            wibble(_pipe@1)\n        end,\n        nil,\n        3\n    ).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/echo.rs\nexpression: \"\\npub type Wobble { Wobble(id: Int, name: String) }\\n\\npub fn main() {\\n  let wobble = Wobble(1, \\\"wobble\\\")\\n  echo Wobble(..wobble, id: 1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wobble { Wobble(id: Int, name: String) }\n\npub fn main() {\n  let wobble = Wobble(1, \"wobble\")\n  echo Wobble(..wobble, id: 1)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([wobble/0]).\n\n-type wobble() :: {wobble, integer(), binary()}.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> wobble().\nmain() ->\n    Wobble = {wobble, 1, <<\"wobble\"/utf8>>},\n    echo({wobble, 1, erlang:element(3, Wobble)}, nil, 6).\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_erlang.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([one/1]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec one(integer()) -> integer().\none(X) ->\n    one:one(X).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_javascript.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(javascript, \\\"./one.mjs\\\", \\\"one\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./one.mjs\", \"one\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([one/1]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec one(integer()) -> integer().\none(X) ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"one\"/utf8>>,\n            line => 4}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__both_externals_no_valid_impl.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn js() -> Nil\\n\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn erl() -> Nil\\n\\npub fn should_not_be_generated() {\\n  js()\\n  erl()\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"one\", \"one\")\npub fn js() -> Nil\n\n@external(erlang, \"one\", \"one\")\npub fn erl() -> Nil\n\npub fn should_not_be_generated() {\n  js()\n  erl()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([erl/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec erl() -> nil.\nerl() ->\n    one:one().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__discarded_arg_in_external_are_passed_correctly.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"wibble\\\", \\\"wobble\\\")\\npub fn woo(_a: a) -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"wibble\", \"wobble\")\npub fn woo(_a: a) -> Nil\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([woo/1]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec woo(any()) -> nil.\nwoo(_a) ->\n    wibble:wobble(_a).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__elixir.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\npub fn main() {\\n  #(do, do())\\n}\\n\\n@external(erlang, \\\"Elixir.String\\\", \\\"main\\\")\\nfn do() -> Int\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  #(do, do())\n}\n\n@external(erlang, \"Elixir.String\", \"main\")\nfn do() -> Int\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> {fun(() -> integer()), integer()}.\nmain() ->\n    {fun 'Elixir.String':main/0, 'Elixir.String':main()}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__erlang_and_javascript.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\n@external(javascript, \\\"./one.mjs\\\", \\\"one\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\n@external(javascript, \"./one.mjs\", \"one\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([one/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec one(integer()) -> integer().\none(X) ->\n    one:one(X).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__hole_parameter_erlang.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn one(x: List(_)) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\npub fn one(x: List(_)) -> Int {\n  todo\n}\n\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:3:20\n  │\n3 │ pub fn one(x: List(_)) -> Int {\n  │                    ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__hole_parameter_javascript.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn one(x: List(_)) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"one\", \"one\")\npub fn one(x: List(_)) -> Int {\n  todo\n}\n\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:3:20\n  │\n3 │ pub fn one(x: List(_)) -> Int {\n  │                    ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__hole_return_erlang.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn one(x: List(Int)) -> List(_) {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\npub fn one(x: List(Int)) -> List(_) {\n  todo\n}\n\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:3:34\n  │\n3 │ pub fn one(x: List(Int)) -> List(_) {\n  │                                  ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__hole_return_javascript.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn one(x: List(Int)) -> List(_) {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"one\", \"one\")\npub fn one(x: List(Int)) -> List(_) {\n  todo\n}\n\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:3:34\n  │\n3 │ pub fn one(x: List(Int)) -> List(_) {\n  │                                  ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__inlining_external_functions_from_another_module.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"import atom\\npub fn main() {\\n  atom.make(\\\"ok\\\")\\n}\\n\"\n---\n----- SOURCE CODE\nimport atom\npub fn main() {\n  atom.make(\"ok\")\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> atom:atom_().\nmain() ->\n    erlang:binary_to_atom(<<\"ok\"/utf8>>).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test1_3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"Elixir.MyApp\\\", \\\"run\\\")\\npub fn run() -> Int\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"Elixir.MyApp\", \"run\")\npub fn run() -> Int\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([run/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec run() -> integer().\nrun() ->\n    'Elixir.MyApp':run().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test7.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"try\\\", \\\"and\\\")\\npub fn receive() -> Int\\npub fn catch(x) { receive() }\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"try\", \"and\")\npub fn receive() -> Int\npub fn catch(x) { receive() }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export(['receive'/0, 'catch'/1]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec 'receive'() -> integer().\n'receive'() ->\n    'try':'and'().\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec 'catch'(any()) -> integer().\n'catch'(X) ->\n    'try':'and'().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\npub fn should_be_generated(x: Int) -> Int {\\n  x\\n}\\n\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn should_not_be_generated(x: Int) -> Int\\n\"\n---\n----- SOURCE CODE\n\npub fn should_be_generated(x: Int) -> Int {\n  x\n}\n\n@external(javascript, \"one\", \"one\")\npub fn should_not_be_generated(x: Int) -> Int\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([should_be_generated/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec should_be_generated(integer()) -> integer().\nshould_be_generated(X) ->\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only_indirect.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\npub fn should_be_generated(x: Int) -> Int {\\n  x\\n}\\n\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn should_not_be_generated(x: Int) -> Int\\n\\npub fn also_should_not_be_generated() {\\n  should_not_be_generated(1)\\n  |> should_be_generated\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn should_be_generated(x: Int) -> Int {\n  x\n}\n\n@external(javascript, \"one\", \"one\")\npub fn should_not_be_generated(x: Int) -> Int\n\npub fn also_should_not_be_generated() {\n  should_not_be_generated(1)\n  |> should_be_generated\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([should_be_generated/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec should_be_generated(integer()) -> integer().\nshould_be_generated(X) ->\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"wibble\\\", \\\"wobble\\\")\\npub fn woo(_: a, _: b) -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"wibble\", \"wobble\")\npub fn woo(_: a, _: b) -> Nil\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([woo/2]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec woo(any(), any()) -> nil.\nwoo(Argument, Argument@1) ->\n    wibble:wobble(Argument, Argument@1).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly_2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"wibble\\\", \\\"wobble\\\")\\npub fn woo(__: a, _two: b) -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"wibble\", \"wobble\")\npub fn woo(__: a, _two: b) -> Nil\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([woo/2]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec woo(any(), any()) -> nil.\nwoo(Argument, _two) ->\n    wibble:wobble(Argument, _two).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_body.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn one(x: Int) -> Int\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int) -> Int\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([one/1]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec one(integer()) -> integer().\none(X) ->\n    one:one(X).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_body_or_implementation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\npub fn one(x: Int) -> Float\\n\"\n---\n----- SOURCE CODE\n\npub fn one(x: Int) -> Float\n\n\n----- ERROR\nerror: Function without an implementation\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ pub fn one(x: Int) -> Float\n  │ ^^^^^^^^^^^^^^^^^^\n\nWe can't compile this function as it doesn't have an\nimplementation. Add a body or an external implementation\nusing the `@external` attribute.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_gleam_impl_no_annotations_function_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"two\\\")\\npub fn no_impl()\\n\\npub type X = UnknownType\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"two\")\npub fn no_impl()\n\npub type X = UnknownType\n\n\n----- ERROR\nerror: Missing type annotation\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub fn no_impl()\n  │ ^^^^^^^^^^^^^^^^\n\nA return annotation is missing from this function.\n\nFunctions with external implementations must have type annotations\nso we can tell what type of values they accept and return.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:5:14\n  │\n5 │ pub type X = UnknownType\n  │              ^^^^^^^^^^^\n\nThe type `UnknownType` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_target_supported_function_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n// This will error for having no support on this platform\\n@external(erlang, \\\"one\\\", \\\"two\\\")\\npub fn no_impl() -> Int\\n\\npub fn main() {\\n  // This will due to no_impl not having an appropriate implementation for the\\n  // target, NOT because it doesn't exist. The analyser should still know about\\n  // it, even though it is invalid.\\n  no_impl()\\n}\\n\"\n---\n----- SOURCE CODE\n\n// This will error for having no support on this platform\n@external(erlang, \"one\", \"two\")\npub fn no_impl() -> Int\n\npub fn main() {\n  // This will due to no_impl not having an appropriate implementation for the\n  // target, NOT because it doesn't exist. The analyser should still know about\n  // it, even though it is invalid.\n  no_impl()\n}\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:4:1\n  │\n4 │ pub fn no_impl() -> Int\n  │ ^^^^^^^^^^^^^^^^\n\nThe `no_impl` function is public but doesn't have an implementation for the\nJavaScript target. All public functions of a package must be able to\ncompile for a module to be valid.\n\nerror: Unsupported target\n   ┌─ /src/one/two.gleam:10:3\n   │\n10 │   no_impl()\n   │   ^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the JavaScript target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_type_annotation_for_parameter.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn one(x: Int, y) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int, y) -> Int {\n  todo\n}\n\n\n----- ERROR\nerror: Missing type annotation\n  ┌─ /src/one/two.gleam:3:20\n  │\n3 │ pub fn one(x: Int, y) -> Int {\n  │                    ^\n\nA parameter annotation is missing from this function.\n\nFunctions with external implementations must have type annotations\nso we can tell what type of values they accept and return.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_type_annotation_for_return.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn one(x: Int) {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\npub fn one(x: Int) {\n  todo\n}\n\n\n----- ERROR\nerror: Missing type annotation\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub fn one(x: Int) {\n  │ ^^^^^^^^^^^^^^^^^^\n\nA return annotation is missing from this function.\n\nFunctions with external implementations must have type annotations\nso we can tell what type of values they accept and return.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\npub fn main() {\\n  do()\\n}\\n\\n@external(erlang, \\\"library\\\", \\\"main\\\")\\nfn do() -> Int\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  do()\n}\n\n@external(erlang, \"library\", \"main\")\nfn do() -> Int\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    library:main().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_external_function_calls.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"m\\\", \\\"f\\\")\\nfn go(x x: Int, y y: Int) -> Int\\n\\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"m\", \"f\")\nfn go(x x: Int, y y: Int) -> Int\n\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec x() -> integer().\nx() ->\n    m:f(1, 2),\n    m:f(4, 3).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_local_function_references.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"m\\\", \\\"f\\\")\\nfn go(x: Int, y: Int) -> Int\\npub fn x() { go }\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"m\", \"f\")\nfn go(x: Int, y: Int) -> Int\npub fn x() { go }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec x() -> fun((integer(), integer()) -> integer()).\nx() ->\n    fun m:f/2.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_elixir.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"Elixir.String\\\", \\\"main\\\")\\npub fn do() -> Int\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"Elixir.String\", \"main\")\npub fn do() -> Int\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([do/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec do() -> integer().\ndo() ->\n    'Elixir.String':main().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_local_function_calls.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"\\n@external(erlang, \\\"m\\\", \\\"f\\\")\\npub fn go(x x: Int, y y: Int) -> Int\\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"m\", \"f\")\npub fn go(x x: Int, y y: Int) -> Int\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/2, x/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec go(integer(), integer()) -> integer().\ngo(X, Y) ->\n    m:f(X, Y).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec x() -> integer().\nx() ->\n    m:f(1, 2),\n    m:f(4, 3).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__reference_to_imported_elixir_external_fn.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"import my_app\\npub fn main() {\\n  let x = my_app.run\\n  id(my_app.run)\\n}\\nfn id(x) { x }\\n\"\n---\n----- SOURCE CODE\nimport my_app\npub fn main() {\n  let x = my_app.run\n  id(my_app.run)\n}\nfn id(x) { x }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec id(K) -> K.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> fun(() -> integer()).\nmain() ->\n    X = fun 'Elixir.MyApp':run/0,\n    id(fun 'Elixir.MyApp':run/0).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_inlining_external_functions_from_another_module.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"import atom.{make}\\npub fn main() {\\n  make(\\\"ok\\\")\\n}\\n\"\n---\n----- SOURCE CODE\nimport atom.{make}\npub fn main() {\n  make(\"ok\")\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> atom:atom_().\nmain() ->\n    erlang:binary_to_atom(<<\"ok\"/utf8>>).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_reference_to_imported_elixir_external_fn.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/external_fn.rs\nexpression: \"import my_app.{run}\\npub fn main() {\\n  let x = run\\n  id(run)\\n}\\nfn id(x) { x }\\n\"\n---\n----- SOURCE CODE\nimport my_app.{run}\npub fn main() {\n  let x = run\n  id(run)\n}\nfn id(x) { x }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec id(K) -> K.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> fun(() -> integer()).\nmain() ->\n    X = fun 'Elixir.MyApp':run/0,\n    id(fun 'Elixir.MyApp':run/0).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_as_value.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nfn other() {\\n  Nil\\n}\\n\\npub fn main() {\\n  other\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn other() {\n  Nil\n}\n\npub fn main() {\n  other\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec other() -> nil.\nother() ->\n    nil.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> fun(() -> nil).\nmain() ->\n    fun other/0.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_called.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  main()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  main()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    main().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__labelled_argument_ordering.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\ntype A { A }\\ntype B { B }\\ntype C { C }\\ntype D { D }\\n\\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\\n  Nil\\n}\\n\\npub fn main() {\\n  wibble(A, C, D, b: B)\\n  wibble(A, C, D, b: B)\\n  wibble(B, C, D, a: A)\\n  wibble(B, C, a: A, d: D)\\n  wibble(B, C, d: D, a: A)\\n  wibble(B, D, a: A, c: C)\\n  wibble(B, D, c: C, a: A)\\n  wibble(C, D, b: B, a: A)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype A { A }\ntype B { B }\ntype C { C }\ntype D { D }\n\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\n  Nil\n}\n\npub fn main() {\n  wibble(A, C, D, b: B)\n  wibble(A, C, D, b: B)\n  wibble(B, C, D, a: A)\n  wibble(B, C, a: A, d: D)\n  wibble(B, C, d: D, a: A)\n  wibble(B, D, a: A, c: C)\n  wibble(B, D, c: C, a: A)\n  wibble(C, D, b: B, a: A)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([a/0, b/0, c/0, d/0]).\n\n-type a() :: a.\n\n-type b() :: b.\n\n-type c() :: c.\n\n-type d() :: d.\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec wibble(a(), b(), c(), d()) -> nil.\nwibble(A, B, C, D) ->\n    nil.\n\n-file(\"project/test/my/mod.gleam\", 11).\n-spec main() -> nil.\nmain() ->\n    wibble(a, b, c, d),\n    wibble(a, b, c, d),\n    wibble(a, b, c, d),\n    wibble(a, b, c, d),\n    wibble(a, b, c, d),\n    wibble(a, b, c, d),\n    wibble(a, b, c, d),\n    wibble(a, b, c, d).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_as_value.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nimport some/other.{wibble as wobble}\\n\\npub fn main() {\\n  wobble\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some/other.{wibble as wobble}\n\npub fn main() {\n  wobble\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> fun(() -> nil).\nmain() ->\n    fun some@other:wibble/0.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_called.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nimport some/other.{wibble as wobble}\\n\\npub fn main() {\\n  wobble()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some/other.{wibble as wobble}\n\npub fn main() {\n  wobble()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> nil.\nmain() ->\n    some@other:wibble().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_as_value.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nimport some/other\\n\\npub fn main() {\\n  other.wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some/other\n\npub fn main() {\n  other.wibble\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> fun(() -> nil).\nmain() ->\n    fun some@other:wibble/0.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_called.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nimport some/other\\n\\npub fn main() {\\n  other.wibble()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some/other\n\npub fn main() {\n  other.wibble()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> nil.\nmain() ->\n    some@other:wibble().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_as_value.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nimport some/other.{wibble}\\n\\npub fn main() {\\n  wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some/other.{wibble}\n\npub fn main() {\n  wibble\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> fun(() -> nil).\nmain() ->\n    fun some@other:wibble/0.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_called.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\nimport some/other.{wibble}\\n\\npub fn main() {\\n  wibble()\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport some/other.{wibble}\n\npub fn main() {\n  wibble()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> nil.\nmain() ->\n    some@other:wibble().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__unused_private_functions.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/functions.rs\nexpression: \"\\npub fn main() -> Int {\\n  used()\\n}\\n\\nfn used() -> Int {\\n  123\\n}\\n\\nfn unused1() -> Int {\\n  unused2()\\n}\\n\\nfn unused2() -> Int {\\n  used()\\n}\\n\\nfn unused3() -> Int {\\n  used()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Int {\n  used()\n}\n\nfn used() -> Int {\n  123\n}\n\nfn unused1() -> Int {\n  unused2()\n}\n\nfn unused2() -> Int {\n  used()\n}\n\nfn unused3() -> Int {\n  used()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec used() -> integer().\nused() ->\n    123.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    used().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main(args) {\\n  case args {\\n    x if x == args -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(args) {\n  case args {\n    x if x == args -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(any()) -> integer().\nmain(Args) ->\n    case Args of\n        X when X =:= Args ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards20.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = 0.123\\n  case x {\\n    _ if 0.123 <. x -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 0.123\n  case x {\n    _ if 0.123 <. x -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 0.123,\n    case X of\n        _ when 0.123 < X ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards21.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    _ if x == [1, 2, 3] -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    _ if x == [1, 2, 3] -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(list(integer())) -> integer().\nmain(X) ->\n    case X of\n        _ when X =:= [1, 2, 3] ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards22.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = 0\\n  case x {\\n    0 -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 0\n  case x {\n    0 -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 0,\n    case X of\n        0 ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards23.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = #(1, 2, 3)\\n  case x {\\n    _ if x == #(1, 2, 3) -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = #(1, 2, 3)\n  case x {\n    _ if x == #(1, 2, 3) -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = {1, 2, 3},\n    case X of\n        _ when X =:= {1, 2, 3} ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards24.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = #(1, 2, 3)\\n  case x {\\n    _ if x == #(1, 2, 3) -> 1\\n    _ if x == #(2, 3, 4) -> 2\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = #(1, 2, 3)\n  case x {\n    _ if x == #(1, 2, 3) -> 1\n    _ if x == #(2, 3, 4) -> 2\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = {1, 2, 3},\n    case X of\n        _ when X =:= {1, 2, 3} ->\n            1;\n\n        _ when X =:= {2, 3, 4} ->\n            2;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards25.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = 0\\n  case x {\\n    _ if x == 0 -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 0\n  case x {\n    _ if x == 0 -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 0,\n    case X of\n        _ when X =:= 0 ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards26.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = 0\\n  case x {\\n    _ if 0 < x -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 0\n  case x {\n    _ if 0 < x -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 0,\n    case X of\n        _ when 0 < X ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards27.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case \\\"test\\\" {\\n    x if x == \\\"test\\\" -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case \"test\" {\n    x if x == \"test\" -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case <<\"test\"/utf8>> of\n        X when X =:= <<\"test\"/utf8>> ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards28.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n    type Test { Test(x: Int, y: Float) }\\n    pub fn main() {\\n      let x = Test(1, 3.0)\\n      case x {\\n        _ if x == Test(1, 1.0) -> 1\\n        _ if x == Test(y: 2.0, x: 2) -> 2\\n        _ if x != Test(2, 3.0) -> 2\\n        _ -> 0\\n      }\\n    }\\n\"\n---\n----- SOURCE CODE\n\n    type Test { Test(x: Int, y: Float) }\n    pub fn main() {\n      let x = Test(1, 3.0)\n      case x {\n        _ if x == Test(1, 1.0) -> 1\n        _ if x == Test(y: 2.0, x: 2) -> 2\n        _ if x != Test(2, 3.0) -> 2\n        _ -> 0\n      }\n    }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([test/0]).\n\n-type test() :: {test, integer(), float()}.\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> integer().\nmain() ->\n    X = {test, 1, 3.0},\n    case X of\n        _ when X =:= {test, 1, 1.0} ->\n            1;\n\n        _ when X =:= {test, 2, 2.0} ->\n            2;\n\n        _ when X =/= {test, 2, 3.0} ->\n            2;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards29.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 0.1, 1.0 {\\n    x, y if x <. y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 0.1, 1.0 {\n    x, y if x <. y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {0.1, 1.0} of\n        {X, Y} when X < Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards30.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 0.1, 1.0 {\\n    x, y if x <=. y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 0.1, 1.0 {\n    x, y if x <=. y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {0.1, 1.0} of\n        {X, Y} when X =< Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards31.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main(args) {\\n  case args {\\n    [x] | [x, _] if x -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(args) {\n  case args {\n    [x] | [x, _] if x -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(list(boolean())) -> integer().\nmain(Args) ->\n    case Args of\n        [X] when X ->\n            1;\n\n        [X, _] when X ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards32.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let wibble = \\\"wobble\\\"\\n  case wibble {\\n    x if x == \\\"wob\\\" <> \\\"ble\\\" -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let wibble = \"wobble\"\n  case wibble {\n    x if x == \"wob\" <> \"ble\" -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    Wibble = <<\"wobble\"/utf8>>,\n    case Wibble of\n        X when X =:= <<\"wob\"/utf8, \"ble\"/utf8>> ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main(args) {\\n  case args {\\n    x if {x != x} == {args == args} -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(args) {\n  case args {\n    x if {x != x} == {args == args} -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(any()) -> integer().\nmain(Args) ->\n    case Args of\n        X when (X =/= X) =:= (Args =:= Args) ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_10.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = 0.123\\n  case x {\\n    _ if x == 3.14 -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 0.123\n  case x {\n    _ if x == 3.14 -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 0.123,\n    case X of\n        _ when X =:= 3.14 ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main(args) {\\n  case args {\\n    x if x && x || x == x && x -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(args) {\n  case args {\n    x if x && x || x == x && x -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(boolean()) -> integer().\nmain(Args) ->\n    case Args of\n        X when (X andalso X) orelse ((X =:= X) andalso X) ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 1, 0 {\\n    x, y if x > y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1, 0 {\n    x, y if x > y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {1, 0} of\n        {X, Y} when X > Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_4.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 1, 0 {\\n    x, y if x >= y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1, 0 {\n    x, y if x >= y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {1, 0} of\n        {X, Y} when X >= Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_5.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 1, 0 {\\n    x, y if x < y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1, 0 {\n    x, y if x < y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {1, 0} of\n        {X, Y} when X < Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_6.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 1, 0 {\\n    x, y if x <= y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1, 0 {\n    x, y if x <= y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {1, 0} of\n        {X, Y} when X =< Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_7.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 1.0, 0.1 {\\n    x, y if x >. y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1.0, 0.1 {\n    x, y if x >. y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {1.0, 0.1} of\n        {X, Y} when X > Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_8.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  case 1.0, 0.1 {\\n    x, y if x >=. y -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1.0, 0.1 {\n    x, y if x >=. y -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {1.0, 0.1} of\n        {X, Y} when X >= Y ->\n            1;\n\n        {_, _} ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_9.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub fn main() {\\n  let x = 0.123\\n  case x {\\n    99.9854 -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 0.123\n  case x {\n    99.9854 -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 0.123,\n    case X of\n        99.9854 ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub const string_value = \\\"constant value\\\"\\npub const float_value = 3.14\\npub const int_value = 42\\npub const tuple_value = #(1, 2.0, \\\"3\\\")\\npub const list_value = [1, 2, 3]\\n\\npub fn main(arg) {\\n  let _ = list_value\\n  case arg {\\n    #(w, x, y, z) if w == tuple_value && x == string_value && y >. float_value && z == int_value -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const string_value = \"constant value\"\npub const float_value = 3.14\npub const int_value = 42\npub const tuple_value = #(1, 2.0, \"3\")\npub const list_value = [1, 2, 3]\n\npub fn main(arg) {\n  let _ = list_value\n  case arg {\n    #(w, x, y, z) if w == tuple_value && x == string_value && y >. float_value && z == int_value -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main({{integer(), float(), binary()}, binary(), float(), integer()}) -> integer().\nmain(Arg) ->\n    _ = [1, 2, 3],\n    case Arg of\n        {W, X, Y, Z} when (((W =:= {1, 2.0, <<\"3\"/utf8>>}) andalso (X =:= <<\"constant value\"/utf8>>)) andalso (Y > 3.14)) andalso (Z =:= 42) ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub const list = [1, 2, 3]\\n\\npub fn main(arg) {\\n  case arg {\\n    _ if arg == list -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const list = [1, 2, 3]\n\npub fn main(arg) {\n  case arg {\n    _ if arg == list -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main(list(integer())) -> integer().\nmain(Arg) ->\n    case Arg of\n        _ when Arg =:= [1, 2, 3] ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__field_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n        pub type Person {\\n          Person(username: String, name: String, age: Int)\\n        }\\n        \\n        pub fn main() {\\n          let given_name = \\\"jack\\\"\\n          let raiden = Person(\\\"raiden\\\", \\\"jack\\\", 31)\\n        \\n          case given_name {\\n            name if name == raiden.name -> \\\"It's jack\\\"\\n            _ -> \\\"It's not jack\\\"\\n          }\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub type Person {\n          Person(username: String, name: String, age: Int)\n        }\n        \n        pub fn main() {\n          let given_name = \"jack\"\n          let raiden = Person(\"raiden\", \"jack\", 31)\n        \n          case given_name {\n            name if name == raiden.name -> \"It's jack\"\n            _ -> \"It's not jack\"\n          }\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([person/0]).\n\n-type person() :: {person, binary(), binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> binary().\nmain() ->\n    Given_name = <<\"jack\"/utf8>>,\n    Raiden = {person, <<\"raiden\"/utf8>>, <<\"jack\"/utf8>>, 31},\n    case Given_name of\n        Name when Name =:= erlang:element(3, Raiden) ->\n            <<\"It's jack\"/utf8>>;\n\n        _ ->\n            <<\"It's not jack\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == hero.ironman.name -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman.name -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> boolean().\nmain() ->\n    Name = <<\"Tony Stark\"/utf8>>,\n    case Name of\n        N when N =:= erlang:element(2, {hero, <<\"Tony Stark\"/utf8>>}) ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_list_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let names = [\\\"Tony Stark\\\", \\\"Bruce Wayne\\\"]\\n            case names {\\n              n if n == hero.heroes -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let names = [\"Tony Stark\", \"Bruce Wayne\"]\n            case names {\n              n if n == hero.heroes -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> boolean().\nmain() ->\n    Names = [<<\"Tony Stark\"/utf8>>, <<\"Bruce Wayne\"/utf8>>],\n    case Names of\n        N when N =:= [<<\"Tony Stark\"/utf8>>, <<\"Bruce Wayne\"/utf8>>] ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_nested_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Bruce Wayne\\\"\\n            case name {\\n              n if n == hero.batman.secret_identity.name -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Bruce Wayne\"\n            case name {\n              n if n == hero.batman.secret_identity.name -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> boolean().\nmain() ->\n    Name = <<\"Bruce Wayne\"/utf8>>,\n    case Name of\n        N when N =:= erlang:element(\n            2,\n            erlang:element(2, {hero, {person, <<\"Bruce Wayne\"/utf8>>}})\n        ) ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_string_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == hero.ironman -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> boolean().\nmain() ->\n    Name = <<\"Tony Stark\"/utf8>>,\n    case Name of\n        N when N =:= <<\"Tony Stark\"/utf8>> ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_tuple_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == hero.hero.1 -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.hero.1 -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> boolean().\nmain() ->\n    Name = <<\"Tony Stark\"/utf8>>,\n    case Name of\n        N when N =:= erlang:element(\n            2,\n            {<<\"ironman\"/utf8>>, <<\"Tony Stark\"/utf8>>}\n        ) ->\n            true;\n\n        _ ->\n            false\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__nested_record_access.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub type A {\\n  A(b: B)\\n}\\n\\npub type B {\\n  B(c: C)\\n}\\n\\npub type C {\\n  C(d: Bool)\\n}\\n\\npub fn a(a: A) {\\n  case a {\\n    _ if a.b.c.d -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type A {\n  A(b: B)\n}\n\npub type B {\n  B(c: C)\n}\n\npub type C {\n  C(d: Bool)\n}\n\npub fn a(a: A) {\n  case a {\n    _ if a.b.c.d -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n-export_type([a/0, b/0, c/0]).\n\n-type a() :: {a, b()}.\n\n-type b() :: {b, c()}.\n\n-type c() :: {c, boolean()}.\n\n-file(\"project/test/my/mod.gleam\", 14).\n-spec a(a()) -> integer().\na(A) ->\n    case A of\n        _ when erlang:element(2, erlang:element(2, erlang:element(2, A))) ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub const string_value = \\\"constant value\\\"\\n\\npub fn main(arg) {\\n  case arg {\\n    _ if arg == string_value -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const string_value = \"constant value\"\n\npub fn main(arg) {\n  case arg {\n    _ if arg == string_value -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main(binary()) -> integer().\nmain(Arg) ->\n    case Arg of\n        _ when Arg =:= <<\"constant value\"/utf8>> ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub const bits = <<1, \\\"ok\\\":utf8, 3, 4:50>>\\n\\npub fn main(arg) {\\n  case arg {\\n    _ if arg == bits -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const bits = <<1, \"ok\":utf8, 3, 4:50>>\n\npub fn main(arg) {\n  case arg {\n    _ if arg == bits -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main(bitstring()) -> integer().\nmain(Arg) ->\n    case Arg of\n        _ when Arg =:= <<1, \"ok\"/utf8, 3, 4:50>> ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub const constant = #(1, 2.0)\\n\\npub fn main(arg) {\\n  case arg {\\n    _ if arg == constant -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const constant = #(1, 2.0)\n\npub fn main(arg) {\n  case arg {\n    _ if arg == constant -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main({integer(), float()}) -> integer().\nmain(Arg) ->\n    case Arg of\n        _ when Arg =:= {1, 2.0} ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/guards.rs\nexpression: \"\\npub const float_value = 3.14\\n\\npub fn main(arg) {\\n  case arg {\\n    _ if arg >. float_value -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const float_value = 3.14\n\npub fn main(arg) {\n  case arg {\n    _ if arg >. float_value -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main(float()) -> integer().\nmain(Arg) ->\n    case Arg of\n        _ when Arg > 3.14 ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n    { 4 |> make_adder }(6)\\n}\\n\\nfn make_adder(a) {\\n  fn(b) { a + b }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    { 4 |> make_adder }(6)\n}\n\nfn make_adder(a) {\n  fn(b) { a + b }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec make_adder(integer()) -> fun((integer()) -> integer()).\nmake_adder(A) ->\n    fun(B) -> A + B end.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    begin\n        _pipe = 4,\n        make_adder(_pipe)\n    end(6).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n    fn(x) { 1 + x }(2) * 3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    fn(x) { 1 + x }(2) * 3\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    (1 + 2) * 3.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__do_not_inline_parameters_that_have_side_effects.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.map(Ok(10), do_side_effects())\\n}\\n\\nfn do_side_effects() {\\n  let function = fn(x) { x + 1 }\\n  panic as \\\"Side effects\\\"\\n  function\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.map(Ok(10), do_side_effects())\n}\n\nfn do_side_effects() {\n  let function = fn(x) { x + 1 }\n  panic as \"Side effects\"\n  function\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec do_side_effects() -> fun((integer()) -> integer()).\ndo_side_effects() ->\n    Function = fun(X) -> X + 1 end,\n    erlang:error(#{gleam_error => panic,\n            message => <<\"Side effects\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"do_side_effects\"/utf8>>,\n            line => 10}),\n    Function.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> {ok, integer()} | {error, any()}.\nmain() ->\n    begin\n        F = do_side_effects(),\n        case {ok, 10} of\n            {ok, Value} ->\n                {ok, F(Value)};\n\n            {error, Error} ->\n                {error, Error}\n        end\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__do_not_inline_parameters_used_more_than_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport testing\\n\\npub fn main() {\\n  testing.always_inline(True)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport testing\n\npub fn main() {\n  testing.always_inline(True)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> boolean().\nmain() ->\n    begin\n        Something = true,\n        case Something of\n            true ->\n                Something;\n\n            false ->\n                false\n        end\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_anonymous_function_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  fn(a, b) { #(a, b) }(42, False)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  fn(a, b) { #(a, b) }(42, False)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> {integer(), boolean()}.\nmain() ->\n    {42, false}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_anonymous_function_in_pipe.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  1 |> fn(x) { x + 1 } |> fn(y) { y * y }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1 |> fn(x) { x + 1 } |> fn(y) { y * y }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    _pipe = 1,\n    _pipe@1 = _pipe + 1,\n    begin\n        Y = _pipe@1,\n        Y * Y\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_capture_in_pipe.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  1 |> add(4, _)\\n}\\n\\nfn add(a, b) { a + b }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1 |> add(4, _)\n}\n\nfn add(a, b) { a + b }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec add(integer(), integer()) -> integer().\nadd(A, B) ->\n    A + B.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    _pipe = 1,\n    add(4, _pipe).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_which_calls_other_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport testing\\n\\npub fn main() {\\n  testing.always_inline(Ok(10), Error)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport testing\n\npub fn main() {\n  testing.always_inline(Ok(10), Error)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> {ok, any()} | {error, integer()}.\nmain() ->\n    case {ok, 10} of\n        {ok, Value} ->\n            {error, Value};\n\n        {error, Error} ->\n            {error, Error}\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/bool\\n\\npub fn divide(a, b) {\\n  use <- bool.guard(when: b == 0, return: 0)\\n  a / b\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.guard(when: b == 0, return: 0)\n  a / b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([divide/2]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec divide(integer(), integer()) -> integer().\ndivide(A, B) ->\n    case B =:= 0 of\n        true ->\n            0;\n\n        false ->\n            case B of\n                0 -> 0;\n                Gleam@denominator -> A div Gleam@denominator\n            end\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_and_anonymous.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/bool\\n\\npub fn divide(a, b) {\\n  use <- bool.lazy_guard(b == 0, fn() { panic as \\\"Cannot divide by 0\\\" })\\n  a / b\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.lazy_guard(b == 0, fn() { panic as \"Cannot divide by 0\" })\n  a / b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([divide/2]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec divide(integer(), integer()) -> integer().\ndivide(A, B) ->\n    case B =:= 0 of\n        true ->\n            erlang:error(#{gleam_error => panic,\n                    message => <<\"Cannot divide by 0\"/utf8>>,\n                    file => <<?FILEPATH/utf8>>,\n                    module => <<\"my/mod\"/utf8>>,\n                    function => <<\"divide\"/utf8>>,\n                    line => 5});\n\n        false ->\n            case B of\n                0 -> 0;\n                Gleam@denominator -> A div Gleam@denominator\n            end\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/bool\\n\\npub fn count(from: Int, to: Int) -> Int {\\n  use <- bool.guard(when: from >= to, return: from)\\n  echo from\\n  count(from + 1, to)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/bool\n\npub fn count(from: Int, to: Int) -> Int {\n  use <- bool.guard(when: from >= to, return: from)\n  echo from\n  count(from + 1, to)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([count/2]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec count(integer(), integer()) -> integer().\ncount(From, To) ->\n    case From >= To of\n        true ->\n            From;\n\n        false ->\n            echo(From, nil, 6),\n            count(From + 1, To)\n    end.\n\n% ...omitted code from `templates/echo.erl`...\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.map(over: Ok(10), with: double)\\n}\\n\\nfn double(x) { x + x }\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.map(over: Ok(10), with: double)\n}\n\nfn double(x) { x + x }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec double(integer()) -> integer().\ndouble(X) ->\n    X + X.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> {ok, integer()} | {error, any()}.\nmain() ->\n    case {ok, 10} of\n        {ok, Value} ->\n            {ok, double(Value)};\n\n        {error, Error} ->\n            {error, Error}\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_anonymous.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.try(Ok(10), fn(value) {\\n    Ok({ value + 2 } * 4)\\n  })\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), fn(value) {\n    Ok({ value + 2 } * 4)\n  })\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> {ok, integer()} | {error, any()}.\nmain() ->\n    case {ok, 10} of\n        {ok, Value} ->\n            {ok, (Value + 2) * 4};\n\n        {error, Error} ->\n            {error, Error}\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_with_capture.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.try(Ok(10), divide(_, 2))\\n}\\n\\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\\n  case a % b {\\n    0 -> Ok(a / b)\\n    _ -> Error(Nil)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), divide(_, 2))\n}\n\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}.\ndivide(A, B) ->\n    case case B of\n        0 -> 0;\n        Gleam@denominator -> A rem Gleam@denominator\n    end of\n        0 ->\n            {ok, case B of\n                    0 -> 0;\n                    Gleam@denominator@1 -> A div Gleam@denominator@1\n                end};\n\n        _ ->\n            {error, nil}\n    end.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> {ok, integer()} | {error, nil}.\nmain() ->\n    case {ok, 10} of\n        {ok, Value} ->\n            divide(Value, 2);\n\n        {error, Error} ->\n            {error, Error}\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  let a = 10\\n  let b = 20\\n\\n  fn(x) {\\n    let a = 7\\n    x + a\\n  }(a + b)\\n\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    A = 10,\n    B = 20,\n    begin\n        _inline_a_0 = 7,\n        (A + B) + _inline_a_0\n    end,\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable_nested.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn sum(a, b) {\\n  fn(x) {\\n    let a = 7\\n    fn(y) {\\n      let a = 10\\n      y - a\\n    }(x + a)\\n\\n    a\\n  }(a + b)\\n\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    fn(y) {\n      let a = 10\n      y - a\n    }(x + a)\n\n    a\n  }(a + b)\n\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([sum/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec sum(integer(), integer()) -> integer().\nsum(A, B) ->\n    begin\n        _inline_a_0 = 7,\n        begin\n            _inline_a_1 = 10,\n            ((A + B) + _inline_a_0) - _inline_a_1\n        end,\n        _inline_a_0\n    end,\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowed_in_case_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn sum() {\\n  let a = 10\\n  let b = 20\\n\\n  fn(x) {\\n    case 7, 8 {\\n      a, b -> a + b + x\\n    }\\n  }(a + b)\\n\\n  a + b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    case 7, 8 {\n      a, b -> a + b + x\n    }\n  }(a + b)\n\n  a + b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([sum/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec sum() -> integer().\nsum() ->\n    A = 10,\n    B = 20,\n    case {7, 8} of\n        {_inline_a_0, _inline_b_1} ->\n            (_inline_a_0 + _inline_b_1) + (A + B)\n    end,\n    A + B.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_case_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn sum() {\\n  case 1, 2 {\\n    a, b -> fn(x) {\\n      let a = 7\\n      x + a\\n    }(a + b)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum() {\n  case 1, 2 {\n    a, b -> fn(x) {\n      let a = 7\n      x + a\n    }(a + b)\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([sum/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec sum() -> integer().\nsum() ->\n    case {1, 2} of\n        {A, B} ->\n            _inline_a_0 = 7,\n            (A + B) + _inline_a_0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_parameter.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn sum(a, b) {\\n  fn(x) {\\n    let a = 7\\n    x + a\\n  }(a + b)\\n\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([sum/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec sum(integer(), integer()) -> integer().\nsum(A, B) ->\n    begin\n        _inline_a_0 = 7,\n        (A + B) + _inline_a_0\n    end,\n    A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_properly_with_record_updates.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n}\\n\\npub fn main() {\\n  let w = Wibble(1, 2)\\n  use b <- result.map(Ok(3))\\n  Wibble(..w, b:)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let w = Wibble(1, 2)\n  use b <- result.map(Ok(3))\n  Wibble(..w, b:)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([wibble/0]).\n\n-type wibble() :: {wibble, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec main() -> {ok, wibble()} | {error, any()}.\nmain() ->\n    W = {wibble, 1, 2},\n    case {ok, 3} of\n        {ok, Value} ->\n            {ok, {wibble, erlang:element(2, W), Value}};\n\n        {error, Error} ->\n            {error, Error}\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_through_blocks.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n    { fn(x) { Ok(x + 1) } }(41)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    { fn(x) { Ok(x + 1) } }(41)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> {ok, integer()} | {error, any()}.\nmain() ->\n    {ok, 41 + 1}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__parameters_from_nested_functions_are_correctly_inlined.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn halve_all(a, b, c) {\\n  use x <- result.try(divide(a, 2))\\n  use y <- result.try(divide(b, 2))\\n  use z <- result.map(divide(c, 2))\\n\\n  #(x, y, z)\\n}\\n\\nfn divide(a, b) {\\n  case a % b {\\n    0 -> Ok(a / b)\\n    _ -> Error(Nil)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn halve_all(a, b, c) {\n  use x <- result.try(divide(a, 2))\n  use y <- result.try(divide(b, 2))\n  use z <- result.map(divide(c, 2))\n\n  #(x, y, z)\n}\n\nfn divide(a, b) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([halve_all/3]).\n\n-file(\"project/test/my/mod.gleam\", 12).\n-spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}.\ndivide(A, B) ->\n    case case B of\n        0 -> 0;\n        Gleam@denominator -> A rem Gleam@denominator\n    end of\n        0 ->\n            {ok, case B of\n                    0 -> 0;\n                    Gleam@denominator@1 -> A div Gleam@denominator@1\n                end};\n\n        _ ->\n            {error, nil}\n    end.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec halve_all(integer(), integer(), integer()) -> {ok,\n        {integer(), integer(), integer()}} |\n    {error, nil}.\nhalve_all(A, B, C) ->\n    case divide(A, 2) of\n        {ok, Value} ->\n            X = Value,\n            case divide(B, 2) of\n                {ok, _inline_value_0} ->\n                    Y = _inline_value_0,\n                    case divide(C, 2) of\n                        {ok, _inline_value_1} ->\n                            {ok, {X, Y, _inline_value_1}};\n\n                        {error, Error} ->\n                            {error, Error}\n                    end;\n\n                {error, _inline_error_2} ->\n                    {error, _inline_error_2}\n            end;\n\n        {error, _inline_error_3} ->\n            {error, _inline_error_3}\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__assignment_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert 123 as x = 123\\n  x\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert 123 as x = 123\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    X@1 = case 123 of\n        123 = X -> X;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 41,\n                        pattern_start => 27,\n                        pattern_end => 35})\n    end,\n    X@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_discard.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn main() {\\n  let assert <<_ as number>> = <<10>>\\n  number\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<_ as number>> = <<10>>\n  number\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    Number@1 = case <<10>> of\n        <<Number>> -> Number;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 54,\n                        pattern_start => 30,\n                        pattern_end => 45})\n    end,\n    Number@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_float.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn main() {\\n  let assert <<3.14 as pi:float>> = <<3.14>>\\n  pi\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<3.14 as pi:float>> = <<3.14>>\n  pi\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> float().\nmain() ->\n    Pi@1 = case <<3.14/float>> of\n        <<Pi/float>> when Pi =:= 3.14 -> Pi;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 61,\n                        pattern_start => 30,\n                        pattern_end => 50})\n    end,\n    Pi@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_int.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn main() {\\n  let assert <<1 as a>> = <<1>>\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<1 as a>> = <<1>>\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    A@1 = case <<1>> of\n        <<A>> when A =:= 1 -> A;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 48,\n                        pattern_start => 30,\n                        pattern_end => 40})\n    end,\n    A@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_string.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn main() {\\n  let assert <<\\\"Hello, world!\\\" as message:utf8>> = <<\\\"Hello, world!\\\">>\\n  message\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<\"Hello, world!\" as message:utf8>> = <<\"Hello, world!\">>\n  message\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> binary().\nmain() ->\n    Message@1 = case <<\"Hello, world!\"/utf8>> of\n        <<Message:13/binary>> when Message =:= <<\"Hello, world!\"/utf8>> -> Message;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 87,\n                        pattern_start => 30,\n                        pattern_end => 65})\n    end,\n    Message@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert <<a:2, b:3, c:3>> = <<123>>\\n  a + b + c\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert <<a:2, b:3, c:3>> = <<123>>\n  a + b + c\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    {A@1, B@1, C@1} = case <<123>> of\n        <<A:2, B:3, C:3>> -> {A, B, C};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 54,\n                        pattern_start => 27,\n                        pattern_end => 44})\n    end,\n    (A@1 + B@1) + C@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert Ok(x) = Error(Nil)\\n  x\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert Ok(x) = Error(Nil)\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> any().\ngo() ->\n    X@1 = case {error, nil} of\n        {ok, X} -> X;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 45,\n                        pattern_start => 27,\n                        pattern_end => 32})\n    end,\n    X@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern_with_multiple_variables.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int, Float)\\n}\\n\\npub fn go() {\\n  let assert Wibble(x, 2.0 as y) = Wibble(1, 2.0)\\n  x\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int, Float)\n}\n\npub fn go() {\n  let assert Wibble(x, 2.0 as y) = Wibble(1, 2.0)\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n-export_type([wibble/0]).\n\n-type wibble() :: {wibble, integer(), float()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec go() -> integer().\ngo() ->\n    {X@1, Y@1} = case {wibble, 1, 2.0} of\n        {wibble, X, 2.0 = Y} -> {X, Y};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 7,\n                        value => _assert_fail,\n                        start => 59,\n                        'end' => 106,\n                        pattern_start => 70,\n                        pattern_end => 89})\n    end,\n    X@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__discard_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert _ = 123\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert _ = 123\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    _ = 123.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__float_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert 1.5 = 5.1\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert 1.5 = 5.1\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> float().\ngo() ->\n    _assert_subject = 5.1,\n    case _assert_subject of\n        1.5 -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 36,\n                        pattern_start => 27,\n                        pattern_end => 30})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__int_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert 1 = 2\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert 1 = 2\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    _assert_subject = 2,\n    case _assert_subject of\n        1 -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 32,\n                        pattern_start => 27,\n                        pattern_end => 28})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__just_variable.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert x = Ok(1)\\n  x\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert x = Ok(1)\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> {ok, integer()} | {error, any()}.\ngo() ->\n    X = {ok, 1},\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_at_end_of_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn go() {\\n  let result = Ok(10)\\n  let x = {\\n    let assert Ok(_) = result\\n  }\\n  x\\n}\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let result = Ok(10)\n  let x = {\n    let assert Ok(_) = result\n  }\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go() -> {ok, integer()} | {error, any()}.\ngo() ->\n    Result = {ok, 10},\n    X = begin\n        case Result of\n            {ok, _} -> Result;\n            _assert_fail ->\n                erlang:error(#{gleam_error => let_assert,\n                            message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                            file => <<?FILEPATH/utf8>>,\n                            module => <<\"my/mod\"/utf8>>,\n                            function => <<\"go\"/utf8>>,\n                            line => 5,\n                            value => _assert_fail,\n                            start => 53,\n                            'end' => 78,\n                            pattern_start => 64,\n                            pattern_end => 69})\n        end\n    end,\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_should_not_use_redefined_variable.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\nfn split_once(x: String, y: String) -> Result(#(String, String), String) {\\n    Ok(#(x, y))\\n}\\n\\npub fn main() {\\n    let string = \\\"Hello, world!\\\"\\n    let assert Ok(#(prefix, string)) = split_once(string, \\\"\\\\n\\\")\\n    as { \\\"Failed to split: \\\" <> string }\\n}\\n        \"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn split_once(x: String, y: String) -> Result(#(String, String), String) {\n    Ok(#(x, y))\n}\n\npub fn main() {\n    let string = \"Hello, world!\"\n    let assert Ok(#(prefix, string)) = split_once(string, \"\\n\")\n    as { \"Failed to split: \" <> string }\n}\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} |\n    {error, binary()}.\nsplit_once(X, Y) ->\n    {ok, {X, Y}}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> {ok, {binary(), binary()}} | {error, binary()}.\nmain() ->\n    String = <<\"Hello, world!\"/utf8>>,\n    _assert_subject = split_once(String, <<\"\\n\"/utf8>>),\n    case _assert_subject of\n        {ok, {Prefix, String@1}} -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => (<<\"Failed to split: \"/utf8, String/binary>>),\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 8,\n                        value => _assert_fail,\n                        start => 148,\n                        'end' => 207,\n                        pattern_start => 159,\n                        pattern_end => 180})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert [1, x, 3] = [1, 2, 3]\\n  x\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert [1, x, 3] = [1, 2, 3]\n  x\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    X@1 = case [1, 2, 3] of\n        [1, X, 3] -> X;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 48,\n                        pattern_start => 27,\n                        pattern_end => 36})\n    end,\n    X@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern_with_multiple_variables.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert [a, b, c] = [1, 2, 3]\\n  a + b + c\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert [a, b, c] = [1, 2, 3]\n  a + b + c\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    {A@1, B@1, C@1} = case [1, 2, 3] of\n        [A, B, C] -> {A, B, C};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 48,\n                        pattern_start => 27,\n                        pattern_end => 36})\n    end,\n    (A@1 + B@1) + C@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn unwrap_or_panic(value) {\\n  let assert Ok(inner) = value as \\\"Oops, there was an error\\\"\\n  inner\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn unwrap_or_panic(value) {\n  let assert Ok(inner) = value as \"Oops, there was an error\"\n  inner\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([unwrap_or_panic/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec unwrap_or_panic({ok, K} | {error, any()}) -> K.\nunwrap_or_panic(Value) ->\n    Inner@1 = case Value of\n        {ok, Inner} -> Inner;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Oops, there was an error\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"unwrap_or_panic\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 35,\n                        'end' => 63,\n                        pattern_start => 46,\n                        pattern_end => 55})\n    end,\n    Inner@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__more_than_one_var.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go(x) {\\n  let assert [1, a, b, c] = x\\n  [a, b, c]\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n  let assert [1, a, b, c] = x\n  [a, b, c]\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go(list(integer())) -> list(integer()).\ngo(X) ->\n    {A@1, B@1, C@1} = case X of\n        [1, A, B, C] -> {A, B, C};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 17,\n                        'end' => 44,\n                        pattern_start => 28,\n                        pattern_end => 40})\n    end,\n    [A@1, B@1, C@1].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__one_var.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert Ok(y) = Ok(1)\\n  y\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert Ok(y) = Ok(1)\n  y\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    Y@1 = case {ok, 1} of\n        {ok, Y} -> Y;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 40,\n                        pattern_start => 27,\n                        pattern_end => 32})\n    end,\n    Y@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__pattern_let.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go(x) {\\n  let assert [1 as a, b, c] = x\\n  [a, b, c]\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n  let assert [1 as a, b, c] = x\n  [a, b, c]\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go(list(integer())) -> list(integer()).\ngo(X) ->\n    {A@1, B@1, C@1} = case X of\n        [1 = A, B, C] -> {A, B, C};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 17,\n                        'end' => 46,\n                        pattern_start => 28,\n                        pattern_end => 42})\n    end,\n    [A@1, B@1, C@1].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__reference_earlier_segment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn main() {\\n  let assert <<length, bytes:size(length)-unit(8)>> = <<3, 1, 2, 3>>\\n  bytes\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<length, bytes:size(length)-unit(8)>> = <<3, 1, 2, 3>>\n  bytes\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    {Length@1, Bytes@1} = case <<3, 1, 2, 3>> of\n        <<Length, Bytes:Length/unit:8>> -> {Length, Bytes};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 85,\n                        pattern_start => 30,\n                        pattern_end => 68})\n    end,\n    Bytes@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert \\\"Hello!\\\" = \\\"Hel\\\" <> \\\"lo!\\\"\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert \"Hello!\" = \"Hel\" <> \"lo!\"\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> binary().\ngo() ->\n    _assert_subject = <<\"Hel\"/utf8, \"lo!\"/utf8>>,\n    case _assert_subject of\n        <<\"Hello!\"/utf8>> -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 52,\n                        pattern_start => 27,\n                        pattern_end => 35})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert \\\"Hello \\\" <> name = \\\"Hello John\\\"\\n  name\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert \"Hello \" <> name = \"Hello John\"\n  name\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> binary().\ngo() ->\n    Name@1 = case <<\"Hello John\"/utf8>> of\n        <<\"Hello \"/utf8, Name/binary>> -> Name;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 58,\n                        pattern_start => 27,\n                        pattern_end => 43})\n    end,\n    Name@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern_with_prefix_binding.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert \\\"Hello \\\" as greeting <> name = \\\"Hello John\\\"\\n  #(greeting, name)\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert \"Hello \" as greeting <> name = \"Hello John\"\n  #(greeting, name)\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> {binary(), binary()}.\ngo() ->\n    {Name@1, Greeting@1} = case <<\"Hello John\"/utf8>> of\n        <<\"Hello \"/utf8, Name/binary>> -> {Name, Greeting};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 70,\n                        pattern_start => 27,\n                        pattern_end => 55})\n    end,\n    Greeting = <<\"Hello \"/utf8>>,\n    {Greeting@1, Name@1}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__tuple_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert #(a, b, c) = #(1, 2, 3)\\n  a + b + c\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert #(a, b, c) = #(1, 2, 3)\n  a + b + c\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    {A, B, C} = {1, 2, 3},\n    (A + B) + C.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_message.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"\\npub fn expect(value, message) {\\n  let assert Ok(inner) = value as message\\n  inner\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn expect(value, message) {\n  let assert Ok(inner) = value as message\n  inner\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([expect/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec expect({ok, L} | {error, any()}, binary()) -> L.\nexpect(Value, Message) ->\n    Inner@1 = case Value of\n        {ok, Inner} -> Inner;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => Message,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"expect\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 35,\n                        'end' => 63,\n                        pattern_start => 46,\n                        pattern_end => 55})\n    end,\n    Inner@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_rewrites.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/let_assert.rs\nexpression: \"pub fn go() {\\n  let assert Ok(y) = Ok(1)\\n  let assert Ok(y) = Ok(1)\\n  y\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let assert Ok(y) = Ok(1)\n  let assert Ok(y) = Ok(1)\n  y\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> integer().\ngo() ->\n    Y@1 = case {ok, 1} of\n        {ok, Y} -> Y;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 40,\n                        pattern_start => 27,\n                        pattern_end => 32})\n    end,\n    Y@3 = case {ok, 1} of\n        {ok, Y@2} -> Y@2;\n        _assert_fail@1 ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"go\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail@1,\n                        start => 43,\n                        'end' => 67,\n                        pattern_start => 54,\n                        pattern_end => 59})\n    end,\n    Y@3.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__int_negation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  let a = 3\\n  let b = -a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 3\n  let b = -a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    A = 3,\n    B = - A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_scientific_notation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\nconst i = 100.001e223\\nconst j = -100.001e-223\\n\\npub fn main() {\\n  i\\n  j\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst i = 100.001e223\nconst j = -100.001e-223\n\npub fn main() {\n  i\n  j\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> float().\nmain() ->\n    100.001e223,\n    -100.001e-223.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  100_000\\n  100_000.00101\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  100_000\n  100_000.00101\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> float().\nmain() ->\n    100000,\n    100000.00101.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\nconst i = 100_000\\nconst f = 100_000.00101\\npub fn main() {\\n  i\\n  f\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst i = 100_000\nconst f = 100_000.00101\npub fn main() {\n  i\n  f\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> float().\nmain() ->\n    100000,\n    100000.00101.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  let assert 100_000 = 1\\n  let assert 100_000.00101 = 1.\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert 100_000 = 1\n  let assert 100_000.00101 = 1.\n  1\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case 1 of\n        100000 -> nil;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 19,\n                        'end' => 41,\n                        pattern_start => 30,\n                        pattern_end => 37})\n    end,\n    case 1.0 of\n        100000.00101 -> nil;\n        _assert_fail@1 ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 4,\n                        value => _assert_fail@1,\n                        start => 44,\n                        'end' => 73,\n                        pattern_start => 55,\n                        pattern_end => 68})\n    end,\n    1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__repeated_int_negation.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  let a = 3\\n  let b = --a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 3\n  let b = --a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    A = 3,\n    B = - - A.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__zero_b_in_hex.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0xffe0bb\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0xffe0bb\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    16#ffe0bb.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/panic.rs\nexpression: \"\\npub fn main() {\\n  panic as \\\"wibble\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  panic as \"wibble\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => panic,\n            message => <<\"wibble\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/panic.rs\nexpression: \"\\npub fn retstring() {\\n  \\\"wibble\\\"\\n}\\npub fn main() {\\n  panic as { retstring() <> \\\"wobble\\\" }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn retstring() {\n  \"wibble\"\n}\npub fn main() {\n  panic as { retstring() <> \"wobble\" }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([retstring/0, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec retstring() -> binary().\nretstring() ->\n    <<\"wibble\"/utf8>>.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => panic,\n            message => (<<(retstring())/binary, \"wobble\"/utf8>>),\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 6}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/panic.rs\nexpression: \"\\npub fn main() {\\n  \\\"lets\\\"\\n  |> panic\\n}\\n    \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  \"lets\"\n  |> panic\n}\n    \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    _pipe = <<\"lets\"/utf8>>,\n    (erlang:error(#{gleam_error => panic,\n            message => <<\"`panic` expression evaluated.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 4}))(_pipe).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped_chain.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/panic.rs\nexpression: \"\\n     pub fn main() {\\n      \\\"lets\\\"\\n      |> panic as \\\"pipe\\\"\\n      |> panic as \\\"other panic\\\"\\n    }\\n    \"\n---\n----- SOURCE CODE\n\n     pub fn main() {\n      \"lets\"\n      |> panic as \"pipe\"\n      |> panic as \"other panic\"\n    }\n    \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    _pipe = <<\"lets\"/utf8>>,\n    _pipe@1 = (erlang:error(#{gleam_error => panic,\n            message => <<\"pipe\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 4}))(_pipe),\n    (erlang:error(#{gleam_error => panic,\n            message => <<\"other panic\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 5}))(_pipe@1).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__plain.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/panic.rs\nexpression: \"\\npub fn main() {\\n  panic\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  panic\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => panic,\n            message => <<\"`panic` expression evaluated.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"\\npub fn main() {\\n  let duplicate_name = 1\\n\\n  case 1 {\\n    1 | 2 -> {\\n      let duplicate_name = duplicate_name + 1\\n      duplicate_name\\n    }\\n    _ -> 0\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let duplicate_name = 1\n\n  case 1 {\n    1 | 2 -> {\n      let duplicate_name = duplicate_name + 1\n      duplicate_name\n    }\n    _ -> 0\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    Duplicate_name = 1,\n    case 1 of\n        1 ->\n            Duplicate_name@1 = Duplicate_name + 1,\n            Duplicate_name@1;\n\n        2 ->\n            Duplicate_name@1 = Duplicate_name + 1,\n            Duplicate_name@1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"\\npub fn main() {\\n  case Ok(1) {\\n    Ok(duplicate_name) | Error(duplicate_name) -> duplicate_name\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Ok(1) {\n    Ok(duplicate_name) | Error(duplicate_name) -> duplicate_name\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    case {ok, 1} of\n        {ok, Duplicate_name} ->\n            Duplicate_name;\n\n        {error, Duplicate_name} ->\n            Duplicate_name\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"\\npub fn main() {\\n    let duplicate_name = 1\\n\\n    case 1 {\\n        1 | 2 if duplicate_name == 1 -> duplicate_name\\n        _ -> 0\\n    }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let duplicate_name = 1\n\n    case 1 {\n        1 | 2 if duplicate_name == 1 -> duplicate_name\n        _ -> 0\n    }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    Duplicate_name = 1,\n    case 1 of\n        1 when Duplicate_name =:= 1 ->\n            Duplicate_name;\n\n        2 when Duplicate_name =:= 1 ->\n            Duplicate_name;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"\\npub const constant = Ok(1)\\n\\npub fn main(arg) {\\n  let _ = constant\\n  case arg {\\n    _ if arg == constant -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const constant = Ok(1)\n\npub fn main(arg) {\n  let _ = constant\n  case arg {\n    _ if arg == constant -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main({ok, integer()} | {error, any()}) -> integer().\nmain(Arg) ->\n    _ = {ok, 1},\n    case Arg of\n        _ when Arg =:= {ok, 1} ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__pattern_as.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"pub fn a(x) {\\n  case x {\\n    Ok(1 as y) -> 1\\n    _ -> 0\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn a(x) {\n  case x {\n    Ok(1 as y) -> 1\n    _ -> 0\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a({ok, integer()} | {error, any()}) -> integer().\na(X) ->\n    case X of\n        {ok, 1 = Y} ->\n            1;\n\n        _ ->\n            0\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_assertion.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"pub fn a(x) {\\n  let assert \\\"a\\\" as a <> rest = \\\"wibble\\\"\\n  a\\n}\"\n---\n----- SOURCE CODE\npub fn a(x) {\n  let assert \"a\" as a <> rest = \"wibble\"\n  a\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a(any()) -> binary().\na(X) ->\n    {Rest@1, A@1} = case <<\"wibble\"/utf8>> of\n        <<\"a\"/utf8, Rest/binary>> -> {Rest, A};\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"a\"/utf8>>,\n                        line => 2,\n                        value => _assert_fail,\n                        start => 16,\n                        'end' => 54,\n                        pattern_start => 27,\n                        pattern_end => 43})\n    end,\n    A = <<\"a\"/utf8>>,\n    A@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_list.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"pub fn a(x) {\\n  case x {\\n    [\\\"a\\\" as a <> _, \\\"b\\\" as b <> _] -> a <> b\\n    _ -> \\\"\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn a(x) {\n  case x {\n    [\"a\" as a <> _, \"b\" as b <> _] -> a <> b\n    _ -> \"\"\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a(list(binary())) -> binary().\na(X) ->\n    case X of\n        [<<\"a\"/utf8, _/binary>>, <<\"b\"/utf8, _/binary>>] ->\n            A = <<\"a\"/utf8>>,\n            B = <<\"b\"/utf8>>,\n            <<A/binary, B/binary>>;\n\n        _ ->\n            <<\"\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"pub fn a(x) {\\n  case x, x {\\n    _, \\\"a\\\" as a <> _  -> a\\n    _, _ -> \\\"a\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn a(x) {\n  case x, x {\n    _, \"a\" as a <> _  -> a\n    _, _ -> \"a\"\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a(binary()) -> binary().\na(X) ->\n    case {X, X} of\n        {_, <<\"a\"/utf8, _/binary>>} ->\n            A = <<\"a\"/utf8>>,\n            A;\n\n        {_, _} ->\n            <<\"a\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects_and_guard.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/patterns.rs\nexpression: \"pub fn a(x) {\\n  case x, x {\\n    _, \\\"a\\\" as a <> rest if rest == \\\"a\\\" -> a\\n    _, _ -> \\\"a\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn a(x) {\n  case x, x {\n    _, \"a\" as a <> rest if rest == \"a\" -> a\n    _, _ -> \"a\"\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec a(binary()) -> binary().\na(X) ->\n    case {X, X} of\n        {_, <<\"a\"/utf8, Rest/binary>>} when Rest =:= <<\"a\"/utf8>> ->\n            A = <<\"a\"/utf8>>,\n            A;\n\n        {_, _} ->\n            <<\"a\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__block_expr_into_pipe.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"fn id(a) { a }\\npub fn main() {\\n  {\\n    let x = 1\\n    x\\n  }\\n  |> id\\n}\"\n---\n----- SOURCE CODE\nfn id(a) { a }\npub fn main() {\n  {\n    let x = 1\n    x\n  }\n  |> id\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec id(I) -> I.\nid(A) ->\n    A.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    _pipe = begin\n        X = 1,\n        X\n    end,\n    id(_pipe).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__call_pipeline_result.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"\\npub fn main() {\\n  { 1 |> add }(1)\\n}\\n\\npub fn add(x) {\\n  fn(y) { x + y }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  { 1 |> add }(1)\n}\n\npub fn add(x) {\n  fn(y) { x + y }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([add/1, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec add(integer()) -> fun((integer()) -> integer()).\nadd(X) ->\n    fun(Y) -> X + Y end.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    begin\n        _pipe = 1,\n        add(_pipe)\n    end(1).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"\\npub fn apply(f: fn(a) -> b, a: a) { a |> f }\\n\"\n---\n----- SOURCE CODE\n\npub fn apply(f: fn(a) -> b, a: a) { a |> f }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([apply/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec apply(fun((I) -> J), I) -> J.\napply(F, A) ->\n    _pipe = A,\n    F(_pipe).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"\\npub fn apply(f: fn(a, Int) -> b, a: a) { a |> f(1) }\\n\"\n---\n----- SOURCE CODE\n\npub fn apply(f: fn(a, Int) -> b, a: a) { a |> f(1) }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([apply/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec apply(fun((I, integer()) -> J), I) -> J.\napply(F, A) ->\n    _pipe = A,\n    F(_pipe, 1).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__multiple_pipes.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"\\npub fn main() {\\n  1 |> x |> x\\n  2 |> x |> x\\n}\\n\\nfn x(x) { x }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1 |> x |> x\n  2 |> x |> x\n}\n\nfn x(x) { x }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec x(J) -> J.\nx(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    _pipe = 1,\n    _pipe@1 = x(_pipe),\n    x(_pipe@1),\n    _pipe@2 = 2,\n    _pipe@3 = x(_pipe@2),\n    x(_pipe@3).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"\\npub fn main() {\\n  123\\n  |> two(\\n    1 |> two(2),\\n    _,\\n  )\\n}\\n\\npub fn two(a, b) {\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  123\n  |> two(\n    1 |> two(2),\n    _,\n  )\n}\n\npub fn two(a, b) {\n  a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([two/2, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 10).\n-spec two(J, any()) -> J.\ntwo(A, B) ->\n    A.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    _pipe = 123,\n    two(\n        begin\n            _pipe@1 = 1,\n            two(_pipe@1, 2)\n        end,\n        _pipe\n    ).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_case_subject.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"pub fn x(f) {\\n  case 1 |> f {\\n    x -> x\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn x(f) {\n  case 1 |> f {\n    x -> x\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x(fun((integer()) -> L)) -> L.\nx(F) ->\n    case begin\n        _pipe = 1,\n        F(_pipe)\n    end of\n        X ->\n            X\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_eq.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"fn id(x) {\\n  x\\n}\\n\\npub fn main() {\\n    1 == 1 |> id\\n}\"\n---\n----- SOURCE CODE\nfn id(x) {\n  x\n}\n\npub fn main() {\n    1 == 1 |> id\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec id(I) -> I.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> boolean().\nmain() ->\n    1 =:= begin\n        _pipe = 1,\n        id(_pipe)\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_list.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"pub fn x(f) {\\n  [\\n    1 |> f\\n  ]\\n}\"\n---\n----- SOURCE CODE\npub fn x(f) {\n  [\n    1 |> f\n  ]\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x(fun((integer()) -> L)) -> list(L).\nx(F) ->\n    [begin\n            _pipe = 1,\n            F(_pipe)\n        end].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"pub type X {\\n  X(a: Int, b: Int)\\n}\\n\\nfn id(x) {\\n  x\\n}\\n\\npub fn main(x) {\\n  X(..x, a: 1 |> id)\\n}\"\n---\n----- SOURCE CODE\npub type X {\n  X(a: Int, b: Int)\n}\n\nfn id(x) {\n  x\n}\n\npub fn main(x) {\n  X(..x, a: 1 |> id)\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n-export_type([x/0]).\n\n-type x() :: {x, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec id(I) -> I.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec main(x()) -> x().\nmain(X) ->\n    {x,\n        begin\n            _pipe = 1,\n            id(_pipe)\n        end,\n        erlang:element(3, X)}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_tuple.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/pipes.rs\nexpression: \"pub fn x(f) {\\n  #(\\n    1 |> f\\n  )\\n}\"\n---\n----- SOURCE CODE\npub fn x(f) {\n  #(\n    1 |> f\n  )\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([x/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec x(fun((integer()) -> K)) -> {K}.\nx(F) ->\n    {begin\n            _pipe = 1,\n            F(_pipe)\n        end}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__basic.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"record_definition(\\\"PetCat\\\",\\n&[(\\\"name\\\", type_::tuple(vec![])), (\\\"is_cute\\\", type_::tuple(vec![]))])\"\n---\n-record(pet_cat, {name :: {}, is_cute :: {}}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__const_record_update_generic_respecialization.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nassertion_line: 421\nexpression: \"\\npub type Box(a) {\\n  Box(name: String, value: a)\\n}\\n\\npub const base = Box(\\\"score\\\", 50)\\npub const updated = Box(..base, value: \\\"Hello\\\")\\n\\npub fn main() {\\n  #(base, updated)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Box(a) {\n  Box(name: String, value: a)\n}\n\npub const base = Box(\"score\", 50)\npub const updated = Box(..base, value: \"Hello\")\n\npub fn main() {\n  #(base, updated)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([box/1]).\n\n-type box(I) :: {box, binary(), I}.\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec main() -> {box(integer()), box(binary())}.\nmain() ->\n    {{box, <<\"score\"/utf8>>, 50}, {box, <<\"score\"/utf8>>, <<\"Hello\"/utf8>>}}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__constant_record_update_with_unlabelled_fields.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int, Float, b: Bool, s: String)\\n}\\n\\npub const record = Wibble(1, 3.14, True, \\\"Hello\\\")\\npub const updated = Wibble(..record, b: False)\\n\\npub fn main() {\\n  updated\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub const record = Wibble(1, 3.14, True, \"Hello\")\npub const updated = Wibble(..record, b: False)\n\npub fn main() {\n  updated\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([wibble/0]).\n\n-type wibble() :: {wibble, integer(), float(), boolean(), binary()}.\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec main() -> wibble().\nmain() ->\n    {wibble, 1, 3.14, false, <<\"Hello\"/utf8>>}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__imported_qualified_constructor_as_fn_name_escape.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"import other_module\\n\\npub fn main() {\\n  other_module.Let\\n}\"\n---\n----- SOURCE CODE\nimport other_module\n\npub fn main() {\n  other_module.Let\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec main() -> fun((integer()) -> other_module:'let'()).\nmain() ->\n    fun(Field@0) -> {'let', Field@0} end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__long_definition_formatting.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"record_definition(\\\"PetCat\\\",\\n&[(\\\"name\\\", type_::generic_var(1)), (\\\"is_cute\\\", type_::unbound_var(1)),\\n(\\\"linked\\\", type_::link(type_::int())),\\n(\\\"whatever\\\",\\ntype_::list(type_::tuple(vec![type_::nil(),\\ntype_::list(type_::tuple(vec![type_::nil(), type_::nil(), type_::nil()])),\\ntype_::nil(),\\ntype_::list(type_::tuple(vec![type_::nil(), type_::nil(), type_::nil()])),\\ntype_::nil(),\\ntype_::list(type_::tuple(vec![type_::nil(), type_::nil(),\\ntype_::nil()])),]))),])\"\n---\n-record(pet_cat, {\n    name :: any(),\n    is_cute :: any(),\n    linked :: integer(),\n    whatever :: list({nil,\n        list({nil, nil, nil}),\n        nil,\n        list({nil, nil, nil}),\n        nil,\n        list({nil, nil, nil})})\n}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__module_types.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"record_definition(\\\"PetCat\\\",\\n&[(\\\"name\\\",\\nArc::new(Type::Named\\n{\\n    publicity: Publicity::Public, package: \\\"package\\\".into(), module:\\n    module_name, name: \\\"my_type\\\".into(), args: vec![], inferred_variant: None,\\n}))])\"\n---\n-record(pet_cat, {name :: name:my_type()}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"pub type Wibble {\\n  Wibble(a: Int, b: Wobble, c: Int)\\n}\\n\\npub type Wobble {\\n  Wobble(a: Int, b: Int)\\n}\\n\\npub fn main() {\\n  let base = Wibble(1, Wobble(2, 3), 4)\\n  Wibble(..base, b: Wobble(..base.b, b: 5))\\n}\"\n---\n----- SOURCE CODE\npub type Wibble {\n  Wibble(a: Int, b: Wobble, c: Int)\n}\n\npub type Wobble {\n  Wobble(a: Int, b: Int)\n}\n\npub fn main() {\n  let base = Wibble(1, Wobble(2, 3), 4)\n  Wibble(..base, b: Wobble(..base.b, b: 5))\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([wibble/0, wobble/0]).\n\n-type wibble() :: {wibble, integer(), wobble(), integer()}.\n\n-type wobble() :: {wobble, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec main() -> wibble().\nmain() ->\n    Base = {wibble, 1, {wobble, 2, 3}, 4},\n    {wibble,\n        erlang:element(2, Base),\n        begin\n            _record = erlang:element(3, Base),\n            {wobble, erlang:element(2, _record), 5}\n        end,\n        erlang:element(4, Base)}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"pub type A { A(b: B) }\\npub type B { B(c: C) }\\npub type C { C(val: Int) }\\n\\npub fn main(a: A) {\\n    A(..a, b: {\\n        B(..a.b, c: {\\n            C(..a.b.c, val: 0)\\n        })\\n    })\\n}\"\n---\n----- SOURCE CODE\npub type A { A(b: B) }\npub type B { B(c: C) }\npub type C { C(val: Int) }\n\npub fn main(a: A) {\n    A(..a, b: {\n        B(..a.b, c: {\n            C(..a.b.c, val: 0)\n        })\n    })\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n-export_type([a/0, b/0, c/0]).\n\n-type a() :: {a, b()}.\n\n-type b() :: {b, c()}.\n\n-type c() :: {c, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main(a()) -> a().\nmain(A) ->\n    {a,\n        begin\n            _record = erlang:element(2, A),\n            {b,\n                begin\n                    _record@1 = erlang:element(2, erlang:element(2, A)),\n                    {c, 0}\n                end}\n        end}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__pipe_update_subject.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"pub type Thing {\\n  Thing(a: Int, b: Int)\\n}\\n\\npub fn identity(x) { x }\\n\\npub fn main() {\\n  let thing = Thing(1, 2)\\n  Thing(..thing |> identity, b: 1000)\\n}\"\n---\n----- SOURCE CODE\npub type Thing {\n  Thing(a: Int, b: Int)\n}\n\npub fn identity(x) { x }\n\npub fn main() {\n  let thing = Thing(1, 2)\n  Thing(..thing |> identity, b: 1000)\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([identity/1, main/0]).\n-export_type([thing/0]).\n\n-type thing() :: {thing, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec identity(I) -> I.\nidentity(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec main() -> thing().\nmain() ->\n    Thing = {thing, 1, 2},\n    _record = begin\n        _pipe = Thing,\n        identity(_pipe)\n    end,\n    {thing, erlang:element(2, _record), 1000}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__private_unused_records.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"type A { A(inner: Int) }\\ntype B { B(String) }\\ntype C { C(Int) }\\n\\npub fn main(x: Int) -> Int {\\n  let a = A(x)\\n  a.inner\\n}\\n\"\n---\n----- SOURCE CODE\ntype A { A(inner: Int) }\ntype B { B(String) }\ntype C { C(Int) }\n\npub fn main(x: Int) -> Int {\n  let a = A(x)\n  a.inner\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n-export_type([a/0, b/0, c/0]).\n\n-type a() :: {a, integer()}.\n\n-type b() :: {b, binary()}.\n\n-type c() :: {c, integer()}.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main(integer()) -> integer().\nmain(X) ->\n    A = {a, X},\n    erlang:element(2, A).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_access_block.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"pub type Thing {\\n  Thing(a: Int, b: Int)\\n}\\n\\npub fn main() {\\n  {\\n    let thing = Thing(1, 2)\\n    thing\\n  }.a\\n}\"\n---\n----- SOURCE CODE\npub type Thing {\n  Thing(a: Int, b: Int)\n}\n\npub fn main() {\n  {\n    let thing = Thing(1, 2)\n    thing\n  }.a\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([thing/0]).\n\n-type thing() :: {thing, integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> integer().\nmain() ->\n    erlang:element(\n        2,\n        begin\n            Thing = {thing, 1, 2},\n            Thing\n        end\n    ).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: String, title: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_name(person: Person) { person.name }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([get_name/1]).\n-export_type([person/0]).\n\n-type person() :: {teacher, binary(), binary()} | {student, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec get_name(person()) -> binary().\nget_name(Person) ->\n    erlang:element(2, Person).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_parameterised_types.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: String, age: List(Int), title: String)\\n    Student(name: String, age: List(Int))\\n}\\npub fn get_name(person: Person) { person.name }\\npub fn get_age(person: Person) { person.age }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, age: List(Int), title: String)\n    Student(name: String, age: List(Int))\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([get_name/1, get_age/1]).\n-export_type([person/0]).\n\n-type person() :: {teacher, binary(), list(integer()), binary()} |\n    {student, binary(), list(integer())}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec get_name(person()) -> binary().\nget_name(Person) ->\n    erlang:element(2, Person).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec get_age(person()) -> list(integer()).\nget_age(Person) ->\n    erlang:element(3, Person).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_positions_other_than_first.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: String, age: Int, title: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_name(person: Person) { person.name }\\npub fn get_age(person: Person) { person.age }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([get_name/1, get_age/1]).\n-export_type([person/0]).\n\n-type person() :: {teacher, binary(), integer(), binary()} |\n    {student, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec get_name(person()) -> binary().\nget_name(Person) ->\n    erlang:element(2, Person).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec get_age(person()) -> integer().\nget_age(Person) ->\n    erlang:element(3, Person).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_with_first_position_different_types.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: Nil, age: Int)\\n    Student(name: String, age: Int)\\n}\\npub fn get_age(person: Person) { person.age }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: Nil, age: Int)\n    Student(name: String, age: Int)\n}\npub fn get_age(person: Person) { person.age }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([get_age/1]).\n-export_type([person/0]).\n\n-type person() :: {teacher, nil, integer()} | {student, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec get_age(person()) -> integer().\nget_age(Person) ->\n    erlang:element(3, Person).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessors.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person { Person(name: String, age: Int) }\\npub fn get_age(person: Person) { person.age }\\npub fn get_name(person: Person) { person.name }\\n\"\n---\n----- SOURCE CODE\n\npub type Person { Person(name: String, age: Int) }\npub fn get_age(person: Person) { person.age }\npub fn get_name(person: Person) { person.name }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([get_age/1, get_name/1]).\n-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec get_age(person()) -> integer().\nget_age(Person) ->\n    erlang:element(3, Person).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec get_name(person()) -> binary().\nget_name(Person) ->\n    erlang:element(2, Person).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_constants.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"pub type Test { A }\\nconst some_test = A\\npub fn a() { A }\"\n---\n----- SOURCE CODE\npub type Test { A }\nconst some_test = A\npub fn a() { A }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([a/0]).\n-export_type([test/0]).\n\n-type test() :: a.\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec a() -> test().\na() ->\n    a.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Triple {\\n    Triple(a: Int, b: Int, c: Int)\\n}\\n\\npub fn main() {\\n  let triple = Triple(1,2,3)\\n  let Triple(the_a, ..) = triple\\n  the_a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Triple {\n    Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  let Triple(the_a, ..) = triple\n  the_a\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([triple/0]).\n\n-type triple() :: {triple, integer(), integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    Triple = {triple, 1, 2, 3},\n    {triple, The_a, _, _} = Triple,\n    The_a.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Triple {\\n  Triple(a: Int, b: Int, c: Int)\\n}\\n\\npub fn main() {\\n  let triple = Triple(1,2,3)\\n  let Triple(b: the_b, ..) = triple\\n  the_b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  let Triple(b: the_b, ..) = triple\n  the_b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([triple/0]).\n\n-type triple() :: {triple, integer(), integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    Triple = {triple, 1, 2, 3},\n    {triple, _, The_b, _} = Triple,\n    The_b.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Triple {\\n  Triple(a: Int, b: Int, c: Int)\\n}\\n\\npub fn main() {\\n  let triple = Triple(1,2,3)\\n  let Triple(the_a, c: the_c, ..) = triple\\n  the_c\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  let Triple(the_a, c: the_c, ..) = triple\n  the_c\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([triple/0]).\n\n-type triple() :: {triple, integer(), integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    Triple = {triple, 1, 2, 3},\n    {triple, The_a, _, The_c} = Triple,\n    The_c.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Triple {\\n  Triple(a: Int, b: Int, c: Int)\\n}\\n\\npub fn main() {\\n  let triple = Triple(1,2,3)\\n  case triple {\\n    Triple(b: the_b, ..) -> the_b\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let triple = Triple(1,2,3)\n  case triple {\n    Triple(b: the_b, ..) -> the_b\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([triple/0]).\n\n-type triple() :: {triple, integer(), integer(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> integer().\nmain() ->\n    Triple = {triple, 1, 2, 3},\n    case Triple of\n        {triple, _, The_b, _} ->\n            The_b\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_update_with_unlabelled_fields.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int, Float, b: Bool, s: String)\\n}\\n\\npub fn main() {\\n  let record = Wibble(1, 3.14, True, \\\"Hello\\\")\\n  Wibble(..record, b: False)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub fn main() {\n  let record = Wibble(1, 3.14, True, \"Hello\")\n  Wibble(..record, b: False)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([wibble/0]).\n\n-type wibble() :: {wibble, integer(), float(), boolean(), binary()}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> wibble().\nmain() ->\n    Record = {wibble, 1, 3.14, true, <<\"Hello\"/utf8>>},\n    {wibble,\n        erlang:element(2, Record),\n        erlang:element(3, Record),\n        false,\n        erlang:element(5, Record)}.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person { Person(name: String, age: Int) }\\n\\npub fn main() {\\n    let p = Person(\\\"Quinn\\\", 27)\\n    let new_p = Person(..p, age: 28)\\n    new_p\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let p = Person(\"Quinn\", 27)\n    let new_p = Person(..p, age: 28)\n    new_p\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> person().\nmain() ->\n    P = {person, <<\"Quinn\"/utf8>>, 27},\n    New_p = {person, erlang:element(2, P), 28},\n    New_p.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person { Person(name: String, age: Int) }\\n\\npub fn main() {\\n    let p = Person(\\\"Quinn\\\", 27)\\n    let new_p = Person(..p, age: p.age + 1)\\n    new_p\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let p = Person(\"Quinn\", 27)\n    let new_p = Person(..p, age: p.age + 1)\n    new_p\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> person().\nmain() ->\n    P = {person, <<\"Quinn\"/utf8>>, 27},\n    New_p = {person, erlang:element(2, P), erlang:element(3, P) + 1},\n    New_p.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person { Person(name: String, age: Int) }\\n\\npub fn main() {\\n    let p = Person(\\\"Quinn\\\", 27)\\n    let new_p = Person(..p, age: 28, name: \\\"Riley\\\")\\n    new_p\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let p = Person(\"Quinn\", 27)\n    let new_p = Person(..p, age: 28, name: \"Riley\")\n    new_p\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> person().\nmain() ->\n    P = {person, <<\"Quinn\"/utf8>>, 27},\n    New_p = {person, <<\"Riley\"/utf8>>, 28},\n    New_p.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Person { Person(name: String, age: Int) }\\n\\npub fn main() {\\n    let new_p = Person(..return_person(), age: 28)\\n    new_p\\n}\\n\\nfn return_person() {\\n    Person(\\\"Quinn\\\", 27)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let new_p = Person(..return_person(), age: 28)\n    new_p\n}\n\nfn return_person() {\n    Person(\"Quinn\", 27)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 9).\n-spec return_person() -> person().\nreturn_person() ->\n    {person, <<\"Quinn\"/utf8>>, 27}.\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> person().\nmain() ->\n    New_p = begin\n        _record = return_person(),\n        {person, erlang:element(2, _record), 28}\n    end,\n    New_p.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates4.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"\\npub type Car { Car(make: String, model: String, driver: Person) }\\npub type Person { Person(name: String, age: Int) }\\n\\npub fn main() {\\n    let car = Car(make: \\\"Amphicar\\\", model: \\\"Model 770\\\", driver: Person(name: \\\"John Doe\\\", age: 27))\\n    let new_p = Person(..car.driver, age: 28)\\n    new_p\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Car { Car(make: String, model: String, driver: Person) }\npub type Person { Person(name: String, age: Int) }\n\npub fn main() {\n    let car = Car(make: \"Amphicar\", model: \"Model 770\", driver: Person(name: \"John Doe\", age: 27))\n    let new_p = Person(..car.driver, age: 28)\n    new_p\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n-export_type([car/0, person/0]).\n\n-type car() :: {car, binary(), binary(), person()}.\n\n-type person() :: {person, binary(), integer()}.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> person().\nmain() ->\n    Car = {car,\n        <<\"Amphicar\"/utf8>>,\n        <<\"Model 770\"/utf8>>,\n        {person, <<\"John Doe\"/utf8>>, 27}},\n    New_p = begin\n        _record = erlang:element(4, Car),\n        {person, erlang:element(2, _record), 28}\n    end,\n    New_p.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__reserve_words.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"record_definition(\\\"div\\\",\\n&[(\\\"receive\\\", type_::int()), (\\\"catch\\\", type_::tuple(vec![])),\\n(\\\"unreserved\\\", type_::tuple(vec![]))])\"\n---\n-record('div', {'receive' :: integer(), 'catch' :: {}, unreserved :: {}}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__type_vars.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/records.rs\nexpression: \"record_definition(\\\"PetCat\\\",\\n&[(\\\"name\\\", type_::generic_var(1)), (\\\"is_cute\\\", type_::unbound_var(1)),\\n(\\\"linked\\\", type_::link(type_::int()))])\"\n---\n-record(pet_cat, {name :: any(), is_cute :: any(), linked :: integer()}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__build_in_erlang_type_escaping.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/reserved.rs\nexpression: pub type Map\n---\n----- SOURCE CODE\npub type Map\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type([map_/0]).\n\n-type map_() :: any().\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__escape_erlang_reserved_keywords_in_type_names.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/reserved.rs\nexpression: \"pub type After { TestAfter }\\npub type And { TestAnd }\\npub type Andalso { TestAndAlso }\\npub type Band { TestBAnd }\\npub type Begin { TestBegin }\\npub type Bnot { TestBNot }\\npub type Bor { TestBOr }\\npub type Bsl { TestBsl }\\npub type Bsr { TestBsr }\\npub type Bxor { TestBXor }\\npub type Case { TestCase }\\npub type Catch { TestCatch }\\npub type Cond { TestCond }\\npub type Div { TestDiv }\\npub type End { TestEnd }\\npub type Fun { TestFun }\\npub type If { TestIf }\\npub type Let { TestLet }\\npub type Maybe { TestMaybe }\\npub type Not { TestNot }\\npub type Of { TestOf }\\npub type Or { TestOr }\\npub type Orelse { TestOrElse }\\npub type Query { TestQuery }\\npub type Receive { TestReceive }\\npub type Rem { TestRem }\\npub type Try { TestTry }\\npub type When { TestWhen }\\npub type Xor { TestXor }\"\n---\n----- SOURCE CODE\npub type After { TestAfter }\npub type And { TestAnd }\npub type Andalso { TestAndAlso }\npub type Band { TestBAnd }\npub type Begin { TestBegin }\npub type Bnot { TestBNot }\npub type Bor { TestBOr }\npub type Bsl { TestBsl }\npub type Bsr { TestBsr }\npub type Bxor { TestBXor }\npub type Case { TestCase }\npub type Catch { TestCatch }\npub type Cond { TestCond }\npub type Div { TestDiv }\npub type End { TestEnd }\npub type Fun { TestFun }\npub type If { TestIf }\npub type Let { TestLet }\npub type Maybe { TestMaybe }\npub type Not { TestNot }\npub type Of { TestOf }\npub type Or { TestOr }\npub type Orelse { TestOrElse }\npub type Query { TestQuery }\npub type Receive { TestReceive }\npub type Rem { TestRem }\npub type Try { TestTry }\npub type When { TestWhen }\npub type Xor { TestXor }\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export_type(['after'/0, 'and'/0, 'andalso'/0, 'band'/0, 'begin'/0, 'bnot'/0, 'bor'/0, 'bsl'/0, 'bsr'/0, 'bxor'/0, 'case'/0, 'catch'/0, 'cond'/0, 'div'/0, 'end'/0, 'fun'/0, 'if'/0, 'let'/0, 'maybe'/0, 'not'/0, 'of'/0, 'or'/0, 'orelse'/0, 'query'/0, 'receive'/0, 'rem'/0, 'try'/0, 'when'/0, 'xor'/0]).\n\n-type 'after'() :: test_after.\n\n-type 'and'() :: test_and.\n\n-type 'andalso'() :: test_and_also.\n\n-type 'band'() :: test_b_and.\n\n-type 'begin'() :: test_begin.\n\n-type 'bnot'() :: test_b_not.\n\n-type 'bor'() :: test_b_or.\n\n-type 'bsl'() :: test_bsl.\n\n-type 'bsr'() :: test_bsr.\n\n-type 'bxor'() :: test_b_xor.\n\n-type 'case'() :: test_case.\n\n-type 'catch'() :: test_catch.\n\n-type 'cond'() :: test_cond.\n\n-type 'div'() :: test_div.\n\n-type 'end'() :: test_end.\n\n-type 'fun'() :: test_fun.\n\n-type 'if'() :: test_if.\n\n-type 'let'() :: test_let.\n\n-type 'maybe'() :: test_maybe.\n\n-type 'not'() :: test_not.\n\n-type 'of'() :: test_of.\n\n-type 'or'() :: test_or.\n\n-type 'orelse'() :: test_or_else.\n\n-type 'query'() :: test_query.\n\n-type 'receive'() :: test_receive.\n\n-type 'rem'() :: test_rem.\n\n-type 'try'() :: test_try.\n\n-type 'when'() :: test_when.\n\n-type 'xor'() :: test_xor.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__ascii_as_unicode_escape_sequence.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn y() -> String {\\n  \\\"\\\\u{79}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn y() -> String {\n  \"\\u{79}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([y/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec y() -> binary().\ny() ->\n    <<\"\\x{79}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nconst cute = \\\"cute\\\"\\nconst cute_bee = cute <> \\\"bee\\\"\\n\\npub fn main() {\\n  cute_bee\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst cute = \"cute\"\nconst cute_bee = cute <> \"bee\"\n\npub fn main() {\n  cute_bee\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> binary().\nmain() ->\n    <<\"cute\"/utf8, \"bee\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nconst big_concat = \\\"a\\\" <> \\\"b\\\" <> \\\"c\\\" <> \\\"d\\\" <> \\\"e\\\" <> \\\"f\\\" <> \\\"g\\\" <> \\\"h\\\" <> \\\"i\\\" <> \\\"j\\\" <> \\\"k\\\" <> \\\"l\\\" <> \\\"m\\\" <> \\\"n\\\" <> \\\"o\\\" <> \\\"p\\\" <> \\\"q\\\" <> \\\"r\\\" <> \\\"s\\\" <> \\\"t\\\" <> \\\"u\\\" <> \\\"v\\\" <> \\\"w\\\" <> \\\"x\\\" <> \\\"y\\\" <> \\\"z\\\"\\n\\npub fn main() {\\n  big_concat\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst big_concat = \"a\" <> \"b\" <> \"c\" <> \"d\" <> \"e\" <> \"f\" <> \"g\" <> \"h\" <> \"i\" <> \"j\" <> \"k\" <> \"l\" <> \"m\" <> \"n\" <> \"o\" <> \"p\" <> \"q\" <> \"r\" <> \"s\" <> \"t\" <> \"u\" <> \"v\" <> \"w\" <> \"x\" <> \"y\" <> \"z\"\n\npub fn main() {\n  big_concat\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> binary().\nmain() ->\n    <<\"a\"/utf8,\n        \"b\"/utf8,\n        \"c\"/utf8,\n        \"d\"/utf8,\n        \"e\"/utf8,\n        \"f\"/utf8,\n        \"g\"/utf8,\n        \"h\"/utf8,\n        \"i\"/utf8,\n        \"j\"/utf8,\n        \"k\"/utf8,\n        \"l\"/utf8,\n        \"m\"/utf8,\n        \"n\"/utf8,\n        \"o\"/utf8,\n        \"p\"/utf8,\n        \"q\"/utf8,\n        \"r\"/utf8,\n        \"s\"/utf8,\n        \"t\"/utf8,\n        \"u\"/utf8,\n        \"v\"/utf8,\n        \"w\"/utf8,\n        \"x\"/utf8,\n        \"y\"/utf8,\n        \"z\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings_in_list.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nconst big_concat_list = [\\\"a\\\" <> \\\"b\\\" <> \\\"c\\\" <> \\\"d\\\" <> \\\"e\\\" <> \\\"f\\\" <> \\\"g\\\" <> \\\"h\\\" <> \\\"i\\\" <> \\\"j\\\" <> \\\"k\\\" <> \\\"l\\\" <> \\\"m\\\" <> \\\"n\\\" <> \\\"o\\\" <> \\\"p\\\" <> \\\"q\\\" <> \\\"r\\\" <> \\\"s\\\" <> \\\"t\\\" <> \\\"u\\\" <> \\\"v\\\" <> \\\"w\\\" <> \\\"x\\\" <> \\\"y\\\" <> \\\"z\\\"]\\n\\npub fn main() {\\n  big_concat_list\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst big_concat_list = [\"a\" <> \"b\" <> \"c\" <> \"d\" <> \"e\" <> \"f\" <> \"g\" <> \"h\" <> \"i\" <> \"j\" <> \"k\" <> \"l\" <> \"m\" <> \"n\" <> \"o\" <> \"p\" <> \"q\" <> \"r\" <> \"s\" <> \"t\" <> \"u\" <> \"v\" <> \"w\" <> \"x\" <> \"y\" <> \"z\"]\n\npub fn main() {\n  big_concat_list\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec main() -> list(binary()).\nmain() ->\n    [<<\"a\"/utf8,\n            \"b\"/utf8,\n            \"c\"/utf8,\n            \"d\"/utf8,\n            \"e\"/utf8,\n            \"f\"/utf8,\n            \"g\"/utf8,\n            \"h\"/utf8,\n            \"i\"/utf8,\n            \"j\"/utf8,\n            \"k\"/utf8,\n            \"l\"/utf8,\n            \"m\"/utf8,\n            \"n\"/utf8,\n            \"o\"/utf8,\n            \"p\"/utf8,\n            \"q\"/utf8,\n            \"r\"/utf8,\n            \"s\"/utf8,\n            \"t\"/utf8,\n            \"u\"/utf8,\n            \"v\"/utf8,\n            \"w\"/utf8,\n            \"x\"/utf8,\n            \"y\"/utf8,\n            \"z\"/utf8>>].\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_other_const_concat.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nconst cute_bee = \\\"cute\\\" <> \\\"bee\\\"\\nconst cute_cute_bee_buzz = cute_bee <> \\\"buzz\\\"\\n\\npub fn main() {\\n  cute_cute_bee_buzz\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst cute_bee = \"cute\" <> \"bee\"\nconst cute_cute_bee_buzz = cute_bee <> \"buzz\"\n\npub fn main() {\n  cute_cute_bee_buzz\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> binary().\nmain() ->\n    <<\"cute\"/utf8, \"bee\"/utf8, \"buzz\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn main(x) {\\n  let assert \\\"m-\\\" <> rest = x\\n  rest\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert \"m-\" <> rest = x\n  rest\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    Rest@1 = case X of\n        <<\"m-\"/utf8, Rest/binary>> -> Rest;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 20,\n                        'end' => 47,\n                        pattern_start => 31,\n                        pattern_end => 43})\n    end,\n    Rest@1.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix_discar.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn main(x) {\\n  let assert \\\"m-\\\" <> _ = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert \"m-\" <> _ = x\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    case X of\n        <<\"m-\"/utf8, _/binary>> -> X;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"main\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 20,\n                        'end' => 44,\n                        pattern_start => 31,\n                        pattern_end => 40})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x, y) {\\n  x <> y\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  x <> y\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/2]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary(), binary()) -> binary().\ngo(X, Y) ->\n    <<X/binary, Y/binary>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_3_variables.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x, y, z) {\\n  x <> y <> z\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, y, z) {\n  x <> y <> z\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/3]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary(), binary(), binary()) -> binary().\ngo(X, Y, Z) ->\n    <<<<X/binary, Y/binary>>/binary, Z/binary>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nconst a = \\\"Hello, \\\"\\nconst b = \\\"Joe!\\\"\\n\\npub fn go() {\\n  a <> b\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst a = \"Hello, \"\nconst b = \"Joe!\"\n\npub fn go() {\n  a <> b\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec go() -> binary().\ngo() ->\n    <<\"Hello, \"/utf8, \"Joe!\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant_fn.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nconst cs = s\\n\\nfn s() {\\n  \\\"s\\\"\\n}\\n\\npub fn go() {\\n  cs() <> cs()\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst cs = s\n\nfn s() {\n  \"s\"\n}\n\npub fn go() {\n  cs() <> cs()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 4).\n-spec s() -> binary().\ns() ->\n    <<\"s\"/utf8>>.\n\n-file(\"project/test/my/mod.gleam\", 8).\n-spec go() -> binary().\ngo() ->\n    <<(s())/binary, (s())/binary>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_function_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nfn x() {\\n  \\\"\\\"\\n}\\n\\npub fn go() {\\n  x() <> x()\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn x() {\n  \"\"\n}\n\npub fn go() {\n  x() <> x()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec x() -> binary().\nx() ->\n    <<\"\"/utf8>>.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec go() -> binary().\ngo() ->\n    <<(x())/binary, (x())/binary>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__discard_concat_rest_pattern.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" <> _ -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" <> _ -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> nil.\ngo(X) ->\n    case X of\n        <<\"Hello, \"/utf8, _/binary>> ->\n            nil;\n\n        _ ->\n            nil\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn not_unicode_escape_sequence() -> String {\\n  \\\"\\\\\\\\u{03a9}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn not_unicode_escape_sequence() -> String {\n  \"\\\\u{03a9}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([not_unicode_escape_sequence/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec not_unicode_escape_sequence() -> binary().\nnot_unicode_escape_sequence() ->\n    <<\"\\\\u{03a9}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn not_unicode_escape_sequence() -> String {\\n  \\\"\\\\\\\\\\\\\\\\u{03a9}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn not_unicode_escape_sequence() -> String {\n  \"\\\\\\\\u{03a9}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([not_unicode_escape_sequence/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec not_unicode_escape_sequence() -> binary().\nnot_unicode_escape_sequence() ->\n    <<\"\\\\\\\\u{03a9}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__pipe_concat.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\nfn id(x) {\\n  x\\n}\\n\\npub fn main() {\\n  { \\\"\\\" |> id } <> { \\\"\\\" |> id }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn id(x) {\n  x\n}\n\npub fn main() {\n  { \"\" |> id } <> { \"\" |> id }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec id(I) -> I.\nid(X) ->\n    X.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec main() -> binary().\nmain() ->\n    <<(begin\n            _pipe = <<\"\"/utf8>>,\n            id(_pipe)\n        end)/binary,\n        (begin\n            _pipe@1 = <<\"\"/utf8>>,\n            id(_pipe@1)\n        end)/binary>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__rest_variable_rewriting.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" <> x -> x\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" <> x -> x\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    case X of\n        <<\"Hello, \"/utf8, X@1/binary>> ->\n            X@1;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_of_number_concat.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  x <> \\\"1\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  x <> \"1\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    <<X/binary, \"1\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" <> name -> name\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" <> name -> name\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    case X of\n        <<\"Hello, \"/utf8, Name/binary>> ->\n            Name;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" as greeting <> name -> greeting\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    case X of\n        <<\"Hello, \"/utf8, Name/binary>> ->\n            Greeting = <<\"Hello, \"/utf8>>,\n            Greeting;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_not_unicode_escape_sequence.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  let _ = case x {\\n    \\\"\\\\\\\\u{9}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{000009}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{21}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{100}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{1000}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{1F600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{1f600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{01F600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{01f600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{9} \\\\\\\\u{000009} \\\\\\\\u{21} \\\\\\\\u{100} \\\\\\\\u{1000} \\\\\\\\u{1F600} \\\\\\\\u{01F600}\\\" as start <> rest -> \\\"test\\\"\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let _ = case x {\n    \"\\\\u{9}\" as start <> rest -> \"test\"\n    \"\\\\u{000009}\" as start <> rest -> \"test\"\n    \"\\\\u{21}\" as start <> rest -> \"test\"\n    \"\\\\u{100}\" as start <> rest -> \"test\"\n    \"\\\\u{1000}\" as start <> rest -> \"test\"\n    \"\\\\u{1F600}\" as start <> rest -> \"test\"\n    \"\\\\u{1f600}\" as start <> rest -> \"test\"\n    \"\\\\u{01F600}\" as start <> rest -> \"test\"\n    \"\\\\u{01f600}\" as start <> rest -> \"test\"\n    \"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\" as start <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    _ = case X of\n        <<\"\\\\u{9}\"/utf8, Rest/binary>> ->\n            Start = <<\"\\\\u{9}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{000009}\"/utf8, Rest@1/binary>> ->\n            Start@1 = <<\"\\\\u{000009}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{21}\"/utf8, Rest@2/binary>> ->\n            Start@2 = <<\"\\\\u{21}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{100}\"/utf8, Rest@3/binary>> ->\n            Start@3 = <<\"\\\\u{100}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{1000}\"/utf8, Rest@4/binary>> ->\n            Start@4 = <<\"\\\\u{1000}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{1F600}\"/utf8, Rest@5/binary>> ->\n            Start@5 = <<\"\\\\u{1F600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{1f600}\"/utf8, Rest@6/binary>> ->\n            Start@6 = <<\"\\\\u{1f600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{01F600}\"/utf8, Rest@7/binary>> ->\n            Start@7 = <<\"\\\\u{01F600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{01f600}\"/utf8, Rest@8/binary>> ->\n            Start@8 = <<\"\\\\u{01f600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\"/utf8, Rest@9/binary>> ->\n            Start@9 = <<\"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_escape_sequences.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  let _ = case x {\\n    \\\"\\\\f\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\n\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\r\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\t\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\"\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\f \\\\n \\\\r \\\\t \\\\\\\" \\\\\\\\\\\" as start <> rest -> \\\"control chars with prefix assignment\\\"\\n    \\\"\\\\u{9}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{000009}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{21}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{100}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{1000}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{1F600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{1f600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{01F600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{01f600}\\\" as start <> rest -> \\\"test\\\"\\n    \\\"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\\\" as start <> rest -> \\\"test\\\"\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let _ = case x {\n    \"\\f\" as start <> rest -> \"test\"\n    \"\\n\" as start <> rest -> \"test\"\n    \"\\r\" as start <> rest -> \"test\"\n    \"\\t\" as start <> rest -> \"test\"\n    \"\\\"\" as start <> rest -> \"test\"\n    \"\\\\\" as start <> rest -> \"test\"\n    \"\\f \\n \\r \\t \\\" \\\\\" as start <> rest -> \"control chars with prefix assignment\"\n    \"\\u{9}\" as start <> rest -> \"test\"\n    \"\\u{000009}\" as start <> rest -> \"test\"\n    \"\\u{21}\" as start <> rest -> \"test\"\n    \"\\u{100}\" as start <> rest -> \"test\"\n    \"\\u{1000}\" as start <> rest -> \"test\"\n    \"\\u{1F600}\" as start <> rest -> \"test\"\n    \"\\u{1f600}\" as start <> rest -> \"test\"\n    \"\\u{01F600}\" as start <> rest -> \"test\"\n    \"\\u{01f600}\" as start <> rest -> \"test\"\n    \"\\u{9} \\u{000009} \\u{21} \\u{100} \\u{1000} \\u{1F600} \\u{01F600}\" as start <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    _ = case X of\n        <<\"\\f\"/utf8, Rest/binary>> ->\n            Start = <<\"\\f\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\n\"/utf8, Rest@1/binary>> ->\n            Start@1 = <<\"\\n\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\r\"/utf8, Rest@2/binary>> ->\n            Start@2 = <<\"\\r\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\t\"/utf8, Rest@3/binary>> ->\n            Start@3 = <<\"\\t\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\"\"/utf8, Rest@4/binary>> ->\n            Start@4 = <<\"\\\"\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\\"/utf8, Rest@5/binary>> ->\n            Start@5 = <<\"\\\\\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\f \\n \\r \\t \\\" \\\\\"/utf8, Rest@6/binary>> ->\n            Start@6 = <<\"\\f \\n \\r \\t \\\" \\\\\"/utf8>>,\n            <<\"control chars with prefix assignment\"/utf8>>;\n\n        <<\"\\x{9}\"/utf8, Rest@7/binary>> ->\n            Start@7 = <<\"\\x{9}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{000009}\"/utf8, Rest@8/binary>> ->\n            Start@8 = <<\"\\x{000009}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{21}\"/utf8, Rest@9/binary>> ->\n            Start@9 = <<\"\\x{21}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{100}\"/utf8, Rest@10/binary>> ->\n            Start@10 = <<\"\\x{100}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{1000}\"/utf8, Rest@11/binary>> ->\n            Start@11 = <<\"\\x{1000}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{1F600}\"/utf8, Rest@12/binary>> ->\n            Start@12 = <<\"\\x{1F600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{1f600}\"/utf8, Rest@13/binary>> ->\n            Start@13 = <<\"\\x{1f600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{01F600}\"/utf8, Rest@14/binary>> ->\n            Start@14 = <<\"\\x{01F600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{01f600}\"/utf8, Rest@15/binary>> ->\n            Start@15 = <<\"\\x{01f600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{9} \\x{000009} \\x{21} \\x{100} \\x{1000} \\x{1F600} \\x{01F600}\"/utf8, Rest@16/binary>> ->\n            Start@16 = <<\"\\x{9} \\x{000009} \\x{21} \\x{100} \\x{1000} \\x{1F600} \\x{01F600}\"/utf8>>,\n            <<\"test\"/utf8>>;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_guard.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" as greeting <> name if name == \\\"Dude\\\" -> greeting <> \\\"Mate\\\"\\n    \\\"Hello, \\\" as greeting <> name -> greeting\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" as greeting <> name if name == \"Dude\" -> greeting <> \"Mate\"\n    \"Hello, \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    case X of\n        <<\"Hello, \"/utf8, Name/binary>> when Name =:= <<\"Dude\"/utf8>> ->\n            Greeting = <<\"Hello, \"/utf8>>,\n            <<Greeting/binary, \"Mate\"/utf8>>;\n\n        <<\"Hello, \"/utf8, Name@1/binary>> ->\n            Greeting@1 = <<\"Hello, \"/utf8>>,\n            Greeting@1;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_multiple_subjects.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"1\\\" as digit <> _ | \\\"2\\\" as digit <> _ -> digit\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"1\" as digit <> _ | \"2\" as digit <> _ -> digit\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    case X of\n        <<\"1\"/utf8, _/binary>> ->\n            Digit = <<\"1\"/utf8>>,\n            Digit;\n\n        <<\"2\"/utf8, _/binary>> ->\n            Digit = <<\"2\"/utf8>>,\n            Digit;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_not_unicode_escape_sequence.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  let _ = case x {\\n    \\\"\\\\\\\\u{9}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{000009}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{21}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{100}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{1000}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{1F600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{1f600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{01F600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{01f600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\u{9} \\\\\\\\u{000009} \\\\\\\\u{21} \\\\\\\\u{100} \\\\\\\\u{1000} \\\\\\\\u{1F600} \\\\\\\\u{01F600}\\\" <> rest -> \\\"test\\\"\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let _ = case x {\n    \"\\\\u{9}\" <> rest -> \"test\"\n    \"\\\\u{000009}\" <> rest -> \"test\"\n    \"\\\\u{21}\" <> rest -> \"test\"\n    \"\\\\u{100}\" <> rest -> \"test\"\n    \"\\\\u{1000}\" <> rest -> \"test\"\n    \"\\\\u{1F600}\" <> rest -> \"test\"\n    \"\\\\u{1f600}\" <> rest -> \"test\"\n    \"\\\\u{01F600}\" <> rest -> \"test\"\n    \"\\\\u{01f600}\" <> rest -> \"test\"\n    \"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\" <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    _ = case X of\n        <<\"\\\\u{9}\"/utf8, Rest/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{000009}\"/utf8, Rest@1/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{21}\"/utf8, Rest@2/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{100}\"/utf8, Rest@3/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{1000}\"/utf8, Rest@4/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{1F600}\"/utf8, Rest@5/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{1f600}\"/utf8, Rest@6/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{01F600}\"/utf8, Rest@7/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{01f600}\"/utf8, Rest@8/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\"/utf8, Rest@9/binary>> ->\n            <<\"test\"/utf8>>;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_shadowing.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" as x <> name -> x\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" as x <> name -> x\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    case X of\n        <<\"Hello, \"/utf8, Name/binary>> ->\n            X@1 = <<\"Hello, \"/utf8>>,\n            X@1;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_with_escape_sequences.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  let _ = case x {\\n    \\\"\\\\f\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\n\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\r\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\t\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\"\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\\\\\\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\f \\\\n \\\\r \\\\t \\\\\\\" \\\\\\\\\\\" <> rest -> \\\"control chars with prefix assignment\\\"\\n    \\\"\\\\u{9}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{000009}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{21}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{100}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{1000}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{1F600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{1f600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{01F600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{01f600}\\\" <> rest -> \\\"test\\\"\\n    \\\"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\\\" <> rest -> \\\"test\\\"\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let _ = case x {\n    \"\\f\" <> rest -> \"test\"\n    \"\\n\" <> rest -> \"test\"\n    \"\\r\" <> rest -> \"test\"\n    \"\\t\" <> rest -> \"test\"\n    \"\\\"\" <> rest -> \"test\"\n    \"\\\\\" <> rest -> \"test\"\n    \"\\f \\n \\r \\t \\\" \\\\\" <> rest -> \"control chars with prefix assignment\"\n    \"\\u{9}\" <> rest -> \"test\"\n    \"\\u{000009}\" <> rest -> \"test\"\n    \"\\u{21}\" <> rest -> \"test\"\n    \"\\u{100}\" <> rest -> \"test\"\n    \"\\u{1000}\" <> rest -> \"test\"\n    \"\\u{1F600}\" <> rest -> \"test\"\n    \"\\u{1f600}\" <> rest -> \"test\"\n    \"\\u{01F600}\" <> rest -> \"test\"\n    \"\\u{01f600}\" <> rest -> \"test\"\n    \"\\u{9} \\u{000009} \\u{21} \\u{100} \\u{1000} \\u{1F600} \\u{01F600}\" <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(binary()) -> binary().\ngo(X) ->\n    _ = case X of\n        <<\"\\f\"/utf8, Rest/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\n\"/utf8, Rest@1/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\r\"/utf8, Rest@2/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\t\"/utf8, Rest@3/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\"\"/utf8, Rest@4/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\\\\"/utf8, Rest@5/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\f \\n \\r \\t \\\" \\\\\"/utf8, Rest@6/binary>> ->\n            <<\"control chars with prefix assignment\"/utf8>>;\n\n        <<\"\\x{9}\"/utf8, Rest@7/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{000009}\"/utf8, Rest@8/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{21}\"/utf8, Rest@9/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{100}\"/utf8, Rest@10/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{1000}\"/utf8, Rest@11/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{1F600}\"/utf8, Rest@12/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{1f600}\"/utf8, Rest@13/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{01F600}\"/utf8, Rest@14/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{01f600}\"/utf8, Rest@15/binary>> ->\n            <<\"test\"/utf8>>;\n\n        <<\"\\x{9} \\x{000009} \\x{21} \\x{100} \\x{1000} \\x{1F600} \\x{01F600}\"/utf8, Rest@16/binary>> ->\n            <<\"test\"/utf8>>;\n\n        _ ->\n            <<\"Unknown\"/utf8>>\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn emoji() -> String {\\n  \\\"\\\\u{1f600}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn emoji() -> String {\n  \"\\u{1f600}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([emoji/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec emoji() -> binary().\nemoji() ->\n    <<\"\\x{1f600}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn y_with_dieresis() -> String {\\n  \\\"\\\\u{0308}y\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn y_with_dieresis() -> String {\n  \"\\u{0308}y\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([y_with_dieresis/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec y_with_dieresis() -> binary().\ny_with_dieresis() ->\n    <<\"\\x{0308}y\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn y_with_dieresis_with_slash() -> String {\\n  \\\"\\\\\\\\\\\\u{0308}y\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn y_with_dieresis_with_slash() -> String {\n  \"\\\\\\u{0308}y\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([y_with_dieresis_with_slash/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec y_with_dieresis_with_slash() -> binary().\ny_with_dieresis_with_slash() ->\n    <<\"\\\\\\x{0308}y\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn main(x) -> String {\\n  x <> \\\"\\\\u{0308}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) -> String {\n  x <> \"\\u{0308}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    <<X/binary, \"\\x{0308}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn main(x) -> String {\\n  x <> \\\"\\\\\\\\u{0308}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) -> String {\n  x <> \"\\\\u{0308}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    <<X/binary, \"\\\\u{0308}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn main(x) -> String {\\n  x <> \\\"\\\\\\\\\\\\u{0308}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) -> String {\n  x <> \"\\\\\\u{0308}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(binary()) -> binary().\nmain(X) ->\n    <<X/binary, \"\\\\\\x{0308}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_escape_sequence_6_digits.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/strings.rs\nexpression: \"\\npub fn unicode_escape_sequence_6_digits() -> String {\\n  \\\"\\\\u{10abcd}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn unicode_escape_sequence_6_digits() -> String {\n  \"\\u{10abcd}\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([unicode_escape_sequence_6_digits/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec unicode_escape_sequence_6_digits() -> binary().\nunicode_escape_sequence_6_digits() ->\n    <<\"\\x{10abcd}\"/utf8>>.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__named.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/todo.rs\nexpression: \"\\npub fn main() {\\n  todo as \\\"testing\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  todo as \"testing\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"testing\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__piped.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/todo.rs\nexpression: \"\\n     pub fn main() {\\n      \\\"lets\\\"\\n      |> todo as \\\"pipe\\\"\\n      |> todo as \\\"other todo\\\"\\n    }\\n    \"\n---\n----- SOURCE CODE\n\n     pub fn main() {\n      \"lets\"\n      |> todo as \"pipe\"\n      |> todo as \"other todo\"\n    }\n    \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    _pipe = <<\"lets\"/utf8>>,\n    _pipe@1 = (erlang:error(#{gleam_error => todo,\n            message => <<\"pipe\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 4}))(_pipe),\n    (erlang:error(#{gleam_error => todo,\n            message => <<\"other todo\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 5}))(_pipe@1).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__plain.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/todo.rs\nexpression: \"\\npub fn main() {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  todo\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/todo.rs\nexpression: \"\\npub fn main() {\\n  todo as \\\"wibble\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  todo as \"wibble\"\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"wibble\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as_function.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/todo.rs\nexpression: \"\\npub fn retstring() {\\n  \\\"wibble\\\"\\n}\\npub fn main() {\\n  todo as { retstring() <> \\\"wobble\\\" }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn retstring() {\n  \"wibble\"\n}\npub fn main() {\n  todo as { retstring() <> \"wobble\" }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([retstring/0, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec retstring() -> binary().\nretstring() ->\n    <<\"wibble\"/utf8>>.\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> any().\nmain() ->\n    erlang:error(#{gleam_error => todo,\n            message => (<<(retstring())/binary, \"wobble\"/utf8>>),\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"main\"/utf8>>,\n            line => 6}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_named_args_count_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub type Wibble(a, b) {\\n            Wibble(a, b)\\n        }\\n\\n        pub fn wibble() -> Wibble(a, a) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub type Wibble(a, b) {\n            Wibble(a, b)\n        }\n\n        pub fn wibble() -> Wibble(a, a) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n-export_type([wibble/2]).\n\n-type wibble(I, J) :: {wibble, I, J}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec wibble() -> wibble(K, K).\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 7}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_named_args_count_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub type Wibble(a, b) {\\n            Wibble(a, b)\\n        }\\n\\n        pub fn wibble() -> Wibble(a, Wibble(a, b)) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub type Wibble(a, b) {\n            Wibble(a, b)\n        }\n\n        pub fn wibble() -> Wibble(a, Wibble(a, b)) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n-export_type([wibble/2]).\n\n-type wibble(I, J) :: {wibble, I, J}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec wibble() -> wibble(K, wibble(K, any())).\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 7}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_result_type_count_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub type Wibble(a) {\\n            Oops\\n        }\\n\\n        pub fn wibble() -> Result(a, Wibble(a)) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub type Wibble(a) {\n            Oops\n        }\n\n        pub fn wibble() -> Result(a, Wibble(a)) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n-export_type([wibble/1]).\n\n-type wibble(I) :: oops | {gleam_phantom, I}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec wibble() -> {ok, any()} | {error, wibble(any())}.\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 7}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_tuple_type_params_count_twice.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub type Wibble(a, b) {\\n            Wibble(a, b)\\n        }\\n\\n        pub fn wibble() -> #(a, Wibble(a, b)) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub type Wibble(a, b) {\n            Wibble(a, b)\n        }\n\n        pub fn wibble() -> #(a, Wibble(a, b)) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n-export_type([wibble/2]).\n\n-type wibble(I, J) :: {wibble, I, J}.\n\n-file(\"project/test/my/mod.gleam\", 6).\n-spec wibble() -> {K, wibble(K, any())}.\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 7}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__nested_result_type_count_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub fn wibble() -> Result(a, Result(a, b)) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble() -> Result(a, Result(a, b)) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec wibble() -> {ok, any()} | {error, {ok, any()} | {error, any()}}.\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_count_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub fn wibble() -> Result(a, a) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble() -> Result(a, a) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec wibble() -> {ok, any()} | {error, any()}.\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_inferred_count_once.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub fn wibble() {\\n            let assert Ok(_) = wobble()\\n        }\\n\\n        pub type Wobble(a) {\\n            Wobble\\n        }\\n\\n        pub fn wobble() -> Result(a, Wobble(a)) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble() {\n            let assert Ok(_) = wobble()\n        }\n\n        pub type Wobble(a) {\n            Wobble\n        }\n\n        pub fn wobble() -> Result(a, Wobble(a)) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wobble/0, wibble/0]).\n-export_type([wobble/1]).\n\n-type wobble(I) :: wobble | {gleam_phantom, I}.\n\n-file(\"project/test/my/mod.gleam\", 10).\n-spec wobble() -> {ok, any()} | {error, wobble(any())}.\nwobble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wobble\"/utf8>>,\n            line => 11}).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec wibble() -> {ok, any()} | {error, wobble(any())}.\nwibble() ->\n    _assert_subject = wobble(),\n    case _assert_subject of\n        {ok, _} -> _assert_subject;\n        _assert_fail ->\n            erlang:error(#{gleam_error => let_assert,\n                        message => <<\"Pattern match failed, no pattern matched the value.\"/utf8>>,\n                        file => <<?FILEPATH/utf8>>,\n                        module => <<\"my/mod\"/utf8>>,\n                        function => <<\"wibble\"/utf8>>,\n                        line => 3,\n                        value => _assert_fail,\n                        start => 39,\n                        'end' => 66,\n                        pattern_start => 50,\n                        pattern_end => 55})\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__tuple_type_params_count_twice.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/type_params.rs\nexpression: \"\\n        pub fn wibble() -> #(a, b) {\\n            todo\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble() -> #(a, b) {\n            todo\n        }\n        \n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([wibble/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec wibble() -> {any(), any()}.\nwibble() ->\n    erlang:error(#{gleam_error => todo,\n            message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n            file => <<?FILEPATH/utf8>>,\n            module => <<\"my/mod\"/utf8>>,\n            function => <<\"wibble\"/utf8>>,\n            line => 3}).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_1.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- pair()\\n  123\\n}\\n\\nfn pair(f) {\\n  let x = f()\\n  #(x, x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- pair()\n  123\n}\n\nfn pair(f) {\n  let x = f()\n  #(x, x)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec pair(fun(() -> L)) -> {L, L}.\npair(F) ->\n    X = F(),\n    {X, X}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> {integer(), integer()}.\nmain() ->\n    pair(fun() -> 123 end).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_2.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- pair(1.0)\\n  123\\n}\\n\\nfn pair(x, f) {\\n  let y = f()\\n  #(x, y)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- pair(1.0)\n  123\n}\n\nfn pair(x, f) {\n  let y = f()\n  #(x, y)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec pair(J, fun(() -> M)) -> {J, M}.\npair(X, F) ->\n    Y = F(),\n    {X, Y}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> {float(), integer()}.\nmain() ->\n    pair(1.0, fun() -> 123 end).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_3.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- trip(1.0, \\\"\\\")\\n  123\\n}\\n\\nfn trip(x, y, f) {\\n  let z = f()\\n  #(x, y, z)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- trip(1.0, \"\")\n  123\n}\n\nfn trip(x, y, f) {\n  let z = f()\n  #(x, y, z)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec trip(J, K, fun(() -> N)) -> {J, K, N}.\ntrip(X, Y, F) ->\n    Z = F(),\n    {X, Y, Z}.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> {float(), binary(), integer()}.\nmain() ->\n    trip(1.0, <<\"\"/utf8>>, fun() -> 123 end).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___no_callback_body.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  let thingy = fn(f) { f() }\\n  use <- thingy()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let thingy = fn(f) { f() }\n  use <- thingy()\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> any().\nmain() ->\n    Thingy = fun(F) -> F() end,\n    Thingy(fun() -> erlang:error(#{gleam_error => todo,\n                    message => <<\"`todo` expression evaluated. This code has not yet been implemented.\"/utf8>>,\n                    file => <<?FILEPATH/utf8>>,\n                    module => <<\"my/mod\"/utf8>>,\n                    function => <<\"main\"/utf8>>,\n                    line => 4}) end).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___pipeline_that_returns_fn.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- 1 |> add\\n  1\\n}\\n\\npub fn add(x) {\\n  fn(f) { f() + x }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- 1 |> add\n  1\n}\n\npub fn add(x) {\n  fn(f) { f() + x }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([add/1, main/0]).\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec add(integer()) -> fun((fun(() -> integer())) -> integer()).\nadd(X) ->\n    fun(F) -> F() + X end.\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    begin\n        _pipe = 1,\n        add(_pipe)\n    end(fun() -> 1 end).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__anon_external_fun_name_escaping.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"\\n@external(erlang, \\\"one.two\\\", \\\"three.four\\\")\\nfn func() -> Nil\\n\\npub fn main() {\\n  func\\n}\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one.two\", \"three.four\")\nfn func() -> Nil\n\npub fn main() {\n  func\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec main() -> fun(() -> nil).\nmain() ->\n    fun 'one.two':'three.four'/0.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__blocks_are_scopes.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  {\\n    let x = 2\\n  }\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 1\n  {\n    let x = 2\n  }\n  x\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/0]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main() -> integer().\nmain() ->\n    X = 1,\n    begin\n        X@1 = 2\n    end,\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__discarded.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"pub fn go() {\\n  let _r = 1\\n  let _r = 2\\n  Nil\\n}\"\n---\n----- SOURCE CODE\npub fn go() {\n  let _r = 1\n  let _r = 2\n  Nil\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/0]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec go() -> nil.\ngo() ->\n    _ = 1,\n    _ = 2,\n    nil.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__module_const_vars.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"const int = 42\\nconst int_alias = int\\npub fn use_int_alias() { int_alias }\\n\\nfn int_identity(i: Int) { i }\\nconst int_identity_alias: fn(Int) -> Int = int_identity\\npub fn use_int_identity_alias() { int_identity_alias(42) }\\n\\nconst compound: #(Int, fn(Int) -> Int, fn(Int) -> Int) = #(int, int_identity, int_identity_alias)\\npub fn use_compound() { compound.1(compound.0) }\\n\"\n---\n----- SOURCE CODE\nconst int = 42\nconst int_alias = int\npub fn use_int_alias() { int_alias }\n\nfn int_identity(i: Int) { i }\nconst int_identity_alias: fn(Int) -> Int = int_identity\npub fn use_int_identity_alias() { int_identity_alias(42) }\n\nconst compound: #(Int, fn(Int) -> Int, fn(Int) -> Int) = #(int, int_identity, int_identity_alias)\npub fn use_compound() { compound.1(compound.0) }\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([use_int_alias/0, use_int_identity_alias/0, use_compound/0]).\n\n-file(\"project/test/my/mod.gleam\", 5).\n-spec int_identity(integer()) -> integer().\nint_identity(I) ->\n    I.\n\n-file(\"project/test/my/mod.gleam\", 3).\n-spec use_int_alias() -> integer().\nuse_int_alias() ->\n    42.\n\n-file(\"project/test/my/mod.gleam\", 7).\n-spec use_int_identity_alias() -> integer().\nuse_int_identity_alias() ->\n    int_identity(42).\n\n-file(\"project/test/my/mod.gleam\", 10).\n-spec use_compound() -> integer().\nuse_compound() ->\n    (erlang:element(2, {42, fun int_identity/1, fun int_identity/1}))(\n        erlang:element(1, {42, fun int_identity/1, fun int_identity/1})\n    ).\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_and_call.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"\\npub fn main(x) {\\n  fn(x) { x }(x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  fn(x) { x }(x)\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(K) -> K.\nmain(X) ->\n    X.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_let.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"\\npub fn go(a) {\\n  case a {\\n    99 -> {\\n      let a = a\\n      1\\n    }\\n    _ -> a\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  case a {\n    99 -> {\n      let a = a\n      1\n    }\n    _ -> a\n  }\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([go/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec go(integer()) -> integer().\ngo(A) ->\n    case A of\n        99 ->\n            A@1 = A,\n            1;\n\n        _ ->\n            A\n    end.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_param.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"pub fn main(board) {\\nfn(board) { board }\\n  board\\n}\"\n---\n----- SOURCE CODE\npub fn main(board) {\nfn(board) { board }\n  board\n}\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 1).\n-spec main(I) -> I.\nmain(Board) ->\n    fun(Board@1) -> Board@1 end,\n    Board.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_pipe.snap",
    "content": "---\nsource: compiler-core/src/erlang/tests/variables.rs\nexpression: \"\\npub fn main(x) {\\n  x\\n  |> fn(x) { x }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  x\n  |> fn(x) { x }\n}\n\n\n----- COMPILED ERLANG\n-module(my@mod).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"project/test/my/mod.gleam\").\n-export([main/1]).\n\n-file(\"project/test/my/mod.gleam\", 2).\n-spec main(K) -> K.\nmain(X) ->\n    _pipe = X,\n    _pipe.\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/strings.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn unicode1() {\n    assert_erl!(\n        r#\"\npub fn emoji() -> String {\n  \"\\u{1f600}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode2() {\n    assert_erl!(\n        r#\"\npub fn y_with_dieresis() -> String {\n  \"\\u{0308}y\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode_concat1() {\n    assert_erl!(\n        r#\"\npub fn main(x) -> String {\n  x <> \"\\u{0308}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode_concat2() {\n    assert_erl!(\n        r#\"\npub fn main(x) -> String {\n  x <> \"\\\\u{0308}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode_concat3() {\n    assert_erl!(\n        r#\"\npub fn main(x) -> String {\n  x <> \"\\\\\\u{0308}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn not_unicode_escape_sequence() {\n    // '\\u'-s must be converted to '\\x' in the Erlang codegen.\n    // but '\\\\u'-s mustn't.\n    assert_erl!(\n        r#\"\npub fn not_unicode_escape_sequence() -> String {\n  \"\\\\u{03a9}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn not_unicode_escape_sequence2() {\n    assert_erl!(\n        r#\"\npub fn not_unicode_escape_sequence() -> String {\n  \"\\\\\\\\u{03a9}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode3() {\n    assert_erl!(\n        r#\"\npub fn y_with_dieresis_with_slash() -> String {\n  \"\\\\\\u{0308}y\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode_escape_sequence_6_digits() {\n    assert_erl!(\n        r#\"\npub fn unicode_escape_sequence_6_digits() -> String {\n  \"\\u{10abcd}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn ascii_as_unicode_escape_sequence() {\n    assert_erl!(\n        r#\"\npub fn y() -> String {\n  \"\\u{79}\"\n}\n\"#,\n    )\n}\n\n#[test]\nfn concat() {\n    assert_erl!(\n        r#\"\npub fn go(x, y) {\n  x <> y\n}\n\"#,\n    );\n}\n\n#[test]\nfn concat_3_variables() {\n    assert_erl!(\n        r#\"\npub fn go(x, y, z) {\n  x <> y <> z\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_prefix() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" <> name -> name\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_prefix_assignment() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_assignment_with_guard() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" as greeting <> name if name == \"Dude\" -> greeting <> \"Mate\"\n    \"Hello, \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3126\n#[test]\nfn string_prefix_assignment_with_escape_sequences() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  let _ = case x {\n    \"\\f\" as start <> rest -> \"test\"\n    \"\\n\" as start <> rest -> \"test\"\n    \"\\r\" as start <> rest -> \"test\"\n    \"\\t\" as start <> rest -> \"test\"\n    \"\\\"\" as start <> rest -> \"test\"\n    \"\\\\\" as start <> rest -> \"test\"\n    \"\\f \\n \\r \\t \\\" \\\\\" as start <> rest -> \"control chars with prefix assignment\"\n    \"\\u{9}\" as start <> rest -> \"test\"\n    \"\\u{000009}\" as start <> rest -> \"test\"\n    \"\\u{21}\" as start <> rest -> \"test\"\n    \"\\u{100}\" as start <> rest -> \"test\"\n    \"\\u{1000}\" as start <> rest -> \"test\"\n    \"\\u{1F600}\" as start <> rest -> \"test\"\n    \"\\u{1f600}\" as start <> rest -> \"test\"\n    \"\\u{01F600}\" as start <> rest -> \"test\"\n    \"\\u{01f600}\" as start <> rest -> \"test\"\n    \"\\u{9} \\u{000009} \\u{21} \\u{100} \\u{1000} \\u{1F600} \\u{01F600}\" as start <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_with_escape_sequences() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  let _ = case x {\n    \"\\f\" <> rest -> \"test\"\n    \"\\n\" <> rest -> \"test\"\n    \"\\r\" <> rest -> \"test\"\n    \"\\t\" <> rest -> \"test\"\n    \"\\\"\" <> rest -> \"test\"\n    \"\\\\\" <> rest -> \"test\"\n    \"\\f \\n \\r \\t \\\" \\\\\" <> rest -> \"control chars with prefix assignment\"\n    \"\\u{9}\" <> rest -> \"test\"\n    \"\\u{000009}\" <> rest -> \"test\"\n    \"\\u{21}\" <> rest -> \"test\"\n    \"\\u{100}\" <> rest -> \"test\"\n    \"\\u{1000}\" <> rest -> \"test\"\n    \"\\u{1F600}\" <> rest -> \"test\"\n    \"\\u{1f600}\" <> rest -> \"test\"\n    \"\\u{01F600}\" <> rest -> \"test\"\n    \"\\u{01f600}\" <> rest -> \"test\"\n    \"\\u{9} \\u{000009} \\u{21} \\u{100} \\u{1000} \\u{1F600} \\u{01F600}\" <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_assignment_not_unicode_escape_sequence() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  let _ = case x {\n    \"\\\\u{9}\" as start <> rest -> \"test\"\n    \"\\\\u{000009}\" as start <> rest -> \"test\"\n    \"\\\\u{21}\" as start <> rest -> \"test\"\n    \"\\\\u{100}\" as start <> rest -> \"test\"\n    \"\\\\u{1000}\" as start <> rest -> \"test\"\n    \"\\\\u{1F600}\" as start <> rest -> \"test\"\n    \"\\\\u{1f600}\" as start <> rest -> \"test\"\n    \"\\\\u{01F600}\" as start <> rest -> \"test\"\n    \"\\\\u{01f600}\" as start <> rest -> \"test\"\n    \"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\" as start <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_not_unicode_escape_sequence() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  let _ = case x {\n    \"\\\\u{9}\" <> rest -> \"test\"\n    \"\\\\u{000009}\" <> rest -> \"test\"\n    \"\\\\u{21}\" <> rest -> \"test\"\n    \"\\\\u{100}\" <> rest -> \"test\"\n    \"\\\\u{1000}\" <> rest -> \"test\"\n    \"\\\\u{1F600}\" <> rest -> \"test\"\n    \"\\\\u{1f600}\" <> rest -> \"test\"\n    \"\\\\u{01F600}\" <> rest -> \"test\"\n    \"\\\\u{01f600}\" <> rest -> \"test\"\n    \"\\\\u{9} \\\\u{000009} \\\\u{21} \\\\u{100} \\\\u{1000} \\\\u{1F600} \\\\u{01F600}\" <> rest -> \"test\"\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2471\n#[test]\nfn string_prefix_assignment_with_multiple_subjects() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"1\" as digit <> _ | \"2\" as digit <> _ -> digit\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_shadowing() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" as x <> name -> x\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn rest_variable_rewriting() {\n    // This test checks that the variable on the right hand side of <> has\n    // it's name written correctly when it shadows an existing variable\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" <> x -> x\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn discard_concat_rest_pattern() {\n    // We can discard the right hand side, it parses and type checks ok\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" <> _ -> Nil\n    _ -> Nil\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_of_number_concat() {\n    assert_erl!(\n        r#\"\npub fn go(x) {\n  x <> \"1\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn concat_function_call() {\n    assert_erl!(\n        r#\"\nfn x() {\n  \"\"\n}\n\npub fn go() {\n  x() <> x()\n}\n\"#,\n    );\n}\n\n#[test]\nfn concat_constant() {\n    assert_erl!(\n        r#\"\nconst a = \"Hello, \"\nconst b = \"Joe!\"\n\npub fn go() {\n  a <> b\n}\n\"#,\n    );\n}\n\n#[test]\nfn concat_constant_fn() {\n    assert_erl!(\n        r#\"\nconst cs = s\n\nfn s() {\n  \"s\"\n}\n\npub fn go() {\n  cs() <> cs()\n}\n\"#,\n    );\n}\n\n#[test]\nfn pipe_concat() {\n    assert_erl!(\n        r#\"\nfn id(x) {\n  x\n}\n\npub fn main() {\n  { \"\" |> id } <> { \"\" |> id }\n}\n\"#,\n    );\n}\n\n#[test]\nfn assert_string_prefix() {\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  let assert \"m-\" <> rest = x\n  rest\n}\n\"#,\n    );\n}\n\n#[test]\nfn assert_string_prefix_discar() {\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  let assert \"m-\" <> _ = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn assert_const_concat() {\n    assert_erl!(\n        r#\"\nconst cute = \"cute\"\nconst cute_bee = cute <> \"bee\"\n\npub fn main() {\n  cute_bee\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_const_concat_many_strings() {\n    assert_erl!(\n        r#\"\nconst big_concat = \"a\" <> \"b\" <> \"c\" <> \"d\" <> \"e\" <> \"f\" <> \"g\" <> \"h\" <> \"i\" <> \"j\" <> \"k\" <> \"l\" <> \"m\" <> \"n\" <> \"o\" <> \"p\" <> \"q\" <> \"r\" <> \"s\" <> \"t\" <> \"u\" <> \"v\" <> \"w\" <> \"x\" <> \"y\" <> \"z\"\n\npub fn main() {\n  big_concat\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_const_concat_many_strings_in_list() {\n    assert_erl!(\n        r#\"\nconst big_concat_list = [\"a\" <> \"b\" <> \"c\" <> \"d\" <> \"e\" <> \"f\" <> \"g\" <> \"h\" <> \"i\" <> \"j\" <> \"k\" <> \"l\" <> \"m\" <> \"n\" <> \"o\" <> \"p\" <> \"q\" <> \"r\" <> \"s\" <> \"t\" <> \"u\" <> \"v\" <> \"w\" <> \"x\" <> \"y\" <> \"z\"]\n\npub fn main() {\n  big_concat_list\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_const_concat_other_const_concat() {\n    assert_erl!(\n        r#\"\nconst cute_bee = \"cute\" <> \"bee\"\nconst cute_cute_bee_buzz = cute_bee <> \"buzz\"\n\npub fn main() {\n  cute_cute_bee_buzz\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/todo.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn plain() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn todo_as() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  todo as \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn named() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  todo as \"testing\"\n}\n\"#\n    );\n}\n\n#[test]\nfn todo_as_function() {\n    assert_erl!(\n        r#\"\npub fn retstring() {\n  \"wibble\"\n}\npub fn main() {\n  todo as { retstring() <> \"wobble\" }\n}\n\"#\n    );\n}\n\n#[test]\nfn piped() {\n    assert_erl!(\n        r#\"\n     pub fn main() {\n      \"lets\"\n      |> todo as \"pipe\"\n      |> todo as \"other todo\"\n    }\n    \"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/type_params.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn result_type_inferred_count_once() {\n    assert_erl!(\n        \"\n        pub fn wibble() {\n            let assert Ok(_) = wobble()\n        }\n\n        pub type Wobble(a) {\n            Wobble\n        }\n\n        pub fn wobble() -> Result(a, Wobble(a)) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn result_type_count_once() {\n    assert_erl!(\n        \"\n        pub fn wibble() -> Result(a, a) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn nested_result_type_count_once() {\n    assert_erl!(\n        \"\n        pub fn wibble() -> Result(a, Result(a, b)) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn custom_type_nested_result_type_count_once() {\n    assert_erl!(\n        \"\n        pub type Wibble(a) {\n            Oops\n        }\n\n        pub fn wibble() -> Result(a, Wibble(a)) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn tuple_type_params_count_twice() {\n    assert_erl!(\n        \"\n        pub fn wibble() -> #(a, b) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn custom_type_named_args_count_once() {\n    assert_erl!(\n        \"\n        pub type Wibble(a, b) {\n            Wibble(a, b)\n        }\n\n        pub fn wibble() -> Wibble(a, a) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn custom_type_nested_named_args_count_once() {\n    assert_erl!(\n        \"\n        pub type Wibble(a, b) {\n            Wibble(a, b)\n        }\n\n        pub fn wibble() -> Wibble(a, Wibble(a, b)) {\n            todo\n        }\n        \"\n    );\n}\n\n#[test]\nfn custom_type_tuple_type_params_count_twice() {\n    assert_erl!(\n        \"\n        pub type Wibble(a, b) {\n            Wibble(a, b)\n        }\n\n        pub fn wibble() -> #(a, Wibble(a, b)) {\n            todo\n        }\n        \"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/use_.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn arity_1() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  use <- pair()\n  123\n}\n\nfn pair(f) {\n  let x = f()\n  #(x, x)\n}\n\"#,\n    )\n}\n\n#[test]\nfn arity_2() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  use <- pair(1.0)\n  123\n}\n\nfn pair(x, f) {\n  let y = f()\n  #(x, y)\n}\n\"#,\n    )\n}\n\n#[test]\nfn arity_3() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  use <- trip(1.0, \"\")\n  123\n}\n\nfn trip(x, y, f) {\n  let z = f()\n  #(x, y, z)\n}\n\"#,\n    )\n}\n\n#[test]\nfn no_callback_body() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let thingy = fn(f) { f() }\n  use <- thingy()\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1863\n#[test]\nfn pipeline_that_returns_fn() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  use <- 1 |> add\n  1\n}\n\npub fn add(x) {\n  fn(f) { f() + x }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests/variables.rs",
    "content": "use crate::assert_erl;\n\n#[test]\nfn shadow_let() {\n    // https://github.com/gleam-lang/gleam/issues/333\n    assert_erl!(\n        r#\"\npub fn go(a) {\n  case a {\n    99 -> {\n      let a = a\n      1\n    }\n    _ -> a\n  }\n}\"#\n    );\n}\n\n#[test]\nfn shadow_param() {\n    // https://github.com/gleam-lang/gleam/issues/772\n    assert_erl!(\n        \"pub fn main(board) {\nfn(board) { board }\n  board\n}\"\n    );\n}\n\n#[test]\nfn shadow_and_call() {\n    // https://github.com/gleam-lang/gleam/issues/762\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  fn(x) { x }(x)\n}\n\"#\n    );\n}\n\n#[test]\nfn shadow_pipe() {\n    assert_erl!(\n        r#\"\npub fn main(x) {\n  x\n  |> fn(x) { x }\n}\n\"#\n    );\n}\n\n#[test]\nfn discarded() {\n    // https://github.com/gleam-lang/gleam/issues/788\n    assert_erl!(\n        r#\"pub fn go() {\n  let _r = 1\n  let _r = 2\n  Nil\n}\"#\n    );\n}\n\n#[test]\nfn anon_external_fun_name_escaping() {\n    // https://github.com/gleam-lang/gleam/issues/1418\n    assert_erl!(\n        r#\"\n@external(erlang, \"one.two\", \"three.four\")\nfn func() -> Nil\n\npub fn main() {\n  func\n}\"#\n    );\n}\n\n#[test]\nfn module_const_vars() {\n    assert_erl!(\n        \"const int = 42\nconst int_alias = int\npub fn use_int_alias() { int_alias }\n\nfn int_identity(i: Int) { i }\nconst int_identity_alias: fn(Int) -> Int = int_identity\npub fn use_int_identity_alias() { int_identity_alias(42) }\n\nconst compound: #(Int, fn(Int) -> Int, fn(Int) -> Int) = #(int, int_identity, int_identity_alias)\npub fn use_compound() { compound.1(compound.0) }\n\"\n    )\n}\n\n#[test]\nfn blocks_are_scopes() {\n    assert_erl!(\n        \"\npub fn main() {\n  let x = 1\n  {\n    let x = 2\n  }\n  x\n}\n\"\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/erlang/tests.rs",
    "content": "use std::time::SystemTime;\n\nuse camino::Utf8PathBuf;\n\nuse crate::analyse::TargetSupport;\nuse crate::config::PackageConfig;\nuse crate::type_::PRELUDE_MODULE_NAME;\nuse crate::warning::WarningEmitter;\nuse crate::{build, inline};\nuse crate::{\n    build::{Origin, Target},\n    erlang::module,\n    line_numbers::LineNumbers,\n    uid::UniqueIdGenerator,\n    warning::TypeWarningEmitter,\n};\nuse camino::Utf8Path;\n\nmod assert;\nmod bit_arrays;\nmod case;\nmod conditional_compilation;\nmod consts;\nmod custom_types;\nmod documentation;\nmod echo;\nmod external_fn;\nmod functions;\nmod guards;\nmod inlining;\nmod let_assert;\nmod numbers;\nmod panic;\nmod patterns;\nmod pipes;\nmod records;\nmod reserved;\nmod strings;\nmod todo;\nmod type_params;\nmod use_;\nmod variables;\n\npub fn compile_test_project(\n    src: &str,\n    src_path: &str,\n    dependencies: Vec<(&str, &str, &str)>,\n) -> String {\n    let mut modules = im::HashMap::new();\n    let ids = UniqueIdGenerator::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(\n        PRELUDE_MODULE_NAME.into(),\n        crate::type_::build_prelude(&ids),\n    );\n    let mut direct_dependencies = std::collections::HashMap::from_iter(vec![]);\n    for (dep_package, dep_name, dep_src) in dependencies {\n        let mut dep_config = PackageConfig::default();\n        dep_config.name = dep_package.into();\n        let parsed = crate::parse::parse_module(\n            Utf8PathBuf::from(\"test/path\"),\n            dep_src,\n            &WarningEmitter::null(),\n        )\n        .expect(\"dep syntax error\");\n        let mut ast = parsed.module;\n        ast.name = dep_name.into();\n        let line_numbers = LineNumbers::new(dep_src);\n\n        let dep = crate::analyse::ModuleAnalyzerConstructor::<()> {\n            target: Target::Erlang,\n            ids: &ids,\n            origin: Origin::Src,\n            importable_modules: &modules,\n            warnings: &TypeWarningEmitter::null(),\n            direct_dependencies: &std::collections::HashMap::new(),\n            dev_dependencies: &std::collections::HashSet::new(),\n            target_support: TargetSupport::NotEnforced,\n            package_config: &dep_config,\n        }\n        .infer_module(ast, line_numbers, \"\".into())\n        .expect(\"should successfully infer dep Erlang\");\n        let _ = modules.insert(dep_name.into(), dep.type_info);\n        let _ = direct_dependencies.insert(dep_package.into(), ());\n    }\n    let path = Utf8PathBuf::from(src_path);\n    let parsed = crate::parse::parse_module(path.clone(), src, &WarningEmitter::null())\n        .expect(\"syntax error\");\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n    let mut ast = parsed.module;\n    ast.name = \"my/mod\".into();\n    let line_numbers = LineNumbers::new(src);\n    let ast = crate::analyse::ModuleAnalyzerConstructor::<()> {\n        target: Target::Erlang,\n        ids: &ids,\n        origin: Origin::Src,\n        importable_modules: &modules,\n        warnings: &TypeWarningEmitter::null(),\n        direct_dependencies: &direct_dependencies,\n        dev_dependencies: &std::collections::HashSet::new(),\n        target_support: TargetSupport::NotEnforced,\n        package_config: &config,\n    }\n    .infer_module(ast, line_numbers, path.clone())\n    .expect(\"should successfully infer root Erlang\");\n\n    let ast = inline::module(ast, &modules);\n\n    // After building everything we still need to attach the module comments, to\n    // do that we're reusing the `attach_doc_and_module_comments` that's used\n    // for the real thing. We just have to make a placeholder module wrapping\n    // the parsed ast and call the function!\n    let mut built_module = build::Module {\n        name: \"my/mod\".into(),\n        code: src.into(),\n        mtime: SystemTime::UNIX_EPOCH,\n        input_path: path,\n        origin: Origin::Src,\n        ast,\n        extra: parsed.extra,\n        dependencies: vec![],\n    };\n    let root = Utf8Path::new(\"/root\");\n    built_module.attach_doc_and_module_comments();\n\n    let line_numbers = LineNumbers::new(src);\n    module(&built_module.ast, &line_numbers, root)\n        .unwrap()\n        .replace(\n            std::include_str!(\"../../templates/echo.erl\"),\n            \"% ...omitted code from `templates/echo.erl`...\",\n        )\n}\n\n#[macro_export]\nmacro_rules! assert_erl {\n    ($(($dep_package:expr, $dep_name:expr, $dep_src:expr)),+, $src:literal $(,)?) => {{\n        let compiled = $crate::erlang::tests::compile_test_project(\n            $src,\n            \"/root/project/test/my/mod.gleam\",\n            vec![$(($dep_package, $dep_name, $dep_src)),*],\n        );\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- COMPILED ERLANG\\n{}\",\n            $src, compiled\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    ($src:expr $(,)?) => {{\n        let compiled = $crate::erlang::tests::compile_test_project(\n            $src,\n            \"/root/project/test/my/mod.gleam\",\n            Vec::new(),\n        );\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- COMPILED ERLANG\\n{}\",\n            $src, compiled,\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n}\n\n#[test]\nfn integration_test() {\n    assert_erl!(\n        r#\"pub fn go() {\nlet x = #(100000000000000000, #(2000000000, 3000000000000, 40000000000), 50000, 6000000000)\n  x\n}\"#\n    );\n}\n\n#[test]\nfn integration_test0_1() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let y = 1\n  let y = 2\n  y\n}\"#\n    );\n}\n\n#[test]\nfn integration_test0_2() {\n    // hex, octal, and binary literals\n    assert_erl!(\n        r#\"pub fn go() {\n    let fifteen = 0xF\n    let nine = 0o11\n    let ten = 0b1010\n  fifteen\n}\"#\n    );\n}\n\n#[test]\nfn integration_test0_3() {\n    assert_erl!(\n        r#\"pub fn go() {\n  let y = 1\n  let y = 2\n  y\n}\"#\n    );\n}\n\n#[test]\nfn integration_test1() {\n    assert_erl!(r#\"pub fn t() { True }\"#);\n}\n\n#[test]\nfn integration_test1_1() {\n    assert_erl!(\n        r#\"pub type Money { Pound(Int) }\npub fn pound(x) { Pound(x) }\"#\n    );\n}\n\n#[test]\nfn integration_test1_2() {\n    assert_erl!(r#\"pub fn loop() { loop() }\"#);\n}\n\n#[test]\nfn integration_test1_4() {\n    assert_erl!(\n        r#\"fn inc(x) { x + 1 }\n                    pub fn go() { 1 |> inc |> inc |> inc }\"#\n    );\n}\n\n#[test]\nfn integration_test1_5() {\n    assert_erl!(\n        r#\"fn add(x, y) { x + y }\n                    pub fn go() { 1 |> add(_, 1) |> add(2, _) |> add(_, 3) }\"#\n    );\n}\n\n#[test]\nfn integration_test1_6() {\n    assert_erl!(\n        r#\"pub fn and(x, y) { x && y }\npub fn or(x, y) { x || y }\npub fn remainder(x, y) { x % y }\npub fn fdiv(x, y) { x /. y }\n            \"#\n    );\n}\n\n#[test]\nfn integration_test2() {\n    assert_erl!(\n        r#\"pub fn second(list) { case list { [x, y] -> y z -> 1 } }\npub fn tail(list) { case list { [x, ..xs] -> xs z -> list } }\n            \"#\n    );\n}\n\n#[test]\nfn integration_test5() {\n    assert_erl!(\n        \"pub fn tail(list) {\n  case list {\n    [x, ..] -> x\n    _ -> 0\n  }\n}\"\n    );\n}\n\n#[test]\nfn integration_test6() {\n    assert_erl!(r#\"pub fn x() { let x = 1 let x = x + 1 x }\"#);\n}\n\n#[test]\nfn integration_test8() {\n    // Translation of Float-specific BinOp into variable-type Erlang term comparison.\n    assert_erl!(r#\"pub fn x() { 1. <. 2.3 }\"#);\n}\n\n#[test]\nfn integration_test9() {\n    // Custom type creation\n    assert_erl!(\n        r#\"pub type Pair(x, y) { Pair(x: x, y: y) } pub fn x() { Pair(1, 2) Pair(3., 4.) }\"#\n    );\n}\n\n#[test]\nfn integration_test10() {\n    assert_erl!(\n        r#\"pub type Null { Null }\npub fn x() { Null }\"#\n    );\n}\n\n#[test]\nfn integration_test3() {\n    assert_erl!(\n        r#\"pub type Point { Point(x: Int, y: Int) }\npub fn y() { fn() { Point }()(4, 6) }\"#\n    );\n}\n\n#[test]\nfn integration_test11() {\n    assert_erl!(\n        r#\"pub type Point { Point(x: Int, y: Int) }\npub fn x() { Point(x: 4, y: 6) Point(y: 1, x: 9) }\"#\n    );\n}\n\n#[test]\nfn integration_test12() {\n    assert_erl!(\n        r#\"pub type Point { Point(x: Int, y: Int) }\npub fn x(y) { let Point(a, b) = y a }\"#\n    );\n}\n//https://github.com/gleam-lang/gleam/issues/1106\n\n#[test]\nfn integration_test13() {\n    assert_erl!(\n        r#\"pub type State{ Start(Int) End(Int) }\n            pub fn build(constructor : fn(Int) -> a) -> a { constructor(1) }\n            pub fn main() { build(End) }\"#\n    );\n}\n\n#[test]\nfn integration_test16() {\n    assert_erl!(\n        r#\"fn go(x xx, y yy) { xx }\npub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) }\"#\n    );\n}\n\n#[test]\nfn integration_test17() {\n    // https://github.com/gleam-lang/gleam/issues/289\n    assert_erl!(\n        r#\"\npub type User { User(id: Int, name: String, age: Int) }\npub fn create_user(user_id) { User(age: 22, id: user_id, name: \"\") }\n\"#\n    );\n}\n\n#[test]\nfn integration_test18() {\n    assert_erl!(r#\"pub fn run() { case 1, 2 { a, b -> a } }\"#);\n}\n\n#[test]\nfn integration_test19() {\n    assert_erl!(\n        r#\"pub type X { X(x: Int, y: Float) }\npub fn x() { X(x: 1, y: 2.) X(y: 3., x: 4) }\"#\n    );\n}\n\n#[test]\nfn integration_test20() {\n    assert_erl!(\n        r#\"\npub fn go(a) {\n  let a = a + 1\n  a\n}\n\n                    \"#\n    );\n}\n\n#[test]\nfn integration_test21() {\n    assert_erl!(\n        r#\"\npub fn go(a) {\n  let a = 1\n  a\n}\n\n                    \"#\n    );\n}\n\n#[test]\nfn integration_test22() {\n    // https://github.com/gleam-lang/gleam/issues/358\n    assert_erl!(\n        r#\"\npub fn factory(f, i) {\n  f(i)\n}\n\npub type Box {\n  Box(i: Int)\n}\n\npub fn main() {\n  factory(Box, 0)\n}\n\"#\n    );\n}\n\n#[test]\nfn integration_test23() {\n    // https://github.com/gleam-lang/gleam/issues/384\n    assert_erl!(\n        r#\"\npub fn main(args) {\n  case args {\n    _ -> {\n      let a = 1\n      a\n    }\n  }\n  let a = 2\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_parens() {\n    // Parentheses are added for binop subexpressions\n    assert_erl!(\n        r#\"\npub fn main() {\n    let a = 2 * {3 + 1} / 2\n    let b = 5 + 3 / 3 * 2 - 6 * 4\n    b\n}\n\"#\n    );\n}\n\n#[test]\nfn field_access_function_call() {\n    // Parentheses are added when calling functions returned by record access\n    assert_erl!(\n        r#\"\npub type FnBox {\n  FnBox(f: fn(Int) -> Int)\n}\n\npub fn main() {\n    let b = FnBox(f: fn(x) { x })\n    b.f(5)\n}\n\"#\n    );\n}\n\n#[test]\nfn field_access_function_call1() {\n    // Parentheses are added when calling functions returned by tuple access\n    assert_erl!(\n        r#\"\npub fn main() {\n    let t = #(fn(x) { x })\n\n    t.0(5)\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/777\n#[test]\nfn block_assignment() {\n    assert_erl!(\n        r#\"\npub fn main() {\n  let x = {\n    1\n    2\n  }\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn recursive_type() {\n    // TODO: we should be able to generalise `id` and we should be\n    // able to handle recursive types. Either of these type features\n    // would make this module type check OK.\n    assert_erl!(\n        r#\"\nfn id(x) {\n  x\n}\n\npub fn main() {\n  id(id)\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_access_in_guard() {\n    assert_erl!(\n        r#\"\npub fn main() {\n    let key = 10\n    let x = [#(10, 2), #(1, 2)]\n    case x {\n        [first, ..rest] if first.0 == key -> \"ok\"\n        _ -> \"ko\"\n    }\n}\n\"#\n    );\n}\n\n#[test]\nfn variable_name_underscores_preserved() {\n    assert_erl!(\n        \"pub fn a(name_: String) -> String {\n    let name__ = name_\n    let name = name__\n    let one_1 = 1\n    let one1 = one_1\n    name\n}\"\n    );\n}\n\n#[test]\nfn allowed_string_escapes() {\n    assert_erl!(r#\"pub fn a() { \"\\n\" \"\\r\" \"\\t\" \"\\\\\" \"\\\"\" \"\\\\^\" }\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1006\n#[test]\nfn keyword_constructors() {\n    assert_erl!(\"pub type X { Div }\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/1006\n#[test]\nfn keyword_constructors1() {\n    assert_erl!(\"pub type X { Fun(Int) }\");\n}\n\n#[test]\nfn discard_in_assert() {\n    assert_erl!(\n        \"pub fn x(y) {\n  let assert Ok(_) = y\n  1\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1424\n#[test]\nfn operator_pipe_right_hand_side() {\n    assert_erl!(\n        \"fn id(x) {\n  x\n}\n\npub fn bool_expr(x, y) {\n  y || x |> id\n}\"\n    );\n}\n\n#[test]\nfn negation() {\n    assert_erl!(\n        \"pub fn negate(x) {\n  !x\n}\"\n    )\n}\n\n#[test]\nfn negation_block() {\n    assert_erl!(\n        \"pub fn negate(x) {\n  !{\n    123\n    x\n  }\n}\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1655\n#[test]\nfn tail_maybe_expr_block() {\n    assert_erl!(\n        \"pub fn a() {\n  let fake_tap = fn(x) { x }\n  let b = [99]\n  [\n    1,\n    2,\n    ..b\n    |> fake_tap\n  ]\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1587\n#[test]\nfn guard_variable_rewriting() {\n    assert_erl!(\n        \"pub fn main() {\n  case 1.0 {\n    a if a <. 0.0 -> {\n      let a = a\n      a\n    }\n    _ -> 0.0\n  }\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1816\n#[test]\nfn function_argument_shadowing() {\n    assert_erl!(\n        \"pub fn main(a) {\n  Box\n}\n\npub type Box {\n  Box(Int)\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2156\n#[test]\nfn dynamic() {\n    assert_erl!(\"pub type Dynamic\")\n}\n\n// https://github.com/gleam-lang/gleam/issues/2166\n#[test]\nfn inline_const_pattern_option() {\n    assert_erl!(\n        \"pub fn main() {\n            let fifteen = 15\n            let x = <<5:size(sixteen)>>\n            case x {\n              <<5:size(sixteen)>> -> <<5:size(sixteen)>>\n              <<6:size(fifteen)>> -> <<5:size(fifteen)>>\n              _ -> <<>>\n            }\n          }\n\n          pub const sixteen = 16\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2349\n#[test]\nfn positive_zero() {\n    assert_erl!(\n        \"\npub fn main() {\n  0.0\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3073\n#[test]\nfn scientific_notation() {\n    assert_erl!(\n        \"\npub fn main() {\n  1.0e6\n  1.e6\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3304\n#[test]\nfn type_named_else() {\n    assert_erl!(\n        \"\npub type Else {\n  Else\n}\n\npub fn main() {\n  Else\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn type_named_module_info() {\n    assert_erl!(\n        \"\npub type ModuleInfo {\n    ModuleInfo\n}\n\npub fn main() {\n    ModuleInfo\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn function_named_module_info() {\n    assert_erl!(\n        \"\npub fn module_info() {\n    1\n}\n\npub fn main() {\n    module_info()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn function_named_module_info_imported() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub fn module_info() {\n    1\n}\n            \"\n        ),\n        \"\nimport some_module\n\npub fn main() {\n    some_module.module_info()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn function_named_module_info_imported_qualified() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub fn module_info() {\n    1\n}\n            \"\n        ),\n        \"\nimport some_module.{module_info}\n\npub fn main() {\n    module_info()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn constant_named_module_info() {\n    assert_erl!(\n        \"\npub const module_info = 1\n\npub fn main() {\n    module_info\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn constant_named_module_info_imported() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub const module_info = 1\n            \"\n        ),\n        \"\nimport some_module\n\npub fn main() {\n    some_module.module_info\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn constant_named_module_info_imported_qualified() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub const module_info = 1\n            \"\n        ),\n        \"\nimport some_module.{module_info}\n\npub fn main() {\n    module_info\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn constant_named_module_info_with_function_inside() {\n    assert_erl!(\n        \"\npub fn function() {\n    1\n}\n\npub const module_info = function\n\npub fn main() {\n    module_info()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn constant_named_module_info_with_function_inside_imported() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub fn function() {\n    1\n}\n\npub const module_info = function\n\"\n        ),\n        \"\nimport some_module\n\npub fn main() {\n    some_module.module_info()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn constant_named_module_info_with_function_inside_imported_qualified() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub fn function() {\n    1\n}\n\npub const module_info = function\n\"\n        ),\n        \"\nimport some_module.{module_info}\n\npub fn main() {\n    module_info()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn function_named_module_info_in_constant() {\n    assert_erl!(\n        \"\npub fn module_info() {\n    1\n}\n\npub const constant = module_info\n\npub fn main() {\n    constant()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn function_named_module_info_in_constant_imported() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub fn module_info() {\n    1\n}\n\npub const constant = module_info\n            \"\n        ),\n        \"\nimport some_module\n\npub fn main() {\n    some_module.constant()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3382\n#[test]\nfn function_named_module_info_in_constant_imported_qualified() {\n    assert_erl!(\n        (\n            \"some_module\",\n            \"some_module\",\n            \"\npub fn module_info() {\n    1\n}\n\npub const constant = module_info\n            \"\n        ),\n        \"\nimport some_module.{constant}\n\npub fn main() {\n    constant()\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3648\n#[test]\nfn windows_file_escaping_bug() {\n    let src = \"pub fn main() { Nil }\";\n    let path = \"C:\\\\root\\\\project\\\\test\\\\my\\\\mod.gleam\";\n    let output = compile_test_project(src, path, Vec::new());\n    insta::assert_snapshot!(insta::internals::AutoName, output, src);\n}\n\n// https://github.com/gleam-lang/gleam/issues/3315\n#[test]\nfn bit_pattern_shadowing() {\n    assert_erl!(\n        \"\npub fn main() {\n  let code = <<\\\"hello world\\\":utf8>>\n  let pre = 1\n  case code {\n    <<pre:bytes-size(pre), _:bytes>> -> pre\n    _ -> panic\n  }\n}        \"\n    );\n}\n\n#[test]\nfn float_division_by_literal_zero() {\n    assert_erl!(\n        \"\npub fn main() {\n  1.0 /. 0.0\n}        \"\n    );\n}\n\n#[test]\nfn float_division_by_literal_non_zero() {\n    assert_erl!(\n        \"\npub fn main() {\n  1.0 /. 2.0\n}        \"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/erlang.rs",
    "content": "// TODO: Refactor this module to be methods on structs rather than free\n// functions with a load of arguments. See the JavaScript code generator and the\n// formatter for examples.\n\nmod pattern;\n#[cfg(test)]\nmod tests;\n\nuse crate::build::{Target, module_erlang_name};\nuse crate::erlang::pattern::{PatternPrinter, StringPatternAssignment};\nuse crate::strings::{convert_string_escape_chars, to_snake_case};\nuse crate::type_::is_prelude_module;\nuse crate::{\n    Result,\n    ast::{Function, *},\n    docvec,\n    line_numbers::LineNumbers,\n    pretty::*,\n    type_::{\n        ModuleValueConstructor, PatternConstructor, Type, TypeVar, TypedCallArg, ValueConstructor,\n        ValueConstructorVariant,\n    },\n};\nuse camino::Utf8Path;\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse regex::{Captures, Regex};\nuse std::collections::HashSet;\nuse std::sync::OnceLock;\nuse std::{collections::HashMap, ops::Deref, str::FromStr, sync::Arc};\nuse vec1::Vec1;\n\nconst INDENT: isize = 4;\nconst MAX_COLUMNS: isize = 80;\n\nfn module_name_atom(module: &str) -> Document<'static> {\n    atom_string(module.replace('/', \"@\").into())\n}\n\n#[derive(Debug, Clone)]\nstruct Env<'a> {\n    module: &'a str,\n    function: &'a str,\n    line_numbers: &'a LineNumbers,\n    needs_function_docs: bool,\n    echo_used: bool,\n    current_scope_vars: im::HashMap<String, usize>,\n    erl_function_scope_vars: im::HashMap<String, usize>,\n}\n\nimpl<'env> Env<'env> {\n    pub fn new(module: &'env str, function: &'env str, line_numbers: &'env LineNumbers) -> Self {\n        let vars: im::HashMap<_, _> = std::iter::once((\"_\".into(), 0)).collect();\n        Self {\n            current_scope_vars: vars.clone(),\n            erl_function_scope_vars: vars,\n            needs_function_docs: false,\n            echo_used: false,\n            line_numbers,\n            function,\n            module,\n        }\n    }\n\n    pub fn local_var_name<'a>(&mut self, name: &str) -> Document<'a> {\n        match self.current_scope_vars.get(name) {\n            None => {\n                let _ = self.current_scope_vars.insert(name.to_string(), 0);\n                let _ = self.erl_function_scope_vars.insert(name.to_string(), 0);\n                variable_name(name).to_doc()\n            }\n            Some(0) => variable_name(name).to_doc(),\n            Some(n) => {\n                use std::fmt::Write;\n                let mut name = variable_name(name);\n                write!(name, \"@{n}\").expect(\"pushing number suffix to name\");\n                name.to_doc()\n            }\n        }\n    }\n\n    pub fn next_local_var_name<'a>(&mut self, name: &str) -> Document<'a> {\n        let next = self.erl_function_scope_vars.get(name).map_or(0, |i| i + 1);\n        let _ = self.erl_function_scope_vars.insert(name.to_string(), next);\n        let _ = self.current_scope_vars.insert(name.to_string(), next);\n        self.local_var_name(name)\n    }\n}\n\npub fn records(module: &TypedModule) -> Vec<(&str, String)> {\n    module\n        .definitions\n        .custom_types\n        .iter()\n        .filter(|custom_type| {\n            custom_type.publicity.is_public()\n                && !module\n                    .unused_definition_positions\n                    .contains(&custom_type.location.start)\n        })\n        .flat_map(|custom_type| &custom_type.constructors)\n        .filter(|constructor| !constructor.arguments.is_empty())\n        .filter_map(|constructor| {\n            constructor\n                .arguments\n                .iter()\n                .map(\n                    |RecordConstructorArg {\n                         label,\n                         ast: _,\n                         location: _,\n                         type_,\n                         ..\n                     }| {\n                        label\n                            .as_ref()\n                            .map(|(_, label)| (label.as_str(), type_.clone()))\n                    },\n                )\n                .collect::<Option<Vec<_>>>()\n                .map(|fields| (constructor.name.as_str(), fields))\n        })\n        .map(|(name, fields)| (name, record_definition(name, &fields)))\n        .collect()\n}\n\npub fn record_definition(name: &str, fields: &[(&str, Arc<Type>)]) -> String {\n    let name = to_snake_case(name);\n    let type_printer = TypePrinter::new(\"\").var_as_any();\n    let fields = fields.iter().map(move |(name, type_)| {\n        let type_ = type_printer.print(type_);\n        docvec![atom_string((*name).into()), \" :: \", type_.group()]\n    });\n    let fields = break_(\"\", \"\")\n        .append(join(fields, break_(\",\", \", \")))\n        .nest(INDENT)\n        .append(break_(\"\", \"\"))\n        .group();\n    docvec![\"-record(\", atom_string(name), \", {\", fields, \"}).\", line()]\n        .to_pretty_string(MAX_COLUMNS)\n}\n\npub fn module<'a>(\n    module: &'a TypedModule,\n    line_numbers: &'a LineNumbers,\n    root: &'a Utf8Path,\n) -> Result<String> {\n    Ok(module_document(module, line_numbers, root)?.to_pretty_string(MAX_COLUMNS))\n}\n\nfn module_document<'a>(\n    module: &'a TypedModule,\n    line_numbers: &'a LineNumbers,\n    root: &'a Utf8Path,\n) -> Result<Document<'a>> {\n    let mut exports = vec![];\n    let mut type_defs = vec![];\n    let mut type_exports = vec![];\n\n    let header = \"-module(\"\n        .to_doc()\n        .append(module.erlang_name())\n        .append(\").\")\n        .append(line());\n\n    // We need to know which private functions are referenced in importable\n    // constants so that we can export them anyway in the generated Erlang.\n    // This is because otherwise when the constant is used in another module it\n    // would result in an error as it tries to reference this private function.\n    let overridden_publicity = find_private_functions_referenced_in_importable_constants(module);\n\n    for function in &module.definitions.functions {\n        register_function_exports(function, &mut exports, &overridden_publicity);\n    }\n\n    for custom_type in &module.definitions.custom_types {\n        register_custom_type_exports(custom_type, &mut type_exports, &mut type_defs, &module.name);\n    }\n\n    let exports = match (!exports.is_empty(), !type_exports.is_empty()) {\n        (false, false) => return Ok(header),\n        (true, false) => \"-export([\"\n            .to_doc()\n            .append(join(exports, \", \".to_doc()))\n            .append(\"]).\")\n            .append(lines(2)),\n\n        (true, true) => \"-export([\"\n            .to_doc()\n            .append(join(exports, \", \".to_doc()))\n            .append(\"]).\")\n            .append(line())\n            .append(\"-export_type([\")\n            .to_doc()\n            .append(join(type_exports, \", \".to_doc()))\n            .append(\"]).\")\n            .append(lines(2)),\n\n        (false, true) => \"-export_type([\"\n            .to_doc()\n            .append(join(type_exports, \", \".to_doc()))\n            .append(\"]).\")\n            .append(lines(2)),\n    };\n\n    let type_defs = if type_defs.is_empty() {\n        nil()\n    } else {\n        join(type_defs, lines(2)).append(lines(2))\n    };\n\n    let src_path_full = &module.type_info.src_path;\n    let src_path_relative = EcoString::from(\n        src_path_full\n            .strip_prefix(root)\n            .unwrap_or(src_path_full)\n            .as_str(),\n    )\n    .replace(\"\\\\\", \"\\\\\\\\\");\n\n    let mut needs_function_docs = false;\n    let mut echo_used = false;\n    let mut statements = vec![];\n    for function in &module.definitions.functions {\n        if let Some((statement_document, env)) = module_function(\n            function,\n            &module.name,\n            module.type_info.is_internal,\n            line_numbers,\n            src_path_relative.clone(),\n            &module.unused_definition_positions,\n        ) {\n            needs_function_docs = needs_function_docs || env.needs_function_docs;\n            echo_used = echo_used || env.echo_used;\n            statements.push(statement_document);\n        }\n    }\n\n    let module_doc = if module.type_info.is_internal {\n        Some(hidden_module_doc().append(lines(2)))\n    } else if module.documentation.is_empty() {\n        None\n    } else {\n        Some(module_doc(&module.documentation).append(lines(2)))\n    };\n\n    // We're going to need the documentation directives if any of the module's\n    // functions need it, or if the module has a module comment that we want to\n    // include in the generated Erlang source, or if the module is internal.\n    let needs_doc_directive = needs_function_docs || module_doc.is_some();\n    let documentation_directive = if needs_doc_directive {\n        \"-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\"\n            .to_doc()\n            .append(lines(2))\n    } else {\n        nil()\n    };\n\n    let module = docvec![\n        header,\n        \"-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\",\n        line(),\n        \"-define(FILEPATH, \\\"\",\n        src_path_relative,\n        \"\\\").\",\n        line(),\n        exports,\n        documentation_directive,\n        module_doc,\n        type_defs,\n        join(statements, lines(2)),\n    ];\n\n    let module = if echo_used {\n        module\n            .append(lines(2))\n            .append(std::include_str!(\"../templates/echo.erl\").to_doc())\n    } else {\n        module\n    };\n\n    Ok(module.append(line()))\n}\n\nfn register_function_exports(\n    function: &TypedFunction,\n    exports: &mut Vec<Document<'_>>,\n    overridden_publicity: &im::HashSet<EcoString>,\n) {\n    let Function {\n        publicity,\n        name: Some((_, name)),\n        arguments,\n        implementations,\n        ..\n    } = function\n    else {\n        return;\n    };\n\n    // If the function isn't for this target then don't attempt to export it\n    if implementations.supports(Target::Erlang)\n        && (publicity.is_importable() || overridden_publicity.contains(name))\n    {\n        let function_name = escape_erlang_existing_name(name);\n        exports.push(\n            atom_string(function_name.into())\n                .append(\"/\")\n                .append(arguments.len()),\n        )\n    }\n}\n\nfn register_custom_type_exports(\n    custom_type: &TypedCustomType,\n    type_exports: &mut Vec<Document<'_>>,\n    type_defs: &mut Vec<Document<'_>>,\n    module_name: &str,\n) {\n    let TypedCustomType {\n        name,\n        constructors,\n        opaque,\n        typed_parameters,\n        external_erlang,\n        ..\n    } = custom_type;\n\n    // Erlang doesn't allow phantom type variables in type definitions but gleam does\n    // so we check the type declaratinon against its constroctors and generate a phantom\n    // value that uses the unused type variables.\n    let type_var_usages = collect_type_var_usages(HashMap::new(), typed_parameters);\n    let mut constructor_var_usages = HashMap::new();\n    for c in constructors {\n        constructor_var_usages =\n            collect_type_var_usages(constructor_var_usages, c.arguments.iter().map(|a| &a.type_));\n    }\n    let phantom_vars: Vec<_> = type_var_usages\n        .keys()\n        .filter(|&id| !constructor_var_usages.contains_key(id))\n        .sorted()\n        .map(|&id| Type::Var {\n            type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id })),\n        })\n        .collect();\n    let phantom_vars_constructor = if !phantom_vars.is_empty() {\n        let type_printer = TypePrinter::new(module_name);\n        Some(tuple(\n            std::iter::once(\"gleam_phantom\".to_doc())\n                .chain(phantom_vars.iter().map(|pv| type_printer.print(pv))),\n        ))\n    } else {\n        None\n    };\n    // Type Exports\n    type_exports.push(\n        erl_safe_type_name(to_snake_case(name))\n            .to_doc()\n            .append(\"/\")\n            .append(typed_parameters.len()),\n    );\n    // Type definitions\n    let definition = if constructors.is_empty() {\n        if let Some((module, external_type, _location)) = external_erlang {\n            let printer = TypePrinter::new(module_name);\n            docvec![\n                module,\n                \":\",\n                external_type,\n                \"(\",\n                join(\n                    typed_parameters\n                        .iter()\n                        .map(|parameter| printer.print(parameter)),\n                    \", \".to_doc()\n                ),\n                \")\"\n            ]\n        } else {\n            let constructors = std::iter::once(\"any()\".to_doc()).chain(phantom_vars_constructor);\n            join(constructors, break_(\" |\", \" | \"))\n        }\n    } else {\n        let constructors = constructors\n            .iter()\n            .map(|constructor| {\n                let name = atom_string(to_snake_case(&constructor.name));\n                if constructor.arguments.is_empty() {\n                    name\n                } else {\n                    let type_printer = TypePrinter::new(module_name);\n                    let arguments = constructor\n                        .arguments\n                        .iter()\n                        .map(|argument| type_printer.print(&argument.type_));\n                    tuple(std::iter::once(name).chain(arguments))\n                }\n            })\n            .chain(phantom_vars_constructor);\n        join(constructors, break_(\" |\", \" | \"))\n    }\n    .nest(INDENT);\n    let type_printer = TypePrinter::new(module_name);\n    let params = join(\n        typed_parameters\n            .iter()\n            .map(|type_| type_printer.print(type_)),\n        \", \".to_doc(),\n    );\n    let doc = if *opaque { \"-opaque \" } else { \"-type \" }\n        .to_doc()\n        .append(erl_safe_type_name(to_snake_case(name)))\n        .append(\"(\")\n        .append(params)\n        .append(\") :: \")\n        .append(definition)\n        .group()\n        .append(\".\");\n    type_defs.push(doc);\n}\n\nfn module_function<'a>(\n    function: &'a TypedFunction,\n    module: &'a str,\n    is_internal_module: bool,\n    line_numbers: &'a LineNumbers,\n    src_path: EcoString,\n    unused_definition_positions: &HashSet<u32>,\n) -> Option<(Document<'a>, Env<'a>)> {\n    // We don't generate any code for unused functions.\n    if unused_definition_positions.contains(&function.location.start) {\n        return None;\n    }\n\n    // Private external functions don't need to render anything, the underlying\n    // Erlang implementation is used directly at the call site.\n    if function.external_erlang.is_some() && function.publicity.is_private() {\n        return None;\n    }\n\n    // If the function has no suitable Erlang implementation then there is nothing\n    // to generate for it.\n    if !function.implementations.supports(Target::Erlang) {\n        return None;\n    }\n\n    let (_, function_name) = function\n        .name\n        .as_ref()\n        .expect(\"A module's function must be named\");\n    let function_name = escape_erlang_existing_name(function_name);\n    let file_attribute = file_attribute(src_path, function, line_numbers);\n\n    let mut env = Env::new(module, function_name, line_numbers);\n    let var_usages = collect_type_var_usages(\n        HashMap::new(),\n        std::iter::once(&function.return_type).chain(function.arguments.iter().map(|a| &a.type_)),\n    );\n    let type_printer = TypePrinter::new(module).with_var_usages(&var_usages);\n    let arguments_spec = function\n        .arguments\n        .iter()\n        .map(|a| type_printer.print(&a.type_));\n    let return_spec = type_printer.print(&function.return_type);\n\n    let spec = fun_spec(function_name, arguments_spec, return_spec);\n    let arguments = if function.external_erlang.is_some() {\n        external_fun_arguments(&function.arguments, &mut env)\n    } else {\n        fun_arguments(&function.arguments, &mut env)\n    };\n\n    let body = function\n        .external_erlang\n        .as_ref()\n        .map(|(module, function, _location)| {\n            docvec![\n                atom(module),\n                \":\",\n                atom(escape_erlang_existing_name(function)),\n                arguments.clone()\n            ]\n        })\n        .unwrap_or_else(|| statement_sequence(&function.body, &mut env));\n\n    let attributes = file_attribute;\n    let attributes = if is_internal_module || function.publicity.is_internal() {\n        // If a function is marked as internal or comes from an internal module\n        // we want to hide its documentation in the Erlang shell!\n        // So the doc directive will look like this: `-doc(false).`\n        env.needs_function_docs = true;\n        docvec![attributes, line(), hidden_function_doc()]\n    } else {\n        match &function.documentation {\n            Some((_, documentation)) => {\n                env.needs_function_docs = true;\n                let doc_lines = documentation\n                    .trim_end()\n                    .split('\\n')\n                    .map(EcoString::from)\n                    .collect_vec();\n                docvec![attributes, line(), function_doc(&doc_lines)]\n            }\n            _ => attributes,\n        }\n    };\n\n    Some((\n        docvec![\n            attributes,\n            line(),\n            spec,\n            atom_string(escape_erlang_existing_name(function_name).into()),\n            arguments,\n            \" ->\",\n            line().append(body).nest(INDENT).group(),\n            \".\",\n        ],\n        env,\n    ))\n}\n\nfn file_attribute<'a>(\n    path: EcoString,\n    function: &'a TypedFunction,\n    line_numbers: &'a LineNumbers,\n) -> Document<'a> {\n    let line = line_numbers.line_number(function.location.start);\n    docvec![\"-file(\\\"\", path, \"\\\", \", line, \").\"]\n}\n\nenum DocCommentKind {\n    Module,\n    Function,\n}\n\nenum DocCommentContent<'a> {\n    String(&'a Vec<EcoString>),\n    False,\n}\n\nfn hidden_module_doc<'a>() -> Document<'a> {\n    doc_attribute(DocCommentKind::Module, DocCommentContent::False)\n}\n\nfn module_doc<'a>(content: &Vec<EcoString>) -> Document<'a> {\n    doc_attribute(DocCommentKind::Module, DocCommentContent::String(content))\n}\n\nfn hidden_function_doc<'a>() -> Document<'a> {\n    doc_attribute(DocCommentKind::Function, DocCommentContent::False)\n}\n\nfn function_doc<'a>(content: &Vec<EcoString>) -> Document<'a> {\n    doc_attribute(DocCommentKind::Function, DocCommentContent::String(content))\n}\n\nfn doc_attribute<'a>(kind: DocCommentKind, content: DocCommentContent<'_>) -> Document<'a> {\n    let prefix = match kind {\n        DocCommentKind::Module => \"?MODULEDOC\",\n        DocCommentKind::Function => \"?DOC\",\n    };\n\n    match content {\n        DocCommentContent::False => prefix.to_doc().append(\"(false).\"),\n        DocCommentContent::String(doc_lines) => {\n            let is_multiline_doc_comment = doc_lines.len() > 1;\n            let doc_lines = join(\n                doc_lines.iter().map(|line| {\n                    let line = line.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\");\n                    docvec![\"\\\"\", line, \"\\\\n\\\"\"]\n                }),\n                line(),\n            );\n            if is_multiline_doc_comment {\n                let nested_documentation = docvec![line(), doc_lines].nest(INDENT);\n                docvec![prefix, \"(\", nested_documentation, line(), \").\"]\n            } else {\n                docvec![prefix, \"(\", doc_lines, \").\"]\n            }\n        }\n    }\n}\n\nfn external_fun_arguments<'a>(arguments: &'a [TypedArg], env: &mut Env<'a>) -> Document<'a> {\n    wrap_arguments(arguments.iter().map(|argument| {\n        let name = match &argument.names {\n            ArgNames::Discard { name, .. }\n            | ArgNames::LabelledDiscard { name, .. }\n            | ArgNames::Named { name, .. }\n            | ArgNames::NamedLabelled { name, .. } => name,\n        };\n        if name.chars().all(|c| c == '_') {\n            env.next_local_var_name(\"argument\")\n        } else {\n            env.next_local_var_name(name)\n        }\n    }))\n}\n\nfn fun_arguments<'a>(arguments: &'a [TypedArg], env: &mut Env<'a>) -> Document<'a> {\n    wrap_arguments(arguments.iter().map(|argument| match &argument.names {\n        ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => \"_\".to_doc(),\n        ArgNames::Named { name, .. } | ArgNames::NamedLabelled { name, .. } => {\n            env.next_local_var_name(name)\n        }\n    }))\n}\n\nfn wrap_arguments<'a, I>(arguments: I) -> Document<'a>\nwhere\n    I: IntoIterator<Item = Document<'a>>,\n{\n    break_(\"\", \"\")\n        .append(join(arguments, break_(\",\", \", \")))\n        .nest(INDENT)\n        .append(break_(\"\", \"\"))\n        .surround(\"(\", \")\")\n        .group()\n}\n\nfn fun_spec<'a>(\n    name: &'a str,\n    arguments: impl IntoIterator<Item = Document<'a>>,\n    return_: Document<'a>,\n) -> Document<'a> {\n    \"-spec \"\n        .to_doc()\n        .append(atom(name))\n        .append(wrap_arguments(arguments))\n        .append(\" -> \")\n        .append(return_)\n        .append(\".\")\n        .append(line())\n        .group()\n}\n\nfn atom_string(value: EcoString) -> Document<'static> {\n    escape_atom_string(value).to_doc()\n}\n\nfn atom_pattern() -> &'static Regex {\n    static ATOM_PATTERN: OnceLock<Regex> = OnceLock::new();\n    ATOM_PATTERN.get_or_init(|| Regex::new(r\"^[a-z][a-z0-9_@]*$\").expect(\"atom RE regex\"))\n}\n\nfn atom(value: &str) -> Document<'_> {\n    if is_erlang_reserved_word(value) {\n        // Escape because of keyword collision\n        eco_format!(\"'{value}'\").to_doc()\n    } else if atom_pattern().is_match(value) {\n        // No need to escape\n        EcoString::from(value).to_doc()\n    } else {\n        // Escape because of characters contained\n        eco_format!(\"'{value}'\").to_doc()\n    }\n}\n\npub fn escape_atom_string(value: EcoString) -> EcoString {\n    if is_erlang_reserved_word(&value) {\n        // Escape because of keyword collision\n        eco_format!(\"'{value}'\")\n    } else if atom_pattern().is_match(&value) {\n        value\n    } else {\n        // Escape because of characters contained\n        eco_format!(\"'{value}'\")\n    }\n}\n\nfn unicode_escape_sequence_pattern() -> &'static Regex {\n    static PATTERN: OnceLock<Regex> = OnceLock::new();\n    PATTERN.get_or_init(|| {\n        Regex::new(r#\"(\\\\+)(u)\"#).expect(\"Unicode escape sequence regex cannot be constructed\")\n    })\n}\n\nfn string_inner(value: &str) -> Document<'_> {\n    let content = unicode_escape_sequence_pattern()\n        // `\\\\u`-s should not be affected, so that \"\\\\u...\" is not converted to\n        // \"\\\\x...\". That's why capturing groups is used to exclude cases that\n        // shouldn't be replaced.\n        .replace_all(value, |caps: &Captures<'_>| {\n            let slashes = caps.get(1).map_or(\"\", |m| m.as_str());\n\n            if slashes.len().is_multiple_of(2) {\n                format!(\"{slashes}u\")\n            } else {\n                format!(\"{slashes}x\")\n            }\n        });\n    EcoString::from(content).to_doc()\n}\n\nfn string(value: &str) -> Document<'_> {\n    string_inner(value).surround(\"<<\\\"\", \"\\\"/utf8>>\")\n}\n\nfn string_length_utf8_bytes(str: &EcoString) -> usize {\n    convert_string_escape_chars(str).len()\n}\n\nfn tuple<'a>(elements: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {\n    join(elements, break_(\",\", \", \"))\n        .nest(INDENT)\n        .surround(\"{\", \"}\")\n        .group()\n}\n\nfn const_string_concatenate_bit_array<'a>(\n    elements: impl IntoIterator<Item = Document<'a>>,\n) -> Document<'a> {\n    join(elements, break_(\",\", \", \"))\n        .nest(INDENT)\n        .surround(\"<<\", \">>\")\n        .group()\n}\n\nfn const_string_concatenate<'a>(\n    left: &'a TypedConstant,\n    right: &'a TypedConstant,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let left = const_string_concatenate_argument(left, env);\n    let right = const_string_concatenate_argument(right, env);\n    const_string_concatenate_bit_array([left, right])\n}\n\nfn const_string_concatenate_inner<'a>(\n    left: &'a TypedConstant,\n    right: &'a TypedConstant,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let left = const_string_concatenate_argument(left, env);\n    let right = const_string_concatenate_argument(right, env);\n    join([left, right], break_(\",\", \", \"))\n}\n\nfn const_string_concatenate_argument<'a>(\n    value: &'a TypedConstant,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    match value {\n        Constant::String { value, .. } => docvec!['\"', string_inner(value), \"\\\"/utf8\"],\n\n        Constant::Var {\n            constructor: Some(constructor),\n            ..\n        } => match &constructor.variant {\n            ValueConstructorVariant::ModuleConstant {\n                literal: Constant::String { value, .. },\n                ..\n            } => docvec!['\"', string_inner(value), \"\\\"/utf8\"],\n            ValueConstructorVariant::ModuleConstant {\n                literal: Constant::StringConcatenation { left, right, .. },\n                ..\n            } => const_string_concatenate_inner(left, right, env),\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::ModuleFn { .. }\n            | ValueConstructorVariant::Record { .. } => const_inline(value, env),\n        },\n\n        Constant::StringConcatenation { left, right, .. } => {\n            const_string_concatenate_inner(left, right, env)\n        }\n\n        Constant::Int { .. }\n        | Constant::Float { .. }\n        | Constant::Tuple { .. }\n        | Constant::List { .. }\n        | Constant::Record { .. }\n        | Constant::RecordUpdate { .. }\n        | Constant::BitArray { .. }\n        | Constant::Var { .. }\n        | Constant::Invalid { .. } => const_inline(value, env),\n    }\n}\n\nfn string_concatenate<'a>(\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let left = string_concatenate_argument(left, env);\n    let right = string_concatenate_argument(right, env);\n    bit_array([left, right])\n}\n\nfn string_concatenate_argument<'a>(value: &'a TypedExpr, env: &mut Env<'a>) -> Document<'a> {\n    match value {\n        TypedExpr::Var {\n            constructor:\n                ValueConstructor {\n                    variant:\n                        ValueConstructorVariant::ModuleConstant {\n                            literal: Constant::String { value, .. },\n                            ..\n                        },\n                    ..\n                },\n            ..\n        }\n        | TypedExpr::String { value, .. } => docvec!['\"', string_inner(value), \"\\\"/utf8\"],\n\n        TypedExpr::Var {\n            name,\n            constructor:\n                ValueConstructor {\n                    variant: ValueConstructorVariant::LocalVariable { .. },\n                    ..\n                },\n            ..\n        } => docvec![env.local_var_name(name), \"/binary\"],\n\n        TypedExpr::BinOp {\n            name: BinOp::Concatenate,\n            ..\n        } => docvec![expr(value, env), \"/binary\"],\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => docvec![\"(\", maybe_block_expr(value, env), \")/binary\"],\n    }\n}\n\nfn bit_array<'a>(elements: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {\n    join(elements, break_(\",\", \", \"))\n        .nest(INDENT)\n        .surround(\"<<\", \">>\")\n        .group()\n}\n\nfn const_segment<'a>(\n    value: &'a TypedConstant,\n    options: &'a [TypedConstantBitArraySegmentOption],\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let value_is_a_string_literal = matches!(value, Constant::String { .. });\n\n    let create_document = |env: &mut Env<'a>| {\n        match value {\n            // Skip the normal <<value/utf8>> surrounds\n            Constant::String { value, .. } => value.to_doc().surround(\"\\\"\", \"\\\"\"),\n\n            // As normal\n            Constant::Int { .. } | Constant::Float { .. } | Constant::BitArray { .. } => {\n                const_inline(value, env)\n            }\n\n            // Wrap anything else in parentheses\n            Constant::Tuple { .. }\n            | Constant::List { .. }\n            | Constant::Record { .. }\n            | Constant::RecordUpdate { .. }\n            | Constant::Var { .. }\n            | Constant::StringConcatenation { .. }\n            | Constant::Invalid { .. } => const_inline(value, env).surround(\"(\", \")\"),\n        }\n    };\n\n    let size = |value: &'a TypedConstant, env: &mut Env<'a>| {\n        if let Constant::Int { .. } = value {\n            Some(\":\".to_doc().append(const_inline(value, env)))\n        } else {\n            Some(\n                \":\".to_doc()\n                    .append(const_inline(value, env).surround(\"(\", \")\")),\n            )\n        }\n    };\n\n    let unit = |value: &'a u8| Some(eco_format!(\"unit:{value}\").to_doc());\n\n    bit_array_segment(\n        create_document,\n        options,\n        size,\n        unit,\n        value_is_a_string_literal,\n        false,\n        env,\n    )\n}\n\nenum Position {\n    Tail,\n    NotTail,\n}\n\nfn statement<'a>(\n    statement: &'a TypedStatement,\n    env: &mut Env<'a>,\n    position: Position,\n) -> Document<'a> {\n    match statement {\n        Statement::Expression(e) => expr(e, env),\n        Statement::Assignment(a) => assignment(a, env, position),\n        Statement::Use(use_) => expr(&use_.call, env),\n        Statement::Assert(a) => assert(a, env),\n    }\n}\n\nfn expr_segment<'a>(\n    value: &'a TypedExpr,\n    options: &'a [BitArrayOption<TypedExpr>],\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let value_is_a_string_literal = matches!(value, TypedExpr::String { .. });\n\n    let create_document = |env: &mut Env<'a>| {\n        match value {\n            // Skip the normal <<value/utf8>> surrounds and set the string literal flag\n            TypedExpr::String { value, .. } => string_inner(value).surround(\"\\\"\", \"\\\"\"),\n\n            // As normal\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::BitArray { .. } => expr(value, env),\n\n            // Wrap anything else in parentheses\n            TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => expr(value, env).surround(\"(\", \")\"),\n        }\n    };\n\n    let size = |expression: &'a TypedExpr, env: &mut Env<'a>| {\n        if let TypedExpr::Int { value, .. } = expression {\n            let v = value.replace(\"_\", \"\");\n            let v = u64::from_str(&v).unwrap_or(0);\n            Some(eco_format!(\":{v}\").to_doc())\n        } else {\n            let inner_expr = maybe_block_expr(expression, env).surround(\"(\", \")\");\n            // The value of size must be a non-negative integer, we use lists:max here to ensure\n            // it is at least 0;\n            let value_guard = \":(lists:max([\"\n                .to_doc()\n                .append(inner_expr)\n                .append(\", 0]))\")\n                .group();\n            Some(value_guard)\n        }\n    };\n\n    let unit = |value: &'a u8| Some(eco_format!(\"unit:{value}\").to_doc());\n\n    bit_array_segment(\n        create_document,\n        options,\n        size,\n        unit,\n        value_is_a_string_literal,\n        false,\n        env,\n    )\n}\n\nfn bit_array_segment<'a, Value: 'a, CreateDoc, SizeToDoc, UnitToDoc, State>(\n    mut create_document: CreateDoc,\n    options: &'a [BitArrayOption<Value>],\n    mut size_to_doc: SizeToDoc,\n    mut unit_to_doc: UnitToDoc,\n    value_is_a_string_literal: bool,\n    value_is_a_discard: bool,\n    state: &mut State,\n) -> Document<'a>\nwhere\n    CreateDoc: FnMut(&mut State) -> Document<'a>,\n    SizeToDoc: FnMut(&'a Value, &mut State) -> Option<Document<'a>>,\n    UnitToDoc: FnMut(&'a u8) -> Option<Document<'a>>,\n{\n    let mut size: Option<Document<'a>> = None;\n    let mut unit: Option<Document<'a>> = None;\n    let mut others = Vec::new();\n\n    // Erlang only allows valid codepoint integers to be used as values for utf segments\n    // We want to support <<string_var:utf8>> for all string variables, but <<StringVar/utf8>> is invalid\n    // To work around this we use the binary type specifier for these segments instead\n    let override_type = if !value_is_a_string_literal && !value_is_a_discard {\n        Some(\"binary\")\n    } else {\n        None\n    };\n\n    for option in options {\n        use BitArrayOption as Opt;\n        if !others.is_empty() && !matches!(option, Opt::Size { .. } | Opt::Unit { .. }) {\n            others.push(\"-\".to_doc());\n        }\n        match option {\n            Opt::Utf8 { .. } => others.push(override_type.unwrap_or(\"utf8\").to_doc()),\n            Opt::Utf16 { .. } => others.push(override_type.unwrap_or(\"utf16\").to_doc()),\n            Opt::Utf32 { .. } => others.push(override_type.unwrap_or(\"utf32\").to_doc()),\n            Opt::Int { .. } => others.push(\"integer\".to_doc()),\n            Opt::Float { .. } => others.push(\"float\".to_doc()),\n            Opt::Bytes { .. } => others.push(\"binary\".to_doc()),\n            Opt::Bits { .. } => others.push(\"bitstring\".to_doc()),\n            Opt::Utf8Codepoint { .. } => others.push(\"utf8\".to_doc()),\n            Opt::Utf16Codepoint { .. } => others.push(\"utf16\".to_doc()),\n            Opt::Utf32Codepoint { .. } => others.push(\"utf32\".to_doc()),\n            Opt::Signed { .. } => others.push(\"signed\".to_doc()),\n            Opt::Unsigned { .. } => others.push(\"unsigned\".to_doc()),\n            Opt::Big { .. } => others.push(\"big\".to_doc()),\n            Opt::Little { .. } => others.push(\"little\".to_doc()),\n            Opt::Native { .. } => others.push(\"native\".to_doc()),\n            Opt::Size { value, .. } => size = size_to_doc(value, state),\n            Opt::Unit { value, .. } => unit = unit_to_doc(value),\n        }\n    }\n\n    let mut document = create_document(state);\n\n    document = document.append(size);\n    let others_is_empty = others.is_empty();\n\n    if !others_is_empty {\n        document = document.append(\"/\").append(others);\n    }\n\n    if unit.is_some() {\n        if !others_is_empty {\n            document = document.append(\"-\").append(unit)\n        } else {\n            document = document.append(\"/\").append(unit)\n        }\n    }\n\n    document\n}\n\nfn block<'a>(statements: &'a Vec1<TypedStatement>, env: &mut Env<'a>) -> Document<'a> {\n    if statements.len() == 1\n        && let Statement::Expression(expression) = statements.first()\n        && !needs_begin_end_wrapping(expression)\n    {\n        return docvec!['(', expr(expression, env), ')'];\n    }\n\n    let vars = env.current_scope_vars.clone();\n    let document = statement_sequence(statements, env);\n    env.current_scope_vars = vars;\n\n    begin_end(document)\n}\n\nfn statement_sequence<'a>(statements: &'a [TypedStatement], env: &mut Env<'a>) -> Document<'a> {\n    let count = statements.len();\n    let mut documents = Vec::with_capacity(count * 3);\n    for (i, expression) in statements.iter().enumerate() {\n        let position = if i + 1 == count {\n            Position::Tail\n        } else {\n            Position::NotTail\n        };\n        documents.push(statement(expression, env, position).group());\n\n        if i + 1 < count {\n            // This isn't the final expression so add the delimeters\n            documents.push(\",\".to_doc());\n            documents.push(line());\n        }\n    }\n    if count == 1 {\n        documents.to_doc()\n    } else {\n        documents.to_doc().force_break()\n    }\n}\n\nfn float_div<'a>(left: &'a TypedExpr, right: &'a TypedExpr, env: &mut Env<'a>) -> Document<'a> {\n    if right.is_non_zero_compile_time_number() {\n        return binop_exprs(left, \"/\", right, env);\n    } else if right.is_zero_compile_time_number() {\n        return \"+0.0\".to_doc();\n    }\n\n    let left = expr(left, env);\n    let right = expr(right, env);\n    let denominator = env.next_local_var_name(\"gleam@denominator\");\n    let clauses = docvec![\n        line(),\n        \"+0.0 -> +0.0;\",\n        line(),\n        \"-0.0 -> -0.0;\",\n        line(),\n        denominator.clone(),\n        \" -> \",\n        binop_documents(left, \"/\", denominator)\n    ];\n    docvec![\"case \", right, \" of\", clauses.nest(INDENT), line(), \"end\"]\n}\n\nfn int_div<'a>(\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n    op: &'static str,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    if right.is_non_zero_compile_time_number() {\n        return binop_exprs(left, op, right, env);\n    }\n\n    // If we have a constant value divided by zero then it's safe to replace it\n    // directly with 0.\n    if left.is_literal() && right.is_zero_compile_time_number() {\n        return \"0\".to_doc();\n    }\n\n    let left = expr(left, env);\n    let right = expr(right, env);\n    let denominator = env.next_local_var_name(\"gleam@denominator\");\n    let clauses = docvec![\n        line(),\n        \"0 -> 0;\",\n        line(),\n        denominator.clone(),\n        \" -> \",\n        binop_documents(left, op, denominator)\n    ];\n    docvec![\"case \", right, \" of\", clauses.nest(INDENT), line(), \"end\"]\n}\n\nfn bin_op<'a>(\n    name: &'a BinOp,\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let op = match name {\n        BinOp::And => \"andalso\",\n        BinOp::Or => \"orelse\",\n        BinOp::LtInt | BinOp::LtFloat => \"<\",\n        BinOp::LtEqInt | BinOp::LtEqFloat => \"=<\",\n        BinOp::Eq => \"=:=\",\n        BinOp::NotEq => \"/=\",\n        BinOp::GtInt | BinOp::GtFloat => \">\",\n        BinOp::GtEqInt | BinOp::GtEqFloat => \">=\",\n        BinOp::AddInt => \"+\",\n        BinOp::AddFloat => \"+\",\n        BinOp::SubInt => \"-\",\n        BinOp::SubFloat => \"-\",\n        BinOp::MultInt => \"*\",\n        BinOp::MultFloat => \"*\",\n        BinOp::DivFloat => return float_div(left, right, env),\n        BinOp::DivInt => return int_div(left, right, \"div\", env),\n        BinOp::RemainderInt => return int_div(left, right, \"rem\", env),\n        BinOp::Concatenate => return string_concatenate(left, right, env),\n    };\n\n    binop_exprs(left, op, right, env)\n}\n\nfn binop_exprs<'a>(\n    left: &'a TypedExpr,\n    op: &'static str,\n    right: &'a TypedExpr,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let left = if let TypedExpr::BinOp { .. } = left {\n        expr(left, env).surround(\"(\", \")\")\n    } else {\n        maybe_block_expr(left, env)\n    };\n    let right = if let TypedExpr::BinOp { .. } = right {\n        expr(right, env).surround(\"(\", \")\")\n    } else {\n        maybe_block_expr(right, env)\n    };\n    binop_documents(left, op, right)\n}\n\nfn binop_documents<'a>(left: Document<'a>, op: &'static str, right: Document<'a>) -> Document<'a> {\n    left.append(break_(\"\", \" \"))\n        .append(op)\n        .group()\n        .append(\" \")\n        .append(right)\n}\n\nfn let_assert<'a>(\n    value: &'a TypedExpr,\n    pattern: &'a TypedPattern,\n    environment: &mut Env<'a>,\n    message: Option<&'a TypedExpr>,\n    position: Position,\n    location: SrcSpan,\n) -> Document<'a> {\n    // If the pattern will never fail, like a tuple or a simple variable, we\n    // simply treat it as if it were a `let` assignment.\n    if pattern.always_matches() {\n        return let_(value, pattern, environment);\n    }\n\n    let message = match message {\n        Some(message) => expr(message, environment),\n        None => string(\"Pattern match failed, no pattern matched the value.\"),\n    };\n\n    let subject = maybe_block_expr(value, environment);\n\n    // The code we generated for a `let assert` assignment looks something like\n    // this. For this Gleam code:\n    //\n    // ```gleam\n    // let assert [a, b, c] = [1, 2, 3]\n    // ```\n    //\n    // We generate (roughly) the following Erlang:\n    //\n    // ```erlang\n    // {A, B, C} = case [1, 2, 3] of\n    //   [A, B, C] -> {A, B, C};\n    //   _ -> erlang:error(...)\n    // end.\n    // ```\n    // This is the most efficient way to properly extract all the required\n    // variables from the pattern. However, if the `let assert` assignment is\n    // the last in a block, like this:\n    //\n    // ```gleam\n    // let x = {\n    //   let assert [a, b, c] = [1, 2, 3]\n    // }\n    // ```\n    //\n    // The generated Erlang code will end up assigning the value `#(1, 2, 3)`\n    // to the variable `x`, instead of `[1, 2, 3]`. In this case, we must\n    // generate slightly different code. Since we know we won't be using the\n    // bound variables anywhere (there is nothing else in this scope to\n    // reference them), we can safely remove the assignment from the generated\n    // code, and generate the following:\n    //\n    // ```erlang\n    // X = begin\n    //   _assert_subject = [1, 2, 3]\n    //   case _assert_subject of\n    //     [A, B, C] -> _assert_subject;\n    //     _ -> erlang:error(...)\n    //   end\n    // end.\n    // ```\n    //\n    // That correctly assigns `[1, 2, 3]` to the `x` variable.\n    //\n    let is_tail = match position {\n        Position::Tail => true,\n        Position::NotTail => false,\n    };\n\n    let (subject_assignment, subject) = if is_tail && !value.is_var() {\n        let variable = environment.next_local_var_name(ASSERT_SUBJECT_VARIABLE);\n        let assignment = docvec![variable.clone(), \" = \", subject, \",\", line()];\n        (assignment, variable)\n    } else {\n        (nil(), subject)\n    };\n\n    let mut pattern_printer = PatternPrinter::new(environment);\n    let pattern_document = pattern_printer.print(pattern);\n    let PatternPrinter {\n        environment,\n        variables,\n        guards,\n        assignments,\n    } = pattern_printer;\n\n    let assignments_map = assignments\n        .iter()\n        .map(|assignment| (assignment.gleam_name.clone(), assignment))\n        .collect();\n    let clause_guard = optional_clause_guard(None, guards, environment, &assignments_map);\n\n    let value_document = match variables.as_slice() {\n        _ if is_tail => subject.clone(),\n        [] => \"nil\".to_doc(),\n        [variable] => environment.local_var_name(variable),\n        variables => {\n            let variables = variables\n                .iter()\n                .map(|variable| environment.local_var_name(variable));\n            docvec![\n                break_(\"{\", \"{\"),\n                join(variables, break_(\",\", \", \")).nest(INDENT),\n                \"}\"\n            ]\n            .group()\n        }\n    };\n\n    let assignment = match variables.as_slice() {\n        _ if is_tail => nil(),\n        [] => nil(),\n        [variable] => environment.next_local_var_name(variable).append(\" = \"),\n        variables => {\n            let variables = variables\n                .iter()\n                .map(|variable| environment.next_local_var_name(variable));\n            docvec![\n                break_(\"{\", \"{\"),\n                join(variables, break_(\",\", \", \")).nest(INDENT),\n                \"} = \"\n            ]\n            .group()\n        }\n    };\n\n    let clauses = docvec![\n        pattern_document,\n        clause_guard,\n        \" -> \",\n        value_document,\n        \";\",\n        line(),\n        environment.next_local_var_name(ASSERT_FAIL_VARIABLE),\n        \" ->\",\n        docvec![\n            line(),\n            erlang_error(\n                \"let_assert\",\n                &message,\n                location,\n                vec![\n                    (\"value\", environment.local_var_name(ASSERT_FAIL_VARIABLE)),\n                    (\"start\", location.start.to_doc()),\n                    (\"'end'\", value.location().end.to_doc()),\n                    (\"pattern_start\", pattern.location().start.to_doc()),\n                    (\"pattern_end\", pattern.location().end.to_doc()),\n                ],\n                environment,\n            )\n            .nest(INDENT)\n        ]\n        .nest(INDENT)\n    ];\n\n    let assignments = if assignments.is_empty() {\n        nil()\n    } else {\n        docvec![\n            \",\",\n            line(),\n            join(\n                assignments\n                    .iter()\n                    .map(|assignment| assignment.to_assignment_doc()),\n                \",\".to_doc().append(line())\n            )\n        ]\n    };\n\n    docvec![\n        subject_assignment,\n        assignment,\n        \"case \",\n        subject,\n        \" of\",\n        docvec![line(), clauses].nest(INDENT),\n        line(),\n        \"end\",\n        assignments,\n    ]\n}\n\nfn let_<'a>(\n    value: &'a TypedExpr,\n    pattern: &'a TypedPattern,\n    environment: &mut Env<'a>,\n) -> Document<'a> {\n    let body = maybe_block_expr(value, environment).group();\n    PatternPrinter::new(environment)\n        .print(pattern)\n        .append(\" = \")\n        .append(body)\n}\n\nfn float<'a>(value: &str) -> Document<'a> {\n    let mut value = value.replace('_', \"\");\n    if value.ends_with('.') {\n        value.push('0')\n    }\n\n    match value.split('.').collect_vec().as_slice() {\n        [\"0\", \"0\"] => \"+0.0\".to_doc(),\n        [before_dot, after_dot] if after_dot.starts_with('e') => {\n            eco_format!(\"{before_dot}.0{after_dot}\").to_doc()\n        }\n        _ => EcoString::from(value).to_doc(),\n    }\n}\n\nfn expr_list<'a>(\n    elements: &'a [TypedExpr],\n    tail: &'a Option<Box<TypedExpr>>,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let elements = join(\n        elements\n            .iter()\n            .map(|element| maybe_block_expr(element, env)),\n        break_(\",\", \", \"),\n    );\n    list(\n        elements,\n        tail.as_ref().map(|element| maybe_block_expr(element, env)),\n    )\n}\n\nfn list<'a>(elements: Document<'a>, tail: Option<Document<'a>>) -> Document<'a> {\n    let elements = match tail {\n        Some(tail) if elements.is_empty() => return tail.to_doc(),\n\n        Some(tail) => elements.append(break_(\" |\", \" | \")).append(tail),\n\n        None => elements,\n    };\n\n    elements.to_doc().nest(INDENT).surround(\"[\", \"]\").group()\n}\n\nfn var<'a>(name: &'a str, constructor: &'a ValueConstructor, env: &mut Env<'a>) -> Document<'a> {\n    match &constructor.variant {\n        ValueConstructorVariant::Record {\n            name: record_name, ..\n        } => match constructor.type_.deref() {\n            Type::Fn { arguments, .. } => {\n                let chars = incrementing_arguments_list(arguments.len());\n                \"fun(\"\n                    .to_doc()\n                    .append(chars.clone())\n                    .append(\") -> {\")\n                    .append(atom_string(to_snake_case(record_name)))\n                    .append(\", \")\n                    .append(chars)\n                    .append(\"} end\")\n            }\n            Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                atom_string(to_snake_case(record_name))\n            }\n        },\n\n        ValueConstructorVariant::LocalVariable { .. } => env.local_var_name(name),\n\n        ValueConstructorVariant::ModuleConstant { literal, .. } => const_inline(literal, env),\n\n        ValueConstructorVariant::ModuleFn {\n            arity,\n            external_erlang: Some((module, name)),\n            ..\n        } if module == env.module => function_reference(None, name, *arity),\n\n        ValueConstructorVariant::ModuleFn {\n            arity,\n            external_erlang: Some((module, name)),\n            ..\n        } => function_reference(Some(module), name, *arity),\n\n        ValueConstructorVariant::ModuleFn { arity, module, .. } if module == env.module => {\n            function_reference(None, name, *arity)\n        }\n\n        ValueConstructorVariant::ModuleFn {\n            arity,\n            module,\n            name,\n            ..\n        } => function_reference(Some(module), name, *arity),\n    }\n}\n\nfn function_reference<'a>(module: Option<&'a str>, name: &'a str, arity: usize) -> Document<'a> {\n    match module {\n        None => \"fun \".to_doc(),\n        Some(module) => \"fun \".to_doc().append(module_name_atom(module)).append(\":\"),\n    }\n    .append(atom(escape_erlang_existing_name(name)))\n    .append(\"/\")\n    .append(arity)\n}\n\nfn int<'a>(value: &str) -> Document<'a> {\n    let mut value = value.replace('_', \"\");\n    if value.starts_with(\"0x\") {\n        value.replace_range(..2, \"16#\");\n    } else if value.starts_with(\"0o\") {\n        value.replace_range(..2, \"8#\");\n    } else if value.starts_with(\"0b\") {\n        value.replace_range(..2, \"2#\");\n    }\n\n    EcoString::from(value).to_doc()\n}\n\nfn const_inline<'a>(literal: &'a TypedConstant, env: &mut Env<'a>) -> Document<'a> {\n    match literal {\n        Constant::Int { value, .. } => int(value),\n        Constant::Float { value, .. } => float(value),\n        Constant::String { value, .. } => string(value),\n        Constant::Tuple { elements, .. } => {\n            tuple(elements.iter().map(|element| const_inline(element, env)))\n        }\n\n        Constant::List { elements, tail, .. } => {\n            let tail_elements = tail\n                .as_deref()\n                .and_then(|tail| tail.list_elements())\n                .unwrap_or_default();\n\n            join(\n                elements\n                    .iter()\n                    .chain(tail_elements)\n                    .map(|element| const_inline(element, env)),\n                break_(\",\", \", \"),\n            )\n            .nest(INDENT)\n            .surround(\"[\", \"]\")\n            .group()\n        }\n\n        Constant::BitArray { segments, .. } => bit_array(\n            segments\n                .iter()\n                .map(|s| const_segment(&s.value, &s.options, env)),\n        ),\n\n        Constant::Record {\n            tag,\n            type_,\n            arguments,\n            ..\n        } if arguments.is_empty() => match type_.deref() {\n            Type::Fn { arguments, .. } => record_constructor_function(tag, arguments.len()),\n            Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                atom_string(to_snake_case(tag))\n            }\n        },\n\n        Constant::Record { tag, arguments, .. } => {\n            // Record updates are fully expanded during type checking, so we just handle arguments\n            let arguments_doc = arguments\n                .iter()\n                .map(|argument| const_inline(&argument.value, env));\n            let tag = atom_string(to_snake_case(tag));\n            tuple(std::iter::once(tag).chain(arguments_doc))\n        }\n\n        Constant::Var {\n            name, constructor, ..\n        } => var(\n            name,\n            constructor\n                .as_ref()\n                .expect(\"This is guaranteed to hold a value.\"),\n            env,\n        ),\n\n        Constant::StringConcatenation { left, right, .. } => {\n            const_string_concatenate(left, right, env)\n        }\n\n        Constant::RecordUpdate { .. } => panic!(\"record updates should not reach code generation\"),\n        Constant::Invalid { .. } => panic!(\"invalid constants should not reach code generation\"),\n    }\n}\n\nfn record_constructor_function(tag: &EcoString, arity: usize) -> Document<'_> {\n    let chars = incrementing_arguments_list(arity);\n    \"fun(\"\n        .to_doc()\n        .append(chars.clone())\n        .append(\") -> {\")\n        .append(atom_string(to_snake_case(tag)))\n        .append(\", \")\n        .append(chars)\n        .append(\"} end\")\n}\n\nfn clause<'a>(clause: &'a TypedClause, environment: &mut Env<'a>) -> Document<'a> {\n    let Clause {\n        guard,\n        pattern,\n        alternative_patterns,\n        then,\n        ..\n    } = clause;\n\n    // These are required to get the alternative patterns working properly.\n    // Simply rendering the duplicate erlang clauses breaks the variable\n    // rewriting because each pattern would define different (rewritten)\n    // variables names.\n    let initial_erlang_vars = environment.erl_function_scope_vars.clone();\n    let initial_scope_vars = environment.current_scope_vars.clone();\n\n    let mut branches_docs = Vec::with_capacity(alternative_patterns.len() + 1);\n    for patterns in std::iter::once(pattern).chain(alternative_patterns) {\n        // Erlang doesn't support alternative patterns, so we turn each\n        // alternative into a branch of its own.\n        // For each alternative, before generating the body, we need to reset\n        // the variables in scope to what they are before the case expression,\n        // so that a branch will not interfere with the other ones!\n        environment.erl_function_scope_vars = initial_erlang_vars.clone();\n        environment.current_scope_vars = initial_scope_vars.clone();\n        let mut pattern_printer = PatternPrinter::new(environment);\n\n        let pattern = match patterns.as_slice() {\n            [pattern] => pattern_printer.print(pattern),\n            _ => tuple(patterns.iter().map(|pattern| {\n                pattern_printer.reset_variables();\n                pattern_printer.print(pattern)\n            })),\n        };\n\n        let PatternPrinter {\n            environment,\n            guards,\n            variables: _,\n            assignments,\n        } = pattern_printer;\n\n        let assignments_map = assignments\n            .iter()\n            .map(|assignment| (assignment.gleam_name.clone(), assignment))\n            .collect();\n\n        let guard = optional_clause_guard(guard.as_ref(), guards, environment, &assignments_map);\n        let then = clause_consequence(then, assignments, environment).group();\n        branches_docs.push(docvec![\n            pattern,\n            guard,\n            \" ->\",\n            docvec![line(), then].nest(INDENT),\n        ]);\n    }\n\n    join(branches_docs, \";\".to_doc().append(lines(2)))\n}\n\nfn clause_consequence<'a>(\n    consequence: &'a TypedExpr,\n    // Further assignments that the pattern might need to introduce at the start\n    // of the new block.\n    assignments: Vec<StringPatternAssignment<'a>>,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let assignment_doc = if assignments.is_empty() {\n        nil()\n    } else {\n        let separator = \",\".to_doc().append(line());\n        join(\n            assignments\n                .iter()\n                .map(|assignment| assignment.to_assignment_doc()),\n            separator.clone(),\n        )\n        .append(separator)\n    };\n\n    let consequence = if let TypedExpr::Block { statements, .. } = consequence {\n        statement_sequence(statements, env)\n    } else {\n        expr(consequence, env)\n    };\n    assignment_doc.append(consequence)\n}\n\nfn optional_clause_guard<'a>(\n    guard: Option<&'a TypedClauseGuard>,\n    additional_guards: Vec<Document<'a>>,\n    env: &mut Env<'a>,\n    assignments: &HashMap<EcoString, &StringPatternAssignment<'a>>,\n) -> Document<'a> {\n    let guard_doc = guard.map(|guard| bare_clause_guard(guard, env, assignments));\n\n    let guards_count = guard_doc.iter().len() + additional_guards.len();\n    let guards_docs = additional_guards.into_iter().chain(guard_doc).map(|guard| {\n        if guards_count > 1 {\n            guard.surround(\"(\", \")\")\n        } else {\n            guard\n        }\n    });\n    let doc = join(guards_docs, \" andalso \".to_doc());\n    if doc.is_empty() {\n        doc\n    } else {\n        \" when \".to_doc().append(doc)\n    }\n}\n\nfn bare_clause_guard<'a>(\n    guard: &'a TypedClauseGuard,\n    env: &mut Env<'a>,\n    assignments: &HashMap<EcoString, &StringPatternAssignment<'a>>,\n) -> Document<'a> {\n    match guard {\n        ClauseGuard::Block { value, .. } => {\n            bare_clause_guard(value, env, assignments).surround(\"(\", \")\")\n        }\n\n        ClauseGuard::Not { expression, .. } => {\n            docvec![\"not \", bare_clause_guard(expression, env, assignments)]\n        }\n\n        ClauseGuard::BinaryOperator {\n            operator,\n            left,\n            right,\n            ..\n        } => {\n            let left_document = clause_guard(left, env, assignments);\n            let right_document = clause_guard(right, env, assignments);\n\n            let operator = match operator {\n                BinOp::Or => \"orelse\",\n                BinOp::And => \"andalso\",\n                BinOp::Eq => \"=:=\",\n                BinOp::NotEq => \"=/=\",\n                BinOp::GtInt | BinOp::GtFloat => \">\",\n                BinOp::GtEqInt | BinOp::GtEqFloat => \">=\",\n                BinOp::LtInt | BinOp::LtFloat => \"<\",\n                BinOp::LtEqInt | BinOp::LtEqFloat => \"=<\",\n                BinOp::AddInt | BinOp::AddFloat => \"+\",\n                BinOp::SubInt | BinOp::SubFloat => \"-\",\n                BinOp::MultInt | BinOp::MultFloat => \"*\",\n                BinOp::DivFloat => \"/\",\n                BinOp::DivInt => \"div\",\n                BinOp::RemainderInt => \"rem\",\n                BinOp::Concatenate => {\n                    return clause_guard_string_concatenate(left, right, env, assignments);\n                }\n            };\n\n            docvec![left_document, \" \", operator, \" \", right_document]\n        }\n\n        // Only local variables are supported and the typer ensures that all\n        // ClauseGuard::Vars are local variables\n        ClauseGuard::Var { name, .. } => {\n            // If we're referencing a variable introduced by a string pattern\n            // assignment we need to replace it with its actual literal value:\n            // in the generated code the variable is only defined later, so\n            // just referencing its name would result in an error.\n            assignments\n                .get(name)\n                .map(|assignment| assignment.literal_value.clone())\n                .unwrap_or_else(|| env.local_var_name(name))\n        }\n\n        ClauseGuard::TupleIndex { tuple, index, .. } => tuple_index_inline(tuple, *index, env),\n\n        ClauseGuard::FieldAccess {\n            container, index, ..\n        } => tuple_index_inline(container, index.expect(\"Unable to find index\") + 1, env),\n\n        ClauseGuard::ModuleSelect { literal, .. } => const_inline(literal, env),\n\n        ClauseGuard::Constant(constant) => const_inline(constant, env),\n    }\n}\n\nfn clause_guard_string_concatenate<'a>(\n    left: &'a TypedClauseGuard,\n    right: &'a TypedClauseGuard,\n    env: &mut Env<'a>,\n    assignments: &HashMap<EcoString, &StringPatternAssignment<'a>>,\n) -> Document<'a> {\n    let left = clause_guard_string_concatenate_argument(left, env, assignments);\n    let right = clause_guard_string_concatenate_argument(right, env, assignments);\n    bit_array([left, right])\n}\n\nfn clause_guard_string_concatenate_argument<'a>(\n    guard: &'a TypedClauseGuard,\n    env: &mut Env<'a>,\n    assignments: &HashMap<EcoString, &StringPatternAssignment<'a>>,\n) -> Document<'a> {\n    match guard {\n        ClauseGuard::Constant(Constant::String { value, .. }) => {\n            docvec!['\"', string_inner(value), \"\\\"/utf8\"]\n        }\n\n        ClauseGuard::Constant(Constant::StringConcatenation { left, right, .. }) => {\n            const_string_concatenate_inner(left, right, env)\n        }\n\n        ClauseGuard::ModuleSelect { literal, .. } => match literal {\n            Constant::String { value, .. } => docvec!['\"', string_inner(value), \"\\\"/utf8\"],\n            Constant::StringConcatenation { left, right, .. } => {\n                const_string_concatenate_inner(left, right, env)\n            }\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::Tuple { .. }\n            | Constant::List { .. }\n            | Constant::Record { .. }\n            | Constant::RecordUpdate { .. }\n            | Constant::BitArray { .. }\n            | Constant::Var { .. }\n            | Constant::Invalid { .. } => docvec![\"(\", const_inline(literal, env), \")/binary\"],\n        },\n\n        ClauseGuard::Var { name, .. } => assignments\n            .get(name)\n            .map(|assignment| docvec![assignment.literal_value.clone(), \"/binary\"])\n            .unwrap_or_else(|| docvec![env.local_var_name(name), \"/binary\"]),\n\n        ClauseGuard::BinaryOperator {\n            operator: BinOp::Concatenate,\n            left,\n            right,\n            ..\n        } => docvec![\n            clause_guard_string_concatenate(left, right, env, assignments),\n            \"/binary\"\n        ],\n\n        ClauseGuard::Block { .. }\n        | ClauseGuard::BinaryOperator { .. }\n        | ClauseGuard::Not { .. }\n        | ClauseGuard::TupleIndex { .. }\n        | ClauseGuard::FieldAccess { .. }\n        | ClauseGuard::Constant(_) => docvec![\n            clause_guard(guard, env, assignments).surround(\"(\", \")\"),\n            \"/binary\"\n        ],\n    }\n}\n\nfn tuple_index_inline<'a>(\n    tuple: &'a TypedClauseGuard,\n    index: u64,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let index_doc = eco_format!(\"{}\", (index + 1)).to_doc();\n    let tuple_doc = bare_clause_guard(tuple, env, &HashMap::new());\n    \"erlang:element\"\n        .to_doc()\n        .append(wrap_arguments([index_doc, tuple_doc]))\n}\n\nfn clause_guard<'a>(\n    guard: &'a TypedClauseGuard,\n    env: &mut Env<'a>,\n    assignments: &HashMap<EcoString, &StringPatternAssignment<'a>>,\n) -> Document<'a> {\n    match guard {\n        // Binary operators are wrapped in parens\n        ClauseGuard::BinaryOperator { .. } => \"(\"\n            .to_doc()\n            .append(bare_clause_guard(guard, env, assignments))\n            .append(\")\"),\n\n        // Other expressions are not\n        ClauseGuard::Constant(_)\n        | ClauseGuard::Not { .. }\n        | ClauseGuard::Var { .. }\n        | ClauseGuard::TupleIndex { .. }\n        | ClauseGuard::FieldAccess { .. }\n        | ClauseGuard::ModuleSelect { .. }\n        | ClauseGuard::Block { .. } => bare_clause_guard(guard, env, assignments),\n    }\n}\n\nfn clauses<'a>(cs: &'a [TypedClause], env: &mut Env<'a>) -> Document<'a> {\n    join(\n        cs.iter().map(|c| {\n            let vars = env.current_scope_vars.clone();\n            let erl = clause(c, env);\n            env.current_scope_vars = vars; // Reset the known variables now the clauses' scope has ended\n            erl\n        }),\n        \";\".to_doc().append(lines(2)),\n    )\n}\n\nfn case<'a>(subjects: &'a [TypedExpr], cs: &'a [TypedClause], env: &mut Env<'a>) -> Document<'a> {\n    let subjects_doc = if subjects.len() == 1 {\n        let subject = subjects\n            .first()\n            .expect(\"erl case printing of single subject\");\n        maybe_block_expr(subject, env).group()\n    } else {\n        tuple(\n            subjects\n                .iter()\n                .map(|element| maybe_block_expr(element, env)),\n        )\n    };\n    \"case \"\n        .to_doc()\n        .append(subjects_doc)\n        .append(\" of\")\n        .append(line().append(clauses(cs, env)).nest(INDENT))\n        .append(line())\n        .append(\"end\")\n        .group()\n}\n\nfn call<'a>(fun: &'a TypedExpr, arguments: &'a [TypedCallArg], env: &mut Env<'a>) -> Document<'a> {\n    docs_arguments_call(\n        fun,\n        arguments\n            .iter()\n            .map(|argument| maybe_block_expr(&argument.value, env))\n            .collect(),\n        env,\n    )\n}\n\nfn module_fn_with_arguments<'a>(\n    module: &'a str,\n    name: &'a str,\n    arguments: Vec<Document<'a>>,\n    env: &Env<'a>,\n) -> Document<'a> {\n    let name = escape_erlang_existing_name(name);\n    let arguments = wrap_arguments(arguments);\n    if module == env.module {\n        atom(name).append(arguments)\n    } else {\n        atom_string(module.replace('/', \"@\").into())\n            .append(\":\")\n            .append(atom(name))\n            .append(arguments)\n    }\n}\n\nfn docs_arguments_call<'a>(\n    fun: &'a TypedExpr,\n    mut arguments: Vec<Document<'a>>,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    match fun {\n        TypedExpr::ModuleSelect {\n            constructor: ModuleValueConstructor::Record { name, .. },\n            ..\n        }\n        | TypedExpr::Var {\n            constructor:\n                ValueConstructor {\n                    variant: ValueConstructorVariant::Record { name, .. },\n                    ..\n                },\n            ..\n        } => tuple(std::iter::once(atom_string(to_snake_case(name))).chain(arguments)),\n\n        TypedExpr::Var {\n            constructor:\n                ValueConstructor {\n                    variant:\n                        ValueConstructorVariant::ModuleFn {\n                            external_erlang: Some((module, name)),\n                            ..\n                        }\n                        | ValueConstructorVariant::ModuleFn { module, name, .. },\n                    ..\n                },\n            ..\n        } => module_fn_with_arguments(module, name, arguments, env),\n\n        // Match against a Constant::Var that contains a function.\n        // We want this to be emitted like a normal function call, not a function variable\n        // substitution.\n        TypedExpr::Var {\n            constructor:\n                ValueConstructor {\n                    variant:\n                        ValueConstructorVariant::ModuleConstant {\n                            literal:\n                                Constant::Var {\n                                    constructor: Some(constructor),\n                                    ..\n                                },\n                            ..\n                        },\n                    ..\n                },\n            ..\n        } if constructor.variant.is_module_fn() => match &constructor.variant {\n            ValueConstructorVariant::ModuleFn {\n                external_erlang: Some((module, name)),\n                ..\n            }\n            | ValueConstructorVariant::ModuleFn { module, name, .. } => {\n                module_fn_with_arguments(module, name, arguments, env)\n            }\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::Record { .. } => {\n                unreachable!(\"The above clause guard ensures that this is a module fn\")\n            }\n        },\n\n        TypedExpr::ModuleSelect {\n            constructor:\n                ModuleValueConstructor::Fn {\n                    external_erlang: Some((module, name)),\n                    ..\n                }\n                | ModuleValueConstructor::Fn { module, name, .. },\n            ..\n        } => {\n            let arguments = wrap_arguments(arguments);\n            let name = escape_erlang_existing_name(name);\n            // We use the constructor Fn variant's `module` and function `name`.\n            // It would also be valid to use the module and label as in the\n            // Gleam code, but using the variant can result in an optimisation\n            // in which the target function is used for `external fn`s, removing\n            // one layer of wrapping.\n            // This also enables an optimisation in the Erlang compiler in which\n            // some Erlang BIFs can be replaced with literals if their arguments\n            // are literals, such as `binary_to_atom`.\n            atom_string(module_erlang_name(module))\n                .append(\":\")\n                .append(atom_string(name.into()))\n                .append(arguments)\n        }\n\n        TypedExpr::Fn { kind, body, .. } if kind.is_capture() => {\n            if let Statement::Expression(TypedExpr::Call {\n                fun,\n                arguments: inner_arguments,\n                ..\n            }) = body.first()\n            {\n                let mut merged_arguments = Vec::with_capacity(inner_arguments.len());\n                for arg in inner_arguments {\n                    if let TypedExpr::Var { name, .. } = &arg.value\n                        && name == CAPTURE_VARIABLE\n                    {\n                        merged_arguments.push(arguments.swap_remove(0))\n                    } else {\n                        merged_arguments.push(maybe_block_expr(&arg.value, env))\n                    }\n                }\n                docs_arguments_call(fun, merged_arguments, env)\n            } else {\n                panic!(\"Erl printing: Capture was not a call\")\n            }\n        }\n\n        TypedExpr::Fn { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::TupleIndex { .. } => {\n            let arguments = wrap_arguments(arguments);\n            expr(fun, env).surround(\"(\", \")\").append(arguments)\n        }\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => {\n            let arguments = wrap_arguments(arguments);\n            maybe_block_expr(fun, env).append(arguments)\n        }\n    }\n}\n\nfn record_update<'a>(\n    record: &'a Option<Box<TypedAssignment>>,\n    constructor: &'a TypedExpr,\n    arguments: &'a [TypedCallArg],\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let vars = env.current_scope_vars.clone();\n\n    let document = match record.as_ref() {\n        Some(record) => docvec![\n            assignment(record, env, Position::NotTail),\n            \",\",\n            line(),\n            call(constructor, arguments, env)\n        ],\n        None => call(constructor, arguments, env),\n    };\n\n    env.current_scope_vars = vars;\n\n    document\n}\n\n/// Wrap a document in begin end\n///\nfn begin_end(document: Document<'_>) -> Document<'_> {\n    docvec![\"begin\", line().append(document).nest(INDENT), line(), \"end\"].force_break()\n}\n\nfn maybe_block_expr<'a>(expression: &'a TypedExpr, env: &mut Env<'a>) -> Document<'a> {\n    if needs_begin_end_wrapping(expression) {\n        begin_end(expr(expression, env))\n    } else {\n        expr(expression, env)\n    }\n}\n\nfn needs_begin_end_wrapping(expression: &TypedExpr) -> bool {\n    match expression {\n        // Record updates are 1 expression if there's no assignment, multiple otherwise.\n        TypedExpr::RecordUpdate {\n            record_assignment, ..\n        } => record_assignment.is_some(),\n\n        TypedExpr::Pipeline { .. } => true,\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => false,\n    }\n}\n\nfn todo<'a>(message: Option<&'a TypedExpr>, location: SrcSpan, env: &mut Env<'a>) -> Document<'a> {\n    let message = match message {\n        Some(m) => expr(m, env),\n        None => string(\"`todo` expression evaluated. This code has not yet been implemented.\"),\n    };\n    erlang_error(\"todo\", &message, location, vec![], env)\n}\n\nfn panic<'a>(location: SrcSpan, message: Option<&'a TypedExpr>, env: &mut Env<'a>) -> Document<'a> {\n    let message = match message {\n        Some(m) => expr(m, env),\n        None => string(\"`panic` expression evaluated.\"),\n    };\n    erlang_error(\"panic\", &message, location, vec![], env)\n}\n\nfn echo<'a>(\n    body: Document<'a>,\n    message: Option<&'a TypedExpr>,\n    location: &SrcSpan,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    env.echo_used = true;\n\n    let message = message\n        .as_ref()\n        .map(|message| maybe_block_expr(message, env))\n        .unwrap_or(\"nil\".to_doc());\n\n    \"echo\".to_doc().append(wrap_arguments(vec![\n        body,\n        message,\n        env.line_numbers.line_number(location.start).to_doc(),\n    ]))\n}\n\nfn erlang_error<'a>(\n    name: &'a str,\n    message: &Document<'a>,\n    location: SrcSpan,\n    fields: Vec<(&'a str, Document<'a>)>,\n    env: &Env<'a>,\n) -> Document<'a> {\n    let mut fields_doc = docvec![\n        \"gleam_error => \",\n        name,\n        \",\",\n        line(),\n        \"message => \",\n        message.clone(),\n        \",\",\n        line(),\n        \"file => <<?FILEPATH/utf8>>,\",\n        line(),\n        \"module => \",\n        env.module.to_doc().surround(\"<<\\\"\", \"\\\"/utf8>>\"),\n        \",\",\n        line(),\n        \"function => \",\n        string(env.function),\n        \",\",\n        line(),\n        \"line => \",\n        env.line_numbers.line_number(location.start),\n    ];\n    for (key, value) in fields {\n        fields_doc = fields_doc\n            .append(\",\")\n            .append(line())\n            .append(key)\n            .append(\" => \")\n            .append(value);\n    }\n    let error = docvec![\"#{\", fields_doc.group().nest(INDENT), \"}\"];\n    docvec![\"erlang:error\", wrap_arguments([error.group()])]\n}\n\nfn expr<'a>(expression: &'a TypedExpr, env: &mut Env<'a>) -> Document<'a> {\n    match expression {\n        TypedExpr::Todo {\n            message: label,\n            location,\n            ..\n        } => todo(label.as_deref(), *location, env),\n\n        TypedExpr::Panic {\n            location, message, ..\n        } => panic(*location, message.as_deref(), env),\n\n        TypedExpr::Echo {\n            expression,\n            location,\n            message,\n            ..\n        } => {\n            let expression = expression\n                .as_ref()\n                .expect(\"echo with no expression outside of pipe\");\n            let expression = maybe_block_expr(expression, env);\n            echo(expression, message.as_deref(), location, env)\n        }\n\n        TypedExpr::Int { value, .. } => int(value),\n        TypedExpr::Float { value, .. } => float(value),\n        TypedExpr::String { value, .. } => string(value),\n\n        TypedExpr::Pipeline {\n            first_value,\n            assignments,\n            finally,\n            ..\n        } => pipeline(first_value, assignments, finally, env),\n\n        TypedExpr::Block { statements, .. } => block(statements, env),\n\n        TypedExpr::TupleIndex { tuple, index, .. } => tuple_index(tuple, *index, env),\n\n        TypedExpr::Var {\n            name, constructor, ..\n        } => var(name, constructor, env),\n\n        TypedExpr::Fn {\n            arguments, body, ..\n        } => fun(arguments, body, env),\n\n        TypedExpr::NegateBool { value, .. } => negate_with(\"not \", value, env),\n\n        TypedExpr::NegateInt { value, .. } => negate_with(\"- \", value, env),\n\n        TypedExpr::List { elements, tail, .. } => expr_list(elements, tail, env),\n\n        TypedExpr::Call { fun, arguments, .. } => call(fun, arguments, env),\n\n        TypedExpr::ModuleSelect {\n            constructor: ModuleValueConstructor::Record { name, arity: 0, .. },\n            ..\n        } => atom_string(to_snake_case(name)),\n\n        TypedExpr::ModuleSelect {\n            constructor: ModuleValueConstructor::Constant { literal, .. },\n            ..\n        } => const_inline(literal, env),\n\n        TypedExpr::ModuleSelect {\n            constructor: ModuleValueConstructor::Record { name, arity, .. },\n            ..\n        } => record_constructor_function(name, *arity as usize),\n\n        TypedExpr::ModuleSelect {\n            type_,\n            constructor:\n                ModuleValueConstructor::Fn {\n                    external_erlang: Some((module, name)),\n                    ..\n                }\n                | ModuleValueConstructor::Fn { module, name, .. },\n            ..\n        } => module_select_fn(type_.clone(), module, name),\n\n        TypedExpr::RecordAccess { record, index, .. } => tuple_index(record, index + 1, env),\n        TypedExpr::PositionalAccess { record, index, .. } => tuple_index(record, index + 1, env),\n\n        TypedExpr::RecordUpdate {\n            record_assignment,\n            constructor,\n            arguments,\n            ..\n        } => record_update(record_assignment, constructor, arguments, env),\n\n        TypedExpr::Case {\n            subjects, clauses, ..\n        } => case(subjects, clauses, env),\n\n        TypedExpr::BinOp {\n            name, left, right, ..\n        } => bin_op(name, left, right, env),\n\n        TypedExpr::Tuple { elements, .. } => tuple(\n            elements\n                .iter()\n                .map(|element| maybe_block_expr(element, env)),\n        ),\n\n        TypedExpr::BitArray { segments, .. } => bit_array(\n            segments\n                .iter()\n                .map(|s| expr_segment(&s.value, &s.options, env)),\n        ),\n\n        TypedExpr::Invalid { .. } => panic!(\"invalid expressions should not reach code generation\"),\n    }\n}\n\nfn pipeline<'a>(\n    first_value: &'a TypedPipelineAssignment,\n    assignments: &'a [(TypedPipelineAssignment, PipelineAssignmentKind)],\n    finally: &'a TypedExpr,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let mut documents = Vec::with_capacity((assignments.len() + 1) * 3);\n\n    let all_assignments = std::iter::once(first_value)\n        .chain(assignments.iter().map(|(assignment, _kind)| assignment));\n\n    let echo_doc = |var_name: &Option<Document<'a>>,\n                    message: Option<&'a TypedExpr>,\n                    location: &SrcSpan,\n                    env: &mut Env<'a>| {\n        let name = var_name\n            .to_owned()\n            .expect(\"echo with no previous step in a pipe\");\n        echo(name, message, location, env)\n    };\n\n    let vars = env.current_scope_vars.clone();\n\n    let mut prev_local_var_name = None;\n    for a in all_assignments {\n        // An echo in a pipeline won't result in an assignment, instead it\n        // just prints the previous variable assigned in the pipeline.\n        if let TypedExpr::Echo {\n            expression: None,\n            message,\n            location,\n            ..\n        } = a.value.as_ref()\n        {\n            documents.push(echo_doc(\n                &prev_local_var_name,\n                message.as_deref(),\n                location,\n                env,\n            ))\n        } else {\n            // Otherwise we assign the intermediate pipe value to a variable.\n            let body = maybe_block_expr(&a.value, env).group();\n            let name = env.next_local_var_name(&a.name);\n            prev_local_var_name = Some(name.clone());\n            documents.push(docvec![name, \" = \", body]);\n        };\n        documents.push(\",\".to_doc());\n        documents.push(line());\n    }\n\n    if let TypedExpr::Echo {\n        expression: None,\n        message,\n        location,\n        ..\n    } = finally\n    {\n        documents.push(echo_doc(\n            &prev_local_var_name,\n            message.as_deref(),\n            location,\n            env,\n        ))\n    } else {\n        documents.push(expr(finally, env))\n    }\n\n    env.current_scope_vars = vars;\n\n    documents.to_doc()\n}\n\nfn assignment<'a>(\n    assignment: &'a TypedAssignment,\n    env: &mut Env<'a>,\n    position: Position,\n) -> Document<'a> {\n    match &assignment.kind {\n        AssignmentKind::Let | AssignmentKind::Generated => {\n            let_(&assignment.value, &assignment.pattern, env)\n        }\n        AssignmentKind::Assert {\n            message, location, ..\n        } => let_assert(\n            &assignment.value,\n            &assignment.pattern,\n            env,\n            message.as_ref(),\n            position,\n            *location,\n        ),\n    }\n}\n\nfn assert<'a>(assert: &'a TypedAssert, env: &mut Env<'a>) -> Document<'a> {\n    let Assert {\n        value,\n        location,\n        message,\n    } = assert;\n\n    let message = match message {\n        Some(message) => expr(message, env),\n        None => string(\"Assertion failed.\"),\n    };\n\n    let mut assignments = Vec::new();\n\n    let (subject, mut fields) = match value {\n        TypedExpr::Call { fun, arguments, .. } => {\n            assert_call(fun, arguments, &mut assignments, env)\n        }\n        TypedExpr::BinOp {\n            name, left, right, ..\n        } => {\n            let operator = match name {\n                BinOp::And => {\n                    return assert_and(left, right, message, *location, env);\n                }\n                BinOp::Or => {\n                    return assert_or(left, right, message, *location, env);\n                }\n                BinOp::Eq => \"=:=\",\n                BinOp::NotEq => \"/=\",\n                BinOp::LtInt | BinOp::LtFloat => \"<\",\n                BinOp::LtEqInt | BinOp::LtEqFloat => \"=<\",\n                BinOp::GtInt | BinOp::GtFloat => \">\",\n                BinOp::GtEqInt | BinOp::GtEqFloat => \">=\",\n                BinOp::AddInt\n                | BinOp::AddFloat\n                | BinOp::SubInt\n                | BinOp::SubFloat\n                | BinOp::MultInt\n                | BinOp::MultFloat\n                | BinOp::DivInt\n                | BinOp::DivFloat\n                | BinOp::RemainderInt\n                | BinOp::Concatenate => {\n                    panic!(\"Non-boolean operators cannot appear here in well-typed code\")\n                }\n            };\n\n            let left_document = assign_to_variable(left, &mut assignments, env);\n            let right_document = assign_to_variable(right, &mut assignments, env);\n            (\n                binop_documents(left_document.clone(), operator, right_document.clone()),\n                vec![\n                    (\"kind\", atom(\"binary_operator\")),\n                    (\"operator\", atom(name.name())),\n                    (\n                        \"left\",\n                        asserted_expression(\n                            AssertExpression::from_expression(left),\n                            Some(left_document),\n                            left.location(),\n                        ),\n                    ),\n                    (\n                        \"right\",\n                        asserted_expression(\n                            AssertExpression::from_expression(right),\n                            Some(right_document),\n                            right.location(),\n                        ),\n                    ),\n                ],\n            )\n        }\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => (\n            maybe_block_expr(value, env),\n            vec![\n                (\"kind\", atom(\"expression\")),\n                (\n                    \"expression\",\n                    asserted_expression(\n                        AssertExpression::from_expression(value),\n                        Some(\"false\".to_doc()),\n                        value.location(),\n                    ),\n                ),\n            ],\n        ),\n    };\n\n    fields.push((\"start\", location.start.to_doc()));\n    fields.push((\"'end'\", value.location().end.to_doc()));\n    fields.push((\"expression_start\", value.location().start.to_doc()));\n\n    let clauses = docvec![\n        line(),\n        \"true -> nil;\",\n        line(),\n        \"false -> \",\n        erlang_error(\"assert\", &message, *location, fields, env),\n    ];\n\n    docvec![\n        assignments,\n        \"case \",\n        subject,\n        \" of\",\n        clauses.nest(INDENT),\n        line(),\n        \"end\"\n    ]\n}\n\nfn assert_call<'a>(\n    function: &'a TypedExpr,\n    arguments: &'a Vec<CallArg<TypedExpr>>,\n    assignments: &mut Vec<Document<'a>>,\n    env: &mut Env<'a>,\n) -> (Document<'a>, Vec<(&'static str, Document<'a>)>) {\n    let argument_variables = arguments\n        .iter()\n        .map(|argument| assign_to_variable(&argument.value, assignments, env))\n        .collect_vec();\n\n    let arguments = join(\n        argument_variables\n            .iter()\n            .zip(arguments)\n            .map(|(variable, argument)| {\n                asserted_expression(\n                    AssertExpression::from_expression(&argument.value),\n                    Some(variable.clone()),\n                    argument.location(),\n                )\n            }),\n        break_(\",\", \", \"),\n    )\n    .nest(INDENT)\n    .surround(\"[\", \"]\");\n\n    (\n        docs_arguments_call(function, argument_variables, env),\n        vec![(\"kind\", atom(\"function_call\")), (\"arguments\", arguments)],\n    )\n}\n\n/// In Gleam, the `&&` operator is short-circuiting, meaning that we can't\n/// pre-evaluate both sides of it, and use them in the exception that is\n/// thrown.\n/// Instead, we need to implement this short-circuiting logic ourself.\n///\n/// If we short-circuit, we must leave the second expression unevaluated,\n/// and signal that using the `unevaluated` variant, as detailed in the\n/// exception format. For the first expression, we know it must be `false`,\n/// otherwise we would have continued by evaluating the second expression.\n///\n/// Similarly, if we do evaluate the second expression and fail, we know\n/// that the first expression must have evaluated to `true`, and the second\n/// to `false`. This way, we avoid needing to evaluate either expression\n/// twice.\n///\n/// The generated code then looks something like this:\n/// ```erlang\n/// case expr1 of\n///   true -> case expr2 of\n///     true -> true;\n///     false -> <throw exception>\n///   end;\n///   false -> <throw exception>\n/// end\n/// ```\n///\nfn assert_and<'a>(\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n    message: Document<'a>,\n    location: SrcSpan,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let left_kind = AssertExpression::from_expression(left);\n    let right_kind = AssertExpression::from_expression(right);\n\n    let fields_if_short_circuiting = vec![\n        (\"kind\", atom(\"binary_operator\")),\n        (\"operator\", atom(\"&&\")),\n        (\n            \"left\",\n            asserted_expression(left_kind, Some(\"false\".to_doc()), left.location()),\n        ),\n        (\n            \"right\",\n            asserted_expression(AssertExpression::Unevaluated, None, right.location()),\n        ),\n        (\"start\", location.start.to_doc()),\n        (\"'end'\", right.location().end.to_doc()),\n        (\"expression_start\", left.location().start.to_doc()),\n    ];\n\n    let fields = vec![\n        (\"kind\", atom(\"binary_operator\")),\n        (\"operator\", atom(\"&&\")),\n        (\n            \"left\",\n            asserted_expression(left_kind, Some(\"true\".to_doc()), left.location()),\n        ),\n        (\n            \"right\",\n            asserted_expression(right_kind, Some(\"false\".to_doc()), right.location()),\n        ),\n        (\"start\", location.start.to_doc()),\n        (\"'end'\", right.location().end.to_doc()),\n        (\"expression_start\", left.location().start.to_doc()),\n    ];\n\n    let right_clauses = docvec![\n        line(),\n        \"true -> nil;\",\n        line(),\n        \"false -> \",\n        erlang_error(\"assert\", &message, location, fields, env),\n    ];\n\n    let left_clauses = docvec![\n        line(),\n        \"true -> \",\n        docvec![\n            \"case \",\n            maybe_block_expr(right, env),\n            \" of\",\n            right_clauses.nest(INDENT),\n            line(),\n            \"end\"\n        ]\n        .nest(INDENT),\n        \";\",\n        line(),\n        \"false -> \",\n        erlang_error(\n            \"assert\",\n            &message,\n            location,\n            fields_if_short_circuiting,\n            env\n        ),\n    ];\n\n    docvec![\n        \"case \",\n        maybe_block_expr(left, env),\n        \" of\",\n        left_clauses.nest(INDENT),\n        line(),\n        \"end\"\n    ]\n}\n\n/// Similar to `&&`, `||` is also short-circuiting in Gleam. However, if `||`\n/// short-circuits, that's because the first expression evaluated to `true`,\n/// meaning the whole assertion succeeds. This allows us to directly use Erlang's\n/// `orelse` operator as the subject of the `case` expression.\n///\n/// The only difference is that due to the nature of `||`, if the assertion fails,\n/// we know that both sides must have evaluated to `false`, so we don't\n/// need to store the values of them in variables beforehand.\nfn assert_or<'a>(\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n    message: Document<'a>,\n    location: SrcSpan,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let fields = vec![\n        (\"kind\", atom(\"binary_operator\")),\n        (\"operator\", atom(\"||\")),\n        (\n            \"left\",\n            asserted_expression(\n                AssertExpression::from_expression(left),\n                Some(\"false\".to_doc()),\n                left.location(),\n            ),\n        ),\n        (\n            \"right\",\n            asserted_expression(\n                AssertExpression::from_expression(right),\n                Some(\"false\".to_doc()),\n                right.location(),\n            ),\n        ),\n        (\"start\", location.start.to_doc()),\n        (\"'end'\", right.location().end.to_doc()),\n        (\"expression_start\", left.location().start.to_doc()),\n    ];\n\n    let clauses = docvec![\n        line(),\n        \"true -> nil;\",\n        line(),\n        \"false -> \",\n        erlang_error(\"assert\", &message, location, fields, env),\n    ];\n\n    docvec![\n        \"case \",\n        docvec![\n            maybe_block_expr(left, env),\n            \" orelse \",\n            maybe_block_expr(right, env)\n        ]\n        .nest(INDENT),\n        \" of\",\n        clauses.nest(INDENT),\n        line(),\n        \"end\"\n    ]\n}\n\nfn assign_to_variable<'a>(\n    value: &'a TypedExpr,\n    assignments: &mut Vec<Document<'a>>,\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    if value.is_var() {\n        expr(value, env)\n    } else {\n        let value = maybe_block_expr(value, env);\n        let variable = env.next_local_var_name(ASSERT_SUBJECT_VARIABLE);\n        let definition = docvec![variable.clone(), \" = \", value, \",\", line()];\n        assignments.push(definition);\n        variable\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\nenum AssertExpression {\n    Literal,\n    Expression,\n    Unevaluated,\n}\n\nimpl AssertExpression {\n    fn from_expression(expression: &TypedExpr) -> Self {\n        if expression.is_literal() {\n            Self::Literal\n        } else {\n            Self::Expression\n        }\n    }\n}\n\nfn asserted_expression(\n    kind: AssertExpression,\n    value: Option<Document<'_>>,\n    location: SrcSpan,\n) -> Document<'_> {\n    let kind = match kind {\n        AssertExpression::Literal => atom(\"literal\"),\n        AssertExpression::Expression => atom(\"expression\"),\n        AssertExpression::Unevaluated => atom(\"unevaluated\"),\n    };\n\n    let start = location.start.to_doc();\n    let end = location.end.to_doc();\n\n    let value_field = if let Some(value) = value {\n        docvec![\"value => \", value, \",\", line()]\n    } else {\n        nil()\n    };\n\n    let fields_doc = docvec![\n        \"kind => \",\n        kind,\n        \",\",\n        line(),\n        value_field,\n        \"start => \",\n        start,\n        \",\",\n        line(),\n        // `end` is a keyword in Erlang, so we have to quote it\n        \"'end' => \",\n        end,\n        line(),\n    ];\n\n    \"#{\".to_doc()\n        .append(fields_doc.group().nest(INDENT))\n        .append(\"}\")\n}\n\nfn negate_with<'a>(op: &'static str, value: &'a TypedExpr, env: &mut Env<'a>) -> Document<'a> {\n    docvec![op, maybe_block_expr(value, env)]\n}\n\nfn tuple_index<'a>(tuple: &'a TypedExpr, index: u64, env: &mut Env<'a>) -> Document<'a> {\n    let index_doc = eco_format!(\"{}\", (index + 1)).to_doc();\n    let tuple_doc = maybe_block_expr(tuple, env);\n    \"erlang:element\"\n        .to_doc()\n        .append(wrap_arguments([index_doc, tuple_doc]))\n}\n\nfn module_select_fn<'a>(type_: Arc<Type>, module_name: &'a str, label: &'a str) -> Document<'a> {\n    match crate::type_::collapse_links(type_).as_ref() {\n        Type::Fn { arguments, .. } => function_reference(Some(module_name), label, arguments.len()),\n\n        Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => module_name_atom(module_name)\n            .append(\":\")\n            .append(atom(label))\n            .append(\"()\"),\n    }\n}\n\nfn fun<'a>(\n    arguments: &'a [TypedArg],\n    body: &'a [TypedStatement],\n    env: &mut Env<'a>,\n) -> Document<'a> {\n    let current_scope_vars = env.current_scope_vars.clone();\n    let doc = \"fun\"\n        .to_doc()\n        .append(fun_arguments(arguments, env).append(\" ->\"))\n        .append(\n            break_(\"\", \" \")\n                .append(statement_sequence(body, env))\n                .nest(INDENT),\n        )\n        .append(break_(\"\", \" \"))\n        .append(\"end\")\n        .group();\n    env.current_scope_vars = current_scope_vars;\n    doc\n}\n\nfn incrementing_arguments_list(arity: usize) -> EcoString {\n    let arguments = (0..arity).map(|c| format!(\"Field@{c}\"));\n    Itertools::intersperse(arguments, \", \".into())\n        .collect::<String>()\n        .into()\n}\n\nfn variable_name(name: &str) -> EcoString {\n    let mut chars = name.chars();\n    let first_char = chars.next();\n    let first_uppercased = first_char.into_iter().flat_map(char::to_uppercase);\n\n    first_uppercased.chain(chars).collect::<EcoString>()\n}\n\n/// When rendering a type variable to an erlang type spec we need all type variables with the\n/// same id to end up with the same name in the generated erlang.\n/// This function converts a usize into base 26 A-Z for this purpose.\nfn id_to_type_var(id: u64) -> Document<'static> {\n    if id < 26 {\n        let mut name = EcoString::from(\"\");\n        name.push(char::from_u32((id % 26 + 65) as u32).expect(\"id_to_type_var 0\"));\n        return name.to_doc();\n    }\n    let mut name = vec![];\n    let mut last_char = id;\n    while last_char >= 26 {\n        name.push(char::from_u32((last_char % 26 + 65) as u32).expect(\"id_to_type_var 1\"));\n        last_char /= 26;\n    }\n    name.push(char::from_u32((last_char % 26 + 64) as u32).expect(\"id_to_type_var 2\"));\n    name.reverse();\n    name.into_iter().collect::<EcoString>().to_doc()\n}\n\npub fn is_erlang_reserved_word(name: &str) -> bool {\n    matches!(\n        name,\n        \"!\" | \"receive\"\n            | \"bnot\"\n            | \"div\"\n            | \"rem\"\n            | \"band\"\n            | \"bor\"\n            | \"bxor\"\n            | \"bsl\"\n            | \"bsr\"\n            | \"not\"\n            | \"and\"\n            | \"or\"\n            | \"xor\"\n            | \"orelse\"\n            | \"andalso\"\n            | \"when\"\n            | \"end\"\n            | \"fun\"\n            | \"try\"\n            | \"catch\"\n            | \"after\"\n            | \"begin\"\n            | \"let\"\n            | \"query\"\n            | \"cond\"\n            | \"if\"\n            | \"of\"\n            | \"case\"\n            | \"maybe\"\n            | \"else\"\n    )\n}\n\n// Includes shell_default & user_default which are looked for by the erlang shell\npub fn is_erlang_standard_library_module(name: &str) -> bool {\n    matches!(\n        name,\n        \"array\"\n            | \"base64\"\n            | \"beam_lib\"\n            | \"binary\"\n            | \"c\"\n            | \"calendar\"\n            | \"dets\"\n            | \"dict\"\n            | \"digraph\"\n            | \"digraph_utils\"\n            | \"epp\"\n            | \"erl_anno\"\n            | \"erl_eval\"\n            | \"erl_expand_records\"\n            | \"erl_id_trans\"\n            | \"erl_internal\"\n            | \"erl_lint\"\n            | \"erl_parse\"\n            | \"erl_pp\"\n            | \"erl_scan\"\n            | \"erl_tar\"\n            | \"ets\"\n            | \"file_sorter\"\n            | \"filelib\"\n            | \"filename\"\n            | \"gb_sets\"\n            | \"gb_trees\"\n            | \"gen_event\"\n            | \"gen_fsm\"\n            | \"gen_server\"\n            | \"gen_statem\"\n            | \"io\"\n            | \"io_lib\"\n            | \"lists\"\n            | \"log_mf_h\"\n            | \"maps\"\n            | \"math\"\n            | \"ms_transform\"\n            | \"orddict\"\n            | \"ordsets\"\n            | \"pool\"\n            | \"proc_lib\"\n            | \"proplists\"\n            | \"qlc\"\n            | \"queue\"\n            | \"rand\"\n            | \"random\"\n            | \"re\"\n            | \"sets\"\n            | \"shell\"\n            | \"shell_default\"\n            | \"shell_docs\"\n            | \"slave\"\n            | \"sofs\"\n            | \"string\"\n            | \"supervisor\"\n            | \"supervisor_bridge\"\n            | \"sys\"\n            | \"timer\"\n            | \"unicode\"\n            | \"uri_string\"\n            | \"user_default\"\n            | \"win32reg\"\n            | \"zip\"\n    )\n}\n\n// Includes the functions that are autogenerated by erlang itself\npub fn escape_erlang_existing_name(name: &str) -> &str {\n    match name {\n        \"module_info\" => \"moduleInfo\",\n        _ => name,\n    }\n}\n\n// A TypeVar can either be rendered as an actual type variable such as `A` or `B`,\n// or it can be rendered as `any()` depending on how many usages it has. If it\n// has only 1 usage it is an `any()` type. If it has more than 1 usage it is a\n// type variable. This function gathers usages for this determination.\n//\n//   Examples:\n//     fn(a) -> String       // `a` is `any()`\n//     fn() -> Result(a, b)  // `a` and `b` are `any()`\n//     fn(a) -> a            // `a` is a type var\nfn collect_type_var_usages<'a>(\n    mut ids: HashMap<u64, u64>,\n    types: impl IntoIterator<Item = &'a Arc<Type>>,\n) -> HashMap<u64, u64> {\n    for type_ in types {\n        type_var_ids(type_, &mut ids);\n    }\n    ids\n}\n\nfn result_type_var_ids(ids: &mut HashMap<u64, u64>, arg_ok: &Type, arg_err: &Type) {\n    let mut ok_ids = HashMap::new();\n    type_var_ids(arg_ok, &mut ok_ids);\n\n    let mut err_ids = HashMap::new();\n    type_var_ids(arg_err, &mut err_ids);\n\n    let mut result_counts = ok_ids;\n    for (id, count) in err_ids {\n        let _ = result_counts\n            .entry(id)\n            .and_modify(|current_count| {\n                if *current_count < count {\n                    *current_count = count;\n                }\n            })\n            .or_insert(count);\n    }\n    for (id, count) in result_counts {\n        let _ = ids\n            .entry(id)\n            .and_modify(|current_count| {\n                *current_count += count;\n            })\n            .or_insert(count);\n    }\n}\n\nfn type_var_ids(type_: &Type, ids: &mut HashMap<u64, u64>) {\n    match type_ {\n        Type::Var { type_ } => match type_.borrow().deref() {\n            TypeVar::Generic { id, .. } | TypeVar::Unbound { id, .. } => {\n                let count = ids.entry(*id).or_insert(0);\n                *count += 1;\n            }\n            TypeVar::Link { type_ } => type_var_ids(type_, ids),\n        },\n        Type::Named {\n            arguments,\n            module,\n            name,\n            ..\n        } => match arguments[..] {\n            [ref arg_ok, ref arg_err] if is_prelude_module(module) && name == \"Result\" => {\n                result_type_var_ids(ids, arg_ok, arg_err)\n            }\n            _ => {\n                for argument in arguments {\n                    type_var_ids(argument, ids)\n                }\n            }\n        },\n        Type::Fn { arguments, return_ } => {\n            for argument in arguments {\n                type_var_ids(argument, ids)\n            }\n            type_var_ids(return_, ids);\n        }\n        Type::Tuple { elements } => {\n            for element in elements {\n                type_var_ids(element, ids)\n            }\n        }\n    }\n}\n\nfn erl_safe_type_name(mut name: EcoString) -> EcoString {\n    if matches!(\n        name.as_str(),\n        \"any\"\n            | \"arity\"\n            | \"atom\"\n            | \"binary\"\n            | \"bitstring\"\n            | \"boolean\"\n            | \"byte\"\n            | \"char\"\n            | \"dynamic\"\n            | \"float\"\n            | \"function\"\n            | \"identifier\"\n            | \"integer\"\n            | \"iodata\"\n            | \"iolist\"\n            | \"list\"\n            | \"map\"\n            | \"maybe_improper_list\"\n            | \"mfa\"\n            | \"module\"\n            | \"neg_integer\"\n            | \"nil\"\n            | \"no_return\"\n            | \"node\"\n            | \"non_neg_integer\"\n            | \"none\"\n            | \"nonempty_improper_list\"\n            | \"nonempty_list\"\n            | \"nonempty_string\"\n            | \"number\"\n            | \"pid\"\n            | \"port\"\n            | \"pos_integer\"\n            | \"reference\"\n            | \"string\"\n            | \"term\"\n            | \"timeout\"\n            | \"tuple\"\n    ) {\n        name.push('_');\n        name\n    } else {\n        escape_atom_string(name)\n    }\n}\n\n#[derive(Debug)]\nstruct TypePrinter<'a> {\n    var_as_any: bool,\n    current_module: &'a str,\n    var_usages: Option<&'a HashMap<u64, u64>>,\n}\n\nimpl<'a> TypePrinter<'a> {\n    fn new(current_module: &'a str) -> Self {\n        Self {\n            current_module,\n            var_usages: None,\n            var_as_any: false,\n        }\n    }\n\n    pub fn with_var_usages(mut self, var_usages: &'a HashMap<u64, u64>) -> Self {\n        self.var_usages = Some(var_usages);\n        self\n    }\n\n    pub fn print(&self, type_: &Type) -> Document<'static> {\n        match type_ {\n            Type::Var { type_ } => self.print_var(&type_.borrow()),\n\n            Type::Named {\n                name,\n                module,\n                arguments,\n                ..\n            } if is_prelude_module(module) => self.print_prelude_type(name, arguments),\n\n            Type::Named {\n                name,\n                module,\n                arguments,\n                ..\n            } => self.print_type_app(module, name, arguments),\n\n            Type::Fn { arguments, return_ } => self.print_fn(arguments, return_),\n\n            Type::Tuple { elements } => tuple(elements.iter().map(|element| self.print(element))),\n        }\n    }\n\n    fn print_var(&self, type_: &TypeVar) -> Document<'static> {\n        match type_ {\n            TypeVar::Generic { .. } | TypeVar::Unbound { .. } if self.var_as_any => {\n                \"any()\".to_doc()\n            }\n            TypeVar::Generic { id, .. } | TypeVar::Unbound { id, .. } => match &self.var_usages {\n                Some(usages) => match usages.get(id) {\n                    Some(&0) => nil(),\n                    Some(&1) => \"any()\".to_doc(),\n                    _ => id_to_type_var(*id),\n                },\n                None => id_to_type_var(*id),\n            },\n            TypeVar::Link { type_ } => self.print(type_),\n        }\n    }\n\n    fn print_prelude_type(&self, name: &str, arguments: &[Arc<Type>]) -> Document<'static> {\n        match name {\n            \"Nil\" => \"nil\".to_doc(),\n            \"Int\" | \"UtfCodepoint\" => \"integer()\".to_doc(),\n            \"String\" => \"binary()\".to_doc(),\n            \"Bool\" => \"boolean()\".to_doc(),\n            \"Float\" => \"float()\".to_doc(),\n            \"BitArray\" => \"bitstring()\".to_doc(),\n            \"List\" => {\n                let arg0 = self.print(arguments.first().expect(\"print_prelude_type list\"));\n                \"list(\".to_doc().append(arg0).append(\")\")\n            }\n            \"Result\" => match arguments {\n                [arg_ok, arg_err] => {\n                    let ok = tuple([\"ok\".to_doc(), self.print(arg_ok)]);\n                    let error = tuple([\"error\".to_doc(), self.print(arg_err)]);\n                    docvec![ok, break_(\" |\", \" | \"), error].nest(INDENT).group()\n                }\n                _ => panic!(\"print_prelude_type result expects ok and err\"),\n            },\n            // Getting here should mean we either forgot a built-in type or there is a\n            // compiler error\n            name => panic!(\"{name} is not a built-in type.\"),\n        }\n    }\n\n    fn print_type_app(\n        &self,\n        module: &str,\n        name: &str,\n        arguments: &[Arc<Type>],\n    ) -> Document<'static> {\n        let arguments = join(\n            arguments.iter().map(|argument| self.print(argument)),\n            \", \".to_doc(),\n        );\n        let name = erl_safe_type_name(to_snake_case(name)).to_doc();\n        if self.current_module == module {\n            docvec![name, \"(\", arguments, \")\"]\n        } else {\n            docvec![module_name_atom(module), \":\", name, \"(\", arguments, \")\"]\n        }\n    }\n\n    fn print_fn(&self, arguments: &[Arc<Type>], return_: &Type) -> Document<'static> {\n        let arguments = join(\n            arguments.iter().map(|argument| self.print(argument)),\n            \", \".to_doc(),\n        );\n        let return_ = self.print(return_);\n        \"fun((\"\n            .to_doc()\n            .append(arguments)\n            .append(\") -> \")\n            .append(return_)\n            .append(\")\")\n    }\n\n    /// Print type vars as `any()`.\n    fn var_as_any(mut self) -> Self {\n        self.var_as_any = true;\n        self\n    }\n}\n\nfn find_private_functions_referenced_in_importable_constants(\n    module: &TypedModule,\n) -> im::HashSet<EcoString> {\n    let mut overridden_publicity = im::HashSet::new();\n\n    for constant in &module.definitions.constants {\n        if constant.publicity.is_importable() {\n            find_referenced_private_functions(&constant.value, &mut overridden_publicity)\n        }\n    }\n    overridden_publicity\n}\n\nfn find_referenced_private_functions(\n    constant: &TypedConstant,\n    already_found: &mut im::HashSet<EcoString>,\n) {\n    match constant {\n        Constant::Invalid { .. } => panic!(\"invalid constants should not reach code generation\"),\n        Constant::RecordUpdate { .. } => {\n            panic!(\"record updates should not reach code generation\")\n        }\n\n        Constant::Int { .. }\n        | Constant::Float { .. }\n        | Constant::String { .. }\n        | Constant::BitArray { .. } => (),\n\n        TypedConstant::Var {\n            name, constructor, ..\n        } => {\n            if let Some(ValueConstructor { type_, .. }) = constructor.as_deref()\n                && let Type::Fn { .. } = **type_\n            {\n                let _ = already_found.insert(name.clone());\n            }\n        }\n\n        TypedConstant::Record { arguments, .. } => arguments\n            .iter()\n            .for_each(|argument| find_referenced_private_functions(&argument.value, already_found)),\n\n        TypedConstant::StringConcatenation { left, right, .. } => {\n            find_referenced_private_functions(left, already_found);\n            find_referenced_private_functions(right, already_found);\n        }\n\n        Constant::Tuple { elements, .. } | Constant::List { elements, .. } => elements\n            .iter()\n            .for_each(|element| find_referenced_private_functions(element, already_found)),\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_bun_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `bun` was not found. Is it installed?\n\nDocumentation for installing Bun can be viewed here:\nhttps://bun.sh/docs/installation/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_bun_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `bun` was not found. Is it installed?\n\nDocumentation for installing Bun can be viewed here:\nhttps://bun.sh/docs/installation/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_bun_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `bun` was not found. Is it installed?\n\nYou can install Bun via homebrew: brew install oven-sh/bun/bun\n\nDocumentation for installing Bun can be viewed here:\nhttps://bun.sh/docs/installation/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_deno_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `deno` was not found. Is it installed?\n\nDocumentation for installing Deno can be viewed here:\nhttps://docs.deno.com/runtime/getting_started/installation/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_deno_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `deno` was not found. Is it installed?\n\nDocumentation for installing Deno can be viewed here:\nhttps://docs.deno.com/runtime/getting_started/installation/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_deno_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `deno` was not found. Is it installed?\n\nYou can install Deno via homebrew: brew install deno\n\nDocumentation for installing Deno can be viewed here:\nhttps://docs.deno.com/runtime/getting_started/installation/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_elixir_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `elixir` was not found. Is it installed?\n\nDocumentation for installing Elixir can be viewed here:\nhttps://elixir-lang.org/install.html\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_elixir_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `elixir` was not found. Is it installed?\n\nYou can install Elixir via apt: sudo apt install elixir\n\nDocumentation for installing Elixir can be viewed here:\nhttps://elixir-lang.org/install.html\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_elixir_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `elixir` was not found. Is it installed?\n\nYou can install Elixir via homebrew: brew install elixir\n\nDocumentation for installing Elixir can be viewed here:\nhttps://elixir-lang.org/install.html\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_erlc_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `erlc` was not found. Is it installed?\n\nDocumentation for installing Erlang can be viewed here:\nhttps://gleam.run/getting-started/installing/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_erlc_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `erlc` was not found. Is it installed?\n\nDocumentation for installing Erlang can be viewed here:\nhttps://gleam.run/getting-started/installing/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_erlc_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `erlc` was not found. Is it installed?\n\nYou can install Erlang via homebrew: brew install erlang\n\nDocumentation for installing Erlang can be viewed here:\nhttps://gleam.run/getting-started/installing/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_git_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `git` was not found. Is it installed?\n\nDocumentation for installing Git can be viewed here:\nhttps://git-scm.com/book/en/v2/Getting-Started-Installing-Git\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_git_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `git` was not found. Is it installed?\n\nYou can install Git via apt: sudo apt install git\n\nDocumentation for installing Git can be viewed here:\nhttps://git-scm.com/book/en/v2/Getting-Started-Installing-Git\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_git_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `git` was not found. Is it installed?\n\nYou can install Git via homebrew: brew install git\n\nDocumentation for installing Git can be viewed here:\nhttps://git-scm.com/book/en/v2/Getting-Started-Installing-Git\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_node_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `node` was not found. Is it installed?\n\nDocumentation for installing Node.js via package manager can be viewed here:\nhttps://nodejs.org/en/download/package-manager/all/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_node_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `node` was not found. Is it installed?\n\nDocumentation for installing Node.js via package manager can be viewed here:\nhttps://nodejs.org/en/download/package-manager/all/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_node_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `node` was not found. Is it installed?\n\nYou can install Node.js via homebrew: brew install node\n\nDocumentation for installing Node.js via package manager can be viewed here:\nhttps://nodejs.org/en/download/package-manager/all/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_rebar3_linux_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `rebar3` was not found. Is it installed?\n\nDocumentation for installing Rebar3 can be viewed here:\nhttps://rebar3.org/docs/getting-started/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_rebar3_linux_ubuntu.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `rebar3` was not found. Is it installed?\n\nDocumentation for installing Rebar3 can be viewed here:\nhttps://rebar3.org/docs/getting-started/\n"
  },
  {
    "path": "compiler-core/src/error/snapshots/gleam_core__error__tests__shell_program_not_found_rebar3_macos_other.snap",
    "content": "---\nsource: compiler-core/src/error/tests.rs\nexpression: \"err[0].text\"\n---\nThe program `rebar3` was not found. Is it installed?\n\nYou can install Rebar3 via homebrew: brew install rebar3\n\nDocumentation for installing Rebar3 can be viewed here:\nhttps://rebar3.org/docs/getting-started/\n"
  },
  {
    "path": "compiler-core/src/error/tests.rs",
    "content": "use super::*;\nuse insta::assert_snapshot;\n\n#[test]\nfn test_shell_program_not_found_error() {\n    let cmds = vec![\"erlc\", \"rebar3\", \"deno\", \"elixir\", \"node\", \"bun\", \"git\"];\n    let oses = vec![\"macos\", \"linux\"];\n    let distros = vec![\"ubuntu\", \"other\"];\n\n    for cmd in &cmds {\n        for os in &oses {\n            if os != &\"linux\" {\n                let err = Error::ShellProgramNotFound {\n                    program: cmd.to_string(),\n                    os: parse_os(os, \"other\"),\n                }\n                .to_diagnostics();\n                assert_snapshot!(\n                    format!(\"shell_program_not_found_{cmd}_{os}_other\"),\n                    err[0].text\n                );\n            } else {\n                for distro in &distros {\n                    let err = Error::ShellProgramNotFound {\n                        program: cmd.to_string(),\n                        os: parse_os(os, distro),\n                    }\n                    .to_diagnostics();\n                    assert_snapshot!(\n                        format!(\"shell_program_not_found_{cmd}_{os}_{distro}\"),\n                        err[0].text\n                    );\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/error.rs",
    "content": "#![allow(clippy::unwrap_used, clippy::expect_used)]\nuse crate::bit_array::UnsupportedOption;\nuse crate::build::{Origin, Outcome, Runtime, Target};\nuse crate::dependency::{PackageFetcher, ResolutionError};\nuse crate::diagnostic::{Diagnostic, ExtraLabel, Label, Location};\n\nuse crate::derivation_tree::DerivationTreePrinter;\nuse crate::parse::error::ParseErrorDetails;\nuse crate::strings::{to_snake_case, to_upper_camel_case};\nuse crate::type_::collapse_links;\nuse crate::type_::error::{\n    IncorrectArityContext, InvalidImportKind, MissingAnnotation, ModuleValueUsageContext, Named,\n    RecordField, UnexpectedLabelledArgKind, UnknownField, UnknownTypeHint,\n    UnsafeRecordUpdateReason,\n};\nuse crate::type_::printer::{Names, Printer};\nuse crate::type_::{FieldAccessUsage, error::PatternMatchKind};\nuse crate::{ast::BinOp, parse::error::ParseErrorType, type_::Type};\nuse crate::{bit_array, diagnostic::Level, type_::UnifyErrorSituation};\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse itertools::Itertools;\nuse std::borrow::Cow;\nuse std::fmt::{Debug, Display};\nuse std::io::Write;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse termcolor::Buffer;\nuse thiserror::Error;\nuse vec1::Vec1;\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\npub type Name = EcoString;\n\npub type Result<Ok, Err = Error> = std::result::Result<Ok, Err>;\n\n#[cfg(test)]\npub mod tests;\n\nmacro_rules! wrap_format {\n    ($($tts:tt)*) => {\n        wrap(&format!($($tts)*))\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct UnknownImportDetails {\n    pub module: Name,\n    pub location: crate::ast::SrcSpan,\n    pub path: Utf8PathBuf,\n    pub src: EcoString,\n    pub modules: Vec<EcoString>,\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct ImportCycleLocationDetails {\n    pub location: crate::ast::SrcSpan,\n    pub path: Utf8PathBuf,\n    pub src: EcoString,\n}\n\n/// Describes where a defined module comes from.\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct DefinedModuleOrigin {\n    /// The package defining the module\n    pub package_name: EcoString,\n    /// The path to the module\n    pub path: Utf8PathBuf,\n}\n\n#[derive(Debug, Eq, PartialEq, Error, Clone)]\npub enum Error {\n    #[error(\"failed to parse Gleam source code\")]\n    Parse {\n        path: Utf8PathBuf,\n        src: EcoString,\n        error: Box<crate::parse::error::ParseError>,\n    },\n\n    #[error(\"type checking failed\")]\n    Type {\n        path: Utf8PathBuf,\n        src: EcoString,\n        errors: Vec1<crate::type_::Error>,\n        names: Box<Names>,\n    },\n\n    #[error(\"unknown import {import}\")]\n    UnknownImport {\n        import: EcoString,\n        // Boxed to prevent this variant from being overly large\n        details: Box<UnknownImportDetails>,\n    },\n\n    #[error(\"duplicate module {module}\")]\n    DuplicateModule {\n        module: Name,\n        first: DefinedModuleOrigin,\n        second: DefinedModuleOrigin,\n    },\n\n    #[error(\"duplicate source file {file}\")]\n    DuplicateSourceFile { file: String },\n\n    #[error(\"duplicate native Erlang module {module}\")]\n    DuplicateNativeErlangModule {\n        module: Name,\n        first: Utf8PathBuf,\n        second: Utf8PathBuf,\n    },\n\n    #[error(\"gleam module {module} clashes with native file of same name\")]\n    ClashingGleamModuleAndNativeFileName {\n        module: Name,\n        gleam_file: Utf8PathBuf,\n        native_file: Utf8PathBuf,\n    },\n\n    #[error(\"cyclical module imports\")]\n    ImportCycle {\n        modules: Vec1<(EcoString, ImportCycleLocationDetails)>,\n    },\n\n    #[error(\"cyclical package dependencies\")]\n    PackageCycle { packages: Vec<EcoString> },\n\n    #[error(\"{action:?} {path:?} failed: {err:?}\")]\n    FileIo {\n        kind: FileKind,\n        action: FileIoAction,\n        path: Utf8PathBuf,\n        err: Option<String>,\n    },\n\n    #[error(\"Non Utf-8 Path: {path}\")]\n    NonUtf8Path { path: PathBuf },\n\n    #[error(\"{error}\")]\n    GitInitialization { error: String },\n\n    #[error(\"io operation failed\")]\n    StandardIo {\n        action: StandardIoAction,\n        err: Option<std::io::ErrorKind>,\n    },\n\n    #[error(\"source code incorrectly formatted\")]\n    Format { problem_files: Vec<Unformatted> },\n\n    #[error(\"Hex error: {0}\")]\n    Hex(String),\n\n    #[error(\"{error}\")]\n    ExpandTar { error: String },\n\n    #[error(\"{err}\")]\n    AddTar { path: Utf8PathBuf, err: String },\n\n    #[error(\"{0}\")]\n    TarFinish(String),\n\n    #[error(\"{0}\")]\n    Gzip(String),\n\n    #[error(\"shell program `{program}` not found\")]\n    ShellProgramNotFound { program: String, os: OS },\n\n    #[error(\"shell program `{program}` failed\")]\n    ShellCommand {\n        program: String,\n        reason: ShellCommandFailureReason,\n    },\n\n    #[error(\"{name} is not a valid project name\")]\n    InvalidProjectName {\n        name: String,\n        reason: InvalidProjectNameReason,\n    },\n\n    #[error(\"{module} is not a valid module name\")]\n    InvalidModuleName { module: String },\n\n    #[error(\"{module} is not module\")]\n    ModuleDoesNotExist {\n        module: EcoString,\n        suggestion: Option<EcoString>,\n    },\n\n    #[error(\"{module} does not have a main function\")]\n    ModuleDoesNotHaveMainFunction { module: EcoString, origin: Origin },\n\n    #[error(\"{module} does not have a public main function\")]\n    MainFunctionIsPrivate { module: EcoString },\n\n    #[error(\"{module}'s main function has the wrong arity so it can not be run\")]\n    MainFunctionHasWrongArity { module: EcoString, arity: usize },\n\n    #[error(\"{module}'s main function does not support the current target\")]\n    MainFunctionDoesNotSupportTarget { module: EcoString, target: Target },\n\n    #[error(\"{input} is not a valid version. {error}\")]\n    InvalidVersionFormat { input: String, error: String },\n\n    #[error(\"incompatible locked version. {error}\")]\n    IncompatibleLockedVersion { error: String },\n\n    #[error(\"project root already exists\")]\n    ProjectRootAlreadyExist { path: String },\n\n    #[error(\"File(s) already exist in {}\",\nfile_names.iter().map(|x| x.as_str()).join(\", \"))]\n    OutputFilesAlreadyExist { file_names: Vec<Utf8PathBuf> },\n\n    #[error(\"Packages not exist: {}\", packages.iter().join(\", \"))]\n    RemovedPackagesNotExist { packages: Vec<String> },\n\n    #[error(\"Packages to update not exist: {}\", packages.iter().join(\", \"))]\n    PackagesToUpdateNotExist { packages: Vec<EcoString> },\n\n    #[error(\"unable to find project root\")]\n    UnableToFindProjectRoot { path: String },\n\n    #[error(\"gleam.toml version {toml_ver} does not match .app version {app_ver}\")]\n    VersionDoesNotMatch { toml_ver: String, app_ver: String },\n\n    #[error(\"warnings are not permitted\")]\n    ForbiddenWarnings { count: usize },\n\n    #[error(\"Invalid runtime for target {target:?}: {invalid_runtime:?}\")]\n    InvalidRuntime {\n        target: Target,\n        invalid_runtime: Runtime,\n    },\n\n    #[error(\"package downloading failed: {error}\")]\n    DownloadPackageError {\n        package_name: String,\n        package_version: String,\n        error: String,\n    },\n\n    #[error(\"{0}\")]\n    Http(String),\n\n    #[error(\"Failed to create canonical path for package {0}\")]\n    DependencyCanonicalizationFailed(String),\n\n    #[error(\"Could not find versions that satisfy dependency requirements\")]\n    DependencyResolutionNoSolution {\n        root_package_name: EcoString,\n        derivation_tree:\n            Box<NeverEqual<pubgrub::DerivationTree<String, pubgrub::Ranges<Version>, String>>>,\n    },\n\n    #[error(\"Dependency resolution failed: {0}\")]\n    DependencyResolutionError(String),\n\n    #[error(\"The package {0} is listed in dependencies and dev_dependencies\")]\n    DuplicateDependency(EcoString),\n\n    #[error(\"Expected package {expected} at path {path} but found {found} instead\")]\n    WrongDependencyProvided {\n        path: Utf8PathBuf,\n        expected: String,\n        found: String,\n    },\n\n    #[error(\"The package {package} is provided multiple times, as {source_1} and {source_2}\")]\n    ProvidedDependencyConflict {\n        package: String,\n        source_1: String,\n        source_2: String,\n    },\n\n    #[error(\"The package was missing required fields for publishing\")]\n    MissingHexPublishFields {\n        description_missing: bool,\n        licence_missing: bool,\n    },\n\n    #[error(\"Dependency {package:?} has not been published to Hex\")]\n    PublishNonHexDependencies { package: String },\n\n    #[error(\"The package {package} uses unsupported build tools {build_tools:?}\")]\n    UnsupportedBuildTool {\n        package: String,\n        build_tools: Vec<EcoString>,\n    },\n\n    #[error(\"Opening docs at {path} failed: {error}\")]\n    FailedToOpenDocs { path: Utf8PathBuf, error: String },\n\n    #[error(\n        \"The package {package} requires a Gleam version satisfying \\\n{required_version} and you are using v{gleam_version}\"\n    )]\n    IncompatibleCompilerVersion {\n        package: String,\n        required_version: String,\n        gleam_version: String,\n    },\n\n    #[error(\"The --javascript-prelude flag must be given when compiling to JavaScript\")]\n    JavaScriptPreludeRequired,\n\n    #[error(\"The modules {unfinished:?} contain todo expressions and so cannot be published\")]\n    CannotPublishTodo { unfinished: Vec<EcoString> },\n\n    #[error(\"The modules {unfinished:?} contain todo expressions and so cannot be published\")]\n    CannotPublishEcho { unfinished: Vec<EcoString> },\n\n    #[error(\n        \"The modules {unfinished:?} contain internal types in their public API so cannot be published\"\n    )]\n    CannotPublishLeakedInternalType { unfinished: Vec<EcoString> },\n\n    #[error(\"The modules {unfinished:?} are empty and so cannot be published\")]\n    CannotPublishEmptyModules { unfinished: Vec<EcoString> },\n\n    #[error(\"Publishing packages with an invalid README is not permitted\")]\n    CannotPublishWithInvalidReadme { reason: InvalidReadmeReason },\n\n    #[error(\"Publishing packages to reserve names is not permitted\")]\n    HexPackageSquatting,\n\n    #[error(\"The package includes the default main function so cannot be published\")]\n    CannotPublishWithDefaultMain { package_name: EcoString },\n\n    #[error(\"Corrupt manifest.toml\")]\n    CorruptManifest,\n\n    #[error(\"The Gleam module {path} would overwrite the Erlang module {name}\")]\n    GleamModuleWouldOverwriteStandardErlangModule { name: EcoString, path: Utf8PathBuf },\n\n    #[error(\"Version already published\")]\n    HexPublishReplaceRequired { version: String },\n\n    #[error(\"Insufficient permissions to publish {name} {version}\")]\n    HexPublishAccessDenied { name: String, version: String },\n\n    #[error(\"The gleam version constraint is wrong and so cannot be published\")]\n    CannotPublishWrongVersion {\n        minimum_required_version: SmallVersion,\n        wrongfully_allowed_version: SmallVersion,\n    },\n\n    #[error(\"Failed to encrypt local Hex API key\")]\n    FailedToEncryptLocalHexApiKey { detail: String },\n\n    #[error(\"Failed to decrypt local Hex API key\")]\n    FailedToDecryptLocalHexApiKey { detail: String },\n\n    #[error(\"Cannot add a package with the same name as a dependency\")]\n    CannotAddSelfAsDependency { name: EcoString },\n\n    #[error(\"Incorrect Hex one-time-password\")]\n    IncorrectHexOneTimePassword,\n}\n\n#[derive(Debug, Eq, PartialEq, Clone, Copy)]\npub enum InvalidReadmeReason {\n    Missing,\n    Empty,\n    Default,\n}\n\n// A wrapper that ignores the inner value for equality:\n#[derive(Debug, Clone)]\npub struct NeverEqual<T>(pub T);\n\nimpl<T> PartialEq for NeverEqual<T> {\n    fn eq(&self, _other: &Self) -> bool {\n        false\n    }\n}\nimpl<T> Eq for NeverEqual<T> {}\n\n/// This is to make clippy happy and not make the error variant too big by\n/// storing an entire `hexpm::version::Version` in the error.\n///\n/// This is enough to report wrong Gleam compiler versions.\n///\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct SmallVersion {\n    major: u8,\n    minor: u8,\n    patch: u8,\n}\n\nimpl Display for SmallVersion {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(&format!(\"{}.{}.{}\", self.major, self.minor, self.patch))\n    }\n}\n\nimpl SmallVersion {\n    pub fn from_hexpm(version: Version) -> Self {\n        Self {\n            major: version.major as u8,\n            minor: version.minor as u8,\n            patch: version.patch as u8,\n        }\n    }\n}\n#[derive(Debug, Clone, Eq, PartialEq, Copy)]\npub enum OS {\n    Linux(Distro),\n    MacOS,\n    Windows,\n    Other,\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Copy)]\npub enum Distro {\n    Ubuntu,\n    Debian,\n    Other,\n}\n\npub fn parse_os(os: &str, distro: &str) -> OS {\n    match os {\n        \"macos\" => OS::MacOS,\n        \"windows\" => OS::Windows,\n        \"linux\" => OS::Linux(parse_linux_distribution(distro)),\n        _ => OS::Other,\n    }\n}\n\npub fn parse_linux_distribution(distro: &str) -> Distro {\n    match distro {\n        \"ubuntu\" => Distro::Ubuntu,\n        \"debian\" => Distro::Debian,\n        _ => Distro::Other,\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone)]\npub enum ShellCommandFailureReason {\n    /// When we don't have any context about the failure\n    Unknown,\n    /// When the actual running of the command failed for some reason.\n    IoError(std::io::ErrorKind),\n    /// When the shell command returned an error status\n    ShellCommandError(String),\n}\n\nimpl Error {\n    pub fn http<E>(error: E) -> Error\n    where\n        E: std::error::Error,\n    {\n        Self::Http(error.to_string())\n    }\n\n    pub fn hex(error: hexpm::ApiError) -> Error {\n        match error {\n            hexpm::ApiError::Json(_)\n            | hexpm::ApiError::Io(_)\n            | hexpm::ApiError::RateLimited\n            | hexpm::ApiError::InvalidCredentials\n            | hexpm::ApiError::UnexpectedResponse(_, _)\n            | hexpm::ApiError::InvalidPackageNameFormat(_)\n            | hexpm::ApiError::IncorrectPayloadSignature\n            | hexpm::ApiError::InvalidProtobuf(_)\n            | hexpm::ApiError::InvalidVersionFormat(_)\n            | hexpm::ApiError::NotFound\n            | hexpm::ApiError::InvalidVersionRequirementFormat(_)\n            | hexpm::ApiError::IncorrectChecksum\n            | hexpm::ApiError::Forbidden\n            | hexpm::ApiError::NotReplacing\n            | hexpm::ApiError::LateModification\n            | hexpm::ApiError::OAuthTimeout\n            | hexpm::ApiError::OAuthAccessDenied\n            | hexpm::ApiError::ExpiredToken\n            | hexpm::ApiError::OAuthRefreshTokenRejected => Self::Hex(error.to_string()),\n\n            hexpm::ApiError::IncorrectOneTimePassword => Self::IncorrectHexOneTimePassword,\n        }\n    }\n\n    pub fn add_tar<P, E>(path: P, error: E) -> Error\n    where\n        P: AsRef<Utf8Path>,\n        E: std::error::Error,\n    {\n        Self::AddTar {\n            path: path.as_ref().to_path_buf(),\n            err: error.to_string(),\n        }\n    }\n\n    pub fn finish_tar<E>(error: E) -> Error\n    where\n        E: std::error::Error,\n    {\n        Self::TarFinish(error.to_string())\n    }\n\n    pub fn dependency_resolution_failed<T: PackageFetcher>(\n        error: ResolutionError<'_, T>,\n        root_package_name: EcoString,\n    ) -> Error {\n        match error {\n            ResolutionError::NoSolution(derivation_tree) => Self::DependencyResolutionNoSolution {\n                root_package_name,\n                derivation_tree: Box::new(NeverEqual(derivation_tree)),\n            },\n\n            ResolutionError::ErrorRetrievingDependencies {\n                package,\n                version,\n                source,\n            } => Self::DependencyResolutionError(format!(\n                \"An error occurred while trying to retrieve dependencies of {package}@{version}: {source}\",\n            )),\n\n            ResolutionError::ErrorChoosingVersion { package, source } => {\n                Self::DependencyResolutionError(format!(\n                    \"An error occurred while choosing the version of {package}: {source}\",\n                ))\n            }\n\n            ResolutionError::ErrorInShouldCancel(err) => Self::DependencyResolutionError(format!(\n                \"Dependency resolution was cancelled. {err}\"\n            )),\n        }\n    }\n\n    pub fn expand_tar<E>(error: E) -> Error\n    where\n        E: std::error::Error,\n    {\n        Self::ExpandTar {\n            error: error.to_string(),\n        }\n    }\n}\n\nimpl<T> From<Error> for Outcome<T, Error> {\n    fn from(error: Error) -> Self {\n        Outcome::TotalFailure(error)\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum InvalidProjectNameReason {\n    Format,\n    FormatNotLowercase,\n    GleamPrefix,\n    ErlangReservedWord,\n    ErlangStandardLibraryModule,\n    GleamReservedWord,\n    GleamReservedModule,\n}\n\npub fn format_invalid_project_name_error(\n    name: &str,\n    reason: &InvalidProjectNameReason,\n    with_suggestion: &Option<String>,\n) -> String {\n    let reason_message = match reason {\n        InvalidProjectNameReason::ErlangReservedWord => \"is a reserved word in Erlang.\",\n        InvalidProjectNameReason::ErlangStandardLibraryModule => {\n            \"is a standard library module in Erlang.\"\n        }\n        InvalidProjectNameReason::GleamReservedWord => \"is a reserved word in Gleam.\",\n        InvalidProjectNameReason::GleamReservedModule => \"is a reserved module name in Gleam.\",\n        InvalidProjectNameReason::FormatNotLowercase => {\n            \"does not have the correct format. Project names \\\nmay only contain lowercase letters.\"\n        }\n        InvalidProjectNameReason::Format => {\n            \"does not have the correct format. Project names \\\nmust start with a lowercase letter and may only contain lowercase letters, \\\nnumbers and underscores.\"\n        }\n        InvalidProjectNameReason::GleamPrefix => {\n            \"has the reserved prefix `gleam_`. \\\nThis prefix is intended for official Gleam packages only.\"\n        }\n    };\n\n    match with_suggestion {\n        Some(suggested_name) => wrap_format!(\n            \"We were not able to create your project as `{}` {}\n\nWould you like to name your project '{}' instead?\",\n            name,\n            reason_message,\n            suggested_name\n        ),\n        None => wrap_format!(\n            \"We were not able to create your project as `{}` {}\n\nPlease try again with a different project name.\",\n            name,\n            reason_message\n        ),\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum StandardIoAction {\n    Read,\n    Write,\n}\n\nimpl StandardIoAction {\n    fn text(&self) -> &'static str {\n        match self {\n            StandardIoAction::Read => \"read from\",\n            StandardIoAction::Write => \"write to\",\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum FileIoAction {\n    Link,\n    Open,\n    Copy,\n    Read,\n    Parse,\n    Delete,\n    // Rename,\n    Create,\n    WriteTo,\n    Canonicalise,\n    UpdatePermissions,\n    FindParent,\n    ReadMetadata,\n}\n\nimpl FileIoAction {\n    fn text(&self) -> &'static str {\n        match self {\n            FileIoAction::Link => \"link\",\n            FileIoAction::Open => \"open\",\n            FileIoAction::Copy => \"copy\",\n            FileIoAction::Read => \"read\",\n            FileIoAction::Parse => \"parse\",\n            FileIoAction::Delete => \"delete\",\n            // FileIoAction::Rename => \"rename\",\n            FileIoAction::Create => \"create\",\n            FileIoAction::WriteTo => \"write to\",\n            FileIoAction::FindParent => \"find the parent of\",\n            FileIoAction::Canonicalise => \"canonicalise\",\n            FileIoAction::UpdatePermissions => \"update permissions of\",\n            FileIoAction::ReadMetadata => \"read metadata of\",\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum FileKind {\n    File,\n    Directory,\n}\n\nimpl FileKind {\n    fn text(&self) -> &'static str {\n        match self {\n            FileKind::File => \"file\",\n            FileKind::Directory => \"directory\",\n        }\n    }\n}\n\n// https://github.com/rust-lang/rust/blob/03994e498df79aa1f97f7bbcfd52d57c8e865049/compiler/rustc_span/src/edit_distance.rs\npub fn edit_distance(a: &str, b: &str, limit: usize) -> Option<usize> {\n    let mut a = &a.chars().collect::<Vec<_>>()[..];\n    let mut b = &b.chars().collect::<Vec<_>>()[..];\n\n    if a.len() < b.len() {\n        std::mem::swap(&mut a, &mut b);\n    }\n\n    let min_dist = a.len() - b.len();\n    // If we know the limit will be exceeded, we can return early.\n    if min_dist > limit {\n        return None;\n    }\n\n    // Strip common prefix.\n    while !b.is_empty() && !a.is_empty() {\n        let (b_first, b_rest) = b.split_last().expect(\"Failed to split 'b' slice\");\n        let (a_first, a_rest) = a.split_last().expect(\"Failed to split 'a' slice\");\n\n        if b_first == a_first {\n            a = a_rest;\n            b = b_rest;\n        } else {\n            break;\n        }\n    }\n\n    // If either string is empty, the distance is the length of the other.\n    // We know that `b` is the shorter string, so we don't need to check `a`.\n    if b.is_empty() {\n        return Some(min_dist);\n    }\n\n    let mut prev_prev = vec![usize::MAX; b.len() + 1];\n    let mut prev = (0..=b.len()).collect::<Vec<_>>();\n    let mut current = vec![0; b.len() + 1];\n\n    // row by row\n    for i in 1..=a.len() {\n        if let Some(element) = current.get_mut(0) {\n            *element = i;\n        }\n        let a_idx = i - 1;\n\n        // column by column\n        for j in 1..=b.len() {\n            let b_idx = j - 1;\n\n            // There is no cost to substitute a character with itself.\n            let substitution_cost = match (a.get(a_idx), b.get(b_idx)) {\n                (Some(&a_char), Some(&b_char)) => {\n                    if a_char == b_char {\n                        0\n                    } else {\n                        1\n                    }\n                }\n                _ => panic!(\"Index out of bounds\"),\n            };\n\n            let insertion = current.get(j - 1).map_or(usize::MAX, |&x| x + 1);\n\n            if let Some(value) = current.get_mut(j) {\n                *value = std::cmp::min(\n                    // deletion\n                    prev.get(j).map_or(usize::MAX, |&x| x + 1),\n                    std::cmp::min(\n                        // insertion\n                        insertion,\n                        // substitution\n                        prev.get(j - 1)\n                            .map_or(usize::MAX, |&x| x + substitution_cost),\n                    ),\n                );\n            }\n\n            if (i > 1)\n                && (j > 1)\n                && let (Some(&a_val), Some(&b_val_prev), Some(&a_val_prev), Some(&b_val)) = (\n                    a.get(a_idx),\n                    b.get(b_idx - 1),\n                    a.get(a_idx - 1),\n                    b.get(b_idx),\n                )\n                && (a_val == b_val_prev)\n                && (a_val_prev == b_val)\n            {\n                // transposition\n                if let Some(curr) = current.get_mut(j)\n                    && let Some(&prev_prev_val) = prev_prev.get(j - 2)\n                {\n                    *curr = std::cmp::min(*curr, prev_prev_val + 1);\n                }\n            }\n        }\n\n        // Rotate the buffers, reusing the memory.\n        [prev_prev, prev, current] = [prev, current, prev_prev];\n    }\n\n    // `prev` because we already rotated the buffers.\n    let distance = match prev.get(b.len()) {\n        Some(&d) => d,\n        None => usize::MAX,\n    };\n    (distance <= limit).then_some(distance)\n}\n\nfn edit_distance_with_substrings(a: &str, b: &str, limit: usize) -> Option<usize> {\n    let n = a.chars().count();\n    let m = b.chars().count();\n\n    // Check one isn't less than half the length of the other. If this is true then there is a\n    // big difference in length.\n    let big_len_diff = (n * 2) < m || (m * 2) < n;\n    let len_diff = m.abs_diff(n);\n    let distance = edit_distance(a, b, limit + len_diff)?;\n\n    // This is the crux, subtracting length difference means exact substring matches will now be 0\n    let score = distance - len_diff;\n\n    // If the score is 0 but the words have different lengths then it's a substring match not a full\n    // word match\n    let score = if score == 0 && len_diff > 0 && !big_len_diff {\n        1 // Exact substring match, but not a total word match so return non-zero\n    } else if !big_len_diff {\n        // Not a big difference in length, discount cost of length difference\n        score + len_diff.div_ceil(2)\n    } else {\n        // A big difference in length, add back the difference in length to the score\n        score + len_diff\n    };\n\n    (score <= limit).then_some(score)\n}\n\nfn did_you_mean(name: &str, options: &[EcoString]) -> Option<String> {\n    // If only one option is given, return that option.\n    // This seems to solve the `unknown_variable_3` test.\n    if options.len() == 1 {\n        return options\n            .first()\n            .map(|option| format!(\"Did you mean `{option}`?\"));\n    }\n\n    // Check for case-insensitive matches.\n    // This solves the comparison to small and single character terms,\n    // such as the test on `type_vars_must_be_declared`.\n    if let Some(exact_match) = options\n        .iter()\n        .find(|&option| option.eq_ignore_ascii_case(name))\n    {\n        return Some(format!(\"Did you mean `{exact_match}`?\"));\n    }\n\n    // Calculate the threshold as one third of the name's length, with a minimum of 1.\n    let threshold = std::cmp::max(name.chars().count() / 3, 1);\n\n    // Filter and sort options based on edit distance.\n    options\n        .iter()\n        .filter(|&option| option != crate::ast::CAPTURE_VARIABLE)\n        .sorted()\n        .filter_map(|option| {\n            edit_distance_with_substrings(option, name, threshold)\n                .map(|distance| (option, distance))\n        })\n        .min_by_key(|&(_, distance)| distance)\n        .map(|(option, _)| format!(\"Did you mean `{option}`?\"))\n}\n\nfn to_ordinal(value: u32) -> String {\n    match value % 10 {\n        // All numbers starting with 1 end in `th` (11th, 12th, 13th, etc.)\n        _ if value / 10 == 1 => format!(\"{value}th\"),\n        1 => format!(\"{value}st\"),\n        2 => format!(\"{value}nd\"),\n        3 => format!(\"{value}rd\"),\n        _ => format!(\"{value}th\"),\n    }\n}\n\nimpl Error {\n    pub fn pretty_string(&self) -> String {\n        let mut nocolor = Buffer::no_color();\n        self.pretty(&mut nocolor);\n        String::from_utf8(nocolor.into_inner()).expect(\"Error printing produced invalid utf8\")\n    }\n\n    pub fn pretty(&self, buffer: &mut Buffer) {\n        for diagnostic in self.to_diagnostics() {\n            diagnostic.write(buffer);\n            writeln!(buffer).expect(\"write new line after diagnostic\");\n        }\n    }\n\n    pub fn to_diagnostics(&self) -> Vec<Diagnostic> {\n        use crate::type_::Error as TypeError;\n        match self {\n            Error::IncorrectHexOneTimePassword => {\n                let text =\n                    \"That two-factor authentication code was rejected by Hex, please try again.\n\nIf you need to reconfigure your Hex two-factor security it can be done\nvia the Hex website: https://hex.pm/dashboard/security\n\"\n                    .into();\n\n                vec![Diagnostic {\n                    title: \"Incorrect two-factor authentication code\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: None,\n                }]\n            }\n\n            Error::HexPackageSquatting => {\n                let text =\n                    \"You appear to be attempting to reserve a name on Hex rather than publishing a\nworking package. This is against the Hex terms of service and can result in\npackage deletion or account suspension.\n\"\n                    .into();\n\n                vec![Diagnostic {\n                    title: \"Invalid Hex package\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: None,\n                }]\n            }\n\n            Error::CannotPublishWithInvalidReadme {\n                reason: InvalidReadmeReason::Default,\n            } => {\n                let text =\n                    \"You appear to be attempting to publish a package with the default README\ngenerated by the `gleam new` command. That is meant as a placeholder and a\npublished package should have its own carefully written README.\n\"\n                    .into();\n\n                vec![Diagnostic {\n                    title: \"Cannot publish with default README\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: Some(\n                        \"Update your project's README to describe it before publishing\".into(),\n                    ),\n                }]\n            }\n\n            Error::CannotPublishWithInvalidReadme {\n                reason: InvalidReadmeReason::Missing,\n            } => {\n                let text = \"You appear to be attempting to publish a package with no README.\nAll published packages should have one.\n\"\n                .into();\n\n                vec![Diagnostic {\n                    title: \"Cannot publish with no README\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: Some(\"Add a README to your project before publishing.\".into()),\n                }]\n            }\n\n            Error::CannotPublishWithInvalidReadme {\n                reason: InvalidReadmeReason::Empty,\n            } => {\n                let text = \"You appear to be attempting to publish a package with an empty README.\nAll published packages should have a non empty README.\n\"\n                .into();\n\n                vec![Diagnostic {\n                    title: \"Cannot publish with empty README\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: Some(\n                        \"Update your project's README to describe it before publishing\".into(),\n                    ),\n                }]\n            }\n\n            Error::CannotPublishWithDefaultMain { package_name } => {\n                let text = wrap_format!(\n                    \"Packages with the default main function cannot be published\n\nRemove or modify the main function that contains only:\n    `io.println(\\\"Hello from {package_name}!\\\")`\"\n                );\n\n                vec![Diagnostic {\n                    title: \"Cannot publish with default main function\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: None,\n                }]\n            }\n\n            Error::InvalidProjectName { name, reason } => {\n                let text = format_invalid_project_name_error(name, reason, &None);\n\n                vec![Diagnostic {\n                    title: \"Invalid project name\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::InvalidModuleName { module } => vec![Diagnostic {\n                title: \"Invalid module name\".into(),\n                text: format!(\n                    \"`{module}` is not a valid module name.\nModule names can only contain lowercase letters, underscore, and\nforward slash and must not end with a slash.\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: None,\n            }],\n\n            Error::ModuleDoesNotExist { module, suggestion } => {\n                let hint = match suggestion {\n                    Some(suggestion) => format!(\"Did you mean `{suggestion}`?\"),\n                    None => format!(\"Try creating the file `src/{module}.gleam`.\"),\n                };\n                vec![Diagnostic {\n                    title: \"Module does not exist\".into(),\n                    text: format!(\"Module `{module}` was not found.\"),\n                    level: Level::Error,\n                    location: None,\n                    hint: Some(hint),\n                }]\n            }\n\n            Error::ModuleDoesNotHaveMainFunction { module, origin } => vec![Diagnostic {\n                title: \"Module does not have a main function\".into(),\n                text: format!(\n                    \"`{module}` does not have a main function so the module can not be run.\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: Some(format!(\n                    \"Add a public `main` function to `{}/{module}.gleam`.\",\n                    origin.folder_name()\n                )),\n            }],\n\n            Error::MainFunctionIsPrivate { module } => vec![Diagnostic {\n                title: \"Module does not have a public main function\".into(),\n                text: wrap_format!(\n                    \"`{module}` has a main function, but it is private, so it cannot be run.\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: Some(wrap_format!(\n                    \"Make the `main` function in the `{module}` module public.\"\n                )),\n            }],\n\n            Error::MainFunctionDoesNotSupportTarget { module, target } => vec![Diagnostic {\n                title: \"Target not supported\".into(),\n                text: wrap_format!(\n                    \"`{module}` has a main function, but it does not support the {target} \\\ntarget, so it cannot be run.\",\n                    target = target.as_presentable_str(),\n                ),\n                level: Level::Error,\n                location: None,\n                hint: None,\n            }],\n\n            Error::MainFunctionHasWrongArity { module, arity } => vec![Diagnostic {\n                title: \"Main function has wrong arity\".into(),\n                text: wrap_format!(\n                    \"`{module}:main` should have an arity of 0 to be run but its arity is {arity}.\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: Some(\"Change the function signature of main to `pub fn main() {}`.\".into()),\n            }],\n\n            Error::ProjectRootAlreadyExist { path } => vec![Diagnostic {\n                title: \"Project folder already exists\".into(),\n                text: format!(\"Project folder root:\\n\\n  {path}\"),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::OutputFilesAlreadyExist { file_names } => vec![Diagnostic {\n                title: format!(\n                    \"{} already exist{} in target directory\",\n                    if file_names.len() == 1 {\n                        \"File\"\n                    } else {\n                        \"Files\"\n                    },\n                    if file_names.len() == 1 { \"\" } else { \"s\" }\n                ),\n                text: format!(\n                    \"{}\nIf you want to overwrite these files, delete them and run the command again.\n\",\n                    file_names\n                        .iter()\n                        .map(|name| format!(\"  - {}\", name.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::RemovedPackagesNotExist { packages } => vec![Diagnostic {\n                title: \"Package not found\".into(),\n                text: format!(\n                    \"These packages are not dependencies of your package so they could not\nbe removed.\n\n{}\n\",\n                    packages\n                        .iter()\n                        .map(|p| format!(\"  - {}\", p.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::PackagesToUpdateNotExist { packages } => vec![Diagnostic {\n                title: \"Packages to update not found\".into(),\n                text: format!(\n                    \"These packages are not dependencies of your package so they could not\nbe updated.\n\n{}\n\",\n                    packages\n                        .iter()\n                        .map(|p| format!(\"  - {}\", p.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::CannotPublishTodo { unfinished } => vec![Diagnostic {\n                title: \"Cannot publish unfinished code\".into(),\n                text: format!(\n                    \"These modules contain todo expressions and cannot be published:\n\n{}\n\nPlease remove them and try again.\n\",\n                    unfinished\n                        .iter()\n                        .map(|name| format!(\"  - {}\", name.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::CannotPublishEcho { unfinished } => vec![Diagnostic {\n                title: \"Cannot publish unfinished code\".into(),\n                text: format!(\n                    \"These modules contain echo expressions and cannot be published:\n\n{}\n\n`echo` is only meant for debug printing, please remove them and try again.\n\",\n                    unfinished\n                        .iter()\n                        .map(|name| format!(\"  - {}\", name.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::CannotPublishWrongVersion {\n                minimum_required_version,\n                wrongfully_allowed_version,\n            } => vec![Diagnostic {\n                title: \"Cannot publish package with wrong Gleam version range\".into(),\n                text: wrap(&format!(\n                    \"Your package uses features that require at least v{minimum_required_version}.\nBut the Gleam version range specified in your `gleam.toml` would allow this \\\ncode to run on an earlier version like v{wrongfully_allowed_version}, \\\nresulting in compilation errors!\"\n                )),\n                level: Level::Error,\n                hint: Some(format!(\n                    \"Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \\\">= {minimum_required_version}\\\"\"\n                )),\n                location: None,\n            }],\n\n            Error::CannotPublishLeakedInternalType { unfinished } => vec![Diagnostic {\n                title: \"Cannot publish unfinished code\".into(),\n                text: format!(\n                    \"These modules leak internal types in their public API and cannot be published:\n\n{}\n\nPlease make sure internal types do not appear in public functions and try again.\n\",\n                    unfinished\n                        .iter()\n                        .map(|name| format!(\"  - {}\", name.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::CannotPublishEmptyModules { unfinished } => vec![Diagnostic {\n                title: \"Cannot publish empty modules\".into(),\n                text: wrap_format!(\n                    \"These modules contain no public definitions and cannot be published:\n\n{}\n\nPlease add public functions, types, or constants to these modules, or remove them and try again.\",\n                    unfinished\n                        .iter()\n                        .map(|name| format!(\"  - {}\", name.as_str()))\n                        .join(\"\\n\")\n                ),\n                level: Level::Error,\n                hint: None,\n                location: None,\n            }],\n\n            Error::UnableToFindProjectRoot { path } => {\n                let text = wrap_format!(\n                    \"We were unable to find gleam.toml.\n\nWe searched in {path} and all parent directories.\"\n                );\n                vec![Diagnostic {\n                    title: \"Project not found\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::VersionDoesNotMatch { toml_ver, app_ver } => {\n                let text = format!(\n                    \"The version in gleam.toml \\\"{toml_ver}\\\" does not match the version in\nyour app.src file \\\"{app_ver}\\\".\"\n                );\n                vec![Diagnostic {\n                    title: \"Version does not match\".into(),\n                    hint: None,\n                    text,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::ShellProgramNotFound { program, os } => {\n                let mut text = format!(\"The program `{program}` was not found. Is it installed?\");\n\n                match os {\n                    OS::MacOS => {\n                        fn brew_install(name: &str, pkg: &str) -> String {\n                            format!(\"\\n\\nYou can install {name} via homebrew: brew install {pkg}\",)\n                        }\n                        match program.as_str() {\n                            \"erl\" | \"erlc\" | \"escript\" => {\n                                text.push_str(&brew_install(\"Erlang\", \"erlang\"))\n                            }\n                            \"rebar3\" => text.push_str(&brew_install(\"Rebar3\", \"rebar3\")),\n                            \"deno\" => text.push_str(&brew_install(\"Deno\", \"deno\")),\n                            \"elixir\" => text.push_str(&brew_install(\"Elixir\", \"elixir\")),\n                            \"node\" => text.push_str(&brew_install(\"Node.js\", \"node\")),\n                            \"bun\" => text.push_str(&brew_install(\"Bun\", \"oven-sh/bun/bun\")),\n                            \"git\" => text.push_str(&brew_install(\"Git\", \"git\")),\n                            _ => (),\n                        }\n                    }\n                    OS::Linux(distro) => {\n                        fn apt_install(name: &str, pkg: &str) -> String {\n                            format!(\"\\n\\nYou can install {name} via apt: sudo apt install {pkg}\")\n                        }\n                        match distro {\n                            Distro::Ubuntu | Distro::Debian => match program.as_str() {\n                                \"elixir\" => text.push_str(&apt_install(\"Elixir\", \"elixir\")),\n                                \"git\" => text.push_str(&apt_install(\"Git\", \"git\")),\n                                _ => (),\n                            },\n                            Distro::Other => (),\n                        }\n                    }\n                    OS::Windows | OS::Other => (),\n                }\n\n                text.push('\\n');\n\n                match program.as_str() {\n                    \"erl\" | \"erlc\" | \"escript\" => text.push_str(\n                        \"\nDocumentation for installing Erlang can be viewed here:\nhttps://gleam.run/getting-started/installing/\",\n                    ),\n                    \"rebar3\" => text.push_str(\n                        \"\nDocumentation for installing Rebar3 can be viewed here:\nhttps://rebar3.org/docs/getting-started/\",\n                    ),\n                    \"deno\" => text.push_str(\n                        \"\nDocumentation for installing Deno can be viewed here:\nhttps://docs.deno.com/runtime/getting_started/installation/\",\n                    ),\n                    \"elixir\" => text.push_str(\n                        \"\nDocumentation for installing Elixir can be viewed here:\nhttps://elixir-lang.org/install.html\",\n                    ),\n                    \"node\" => text.push_str(\n                        \"\nDocumentation for installing Node.js via package manager can be viewed here:\nhttps://nodejs.org/en/download/package-manager/all/\",\n                    ),\n                    \"bun\" => text.push_str(\n                        \"\nDocumentation for installing Bun can be viewed here:\nhttps://bun.sh/docs/installation/\",\n                    ),\n                    \"git\" => text.push_str(\n                        \"\nDocumentation for installing Git can be viewed here:\nhttps://git-scm.com/book/en/v2/Getting-Started-Installing-Git\",\n                    ),\n                    _ => (),\n                }\n\n                vec![Diagnostic {\n                    title: \"Program not found\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::ShellCommand {\n                program: command,\n                reason: ShellCommandFailureReason::Unknown,\n            } => {\n                let text =\n                    format!(\"There was a problem when running the shell command `{command}`.\");\n                vec![Diagnostic {\n                    title: \"Shell command failure\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::ShellCommand {\n                program: command,\n                reason: ShellCommandFailureReason::IoError(err),\n            } => {\n                let text = format!(\n                    \"There was a problem when running the shell command `{}`.\n\nThe error from the shell command library was:\n\n    {}\",\n                    command,\n                    std_io_error_kind_text(err)\n                );\n                vec![Diagnostic {\n                    title: \"Shell command failure\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::ShellCommand {\n                program: command,\n                reason: ShellCommandFailureReason::ShellCommandError(err),\n            } => {\n                let text = format!(\n                    \"There was a problem when running the shell command `{command}`.\n\nThe error from the shell command was:\n\n    {err}\"\n                );\n                vec![Diagnostic {\n                    title: \"Shell command failure\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::Gzip(detail) => {\n                let text = format!(\n                    \"There was a problem when applying gzip compression.\n\nThis was error from the gzip library:\n\n    {detail}\"\n                );\n                vec![Diagnostic {\n                    title: \"Gzip compression failure\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::AddTar { path, err } => {\n                let text = format!(\n                    \"There was a problem when attempting to add the file {path}\nto a tar archive.\n\nThis was error from the tar library:\n\n    {err}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failure creating tar archive\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::ExpandTar { error } => {\n                let text = format!(\n                    \"There was a problem when attempting to expand a to a tar archive.\n\nThis was error from the tar library:\n\n    {error}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failure opening tar archive\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::TarFinish(detail) => {\n                let text = format!(\n                    \"There was a problem when creating a tar archive.\n\nThis was error from the tar library:\n\n    {detail}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failure creating tar archive\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::Hex(detail) => {\n                let text = format!(\n                    \"There was a problem when using the Hex API.\n\nThis was error from the Hex client library:\n\n    {detail}\"\n                );\n                vec![Diagnostic {\n                    title: \"Hex API failure\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::DuplicateModule {\n                module,\n                first,\n                second,\n            } => {\n                // If the conflicting modules come from the same package just\n                // showing the same package name twice is not all that useful.\n                // So we will show the path to each one!\n                let should_show_path = first.package_name == second.package_name;\n                let format_origin = |origin: &DefinedModuleOrigin| {\n                    if should_show_path {\n                        format!(\"at {}\", origin.path)\n                    } else {\n                        format!(\"by the package {}\", origin.package_name)\n                    }\n                };\n\n                let text = format!(\n                    \"The module `{module}` is defined multiple times.\n\nIt is first defined {}\nIt is defined a second time {}\",\n                    format_origin(first),\n                    format_origin(second)\n                );\n\n                vec![Diagnostic {\n                    title: \"Duplicate module\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::ClashingGleamModuleAndNativeFileName {\n                module,\n                gleam_file,\n                native_file,\n            } => {\n                let text = format!(\n                    \"The Gleam module `{module}` is clashing with a native file\nwith the same name:\n\n    Gleam module: {gleam_file}\n    Native file:  {native_file}\n\nThis is a problem because the Gleam module would be compiled to a file with the\nsame name and extension, unintentionally overwriting the native file.\"\n                );\n\n                vec![Diagnostic {\n                    title: \"Gleam module clashes with native file\".into(),\n                    text,\n                    hint: Some(\n                        \"Consider renaming one of the files, such as by \\\nadding an `_ffi` suffix to the native file's name, and trying again.\"\n                            .into(),\n                    ),\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::DuplicateSourceFile { file } => vec![Diagnostic {\n                title: \"Duplicate Source file\".into(),\n                text: format!(\"The file `{file}` is defined multiple times.\"),\n                hint: None,\n                level: Level::Error,\n                location: None,\n            }],\n\n            Error::DuplicateNativeErlangModule {\n                module,\n                first,\n                second,\n            } => {\n                let text = format!(\n                    \"The native Erlang module `{module}` is defined multiple times.\n\nFirst:  {first}\nSecond: {second}\n\nErlang modules must have unique names regardless of the subfolders where their\n`.erl` files are located.\"\n                );\n\n                vec![Diagnostic {\n                    title: \"Duplicate native Erlang module\".into(),\n                    text,\n                    hint: Some(\"Rename one of the native Erlang modules and try again.\".into()),\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::FileIo {\n                kind,\n                action,\n                path,\n                err,\n            } => {\n                let err = match err {\n                    Some(e) => {\n                        format!(\"\\nThe error message from the file IO library was:\\n\\n    {e}\\n\")\n                    }\n                    None => \"\".into(),\n                };\n                let mut text = format!(\n                    \"An error occurred while trying to {} this {}:\n\n    {}\n{}\",\n                    action.text(),\n                    kind.text(),\n                    path,\n                    err,\n                );\n                if cfg!(target_family = \"windows\") && action == &FileIoAction::Link {\n                    text.push_str(\"\n\nWindows does not support symbolic links without developer mode\nor admin privileges. Please enable developer mode and try again.\n\nhttps://learn.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development#activate-developer-mode\");\n                }\n                vec![Diagnostic {\n                    title: \"File IO failure\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::FailedToEncryptLocalHexApiKey { detail } => {\n                let text = wrap_format!(\n                    \"A problem was encountered \\\nencrypting the local Hex API key with the given password.\nThe error from the encryption library was:\n\n    {detail}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failed to encrypt data\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::FailedToDecryptLocalHexApiKey { detail } => {\n                let text = wrap_format!(\n                    \"Unable to decrypt the local Hex API key with the given password.\nThe error from the encryption library was:\n\n    {detail}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failed to decrypt local Hex API key\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::NonUtf8Path { path } => {\n                let text = format!(\n                    \"Encountered a non UTF-8 path '{}', but only UTF-8 paths are supported.\",\n                    path.to_string_lossy()\n                );\n                vec![Diagnostic {\n                    title: \"Non UTF-8 Path Encountered\".into(),\n                    text,\n                    level: Level::Error,\n                    location: None,\n                    hint: None,\n                }]\n            }\n\n            Error::GitInitialization { error } => {\n                let text = format!(\n                    \"An error occurred while trying make a git repository for this project:\n\n    {error}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failed to initialize git repository\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::Type {\n                path,\n                src,\n                errors: error,\n                names,\n            } => error\n                .iter()\n                .map(|error| match error {\n                    TypeError::LiteralFloatOutOfRange { location, .. } => Diagnostic {\n                        title: \"Float outside of valid range\".into(),\n                        text: wrap(\n                            \"This float value is too large to be represented by \\\na floating point type: float values must be in the range -1.7976931348623157e308 \\\n- 1.7976931348623157e308.\",\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::InvalidImport {\n                        location,\n                        importing_module,\n                        imported_module,\n                        kind: InvalidImportKind::SrcImportingTest,\n                    } => {\n                        let text = wrap_format!(\n                            \"The application module `{importing_module}` \\\nis importing the test module `{imported_module}`.\n\nTest modules are not included in production builds so application \\\nmodules cannot import them. Perhaps move the `{imported_module}` \\\nmodule to the src directory.\",\n                        );\n\n                        Diagnostic {\n                            title: \"App importing test module\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Imported here\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::InvalidImport {\n                        location,\n                        importing_module,\n                        imported_module,\n                        kind: InvalidImportKind::SrcImportingDev,\n                    } => {\n                        let text = wrap_format!(\n                            \"The application module `{importing_module}` \\\nis importing the development module `{imported_module}`.\n\nDevelopment modules are not included in production builds so application \\\nmodules cannot import them. Perhaps move the `{imported_module}` \\\nmodule to the src directory.\",\n                        );\n\n                        Diagnostic {\n                            title: \"App importing dev module\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Imported here\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::InvalidImport {\n                        location,\n                        importing_module,\n                        imported_module,\n                        kind: InvalidImportKind::DevImportingTest,\n                    } => {\n                        let text = wrap_format!(\n                            \"The development module `{importing_module}` \\\nis importing the test module `{imported_module}`.\n\nTest modules should only contain test-related code, and not general development \\\ncode. Perhaps move the `{imported_module}` module to the dev directory.\",\n                        );\n\n                        Diagnostic {\n                            title: \"Dev importing test module\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Imported here\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnknownLabels {\n                        unknown,\n                        valid,\n                        supplied,\n                    } => {\n                        let other_labels: Vec<_> = valid\n                            .iter()\n                            .filter(|label| !supplied.contains(label))\n                            .cloned()\n                            .collect();\n\n                        let title = if unknown.len() > 1 {\n                            \"Unknown labels\"\n                        } else {\n                            \"Unknown label\"\n                        }\n                        .into();\n\n                        let mut labels = unknown.iter().map(|(label, location)| {\n                            let text = did_you_mean(label, &other_labels)\n                                .unwrap_or_else(|| \"Unexpected label\".into());\n                            Label {\n                                text: Some(text),\n                                span: *location,\n                            }\n                        });\n                        let label = labels.next().expect(\"Unknown labels first label\");\n                        let extra_labels = labels\n                            .map(|label| ExtraLabel {\n                                src_info: None,\n                                label,\n                            })\n                            .collect();\n                        let text = if valid.is_empty() {\n                            \"This constructor does not accept any labelled arguments.\".into()\n                        } else if other_labels.is_empty() {\n                            \"You have already supplied all the labelled arguments that this\nconstructor accepts.\"\n                                .into()\n                        } else {\n                            let mut label_text = String::from(\"It accepts these labels:\\n\");\n                            for label in other_labels.iter().sorted() {\n                                label_text.push_str(\"\\n    \");\n                                label_text.push_str(label);\n                            }\n                            label_text\n                        };\n                        Diagnostic {\n                            title,\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label,\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels,\n                            }),\n                        }\n                    }\n\n                    TypeError::UnexpectedLabelledArg {\n                        location,\n                        label,\n                        kind,\n                    } => {\n                        let kind = match kind {\n                            UnexpectedLabelledArgKind::FunctionParameter => \"function\",\n                            UnexpectedLabelledArgKind::RecordConstructorArgument => {\n                                \"record constructor\"\n                            }\n                        };\n                        let text = format!(\n                            \"This argument has been given a label but the {kind} does\nnot expect any. Please remove the label `{label}`.\"\n                        );\n                        Diagnostic {\n                            title: \"Unexpected labelled argument\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::PositionalArgumentAfterLabelled { location } => {\n                        let text = wrap(\n                            \"This unlabeled argument has been \\\nsupplied after a labelled argument.\nOnce a labelled argument has been supplied all following arguments must\nalso be labelled.\",\n                        );\n\n                        Diagnostic {\n                            title: \"Unexpected positional argument\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateImport {\n                        location,\n                        previous_location,\n                        name,\n                    } => {\n                        let text = format!(\n                            \"`{name}` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\"\n                        );\n                        Diagnostic {\n                            title: \"Duplicate import\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Reimported here\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![ExtraLabel {\n                                    src_info: None,\n                                    label: Label {\n                                        text: Some(\"First imported here\".into()),\n                                        span: *previous_location,\n                                    },\n                                }],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateName {\n                        location_a,\n                        location_b,\n                        name,\n                        ..\n                    } => {\n                        let (first_location, second_location) =\n                            if location_a.start < location_b.start {\n                                (location_a, location_b)\n                            } else {\n                                (location_b, location_a)\n                            };\n                        let text = format!(\n                            \"`{name}` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\"\n                        );\n                        Diagnostic {\n                            title: \"Duplicate definition\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Redefined here\".into()),\n                                    span: *second_location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![ExtraLabel {\n                                    src_info: None,\n                                    label: Label {\n                                        text: Some(\"First defined here\".into()),\n                                        span: *first_location,\n                                    },\n                                }],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateTypeName {\n                        name,\n                        location,\n                        previous_location,\n                        ..\n                    } => {\n                        let text = format!(\n                            \"The type `{name}` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\"\n                        );\n                        Diagnostic {\n                            title: \"Duplicate type definition\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Redefined here\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![ExtraLabel {\n                                    src_info: None,\n                                    label: Label {\n                                        text: Some(\"First defined here\".into()),\n                                        span: *previous_location,\n                                    },\n                                }],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateField { location, label } => {\n                        let text = format!(\n                            \"The label `{label}` has already been defined. Rename this label.\"\n                        );\n                        Diagnostic {\n                            title: \"Duplicate label\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateArgument { location, label } => {\n                        let text =\n                            format!(\"The labelled argument `{label}` has already been supplied.\");\n                        Diagnostic {\n                            title: \"Duplicate argument\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::RecursiveType { location } => {\n                        let text = wrap(\n                            \"I don't know how to work out what type this \\\nvalue has. It seems to be defined in terms of itself.\",\n                        );\n                        Diagnostic {\n                            title: \"Recursive type\".into(),\n                            text,\n                            hint: Some(\"Add some type annotations and try again.\".into()),\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::NotFn { location, type_ } => {\n                        let mut printer = Printer::new(names);\n                        let text = format!(\n                            \"This value is being called as a function but its type is:\\n\\n    {}\",\n                            printer.print_type(type_)\n                        );\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnknownRecordField {\n                        usage,\n                        location,\n                        type_,\n                        label,\n                        fields,\n                        unknown_field: variants,\n                    } => {\n                        let mut printer = Printer::new(names);\n\n                        // Give a hint about what type this value has.\n                        let mut text = format!(\n                            \"The value being accessed has this type:\\n\\n    {}\\n\",\n                            printer.print_type(type_)\n                        );\n\n                        // Give a hint about what record fields this value has, if any.\n                        if fields.is_empty() {\n                            if variants == &UnknownField::NoFields {\n                                text.push_str(\"\\nIt does not have any fields.\");\n                            } else {\n                                text.push_str(\n                                    \"\\nIt does not have fields that are common \\\nacross all variants.\",\n                                );\n                            }\n                        } else {\n                            text.push_str(\"\\nIt has these accessible fields:\\n\");\n                        }\n                        for field in fields.iter().sorted() {\n                            text.push_str(\"\\n    .\");\n                            text.push_str(field);\n                        }\n\n                        match variants {\n                            UnknownField::AppearsInAVariant => {\n                                let msg = wrap(\n                                    \"Note: The field you are trying to access is \\\nnot defined consistently across all variants of this custom type. To fix this, \\\nensure that all variants include the field with the same name, position, and \\\ntype.\",\n                                );\n                                text.push_str(\"\\n\\n\");\n                                text.push_str(&msg);\n                            }\n                            UnknownField::AppearsInAnImpossibleVariant => {\n                                let msg = wrap(\n                                    \"Note: The field exists in this custom type \\\nbut is not defined for the current variant. Ensure that you are accessing the \\\nfield on a variant where it is valid.\",\n                                );\n                                text.push_str(\"\\n\\n\");\n                                text.push_str(&msg);\n                            }\n                            UnknownField::TrulyUnknown => (),\n                            UnknownField::NoFields => (),\n                        }\n\n                        // Give a hint about Gleam not having OOP methods if it\n                        // looks like they might be trying to call one.\n                        match usage {\n                            FieldAccessUsage::MethodCall => {\n                                let msg = wrap(\n                                    \"Gleam is not object oriented, so if you are trying \\\nto call a method on this value you may want to use the function syntax instead.\",\n                                );\n                                text.push_str(\"\\n\\n\");\n                                text.push_str(&msg);\n                                text.push_str(\"\\n\\n    \");\n                                text.push_str(label);\n                                text.push_str(\"(value)\");\n                            }\n                            FieldAccessUsage::Other | FieldAccessUsage::RecordUpdate => (),\n                        }\n\n                        let label = did_you_mean(label, fields)\n                            .unwrap_or_else(|| \"This field does not exist\".into());\n                        Diagnostic {\n                            title: \"Unknown record field\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(label),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::CouldNotUnify {\n                        location,\n                        expected,\n                        given,\n                        situation: Some(UnifyErrorSituation::Operator(op)),\n                    } => {\n                        let mut printer = Printer::new(names);\n                        let mut text = format!(\n                            \"The {op} operator expects arguments of this type:\n\n    {expected}\n\nBut this argument has this type:\n\n    {given}\\n\",\n                            op = op.name(),\n                            expected = printer.print_type(expected),\n                            given = printer.print_type(given),\n                        );\n                        if let Some(hint) = hint_alternative_operator(op, given) {\n                            text.push('\\n');\n                            text.push_str(\"Hint: \");\n                            text.push_str(&hint);\n                        }\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::CouldNotUnify {\n                        location,\n                        expected,\n                        given,\n                        situation: Some(UnifyErrorSituation::PipeTypeMismatch),\n                    } => {\n                        // Remap the pipe function type into just the type expected by the pipe.\n                        let expected = expected\n                            .fn_types()\n                            .and_then(|(arguments, _)| arguments.first().cloned());\n\n                        // Remap the argument as well, if it's a function.\n                        let given = given\n                            .fn_types()\n                            .and_then(|(arguments, _)| arguments.first().cloned())\n                            .unwrap_or_else(|| given.clone());\n\n                        let mut printer = Printer::new(names);\n                        let text = format!(\n                            \"The argument is:\n\n    {given}\n\nBut function expects:\n\n    {expected}\",\n                            expected = expected\n                                .map(|v| printer.print_type(&v))\n                                .unwrap_or_else(|| \"    No arguments\".into()),\n                            given = printer.print_type(&given)\n                        );\n\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\n                                        \"This function does not accept the piped type\".into(),\n                                    ),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::CouldNotUnify {\n                        location,\n                        expected,\n                        given,\n                        situation,\n                    } => {\n                        let mut printer = Printer::new(names);\n                        let mut text = if let Some(description) =\n                            situation.as_ref().and_then(|s| s.description())\n                        {\n                            let mut text = description.to_string();\n                            text.push('\\n');\n                            text.push('\\n');\n                            text\n                        } else {\n                            \"\".into()\n                        };\n                        text.push_str(\"Expected type:\\n\\n    \");\n                        text.push_str(&printer.print_type(expected));\n                        text.push_str(\"\\n\\nFound type:\\n\\n    \");\n                        text.push_str(&printer.print_type(given));\n\n                        let (main_message_location, main_message_text, extra_labels) =\n                            match situation {\n                                // When the mismatch error comes from a case clause we want to highlight the\n                                // entire branch (pattern included) when reporting the error; in addition,\n                                // if the error could be resolved just by wrapping the value in an `Ok`\n                                // or `Error` we want to add an additional label with this hint below the\n                                // offending value.\n                                Some(UnifyErrorSituation::CaseClauseMismatch {\n                                    clause_location,\n                                }) => (clause_location, None, vec![]),\n                                // In all other cases we just highlight the offending expression, optionally\n                                // adding the wrapping hint if it makes sense.\n                                Some(_) | None => {\n                                    (location, hint_wrap_value_in_result(expected, given), vec![])\n                                }\n                            };\n\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: main_message_text,\n                                    span: *main_message_location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels,\n                            }),\n                        }\n                    }\n\n                    TypeError::IncorrectTypeArity {\n                        location,\n                        expected,\n                        given: given_number,\n                        name,\n                    } => {\n                        let expected = match expected {\n                            0 => \"no type arguments\".into(),\n                            1 => \"1 type argument\".into(),\n                            _ => format!(\"{expected} type arguments\"),\n                        };\n                        let given = match given_number {\n                            0 => \"none\",\n                            _ => &format!(\"{given_number}\"),\n                        };\n                        let text = wrap_format!(\n                            \"`{name}` requires {expected} \\\nbut {given} where provided.\"\n                        );\n                        Diagnostic {\n                            title: \"Incorrect arity\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(format!(\"Expected {expected}, got {given_number}\")),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::TypeUsedAsAConstructor { location, name } => {\n                        let text = wrap_format!(\n                            \"`{name}` is a type with no parameters, but here it's \\\nbeing used as a type constructor.\"\n                        );\n\n                        Diagnostic {\n                            title: \"Type used as a type constructor\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"You can remove this\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::IncorrectArity {\n                        labels,\n                        location,\n                        context,\n                        expected,\n                        given,\n                    } => {\n                        let text = if labels.is_empty() {\n                            \"\".into()\n                        } else {\n                            let subject = match context {\n                                IncorrectArityContext::Pattern => \"pattern\",\n                                IncorrectArityContext::Function => \"call\",\n                            };\n                            let labels = labels\n                                .iter()\n                                .map(|p| format!(\"  - {p}\"))\n                                .sorted()\n                                .join(\"\\n\");\n                            format!(\n                                \"This {subject} accepts these additional labelled \\\n                                arguments:\\n\\n{labels}\",\n                            )\n                        };\n                        let expected = match expected {\n                            0 => \"no arguments\".into(),\n                            1 => \"1 argument\".into(),\n                            _ => format!(\"{expected} arguments\"),\n                        };\n                        let label = format!(\"Expected {expected}, got {given}\");\n                        Diagnostic {\n                            title: \"Incorrect arity\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(label),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnnecessarySpreadOperator { location, arity } => {\n                        let text = wrap_format!(\n                            \"This record has {arity} fields and you have already \\\nassigned variables to all of them.\"\n                        );\n                        Diagnostic {\n                            title: \"Unnecessary spread operator\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnsafeRecordUpdate { location, reason } => match reason {\n                        UnsafeRecordUpdateReason::UnknownVariant {\n                            constructed_variant,\n                        } => {\n                            let text = wrap_format!(\n                                \"This value cannot be used to build an updated \\\n`{constructed_variant}` as it could be some other variant.\n\nConsider pattern matching on it with a case expression and then \\\nconstructing a new record with its values.\"\n                            );\n\n                            Diagnostic {\n                                title: \"Unsafe record update\".into(),\n                                text,\n                                hint: None,\n                                level: Level::Error,\n                                location: Some(Location {\n                                    label: Label {\n                                        text: Some(format!(\n                                            \"I'm not sure this is always a `{constructed_variant}`\"\n                                        )),\n                                        span: *location,\n                                    },\n                                    path: path.clone(),\n                                    src: src.clone(),\n                                    extra_labels: vec![],\n                                }),\n                            }\n                        }\n                        UnsafeRecordUpdateReason::WrongVariant {\n                            constructed_variant,\n                            spread_variant,\n                        } => {\n                            let text = wrap_format!(\n                                \"This value is a `{spread_variant}` so \\\nit cannot be used to build a `{constructed_variant}`, even if they share some fields.\n\nNote: If you want to change one variant of a type into another, you should \\\nspecify all fields explicitly instead of using the record update syntax.\"\n                            );\n\n                            Diagnostic {\n                                title: \"Incorrect record update\".into(),\n                                text,\n                                hint: None,\n                                level: Level::Error,\n                                location: Some(Location {\n                                    label: Label {\n                                        text: Some(format!(\"This is a `{spread_variant}`\")),\n                                        span: *location,\n                                    },\n                                    path: path.clone(),\n                                    src: src.clone(),\n                                    extra_labels: vec![],\n                                }),\n                            }\n                        }\n                        UnsafeRecordUpdateReason::IncompatibleFieldTypes {\n                            expected_field_type,\n                            record_field_type,\n                            record_variant,\n                            field,\n                            ..\n                        } => {\n                            let mut printer = Printer::new(names);\n                            let expected_field_type = printer.print_type(expected_field_type);\n                            let record_field_type = printer.print_type(record_field_type);\n                            let record_variant = printer.print_type(record_variant);\n                            let text = match field {\n                                RecordField::Labelled(label) => wrap_format!(\n                                    \"The `{label}` field \\\nof this value is a `{record_field_type}`, but the arguments given to the record \\\nupdate indicate that it should be a `{expected_field_type}`.\n\nNote: If the same type variable is used for multiple fields, all those fields \\\nneed to be updated at the same time if their type changes.\"\n                                ),\n                                RecordField::Unlabelled(index) => wrap_format!(\n                                    \"The {} field \\\nof this value is a `{record_field_type}`, but the arguments given to the record \\\nupdate indicate that it should be a `{expected_field_type}`.\n\nNote: Unlabelled fields cannot be updated in a record update, so either add \\\na label or use a record constructor.\",\n                                    to_ordinal(*index + 1),\n                                ),\n                            };\n\n                            Diagnostic {\n                                title: \"Incomplete record update\".into(),\n                                text,\n                                hint: None,\n                                level: Level::Error,\n                                location: Some(Location {\n                                    label: Label {\n                                        text: Some(format!(\"This is a `{record_variant}`\")),\n                                        span: *location,\n                                    },\n                                    path: path.clone(),\n                                    src: src.clone(),\n                                    extra_labels: vec![],\n                                }),\n                            }\n                        }\n                    },\n\n                    TypeError::UnknownType {\n                        location,\n                        name,\n                        hint,\n                    } => {\n                        let label_text = match hint {\n                            UnknownTypeHint::AlternativeTypes(types) => did_you_mean(name, types),\n                            UnknownTypeHint::ValueInScopeWithSameName => None,\n                        };\n\n                        let mut text = wrap_format!(\n                            \"The type `{name}` is not defined or imported in this module.\"\n                        );\n\n                        match hint {\n                            UnknownTypeHint::ValueInScopeWithSameName => {\n                                let hint = wrap_format!(\n                                    \"There is a value in scope with the name `{name}`, \\\nbut no type in scope with that name.\"\n                                );\n                                text.push('\\n');\n                                text.push_str(hint.as_str());\n                            }\n                            UnknownTypeHint::AlternativeTypes(_) => {}\n                        };\n\n                        Diagnostic {\n                            title: \"Unknown type\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: label_text,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnknownVariable {\n                        location,\n                        variables,\n                        discarded_location,\n                        name,\n                        type_with_name_in_scope,\n                    } => {\n                        let title = String::from(\"Unknown variable\");\n\n                        if let Some(ignored_location) = discarded_location {\n                            let location = Location {\n                                label: Label {\n                                    text: Some(\"So this is not in scope\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![ExtraLabel {\n                                    src_info: None,\n                                    label: Label {\n                                        text: Some(\"This value is discarded\".into()),\n                                        span: *ignored_location,\n                                    },\n                                }],\n                            };\n                            Diagnostic {\n                                title,\n                                text: \"\".into(),\n                                hint: Some(wrap_format!(\n                                    \"Change `_{name}` to `{name}` or reference another variable\",\n                                )),\n                                level: Level::Error,\n                                location: Some(location),\n                            }\n                        } else {\n                            let text = if *type_with_name_in_scope {\n                                wrap_format!(\"`{name}` is a type, it cannot be used as a value.\")\n                            } else {\n                                let is_first_char_uppercase =\n                                    name.chars().next().is_some_and(char::is_uppercase);\n\n                                if is_first_char_uppercase {\n                                    wrap_format!(\n                                        \"The custom type variant constructor \\\n`{name}` is not in scope here.\"\n                                    )\n                                } else {\n                                    wrap_format!(\"The name `{name}` is not in scope here.\")\n                                }\n                            };\n\n                            Diagnostic {\n                                title,\n                                text,\n                                hint: None,\n                                level: Level::Error,\n                                location: Some(Location {\n                                    label: Label {\n                                        text: did_you_mean(name, variables),\n                                        span: *location,\n                                    },\n                                    path: path.clone(),\n                                    src: src.clone(),\n                                    extra_labels: vec![],\n                                }),\n                            }\n                        }\n                    }\n\n                    TypeError::PrivateTypeLeak { location, leaked } => {\n                        let mut printer = Printer::new(names);\n\n                        // TODO: be more precise.\n                        // - is being returned by this public function\n                        // - is taken as an argument by this public function\n                        // - is taken as an argument by this public enum constructor\n                        // etc\n                        let text = wrap_format!(\n                            \"The following type is private, but is \\\nbeing used by this public export.\n\n    {}\n\nPrivate types can only be used within the module that defines them.\",\n                            printer.print_type(leaked),\n                        );\n                        Diagnostic {\n                            title: \"Private type used in public interface\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnknownModule {\n                        location,\n                        name,\n                        suggestions,\n                    } => Diagnostic {\n                        title: \"Unknown module\".into(),\n                        text: format!(\"No module has been found with the name `{name}`.\"),\n                        hint: suggestions\n                            .first()\n                            .map(|suggestion| suggestion.suggestion(name)),\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::UnknownModuleType {\n                        location,\n                        name,\n                        module_name,\n                        type_constructors,\n                        value_with_same_name: imported_type_as_value,\n                    } => {\n                        let text = if *imported_type_as_value {\n                            format!(\"`{name}` is only a value, it cannot be imported as a type.\")\n                        } else {\n                            format!(\"The module `{module_name}` does not have a `{name}` type.\")\n                        };\n                        Diagnostic {\n                            title: \"Unknown module type\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: if *imported_type_as_value {\n                                        Some(format!(\"Did you mean `{name}`?\"))\n                                    } else {\n                                        did_you_mean(name, type_constructors)\n                                    },\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnknownModuleValue {\n                        location,\n                        name,\n                        module_name,\n                        value_constructors,\n                        type_with_same_name: imported_value_as_type,\n                        context,\n                    } => {\n                        let text = if *imported_value_as_type {\n                            match context {\n                                ModuleValueUsageContext::UnqualifiedImport => wrap_format!(\n                                    \"`{name}` is only a type, it cannot be imported as a value.\"\n                                ),\n                                ModuleValueUsageContext::ModuleAccess => wrap_format!(\n                                    \"{module_name}.{name} is a type constructor, \\\nit cannot be used as a value\"\n                                ),\n                            }\n                        } else {\n                            wrap_format!(\n                                \"The module `{module_name}` does not have a `{name}` value.\"\n                            )\n                        };\n                        Diagnostic {\n                            title: \"Unknown module value\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: if *imported_value_as_type\n                                        && matches!(\n                                            context,\n                                            ModuleValueUsageContext::UnqualifiedImport\n                                        ) {\n                                        Some(format!(\"Did you mean `type {name}`?\"))\n                                    } else {\n                                        did_you_mean(name, value_constructors)\n                                    },\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::ModuleAliasUsedAsName { location, name } => {\n                        let text = wrap(\n                            \"Modules are not values, so you cannot assign them \\\nto variables, pass them to functions, or anything else that you would do with a value.\",\n                        );\n                        Diagnostic {\n                            title: format!(\"Module `{name}` used as a value\"),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::IncorrectNumClausePatterns {\n                        location,\n                        expected,\n                        given,\n                    } => {\n                        let subject = if *expected == 1 {\n                            \"subject\"\n                        } else {\n                            \"subjects\"\n                        };\n                        let pattern = if *expected == 1 {\n                            \"pattern\"\n                        } else {\n                            \"patterns\"\n                        };\n                        let text = wrap_format!(\n                            \"This case expression has {expected} {subject}, \\\nbut this pattern matches {given}.\nEach clause must have a pattern for every subject value.\",\n                        );\n                        Diagnostic {\n                            title: \"Incorrect number of patterns\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(format!(\n                                        \"Expected {expected} {pattern}, got {given}\"\n                                    )),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::NonLocalClauseGuardVariable { location, name } => {\n                        let text = wrap_format!(\n                            \"Variables used in guards must be either defined in the \\\nfunction, or be an argument to the function. The variable \\\n`{name}` is not defined locally.\",\n                        );\n                        Diagnostic {\n                            title: \"Invalid guard variable\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Is not locally defined\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::ExtraVarInAlternativePattern { location, name } => {\n                        let text = wrap_format!(\n                            \"All alternative patterns must define the same variables as \\\nthe initial pattern. This variable `{name}` has not been previously defined.\",\n                        );\n                        Diagnostic {\n                            title: \"Extra alternative pattern variable\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Has not been previously defined\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::MissingVarInAlternativePattern { location, name } => {\n                        let text = wrap_format!(\n                            \"All alternative patterns must define the same variables \\\nas the initial pattern, but the `{name}` variable is missing.\",\n                        );\n                        Diagnostic {\n                            title: \"Missing alternative pattern variable\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\n                                        \"This does not define all required variables\".into(),\n                                    ),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateVarInPattern { location, name } => {\n                        let text = wrap_format!(\n                            \"Variables can only be used once per pattern. This \\\nvariable `{name}` appears multiple times.\nIf you used the same variable twice deliberately in order to check for equality \\\nplease use a guard clause instead.\ne.g. (x, y) if x == y -> ...\",\n                        );\n                        Diagnostic {\n                            title: \"Duplicate variable in pattern\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"This has already been used\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::OutOfBoundsTupleIndex {\n                        location, size: 0, ..\n                    } => Diagnostic {\n                        title: \"Out of bounds tuple index\".into(),\n                        text: \"This tuple has no elements so it cannot be indexed at all.\".into(),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::OutOfBoundsTupleIndex {\n                        location,\n                        index,\n                        size,\n                    } => {\n                        let text = wrap_format!(\n                            \"The index being accessed for this tuple is {}, but this \\\ntuple has {} elements so the highest valid index is {}.\",\n                            index,\n                            size,\n                            size - 1,\n                        );\n                        Diagnostic {\n                            title: \"Out of bounds tuple index\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"This index is too large\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::NotATuple { location, given } => {\n                        let mut printer = Printer::new(names);\n                        let text = format!(\n                            \"To index into this value it needs to be a tuple, \\\nhowever it has this type:\n\n    {}\",\n                            printer.print_type(given),\n                        );\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"This is not a tuple\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::NotATupleUnbound { location } => {\n                        let text = wrap(\n                            \"To index into a tuple we need to \\\nknow its size, but we don't know anything about this type yet. \\\nPlease add some type annotations so we can continue.\",\n                        );\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"What type is this?\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::RecordAccessUnknownType { location } => {\n                        let text = wrap(\n                            \"In order to access a record field \\\nwe need to know what type it is, but I can't tell \\\nthe type here. Try adding type annotations to your \\\nfunction and try again.\",\n                        );\n                        Diagnostic {\n                            title: \"Unknown type for record access\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"I don't know what type this is\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::BitArraySegmentError { error, location } => {\n                        let (label, mut extra) = match error {\n                            bit_array::ErrorType::ConflictingTypeOptions { existing_type } => (\n                                \"This is an extra type specifier\",\n                                vec![format!(\n                                    \"Hint: This segment already has the type {existing_type}.\"\n                                )],\n                            ),\n\n                            bit_array::ErrorType::ConflictingSignednessOptions {\n                                existing_signed,\n                            } => (\n                                \"This is an extra signedness specifier\",\n                                vec![format!(\n                                    \"Hint: This segment already has a \\\nsignedness of {existing_signed}.\"\n                                )],\n                            ),\n\n                            bit_array::ErrorType::ConflictingEndiannessOptions {\n                                existing_endianness,\n                            } => (\n                                \"This is an extra endianness specifier\",\n                                vec![format!(\n                                    \"Hint: This segment already has an \\\nendianness of {existing_endianness}.\"\n                                )],\n                            ),\n\n                            bit_array::ErrorType::ConflictingSizeOptions => (\n                                \"This is an extra size specifier\",\n                                vec![\"Hint: This segment already has a size.\".into()],\n                            ),\n\n                            bit_array::ErrorType::ConflictingUnitOptions => (\n                                \"This is an extra unit specifier\",\n                                vec![\"Hint: A BitArray segment can have at most 1 unit.\".into()],\n                            ),\n\n                            bit_array::ErrorType::FloatWithSize => (\n                                \"Invalid float size\",\n                                vec![\"Hint: floats have an exact size of 16/32/64 bits.\".into()],\n                            ),\n\n                            bit_array::ErrorType::InvalidEndianness => (\n                                \"This option is invalid here\",\n                                vec![wrap(\n                                    \"Hint: signed and unsigned \\\ncan only be used with int, float, utf16 and utf32 types.\",\n                                )],\n                            ),\n\n                            bit_array::ErrorType::OptionNotAllowedInValue => (\n                                \"This option is only allowed in BitArray patterns\",\n                                vec![\"Hint: This option has no effect in BitArray values.\".into()],\n                            ),\n\n                            bit_array::ErrorType::SignednessUsedOnNonInt { type_ } => (\n                                \"Signedness is only valid with int types\",\n                                vec![format!(\"Hint: This segment has a type of {type_}\")],\n                            ),\n                            bit_array::ErrorType::TypeDoesNotAllowSize { type_ } => (\n                                \"Size cannot be specified here\",\n                                vec![format!(\"Hint: {type_} segments have an automatic size.\")],\n                            ),\n                            bit_array::ErrorType::TypeDoesNotAllowUnit { type_ } => (\n                                \"Unit cannot be specified here\",\n                                vec![wrap(&format!(\n                                    \"Hint: {type_} segments \\\nare sized based on their value and cannot have a unit.\"\n                                ))],\n                            ),\n                            bit_array::ErrorType::VariableUtfSegmentInPattern => (\n                                \"This cannot be a variable\",\n                                vec![wrap(\n                                    \"Hint: in patterns utf8, utf16, and \\\nutf32  must be an exact string.\",\n                                )],\n                            ),\n                            bit_array::ErrorType::SegmentMustHaveSize => (\n                                \"This segment has no size\",\n                                vec![wrap(\n                                    \"Hint: Bit array segments without \\\na size are only allowed at the end of a bin pattern.\",\n                                )],\n                            ),\n                            bit_array::ErrorType::UnitMustHaveSize => (\n                                \"This needs an explicit size\",\n                                vec![\n                                    \"Hint: If you specify unit() you must also specify size().\"\n                                        .into(),\n                                ],\n                            ),\n                            bit_array::ErrorType::ConstantSizeNotPositive => {\n                                (\"A constant size must be a positive number\", vec![])\n                            }\n                            bit_array::ErrorType::OptionNotSupportedForTarget {\n                                target,\n                                option: UnsupportedOption::NativeEndianness,\n                            } => (\n                                \"Unsupported endianness\",\n                                vec![wrap_format!(\n                                    \"The {target} target does not support the `native` \\\nendianness option.\",\n                                    target = target.as_presentable_str(),\n                                )],\n                            ),\n                            bit_array::ErrorType::OptionNotSupportedForTarget {\n                                target,\n                                option: UnsupportedOption::UtfCodepointPattern,\n                            } => (\n                                \"UTF-codepoint pattern matching is not supported\",\n                                vec![wrap_format!(\n                                    \"The {target} target does not support \\\nUTF-codepoint pattern matching.\",\n                                    target = target.as_presentable_str(),\n                                )],\n                            ),\n                        };\n                        extra.push(\"See: https://tour.gleam.run/data-types/bit-arrays/\".into());\n                        let text = extra.join(\"\\n\");\n                        Diagnostic {\n                            title: \"Invalid bit array segment\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(label.into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n                    TypeError::RecordUpdateInvalidConstructor { location } => Diagnostic {\n                        title: \"Invalid record constructor\".into(),\n                        text: \"Only record constructors can be used with the update syntax.\".into(),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: Some(\"This is not a record constructor\".into()),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::UnexpectedTypeHole { location } => Diagnostic {\n                        title: \"Unexpected type hole\".into(),\n                        text: \"We need to know the exact type here so type holes cannot be used.\"\n                            .into(),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: Some(\"I need to know what this is\".into()),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::ReservedModuleName { name } => {\n                        let text = format!(\n                            \"The module name `{name}` is reserved.\nTry a different name for this module.\"\n                        );\n                        Diagnostic {\n                            title: \"Reserved module name\".into(),\n                            text,\n                            hint: None,\n                            location: None,\n                            level: Level::Error,\n                        }\n                    }\n\n                    TypeError::KeywordInModuleName { name, keyword } => {\n                        let text = wrap_format!(\n                            \"The module name `{name}` contains the keyword `{keyword}`, \\\nso importing it would be a syntax error.\nTry a different name for this module.\"\n                        );\n                        Diagnostic {\n                            title: \"Invalid module name\".into(),\n                            text,\n                            hint: None,\n                            location: None,\n                            level: Level::Error,\n                        }\n                    }\n\n                    TypeError::NotExhaustivePatternMatch {\n                        location,\n                        unmatched,\n                        kind,\n                    } => {\n                        let mut text = match kind {\n                            PatternMatchKind::Case => {\n                                \"This case expression does not match all possibilities.\nEach constructor must have a pattern that matches it or\nelse it could crash.\"\n                            }\n                            PatternMatchKind::Assignment => {\n                                \"This assignment does not match all possibilities.\nEither use a case expression with patterns for each possible\nvalue, or use `let assert` rather than `let`.\"\n                            }\n                        }\n                        .to_string();\n\n                        text.push_str(\"\\n\\nThese values are not matched:\\n\\n\");\n                        for unmatched in unmatched {\n                            text.push_str(\"  - \");\n                            text.push_str(unmatched);\n                            text.push('\\n');\n                        }\n                        Diagnostic {\n                            title: \"Not exhaustive pattern match\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::ArgumentNameAlreadyUsed { location, name } => Diagnostic {\n                        title: \"Argument name already used\".into(),\n                        text: format!(\n                            \"Two `{name}` arguments have been defined for this function.\"\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::UnlabelledAfterlabelled { location } => Diagnostic {\n                        title: \"Unlabelled argument after labelled argument\".into(),\n                        text: wrap(\n                            \"All unlabelled arguments must come before any labelled arguments.\",\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::RecursiveTypeAlias { location, cycle } => {\n                        let mut text = \"This type alias is defined in terms of itself.\\n\".into();\n                        write_cycle(&mut text, cycle);\n                        text.push_str(\n                            \"If we tried to compile this recursive type it would expand\nforever in a loop, and we'd never get the final type.\",\n                        );\n                        Diagnostic {\n                            title: \"Type cycle\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::ExternalMissingAnnotation { location, kind } => {\n                        let kind = match kind {\n                            MissingAnnotation::Parameter => \"parameter\",\n                            MissingAnnotation::Return => \"return\",\n                        };\n                        let text = format!(\n                            \"A {kind} annotation is missing from this function.\n\nFunctions with external implementations must have type annotations\nso we can tell what type of values they accept and return.\",\n                        );\n                        Diagnostic {\n                            title: \"Missing type annotation\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::NoImplementation { location } => {\n                        let text = \"We can't compile this function as it doesn't have an\nimplementation. Add a body or an external implementation\nusing the `@external` attribute.\"\n                            .into();\n                        Diagnostic {\n                            title: \"Function without an implementation\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::InvalidExternalJavascriptModule {\n                        location,\n                        name,\n                        module,\n                    } => {\n                        let text = wrap_format!(\n                            \"The function `{name}` has an external JavaScript \\\nimplementation but the module path `{module}` is not valid.\"\n                        );\n                        Diagnostic {\n                            title: \"Invalid JavaScript module\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::InvalidExternalJavascriptFunction {\n                        location,\n                        name,\n                        function,\n                    } => {\n                        let text = wrap_format!(\n                            \"The function `{name}` has an external JavaScript \\\nimplementation but the function name `{function}` is not valid.\"\n                        );\n                        Diagnostic {\n                            title: \"Invalid JavaScript function\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::InexhaustiveLetAssignment { location, missing } => {\n                        let mut text = wrap(\n                            \"This assignment uses a pattern that does not \\\nmatch all possible values. If one of the other values \\\nis used then the assignment will crash.\n\nThe missing patterns are:\\n\",\n                        );\n                        for missing in missing {\n                            text.push_str(\"\\n    \");\n                            text.push_str(missing);\n                        }\n                        text.push('\\n');\n\n                        Diagnostic {\n                            title: \"Inexhaustive pattern\".into(),\n                            text,\n                            hint: Some(\n                                \"Use a more general pattern or use `let assert` instead.\".into(),\n                            ),\n                            level: Level::Error,\n                            location: Some(Location {\n                                src: src.clone(),\n                                path: path.to_path_buf(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: Vec::new(),\n                            }),\n                        }\n                    }\n\n                    TypeError::InexhaustiveCaseExpression { location, missing } => {\n                        let mut text = wrap(\n                            \"This case expression does not have a pattern \\\nfor all possible values. If it is run on one of the \\\nvalues without a pattern then it will crash.\n\nThe missing patterns are:\\n\",\n                        );\n                        for missing in missing {\n                            text.push_str(\"\\n    \");\n                            text.push_str(missing);\n                        }\n                        Diagnostic {\n                            title: \"Inexhaustive patterns\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                src: src.clone(),\n                                path: path.to_path_buf(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: Vec::new(),\n                            }),\n                        }\n                    }\n\n                    TypeError::MissingCaseBody { location } => {\n                        let text = wrap(\"This case expression is missing its body.\");\n                        Diagnostic {\n                            title: \"Missing case body\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                src: src.clone(),\n                                path: path.to_path_buf(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: Vec::new(),\n                            }),\n                        }\n                    }\n\n                    TypeError::UnsupportedExpressionTarget {\n                        location,\n                        target: current_target,\n                    } => {\n                        let text = wrap_format!(\n                            \"This value is not available as it is defined using externals, \\\nand there is no implementation for the {} target.\\n\",\n                            match current_target {\n                                Target::Erlang => \"Erlang\",\n                                Target::JavaScript => \"JavaScript\",\n                            }\n                        );\n                        let hint = wrap(\"Did you mean to build for a different target?\");\n                        Diagnostic {\n                            title: \"Unsupported target\".into(),\n                            text,\n                            hint: Some(hint),\n                            level: Level::Error,\n                            location: Some(Location {\n                                path: path.clone(),\n                                src: src.clone(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnsupportedPublicFunctionTarget {\n                        location,\n                        name,\n                        target,\n                    } => {\n                        let target = match target {\n                            Target::Erlang => \"Erlang\",\n                            Target::JavaScript => \"JavaScript\",\n                        };\n                        let text = wrap_format!(\n                            \"The `{name}` function is public but doesn't have an \\\nimplementation for the {target} target. All public functions of a package \\\nmust be able to compile for a module to be valid.\"\n                        );\n                        Diagnostic {\n                            title: \"Unsupported target\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                path: path.clone(),\n                                src: src.clone(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UnusedTypeAliasParameter { location, name } => {\n                        let text = wrap_format!(\n                            \"The type variable `{name}` is unused. It can be safely removed.\",\n                        );\n                        Diagnostic {\n                            title: \"Unused type parameter\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                path: path.clone(),\n                                src: src.clone(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::DuplicateTypeParameter { location, name } => {\n                        let text = wrap_format!(\n                            \"This definition has multiple type parameters named `{name}`.\nRename or remove one of them.\",\n                        );\n                        Diagnostic {\n                            title: \"Duplicate type parameter\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                path: path.clone(),\n                                src: src.clone(),\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::NotFnInUse { location, type_ } => {\n                        let mut printer = Printer::new(names);\n                        let text = wrap_format!(\n                            \"In a use expression, there should be a function on \\\nthe right hand side of `<-`, but this value has type:\n\n    {}\n\nSee: https://tour.gleam.run/advanced-features/use/\",\n                            printer.print_type(type_)\n                        );\n\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UseFnDoesntTakeCallback {\n                        location,\n                        actual_type: None,\n                    }\n                    | TypeError::UseFnIncorrectArity {\n                        location,\n                        expected: 0,\n                        given: 1,\n                    } => {\n                        let text = wrap(\n                            \"The function on the right of `<-` here \\\ntakes no arguments, but it has to take at least \\\none argument, a callback function.\n\nSee: https://tour.gleam.run/advanced-features/use/\",\n                        );\n                        Diagnostic {\n                            title: \"Incorrect arity\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(\"Expected no arguments, got 1\".into()),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UseFnIncorrectArity {\n                        location,\n                        expected,\n                        given,\n                    } => {\n                        let expected_string = match expected {\n                            0 => \"no arguments\".into(),\n                            1 => \"1 argument\".into(),\n                            _ => format!(\"{expected} arguments\"),\n                        };\n                        let supplied_arguments = given - 1;\n                        let supplied_arguments_string = match supplied_arguments {\n                            0 => \"no arguments\".into(),\n                            1 => \"1 argument\".into(),\n                            _ => format!(\"{given} arguments\"),\n                        };\n                        let label = format!(\"Expected {expected_string}, got {given}\");\n                        let mut text: String = format!(\n                            \"The function on the right of `<-` \\\nhere takes {expected_string}.\\n\"\n                        );\n\n                        if expected > given {\n                            if supplied_arguments == 0 {\n                                text.push_str(\n                                    \"The only argument that was supplied is \\\nthe `use` callback function.\\n\",\n                                )\n                            } else {\n                                text.push_str(&format!(\n                                    \"You supplied {supplied_arguments_string} \\\nand the final one is the `use` callback function.\\n\"\n                                ));\n                            }\n                        } else {\n                            text.push_str(\n                                \"All the arguments have already been supplied, \\\nso it cannot take the `use` callback function as a final argument.\\n\",\n                            )\n                        };\n\n                        text.push_str(\"\\nSee: https://tour.gleam.run/advanced-features/use/\");\n\n                        Diagnostic {\n                            title: \"Incorrect arity\".into(),\n                            text: wrap(&text),\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(label),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UseFnDoesntTakeCallback {\n                        location,\n                        actual_type: Some(actual),\n                    } => {\n                        let mut printer = Printer::new(names);\n                        let text = wrap_format!(\n                            \"The function on the right hand side of `<-` \\\nhas to take a callback function as its last argument. \\\nBut the last argument of this function has type:\n\n    {}\n\nSee: https://tour.gleam.run/advanced-features/use/\",\n                            printer.print_type(actual)\n                        );\n                        Diagnostic {\n                            title: \"Type mismatch\".into(),\n                            text: wrap(&text),\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::UseCallbackIncorrectArity {\n                        pattern_location,\n                        call_location,\n                        expected,\n                        given,\n                    } => {\n                        let expected = match expected {\n                            0 => \"no arguments\".into(),\n                            1 => \"1 argument\".into(),\n                            _ => format!(\"{expected} arguments\"),\n                        };\n\n                        let specified = match given {\n                            0 => \"none were provided\".into(),\n                            1 => \"1 was provided\".into(),\n                            _ => format!(\"{given} were provided\"),\n                        };\n\n                        let text = wrap_format!(\n                            \"This function takes a callback that expects {expected}. \\\nBut {specified} on the left hand side of `<-`.\n\nSee: https://tour.gleam.run/advanced-features/use/\"\n                        );\n                        Diagnostic {\n                            title: \"Incorrect arity\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *call_location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![ExtraLabel {\n                                    src_info: None,\n                                    label: Label {\n                                        text: Some(format!(\"Expected {expected}, got {given}\")),\n                                        span: *pattern_location,\n                                    },\n                                }],\n                            }),\n                        }\n                    }\n\n                    TypeError::BadName {\n                        location,\n                        name,\n                        kind,\n                    } => {\n                        let kind_str = kind.as_str();\n                        let label = format!(\"This is not a valid {} name\", kind_str.to_lowercase());\n                        let text = match kind {\n                            Named::Type | Named::TypeAlias | Named::CustomTypeVariant => {\n                                wrap_format!(\n                                    \"Hint: {} names start with an uppercase \\\nletter and contain only lowercase letters, numbers, \\\nand uppercase letters.\nTry: {}\",\n                                    kind_str,\n                                    to_upper_camel_case(name)\n                                )\n                            }\n                            Named::Variable\n                            | Named::TypeVariable\n                            | Named::Argument\n                            | Named::Label\n                            | Named::Constant\n                            | Named::Function => wrap_format!(\n                                \"Hint: {} names start with a lowercase letter \\\nand contain a-z, 0-9, or _.\nTry: {}\",\n                                kind_str,\n                                to_snake_case(name)\n                            ),\n                            Named::Discard => wrap_format!(\n                                \"Hint: {} names start with _ and contain \\\na-z, 0-9, or _.\nTry: _{}\",\n                                kind_str,\n                                to_snake_case(name)\n                            ),\n                        };\n\n                        Diagnostic {\n                            title: format!(\"Invalid {} name\", kind_str.to_lowercase()),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: Some(label),\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::AllVariantsDeprecated { location } => {\n                        let text = String::from(\n                            \"Consider deprecating the type as a whole.\n\n  @deprecated(\\\"message\\\")\n  type Wibble {\n    Wobble1\n    Wobble2\n  }\n\",\n                        );\n                        Diagnostic {\n                            title: \"All variants of custom type deprecated.\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n                    TypeError::DeprecatedVariantOnDeprecatedType { location } => {\n                        let text = wrap(\n                            \"This custom type has already been deprecated, so deprecating \\\none of its variants does nothing.\nConsider removing the deprecation attribute on the variant.\",\n                        );\n\n                        Diagnostic {\n                            title: \"Custom type already deprecated\".into(),\n                            text,\n                            hint: None,\n                            level: Level::Error,\n                            location: Some(Location {\n                                label: Label {\n                                    text: None,\n                                    span: *location,\n                                },\n                                path: path.clone(),\n                                src: src.clone(),\n                                extra_labels: vec![],\n                            }),\n                        }\n                    }\n\n                    TypeError::EchoWithNoFollowingExpression { location } => Diagnostic {\n                        title: \"Invalid echo use\".to_string(),\n                        text: wrap(\"The `echo` keyword should be followed by a value to print.\"),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: Some(\"I was expecting a value after this\".into()),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::StringConcatenationWithAddInt { location } => Diagnostic {\n                        title: \"Type mismatch\".to_string(),\n                        text: wrap(\n                            \"The + operator can only be used on Ints.\nTo join two strings together you can use the <> operator.\",\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: Some(\"Use <> instead\".into()),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::IntOperatorOnFloats { location, operator } => Diagnostic {\n                        title: \"Type mismatch\".to_string(),\n                        text: wrap_format!(\n                            \"The {} operator can only be used on Ints.\",\n                            operator.name()\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: operator\n                                    .float_equivalent()\n                                    .map(|operator| format!(\"Use {} instead\", operator.name())),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::FloatOperatorOnInts { location, operator } => Diagnostic {\n                        title: \"Type mismatch\".to_string(),\n                        text: wrap_format!(\n                            \"The {} operator can only be used on Floats.\",\n                            operator.name()\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: operator\n                                    .int_equivalent()\n                                    .map(|operator| format!(\"Use {} instead\", operator.name())),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::DoubleVariableAssignmentInBitArray { location } => Diagnostic {\n                        title: \"Double variable assignment\".to_string(),\n                        text: wrap(\n                            \"This pattern assigns to two different variables \\\nat once, which is not possible in bit arrays.\",\n                        ),\n                        hint: Some(wrap(\"Remove the `as` assignment.\")),\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::NonUtf8StringAssignmentInBitArray { location } => Diagnostic {\n                        title: \"Non UTF-8 string assignment\".to_string(),\n                        text: wrap(\n                            \"This pattern assigns a non UTF-8 string to a \\\nvariable in a bit array. This is planned to be supported in the future, but we are \\\nunsure of the desired behaviour. Please go to https://github.com/gleam-lang/gleam/issues/4566 \\\nand explain your usecase for this pattern, and how you would expect it to behave.\",\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::PrivateOpaqueType { location } => Diagnostic {\n                        title: \"Private opaque type\".to_string(),\n                        text: wrap(\"Only a public type can be opaque.\"),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: Some(\"You can safely remove this.\".to_string()),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::SrcImportingDevDependency {\n                        location,\n                        importing_module,\n                        imported_module,\n                        package,\n                    } => Diagnostic {\n                        title: \"App importing dev dependency\".to_string(),\n                        text: wrap_format!(\n                            \"The application module `{importing_module}` is \\\nimporting the module `{imported_module}`, but `{package}`, the package it \\\nbelongs to, is a dev dependency.\n\nDev dependencies are not included in production builds so application \\\nmodules should not import them. Perhaps change `{package}` to a regular dependency.\"\n                        ),\n                        hint: None,\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::ExternalTypeWithConstructors { location } => Diagnostic {\n                        title: \"External type with constructors\".to_string(),\n                        text: wrap_format!(\n                            \"This type is annotated with the `@external` annotation, \\\nbut it has constructors. The `@external` annotation is only for external types \\\nwith no constructors.\"\n                        ),\n                        hint: Some(\"Remove the `@external` annotation\".into()),\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n\n                    TypeError::LowercaseBoolPattern { location } => Diagnostic {\n                        title: \"Lowercase bool pattern\".to_string(),\n                        text: \"See: https://tour.gleam.run/basics/bools/\".into(),\n                        hint: Some(\"In Gleam bool literals are `True` and `False`.\".into()),\n                        level: Level::Error,\n                        location: Some(Location {\n                            label: Label {\n                                text: Some(\"This is not a bool\".into()),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    },\n                })\n                .collect_vec(),\n\n            Error::Parse { path, src, error } => {\n                let location = if error.error == ParseErrorType::UnexpectedEof {\n                    crate::ast::SrcSpan {\n                        start: (src.len() - 1) as u32,\n                        end: (src.len() - 1) as u32,\n                    }\n                } else {\n                    error.location\n                };\n\n                let title = String::from(\"Syntax error\");\n                let ParseErrorDetails {\n                    text,\n                    label_text,\n                    extra_labels,\n                    hint,\n                } = error.error.details();\n                vec![Diagnostic {\n                    title,\n                    text,\n                    level: Level::Error,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.clone(),\n                        label: Label {\n                            text: Some(label_text.into()),\n                            span: location,\n                        },\n                        extra_labels,\n                    }),\n                    hint,\n                }]\n            }\n\n            Error::ImportCycle { modules } => {\n                let first_location = &modules.first().1;\n                let rest_locations = modules\n                    .iter()\n                    .skip(1)\n                    .map(|(_, l)| ExtraLabel {\n                        label: Label {\n                            text: Some(\"Imported here\".into()),\n                            span: l.location,\n                        },\n                        src_info: Some((l.src.clone(), l.path.clone())),\n                    })\n                    .collect_vec();\n                let mut text = \"The import statements for these modules form a cycle:\n\"\n                .into();\n                let mod_names = modules.iter().map(|m| m.0.clone()).collect_vec();\n                write_cycle(&mut text, &mod_names);\n                text.push_str(\n                    \"Gleam doesn't support dependency cycles like these, please break the\ncycle to continue.\",\n                );\n                vec![Diagnostic {\n                    title: \"Import cycle\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: Some(Location {\n                        label: Label {\n                            text: Some(\"Imported here\".into()),\n                            span: first_location.location,\n                        },\n                        path: first_location.path.clone(),\n                        src: first_location.src.clone(),\n                        extra_labels: rest_locations,\n                    }),\n                }]\n            }\n\n            Error::PackageCycle { packages } => {\n                let mut text = \"The dependencies for these packages form a cycle:\n\"\n                .into();\n                write_cycle(&mut text, packages);\n                text.push_str(\n                    \"Gleam doesn't support dependency cycles like these, please break the\ncycle to continue.\",\n                );\n                vec![Diagnostic {\n                    title: \"Dependency cycle\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::UnknownImport { import, details } => {\n                let UnknownImportDetails {\n                    module,\n                    location,\n                    path,\n                    src,\n                    modules,\n                } = details.as_ref();\n                let text = wrap(&format!(\n                    \"The module `{module}` is trying to import the module `{import}`, \\\nbut it cannot be found.\"\n                ));\n                vec![Diagnostic {\n                    title: \"Unknown import\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: Some(Location {\n                        label: Label {\n                            text: did_you_mean(import, modules),\n                            span: *location,\n                        },\n                        path: path.clone(),\n                        src: src.clone(),\n                        extra_labels: vec![],\n                    }),\n                }]\n            }\n\n            Error::StandardIo { action, err } => {\n                let err = match err {\n                    Some(e) => format!(\n                        \"\\nThe error message from the stdio library was:\\n\\n    {}\\n\",\n                        std_io_error_kind_text(e)\n                    ),\n                    None => \"\".into(),\n                };\n                vec![Diagnostic {\n                    title: \"Standard IO failure\".into(),\n                    text: format!(\n                        \"An error occurred while trying to {}:\n\n{}\",\n                        action.text(),\n                        err,\n                    ),\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::Format { problem_files } => {\n                let files: Vec<_> = problem_files\n                    .iter()\n                    .map(|formatted| formatted.source.as_str())\n                    .map(|p| format!(\"  - {p}\"))\n                    .sorted()\n                    .collect();\n                let mut text = files.iter().join(\"\\n\");\n                text.push('\\n');\n                vec![Diagnostic {\n                    title: \"These files have not been formatted\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::ForbiddenWarnings { count } => {\n                let word_warning = match count {\n                    1 => \"warning\",\n                    _ => \"warnings\",\n                };\n                let text = \"Your project was compiled with the `--warnings-as-errors` flag.\nFix the warnings and try again.\"\n                    .into();\n                vec![Diagnostic {\n                    title: format!(\"{count} {word_warning} generated.\"),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::DownloadPackageError {\n                package_name,\n                package_version,\n                error,\n            } => {\n                let text = format!(\n                    \"A problem was encountered when downloading `{package_name}` {package_version}.\nThe error from the package manager client was:\n\n    {error}\"\n                );\n                vec![Diagnostic {\n                    title: \"Failed to download package\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::Http(error) => {\n                let text = format!(\n                    \"A HTTP request failed.\nThe error from the HTTP client was:\n\n    {error}\"\n                );\n                vec![Diagnostic {\n                    title: \"HTTP error\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::InvalidVersionFormat { input, error } => {\n                let text = format!(\n                    \"I was unable to parse the version \\\"{input}\\\".\nThe error from the parser was:\n\n    {error}\"\n                );\n                vec![Diagnostic {\n                    title: \"Invalid version format\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::IncompatibleLockedVersion { error } => {\n                let text = format!(\n                    \"There is an incompatiblity between a version specified in\nmanifest.toml and a version range specified in gleam.toml:\n\n    {error}\"\n                );\n                vec![Diagnostic {\n                    title: \"Incompatible locked version\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::DependencyCanonicalizationFailed(package) => {\n                let text = format!(\"Local package `{package}` has no canonical path\");\n\n                vec![Diagnostic {\n                    title: \"Failed to create canonical path\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::DependencyResolutionError(error) => vec![Diagnostic {\n                title: \"Dependency resolution failed\".into(),\n                text: wrap(error),\n                hint: None,\n                location: None,\n                level: Level::Error,\n            }],\n\n            Error::DependencyResolutionNoSolution {\n                root_package_name,\n                derivation_tree,\n            } => {\n                let text = wrap(\n                    &DerivationTreePrinter::new(\n                        root_package_name.clone(),\n                        derivation_tree.0.clone(),\n                    )\n                    .print(),\n                );\n                vec![Diagnostic {\n                    title: \"Dependency resolution failed\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::WrongDependencyProvided {\n                path,\n                expected,\n                found,\n            } => {\n                let text = format!(\n                    \"Expected package `{expected}` at path `{path}` but found `{found}` instead.\",\n                );\n\n                vec![Diagnostic {\n                    title: \"Wrong dependency provided\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::ProvidedDependencyConflict {\n                package,\n                source_1,\n                source_2,\n            } => {\n                let text = format!(\n                    \"The package `{package}` is provided as both `{source_1}` and `{source_2}`.\",\n                );\n\n                vec![Diagnostic {\n                    title: \"Conflicting provided dependencies\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::DuplicateDependency(name) => {\n                let text = format!(\n                    \"The package `{name}` is specified in both the dependencies and\ndev_dependencies sections of the gleam.toml file.\"\n                );\n                vec![Diagnostic {\n                    title: \"Dependency duplicated\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::MissingHexPublishFields {\n                description_missing,\n                licence_missing,\n            } => {\n                let mut text =\n                    \"Licence information and package description are required to publish a\npackage to Hex.\\n\"\n                        .to_string();\n                text.push_str(if *description_missing && *licence_missing {\n                    r#\"Add the licences and description fields to your gleam.toml file.\n\ndescription = \"\"\nlicences = [\"Apache-2.0\"]\"#\n                } else if *description_missing {\n                    r#\"Add the description field to your gleam.toml file.\n\ndescription = \"\"\"#\n                } else {\n                    r#\"Add the licences field to your gleam.toml file.\n\nlicences = [\"Apache-2.0\"]\"#\n                });\n                vec![Diagnostic {\n                    title: \"Missing required package fields\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::PublishNonHexDependencies { package } => vec![Diagnostic {\n                title: \"Unpublished dependencies\".into(),\n                text: wrap_format!(\n                    \"The package cannot be published to Hex \\\nbecause dependency `{package}` is not a Hex dependency.\",\n                ),\n                hint: None,\n                location: None,\n                level: Level::Error,\n            }],\n\n            Error::UnsupportedBuildTool {\n                package,\n                build_tools,\n            } => {\n                let text = wrap_format!(\n                    \"The package `{}` cannot be built as it does not use \\\na build tool supported by Gleam. It uses {:?}.\n\nIf you would like us to support this package please let us know by opening an \\\nissue in our tracker: https://github.com/gleam-lang/gleam/issues\",\n                    package,\n                    build_tools\n                );\n                vec![Diagnostic {\n                    title: \"Unsupported build tool\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::FailedToOpenDocs { path, error } => {\n                let error = format!(\"\\nThe error message from the library was:\\n\\n    {error}\\n\");\n                let text = format!(\n                    \"An error occurred while trying to open the docs:\n\n    {path}\n{error}\",\n                );\n                vec![Diagnostic {\n                    title: \"Failed to open docs\".into(),\n                    text,\n                    hint: None,\n                    level: Level::Error,\n                    location: None,\n                }]\n            }\n\n            Error::IncompatibleCompilerVersion {\n                package,\n                required_version,\n                gleam_version,\n            } => {\n                let text = format!(\n                    \"The package `{package}` requires a Gleam version \\\nsatisfying {required_version} but you are using v{gleam_version}.\",\n                );\n                vec![Diagnostic {\n                    title: \"Incompatible Gleam version\".into(),\n                    text,\n                    hint: None,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::InvalidRuntime {\n                target,\n                invalid_runtime,\n            } => {\n                let text = format!(\n                    \"Invalid runtime for {target} target: {invalid_runtime}\",\n                    target = target.as_presentable_str(),\n                    invalid_runtime = invalid_runtime.as_presentable_str(),\n                );\n\n                let hint = match target {\n                    Target::JavaScript => {\n                        Some(\"available runtimes for JavaScript are: node, deno.\".into())\n                    }\n                    Target::Erlang => Some(\n                        \"You can not set a runtime for Erlang. Did you mean to target JavaScript?\"\n                            .into(),\n                    ),\n                };\n\n                vec![Diagnostic {\n                    title: format!(\n                        \"Invalid runtime for {target}\",\n                        target = target.as_presentable_str(),\n                    ),\n                    text,\n                    hint,\n                    location: None,\n                    level: Level::Error,\n                }]\n            }\n\n            Error::JavaScriptPreludeRequired => vec![Diagnostic {\n                title: \"JavaScript prelude required\".into(),\n                text: \"The --javascript-prelude flag must be given when compiling to JavaScript.\"\n                    .into(),\n                level: Level::Error,\n                location: None,\n                hint: None,\n            }],\n            Error::CorruptManifest => vec![Diagnostic {\n                title: \"Corrupt manifest.toml\".into(),\n                text: \"The `manifest.toml` file is corrupt.\".into(),\n                level: Level::Error,\n                location: None,\n                hint: Some(\"Please run `gleam update` to fix it.\".into()),\n            }],\n\n            Error::GleamModuleWouldOverwriteStandardErlangModule { name, path } => {\n                vec![Diagnostic {\n                    title: \"Erlang module name collision\".into(),\n                    text: wrap_format!(\n                        \"The module `{path}` compiles to an Erlang module \\\nnamed `{name}`.\n\nBy default Erlang includes a module with the same name so if we were \\\nto compile and load your module it would overwrite the Erlang one, potentially \\\ncausing confusing errors and crashes.\n\"\n                    ),\n                    level: Level::Error,\n                    location: None,\n                    hint: Some(\"Rename this module and try again.\".into()),\n                }]\n            }\n\n            Error::HexPublishReplaceRequired { version } => vec![Diagnostic {\n                title: \"Version already published\".into(),\n                text: wrap_format!(\n                    \"Version v{version} has already been published.\nThis release has been recently published so you can replace it \\\nor you can publish it using a different version number\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: Some(\n                    \"Please add the --replace flag if you want to replace the release.\".into(),\n                ),\n            }],\n            Error::HexPublishAccessDenied { name, version } => vec![Diagnostic {\n                title: \"Access denied\".to_string(),\n                text: wrap_format!(\n                    \"You are not one of the maintainers of the {name} package, so \\\nyou cannot publish a new {version} version. Are you logged into the correct account?\n\nIf you are trying to publish a new package then you will need to pick another, \\\nas this one is already in use.\n\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: None,\n            }],\n\n            Error::CannotAddSelfAsDependency { name } => vec![Diagnostic {\n                title: \"Dependency cycle\".into(),\n                text: wrap_format!(\n                    \"A package cannot depend on itself, so you cannot \\\nadd `gleam add {name}` in this project.\"\n                ),\n                level: Level::Error,\n                location: None,\n                hint: None,\n            }],\n        }\n    }\n}\n\nfn std_io_error_kind_text(kind: &std::io::ErrorKind) -> String {\n    use std::io::ErrorKind;\n    match kind {\n        ErrorKind::NotFound => \"Could not find the stdio stream\".into(),\n        ErrorKind::PermissionDenied => \"Permission was denied\".into(),\n        ErrorKind::ConnectionRefused => \"Connection was refused\".into(),\n        ErrorKind::ConnectionReset => \"Connection was reset\".into(),\n        ErrorKind::ConnectionAborted => \"Connection was aborted\".into(),\n        ErrorKind::NotConnected => \"Was not connected\".into(),\n        ErrorKind::AddrInUse => \"The stream was already in use\".into(),\n        ErrorKind::AddrNotAvailable => \"The stream was not available\".into(),\n        ErrorKind::BrokenPipe => \"The pipe was broken\".into(),\n        ErrorKind::AlreadyExists => \"A handle to the stream already exists\".into(),\n        ErrorKind::WouldBlock => \"This operation would block when it was requested not to\".into(),\n        ErrorKind::InvalidInput => \"Some parameter was invalid\".into(),\n        ErrorKind::InvalidData => \"The data was invalid.  Check that the encoding is UTF-8\".into(),\n        ErrorKind::TimedOut => \"The operation timed out\".into(),\n        ErrorKind::WriteZero => {\n            \"An attempt was made to write, but all bytes could not be written\".into()\n        }\n        ErrorKind::Interrupted => \"The operation was interrupted\".into(),\n        ErrorKind::UnexpectedEof => \"The end of file was reached before it was expected\".into(),\n        ErrorKind::HostUnreachable\n        | ErrorKind::NetworkUnreachable\n        | ErrorKind::NetworkDown\n        | ErrorKind::NotADirectory\n        | ErrorKind::IsADirectory\n        | ErrorKind::DirectoryNotEmpty\n        | ErrorKind::ReadOnlyFilesystem\n        | ErrorKind::StaleNetworkFileHandle\n        | ErrorKind::StorageFull\n        | ErrorKind::NotSeekable\n        | ErrorKind::QuotaExceeded\n        | ErrorKind::FileTooLarge\n        | ErrorKind::ResourceBusy\n        | ErrorKind::ExecutableFileBusy\n        | ErrorKind::Deadlock\n        | ErrorKind::CrossesDevices\n        | ErrorKind::TooManyLinks\n        | ErrorKind::InvalidFilename\n        | ErrorKind::ArgumentListTooLong\n        | ErrorKind::Unsupported\n        | ErrorKind::OutOfMemory\n        | ErrorKind::Other\n        | _ => \"An unknown error occurred\".into(),\n    }\n}\n\nfn write_cycle(buffer: &mut String, cycle: &[EcoString]) {\n    buffer.push_str(\n        \"\n    ┌─────┐\\n\",\n    );\n    for (index, name) in cycle.iter().enumerate() {\n        if index != 0 {\n            buffer.push_str(\"    │     ↓\\n\");\n        }\n        buffer.push_str(\"    │     \");\n        buffer.push_str(name);\n        buffer.push('\\n');\n    }\n    buffer.push_str(\"    └─────┘\\n\");\n}\n\nfn hint_alternative_operator(op: &BinOp, given: &Type) -> Option<String> {\n    match op {\n        BinOp::AddInt if given.is_float() => Some(hint_numeric_message(\"+.\", \"Float\")),\n        BinOp::DivInt if given.is_float() => Some(hint_numeric_message(\"/.\", \"Float\")),\n        BinOp::GtEqInt if given.is_float() => Some(hint_numeric_message(\">=.\", \"Float\")),\n        BinOp::GtInt if given.is_float() => Some(hint_numeric_message(\">.\", \"Float\")),\n        BinOp::LtEqInt if given.is_float() => Some(hint_numeric_message(\"<=.\", \"Float\")),\n        BinOp::LtInt if given.is_float() => Some(hint_numeric_message(\"<.\", \"Float\")),\n        BinOp::MultInt if given.is_float() => Some(hint_numeric_message(\"*.\", \"Float\")),\n        BinOp::SubInt if given.is_float() => Some(hint_numeric_message(\"-.\", \"Float\")),\n\n        BinOp::AddFloat if given.is_int() => Some(hint_numeric_message(\"+\", \"Int\")),\n        BinOp::DivFloat if given.is_int() => Some(hint_numeric_message(\"/\", \"Int\")),\n        BinOp::GtEqFloat if given.is_int() => Some(hint_numeric_message(\">=\", \"Int\")),\n        BinOp::GtFloat if given.is_int() => Some(hint_numeric_message(\">\", \"Int\")),\n        BinOp::LtEqFloat if given.is_int() => Some(hint_numeric_message(\"<=\", \"Int\")),\n        BinOp::LtFloat if given.is_int() => Some(hint_numeric_message(\"<\", \"Int\")),\n        BinOp::MultFloat if given.is_int() => Some(hint_numeric_message(\"*\", \"Int\")),\n        BinOp::SubFloat if given.is_int() => Some(hint_numeric_message(\"-\", \"Int\")),\n\n        BinOp::AddInt if given.is_string() => Some(hint_string_message()),\n        BinOp::AddFloat if given.is_string() => Some(hint_string_message()),\n\n        BinOp::And\n        | BinOp::Or\n        | BinOp::Eq\n        | BinOp::NotEq\n        | BinOp::LtInt\n        | BinOp::LtEqInt\n        | BinOp::LtFloat\n        | BinOp::LtEqFloat\n        | BinOp::GtEqInt\n        | BinOp::GtInt\n        | BinOp::GtEqFloat\n        | BinOp::GtFloat\n        | BinOp::AddInt\n        | BinOp::AddFloat\n        | BinOp::SubInt\n        | BinOp::SubFloat\n        | BinOp::MultInt\n        | BinOp::MultFloat\n        | BinOp::DivInt\n        | BinOp::DivFloat\n        | BinOp::RemainderInt\n        | BinOp::Concatenate => None,\n    }\n}\n\nfn hint_wrap_value_in_result(expected: &Arc<Type>, given: &Arc<Type>) -> Option<String> {\n    let expected = collapse_links(expected.clone());\n    let (expected_ok_type, expected_error_type) = expected.result_types()?;\n\n    if given.same_as(expected_ok_type.as_ref()) {\n        Some(\"Did you mean to wrap this in an `Ok`?\".into())\n    } else if given.same_as(expected_error_type.as_ref()) {\n        Some(\"Did you mean to wrap this in an `Error`?\".into())\n    } else {\n        None\n    }\n}\n\nfn hint_numeric_message(alt: &str, type_: &str) -> String {\n    format!(\"the {alt} operator can be used with {type_}s\\n\")\n}\n\nfn hint_string_message() -> String {\n    wrap(\"Strings can be joined using the `<>` operator.\")\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Unformatted {\n    pub source: Utf8PathBuf,\n    pub destination: Utf8PathBuf,\n    pub input: EcoString,\n    pub output: String,\n}\n\npub fn wrap(text: &str) -> String {\n    let mut result = String::with_capacity(text.len());\n\n    for (i, line) in wrap_text(text, 75).iter().enumerate() {\n        if i > 0 {\n            result.push('\\n');\n        }\n        result.push_str(line);\n    }\n\n    result\n}\n\nfn wrap_text(text: &str, width: usize) -> Vec<Cow<'_, str>> {\n    let mut lines: Vec<Cow<'_, str>> = Vec::new();\n    for line in text.split('\\n') {\n        // check if line needs to be broken\n        match line.len() > width {\n            false => lines.push(Cow::from(line)),\n            true => {\n                let mut new_lines = break_line(line, width);\n                lines.append(&mut new_lines);\n            }\n        };\n    }\n\n    lines\n}\n\nfn break_line(line: &str, width: usize) -> Vec<Cow<'_, str>> {\n    let mut lines: Vec<Cow<'_, str>> = Vec::new();\n    let mut newline = String::from(\"\");\n\n    // split line by spaces\n    for (i, word) in line.split(' ').enumerate() {\n        let is_new_line = i < 1 || newline.is_empty();\n\n        let can_add_word = match is_new_line {\n            true => newline.len() + word.len() <= width,\n            // +1 accounts for space added before word\n            false => newline.len() + (word.len() + 1) <= width,\n        };\n\n        if can_add_word {\n            if !is_new_line {\n                newline.push(' ');\n            }\n            newline.push_str(word);\n        } else {\n            // word too big, save existing line if present\n            if !newline.is_empty() {\n                // save current line and reset it\n                lines.push(Cow::from(newline.to_owned()));\n                newline.clear();\n            }\n\n            // then save word to a new line or break it\n            match word.len() > width {\n                false => newline.push_str(word),\n                true => {\n                    let (mut newlines, remainder) = break_word(word, width);\n                    lines.append(&mut newlines);\n                    newline.push_str(remainder);\n                }\n            }\n        }\n    }\n\n    // save last line after loop finishes\n    if !newline.is_empty() {\n        lines.push(Cow::from(newline));\n    }\n\n    lines\n}\n\n// breaks word into n lines based on width. Returns list of new lines and remainder\nfn break_word(word: &str, width: usize) -> (Vec<Cow<'_, str>>, &str) {\n    let mut new_lines: Vec<Cow<'_, str>> = Vec::new();\n    let (first, mut remainder) = word.split_at(width);\n    new_lines.push(Cow::from(first));\n\n    // split remainder until it's small enough\n    while remainder.len() > width {\n        let (first, second) = remainder.split_at(width);\n        new_lines.push(Cow::from(first));\n        remainder = second;\n    }\n\n    (new_lines, remainder)\n}\n"
  },
  {
    "path": "compiler-core/src/exhaustiveness/missing_patterns.rs",
    "content": "use super::{CompileCaseResult, Decision, FallbackCheck, RuntimeCheck, Variable, printer::Printer};\nuse crate::type_::environment::Environment;\nuse ecow::EcoString;\nuse indexmap::IndexSet;\nuse std::collections::HashMap;\n\n/// Returns a list of patterns not covered by the match expression.\npub fn missing_patterns(\n    result: &CompileCaseResult,\n    environment: &Environment<'_>,\n) -> Vec<EcoString> {\n    let subjects = &result.compiled_case.subject_variables;\n    let mut generator = MissingPatternsGenerator::new(subjects, environment);\n    generator.add_missing_patterns(&result.compiled_case.tree);\n\n    generator.missing.into_iter().collect()\n}\n\n#[derive(Debug, Clone)]\npub struct VariantField {\n    pub label: Option<EcoString>,\n    pub variable: Variable,\n}\n\n/// Information about a single constructor/value (aka term) being tested, used\n/// to build a list of names of missing patterns.\n#[derive(Debug)]\npub enum Term {\n    Variant {\n        variable: Variable,\n        name: EcoString,\n        module: EcoString,\n        fields: Vec<VariantField>,\n    },\n    Tuple {\n        variable: Variable,\n        elements: Vec<Variable>,\n    },\n    Infinite {\n        variable: Variable,\n    },\n    EmptyList {\n        variable: Variable,\n    },\n    List {\n        variable: Variable,\n        first: Variable,\n        rest: Variable,\n    },\n}\n\nimpl Term {\n    pub fn variable(&self) -> &Variable {\n        match self {\n            Term::Variant { variable, .. } => variable,\n            Term::Tuple { variable, .. } => variable,\n            Term::Infinite { variable } => variable,\n            Term::EmptyList { variable } => variable,\n            Term::List { variable, .. } => variable,\n        }\n    }\n}\n\nstruct MissingPatternsGenerator<'a, 'env> {\n    subjects: &'a Vec<Variable>,\n    terms: Vec<Term>,\n    missing: IndexSet<EcoString>,\n    environment: &'a Environment<'env>,\n    printer: Printer<'a>,\n}\n\nimpl<'a, 'env> MissingPatternsGenerator<'a, 'env> {\n    fn new(subjects: &'a Vec<Variable>, environment: &'a Environment<'env>) -> Self {\n        MissingPatternsGenerator {\n            subjects,\n            terms: vec![],\n            missing: IndexSet::new(),\n            environment,\n            printer: Printer::new(environment.current_module.clone(), &environment.names),\n        }\n    }\n\n    fn print_terms(&self, mapping: HashMap<usize, usize>) -> EcoString {\n        self.printer\n            .print_terms(self.subjects, &self.terms, &mapping)\n    }\n\n    fn add_missing_patterns(&mut self, node: &Decision) {\n        match node {\n            Decision::Run { .. } => {}\n\n            Decision::Guard { if_false, .. } => self.add_missing_patterns(if_false),\n\n            Decision::Fail => {\n                // At this point the terms stack looks something like this:\n                // `[term, term + arguments, term, ...]`. To construct a pattern\n                // name from this stack, we first map all variables to their\n                // term indexes. This is needed because when a term defines\n                // arguments, the terms for those arguments don't necessarily\n                // appear in order in the term stack.\n                //\n                // This mapping is then used when (recursively) generating a\n                // pattern name.\n                //\n                // This approach could probably be done more efficiently, so if\n                // you're reading this and happen to know of a way, please\n                // submit a merge request :)\n                let mut mapping = HashMap::new();\n                for (index, step) in self.terms.iter().enumerate() {\n                    _ = mapping.insert(step.variable().id, index);\n                }\n                let pattern = self.print_terms(mapping);\n\n                _ = self.missing.insert(pattern);\n            }\n\n            Decision::Switch {\n                var,\n                choices,\n                fallback,\n                fallback_check,\n            } => {\n                for (check, body) in choices {\n                    self.add_missing_patterns_after_check(var, check, body);\n                }\n\n                match fallback_check.as_ref() {\n                    FallbackCheck::InfiniteCatchAll => {\n                        self.add_missing_patterns(fallback);\n                    }\n                    FallbackCheck::RuntimeCheck { check } => {\n                        self.add_missing_patterns_after_check(var, check, fallback)\n                    }\n                    FallbackCheck::CatchAll { ignored_checks } => {\n                        for check in ignored_checks {\n                            self.add_missing_patterns_after_check(var, check, fallback);\n                        }\n                    }\n                };\n            }\n        }\n    }\n\n    fn add_missing_patterns_after_check(\n        &mut self,\n        var: &Variable,\n        check: &RuntimeCheck,\n        body: &Decision,\n    ) {\n        let term = self.check_to_term(var.clone(), check);\n        self.terms.push(term);\n        self.add_missing_patterns(body);\n        _ = self.terms.pop();\n    }\n\n    fn check_to_term(&self, variable: Variable, check: &RuntimeCheck) -> Term {\n        match check {\n            RuntimeCheck::Int { .. }\n            | RuntimeCheck::Float { .. }\n            | RuntimeCheck::String { .. }\n            | RuntimeCheck::BitArray { .. }\n            | RuntimeCheck::StringPrefix { .. } => Term::Infinite { variable },\n\n            RuntimeCheck::Tuple { elements, .. } => Term::Tuple {\n                variable,\n                elements: elements.clone(),\n            },\n\n            RuntimeCheck::Variant {\n                index,\n                fields,\n                labels,\n                ..\n            } => {\n                let (module, name) = variable\n                    .type_\n                    .named_type_name()\n                    .expect(\"Should be a named type\");\n\n                let name = self\n                    .environment\n                    .get_constructors_for_type(&module, &name)\n                    .expect(\"Custom type constructor must have custom type kind\")\n                    .variants\n                    .get(*index)\n                    .expect(\"Custom type constructor exist for type\")\n                    .name\n                    .clone();\n\n                let fields = fields\n                    .iter()\n                    .enumerate()\n                    .map(|(index, variable)| VariantField {\n                        label: labels.get(&index).cloned(),\n                        variable: variable.clone(),\n                    })\n                    .collect();\n\n                Term::Variant {\n                    variable,\n                    name,\n                    module,\n                    fields,\n                }\n            }\n\n            RuntimeCheck::NonEmptyList { first, rest } => Term::List {\n                variable,\n                first: first.clone(),\n                rest: rest.clone(),\n            },\n\n            RuntimeCheck::EmptyList => Term::EmptyList { variable },\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/exhaustiveness/printer.rs",
    "content": "use std::collections::HashMap;\n\nuse ecow::EcoString;\n\nuse crate::{\n    ast::Publicity,\n    type_::printer::{NameContextInformation, Names},\n};\n\nuse super::{Variable, missing_patterns::Term};\n\n#[derive(Debug)]\npub struct Printer<'a> {\n    names: &'a Names,\n    /// This is the module that is being currently analysed.\n    current_module: EcoString,\n}\n\nimpl<'a> Printer<'a> {\n    pub fn new(current_module: EcoString, names: &'a Names) -> Self {\n        Printer {\n            current_module,\n            names,\n        }\n    }\n\n    pub fn print_terms(\n        &self,\n        subjects: &[Variable],\n        terms: &[Term],\n        mapping: &HashMap<usize, usize>,\n    ) -> EcoString {\n        let mut buffer = EcoString::new();\n        for (i, subject) in subjects.iter().enumerate() {\n            if i != 0 {\n                buffer.push_str(\", \");\n            }\n\n            match mapping.get(&subject.id) {\n                Some(&index) => {\n                    let term = terms.get(index).expect(\"Term must exist\");\n                    self.print(term, terms, mapping, &mut buffer);\n                }\n                None => buffer.push('_'),\n            }\n        }\n        buffer\n    }\n\n    fn print(\n        &self,\n        term: &Term,\n        terms: &[Term],\n        mapping: &HashMap<usize, usize>,\n        buffer: &mut EcoString,\n    ) {\n        match term {\n            Term::Variant {\n                name,\n                module,\n                fields,\n                variable,\n            } => {\n                let is_defined_in_current_module = *module == self.current_module;\n                let is_internal = variable\n                    .type_\n                    .named_type_publicity()\n                    .unwrap_or(Publicity::Public)\n                    .is_internal();\n\n                // We don't want to expose information about an internal type,\n                // making it easy to rely on its internal structure.\n                // So what we do is we just show a catch all pattern `_` for\n                // those.\n                // We do this only if the internal type is defined in a\n                // different module from the one being analysed, otherwise it's\n                // totally fair to want to match on such type.\n                if is_internal && !is_defined_in_current_module {\n                    buffer.push('_');\n                    return;\n                }\n\n                let (module, name) = match self.names.named_constructor(module, name) {\n                    NameContextInformation::Qualified(module, name) => (Some(module), name),\n                    NameContextInformation::Unqualified(name) => (None, name),\n                    NameContextInformation::Unimported(module, name) => {\n                        (module.split('/').next_back(), name)\n                    }\n                };\n\n                if let Some(module) = module {\n                    buffer.push_str(module);\n                    buffer.push('.');\n                }\n                buffer.push_str(name);\n\n                if fields.is_empty() {\n                    return;\n                }\n                buffer.push('(');\n                for (i, field) in fields.iter().enumerate() {\n                    if i != 0 {\n                        buffer.push_str(\", \");\n                    }\n\n                    let mut has_label = false;\n\n                    if let Some(label) = &field.label {\n                        buffer.push_str(label);\n                        buffer.push(':');\n                        has_label = true;\n                    }\n\n                    if let Some(&idx) = mapping.get(&field.variable.id) {\n                        let term = terms.get(idx).expect(\"Term must exist\");\n\n                        match term {\n                            // If it is an infinite term and this field is labelled, it is generally\n                            // more useful to print just the label using label shorthand syntax.\n                            // For example, printing `Person(name:, age:)` instead of\n                            // `Person(name: _, age: _)`.\n                            Term::Infinite { .. } if has_label => {}\n                            Term::Infinite { .. }\n                            | Term::Variant { .. }\n                            | Term::Tuple { .. }\n                            | Term::EmptyList { .. }\n                            | Term::List { .. } => {\n                                // If this field has a label, the current buffer looks like `label:`,\n                                // so we want to print a space before printing the pattern for it.\n                                // If there is no label, we don't need to print the space.\n                                if has_label {\n                                    buffer.push(' ');\n                                }\n                                self.print(term, terms, mapping, buffer);\n                            }\n                        }\n                    } else if !has_label {\n                        buffer.push('_');\n                    }\n                }\n                buffer.push(')');\n            }\n            Term::Tuple { elements, .. } => {\n                buffer.push_str(\"#(\");\n                for (i, variable) in elements.iter().enumerate() {\n                    if i != 0 {\n                        buffer.push_str(\", \");\n                    }\n\n                    if let Some(&idx) = mapping.get(&variable.id) {\n                        self.print(\n                            terms.get(idx).expect(\"Term must exist\"),\n                            terms,\n                            mapping,\n                            buffer,\n                        );\n                    } else {\n                        buffer.push('_');\n                    }\n                }\n                buffer.push(')');\n            }\n            Term::Infinite { .. } => buffer.push('_'),\n            Term::EmptyList { .. } => buffer.push_str(\"[]\"),\n            Term::List { .. } => {\n                buffer.push('[');\n                self.print_list(term, terms, mapping, buffer);\n                buffer.push(']');\n            }\n        }\n    }\n\n    fn print_list(\n        &self,\n        term: &Term,\n        terms: &[Term],\n        mapping: &HashMap<usize, usize>,\n        buffer: &mut EcoString,\n    ) {\n        match term {\n            Term::Infinite { .. } | Term::Variant { .. } | Term::Tuple { .. } => buffer.push('_'),\n\n            Term::EmptyList { .. } => {}\n\n            Term::List { first, rest, .. } => {\n                if let Some(&idx) = mapping.get(&first.id) {\n                    self.print(\n                        terms.get(idx).expect(\"Term must exist\"),\n                        terms,\n                        mapping,\n                        buffer,\n                    )\n                } else {\n                    buffer.push('_');\n                }\n\n                if let Some(&idx) = mapping.get(&rest.id) {\n                    let term = terms.get(idx).expect(\"Term must exist\");\n\n                    match term {\n                        Term::EmptyList { .. } => {}\n                        Term::Variant { .. }\n                        | Term::Tuple { .. }\n                        | Term::Infinite { .. }\n                        | Term::List { .. } => {\n                            buffer.push_str(\", \");\n                            self.print_list(term, terms, mapping, buffer)\n                        }\n                    }\n                } else {\n                    buffer.push_str(\", ..\");\n                }\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use ecow::EcoString;\n\n    use super::Printer;\n    use std::{collections::HashMap, sync::Arc};\n\n    use crate::{\n        ast::SrcSpan,\n        exhaustiveness::{\n            Variable,\n            missing_patterns::{Term, VariantField},\n        },\n        type_::{Type, printer::Names},\n    };\n\n    /// Create a variable with a dummy type, for ease of writing tests\n    fn make_variable(id: usize) -> Variable {\n        Variable {\n            id,\n            type_: Arc::new(Type::Tuple {\n                elements: Vec::new(),\n            }),\n        }\n    }\n\n    fn field(variable: Variable, label: Option<&str>) -> VariantField {\n        VariantField {\n            variable,\n            label: label.map(EcoString::from),\n        }\n    }\n\n    fn get_mapping(terms: &[Term]) -> HashMap<usize, usize> {\n        let mut mapping: HashMap<usize, usize> = HashMap::new();\n\n        for (index, term) in terms.iter().enumerate() {\n            _ = mapping.insert(term.variable().id, index);\n        }\n        mapping\n    }\n\n    #[test]\n    fn test_value_in_current_module() {\n        let current_module = EcoString::from(\"module\");\n        let mut names = Names::new();\n        names.named_constructor_in_scope(current_module.clone(), \"Wibble\".into(), \"Wibble\".into());\n\n        let printer = Printer::new(current_module.clone(), &names);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::Variant {\n            variable: subjects[0].clone(),\n            name: \"Wibble\".into(),\n            module: current_module,\n            fields: Vec::new(),\n        };\n\n        let terms = &[term];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(printer.print_terms(subjects, terms, &mapping), \"Wibble\");\n    }\n\n    #[test]\n    fn test_value_in_current_module_with_arguments() {\n        let current_module = EcoString::from(\"module\");\n        let mut names = Names::new();\n        names.named_constructor_in_scope(current_module.clone(), \"Wibble\".into(), \"Wibble\".into());\n\n        let printer = Printer::new(current_module.clone(), &names);\n\n        let var1 = make_variable(1);\n\n        let var2 = make_variable(2);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::Variant {\n            variable: subjects[0].clone(),\n            name: \"Wibble\".into(),\n            module: current_module,\n            fields: vec![field(var1.clone(), None), field(var2.clone(), None)],\n        };\n\n        let terms = &[\n            term,\n            Term::EmptyList { variable: var1 },\n            Term::Infinite { variable: var2 },\n        ];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(\n            printer.print_terms(subjects, terms, &mapping),\n            \"Wibble([], _)\"\n        );\n    }\n\n    #[test]\n    fn test_value_in_current_module_with_labelled_arguments() {\n        let current_module = EcoString::from(\"module\");\n        let mut names = Names::new();\n        names.named_constructor_in_scope(current_module.clone(), \"Wibble\".into(), \"Wibble\".into());\n\n        let printer = Printer::new(current_module.clone(), &names);\n\n        let var1 = make_variable(1);\n\n        let var2 = make_variable(2);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::Variant {\n            variable: subjects[0].clone(),\n            name: \"Wibble\".into(),\n            module: current_module,\n            fields: vec![\n                field(var1.clone(), Some(\"list\")),\n                field(var2.clone(), Some(\"other\")),\n            ],\n        };\n\n        let terms = &[\n            term,\n            Term::EmptyList { variable: var1 },\n            Term::Infinite { variable: var2 },\n        ];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(\n            printer.print_terms(subjects, terms, &mapping),\n            \"Wibble(list: [], other:)\"\n        );\n    }\n\n    #[test]\n    fn test_module_alias() {\n        let mut names = Names::new();\n\n        assert!(\n            names\n                .imported_module(\"mod\".into(), \"shapes\".into(), SrcSpan::new(50, 60))\n                .is_none()\n        );\n\n        let printer = Printer::new(\"module\".into(), &names);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::Variant {\n            variable: subjects[0].clone(),\n            name: \"Rectangle\".into(),\n            module: \"mod\".into(),\n            fields: Vec::new(),\n        };\n\n        let terms = &[term];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(\n            printer.print_terms(subjects, terms, &mapping),\n            \"shapes.Rectangle\"\n        );\n    }\n\n    #[test]\n    fn test_unqualified_value() {\n        let mut names = Names::new();\n\n        names.named_constructor_in_scope(\"regex\".into(), \"Regex\".into(), \"Regex\".into());\n\n        let printer = Printer::new(\"module\".into(), &names);\n\n        let arg = make_variable(1);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::Variant {\n            variable: subjects[0].clone(),\n            name: \"Regex\".into(),\n            module: \"regex\".into(),\n            fields: vec![field(arg.clone(), None)],\n        };\n\n        let terms = &[term, Term::Infinite { variable: arg }];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(printer.print_terms(subjects, terms, &mapping), \"Regex(_)\");\n    }\n\n    #[test]\n    fn test_unqualified_value_with_alias() {\n        let mut names = Names::new();\n\n        names.named_constructor_in_scope(\"regex\".into(), \"Regex\".into(), \"Reg\".into());\n        names.named_constructor_in_scope(\"gleam\".into(), \"None\".into(), \"None\".into());\n\n        let printer = Printer::new(\"current_module\".into(), &names);\n\n        let arg = make_variable(1);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::Variant {\n            variable: subjects[0].clone(),\n            name: \"Regex\".into(),\n            module: \"regex\".into(),\n            fields: vec![field(arg.clone(), None)],\n        };\n\n        let terms = &[\n            term,\n            Term::Variant {\n                variable: arg,\n                name: \"None\".into(),\n                module: \"gleam\".into(),\n                fields: vec![],\n            },\n        ];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(printer.print_terms(subjects, terms, &mapping), \"Reg(None)\");\n    }\n\n    #[test]\n    fn test_list_pattern() {\n        let mut names = Names::new();\n\n        names.named_constructor_in_scope(\"module\".into(), \"Type\".into(), \"Type\".into());\n\n        let printer = Printer::new(\"module\".into(), &names);\n\n        let var1 = make_variable(1);\n        let var2 = make_variable(2);\n        let var3 = make_variable(3);\n\n        let subjects = &[make_variable(0)];\n        let term = Term::List {\n            variable: subjects[0].clone(),\n            first: var1.clone(),\n            rest: var2.clone(),\n        };\n\n        let terms = &[\n            term,\n            Term::Variant {\n                variable: var1,\n                name: \"Type\".into(),\n                module: \"module\".into(),\n                fields: Vec::new(),\n            },\n            Term::List {\n                variable: var2,\n                first: var3.clone(),\n                rest: make_variable(4),\n            },\n            Term::Infinite { variable: var3 },\n        ];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(\n            printer.print_terms(subjects, terms, &mapping),\n            \"[Type, _, ..]\"\n        );\n    }\n\n    #[test]\n    fn test_multi_pattern() {\n        let mut names = Names::new();\n\n        names.named_constructor_in_scope(\"gleam\".into(), \"Ok\".into(), \"Ok\".into());\n        names.named_constructor_in_scope(\"gleam\".into(), \"False\".into(), \"False\".into());\n\n        let printer = Printer::new(\"module\".into(), &names);\n\n        let subjects = &[make_variable(0), make_variable(1), make_variable(2)];\n\n        let terms = &[\n            Term::Variant {\n                variable: subjects[0].clone(),\n                name: \"Ok\".into(),\n                module: \"gleam\".into(),\n                fields: vec![field(make_variable(3), None)],\n            },\n            Term::Variant {\n                variable: subjects[2].clone(),\n                name: \"False\".into(),\n                module: \"gleam\".into(),\n                fields: Vec::new(),\n            },\n        ];\n        let mapping = get_mapping(terms);\n\n        assert_eq!(\n            printer.print_terms(subjects, terms, &mapping),\n            \"Ok(_), _, False\"\n        );\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/exhaustiveness.rs",
    "content": "//! An implementation of the algorithm described in:\n//!\n//! - How to compile pattern matching, Jules Jacobs.\n//!   <https://julesjacobs.com/notes/patternmatching/patternmatching.pdf>\n//!\n//! - Efficient manipulation of binary data using pattern matching,\n//!   Per Gustafsson and Konstantinos Sagonas.\n//!   <https://user.it.uu.se/~kostis/Papers/JFP_06.pdf>\n//!\n//! - Compiling Pattern Matching to good Decision Trees, Luc Maranget.\n//!   <https://www.cs.tufts.edu/~nr/cs257/archive/luc-maranget/jun08.pdf>\n//!\n//! The first implementation of the decision tree was adapted from Yorick\n//! Peterse's implementation at\n//! <https://github.com/yorickpeterse/pattern-matching-in-rust>.\n//! Thank you Yorick!\n//!\n//! > This module comment (and all the following doc comments) are a rough\n//! > explanation. It's great to set some expectations on what to expect from\n//! > the following code and why the data looks the way it does.\n//! > If you want a more detailed explanation, the original paper is a lot more\n//! > detailed!\n//!\n//! A case to be compiled looks a bit different from the case expressions we're\n//! used to in Gleam: instead of having a variable to match on and a series of\n//! branches, a `CaseToCompile` is made up of a series of branches that can each\n//! contain multiple pattern checks. With a psedo-Gleam syntax, this is what it\n//! would look like:\n//!\n//! ```txt\n//! case {\n//!   a is Some, b is 1, c is _ -> todo\n//!   a is wibble -> todo\n//! }\n//! ```\n//!\n//! > You may wonder, why are we writing branches like this? Usually a case\n//! > expression matches on a single variable and each branch refers to it. For\n//! > example in gleam you'd write:\n//! >\n//! > ```gleam\n//! > case a {\n//! >   Some(_) -> todo\n//! >   None -> todo\n//! > }\n//! > ```\n//! >\n//! > In out representation that would turn into:\n//! >\n//! > ```txt\n//! > case {\n//! >   a is Some(_) -> todo\n//! >   a is None -> todo\n//! > }\n//! > ```\n//! >\n//! > This change makes it way easier to compile the pattern matching into a\n//! > decision tree, because now we can add multiple checks on different\n//! > variables in each branch.\n//!\n//! Starting from this data structure, we'll be splitting all the branches into\n//! a decision tree that can be used to perform exhaustiveness checking and code\n//! generation.\n//!\n\nmod missing_patterns;\npub mod printer;\n\nuse crate::{\n    ast::{\n        self, AssignName, BitArraySize, Endianness, IntOperator, SrcSpan, TypedBitArraySize,\n        TypedClause, TypedPattern, TypedPatternBitArraySegment,\n    },\n    parse::LiteralFloatValue,\n    strings::{\n        convert_string_escape_chars, length_utf16, length_utf32, string_to_utf16_bytes,\n        string_to_utf32_bytes,\n    },\n    type_::{\n        Environment, Opaque, Type, TypeValueConstructor, TypeValueConstructorField, TypeVar,\n        TypeVariantConstructors, collapse_links, error::UnreachablePatternReason,\n        is_prelude_module, string,\n    },\n};\nuse bitvec::{order::Msb0, slice::BitSlice, vec::BitVec, view::BitView};\nuse ecow::EcoString;\nuse id_arena::{Arena, Id};\nuse itertools::Itertools;\nuse num_bigint::{BigInt, Sign};\nuse num_traits::ToPrimitive;\nuse radix_trie::{Trie, TrieCommon};\nuse std::{\n    cell::RefCell,\n    cmp::Ordering,\n    collections::{HashMap, HashSet, VecDeque},\n    hash::Hash,\n    sync::Arc,\n};\n\n/// A single branch composing a `case` expression to be compiled into a decision\n/// tree.\n///\n/// As shown in the module documentation, branches are a bit different from the\n/// usual branches we see in Gleam's case expressions. Each branch can perform\n/// multiple checks (each on a different variable, which appears in the check\n/// itself!):\n///\n/// ```txt\n/// a is Some, b is 1 if condition -> todo\n/// ─┬───────  ─┬──── ─┬──────────    ─┬──\n///  │          │      │               ╰── body: an arbitrary expression\n///  │          │      ╰── guard: an additional boolean condition\n///  ╰──────────┴── checks: check that a variable matches with a pattern\n/// ─┬────────────────────────────────────\n///  ╰── branch: one of the branches making up a pattern matching expression\n/// ```\n///\n/// As shown here a branch can also optionally include a guard with a boolean\n/// condition and is followed by a body that is to be executed if all the checks\n/// match (and the guard evaluates to true).\n///\n#[derive(Clone, Eq, PartialEq, Debug)]\nstruct Branch {\n    /// Each branch is identified by a numeric index, so we can nicely\n    /// report errors once we find something's wrong with a branch.\n    ///\n    clause_index: usize,\n\n    /// Each alternative pattern in an alternative pattern matching (e.g.\n    /// `one | two | three -> todo`) gets turned into its own branch in this\n    /// internal representation. So we also keep track of the index of the\n    /// alternative this comes from (0 being the first one and so on...)\n    ///\n    alternative_index: usize,\n    checks: Vec<PatternCheck>,\n    guard: Option<usize>,\n    body: Body,\n}\n\nimpl Branch {\n    fn new(\n        clause_index: usize,\n        alternative_index: usize,\n        checks: Vec<PatternCheck>,\n        has_guard: bool,\n    ) -> Self {\n        Self {\n            clause_index,\n            alternative_index,\n            checks,\n            guard: if has_guard { Some(clause_index) } else { None },\n            body: Body::new(clause_index),\n        }\n    }\n\n    /// Removes and returns a `PatternCheck` on the given variable from this\n    /// branch.\n    ///\n    fn pop_check_on_var(&mut self, var: &Variable) -> Option<PatternCheck> {\n        let index = self.checks.iter().position(|check| check.var == *var)?;\n        Some(self.checks.remove(index))\n    }\n\n    fn add_check(&mut self, check: PatternCheck) {\n        self.checks.push(check);\n    }\n\n    /// To simplify compiling the pattern we can get rid of all catch-all\n    /// patterns that are guaranteed to match by turning those into assignments.\n    ///\n    /// What does this look like in practice?  Let's go over an example.\n    /// Let's say we have this case to compile:\n    ///\n    /// ```gleam\n    /// case a {\n    ///   Some(1) -> Some(2)\n    ///   otherwise -> otherwise\n    /// }\n    /// ```\n    ///\n    /// In our internal representation this would become:\n    ///\n    /// ```txt\n    /// case {\n    ///   a is Some(1) -> Some(2)\n    ///   a is otherwise -> otherwise\n    ///   ─┬────────────\n    ///    ╰── `a` will always match with this \"catch all\" variable pattern\n    /// }\n    /// ```\n    ///\n    /// Focusing on the last branch, we can remove that check that always matches\n    /// by keeping track in its body of the correspondence. So it would end up\n    /// looking like this:\n    ///\n    /// ```txt\n    /// case {\n    ///   a is Some(1) -> Some(2)\n    ///   ∅ -> {\n    ///   ┬\n    ///   ╰── This represents the fact that there's no checks left for this branch!\n    ///       So we can make another observation: if there's no checks left in a\n    ///       branch we know it will always match and we can produce a leaf in the\n    ///       decision tree (there's an exception when we have guards, but we'll\n    ///       get to it later)!\n    ///\n    ///     let otherwise = a\n    ///     ─┬───────────────\n    ///      ╰── And now we can understand what those `bindings` at the start of\n    ///          a body are: as we remove variable patterns, we will rewrite those\n    ///          as assignments at the top of the body of the corresponding branch.\n    ///\n    ///     otherwise\n    ///   }\n    /// }\n    /// ```\n    ///\n    fn move_unconditional_patterns(&mut self, compiler: &mut Compiler<'_>) {\n        self.checks.retain_mut(|check| {\n            loop {\n                match compiler.pattern(check.pattern) {\n                    // Variable patterns always match, so we move those to the body\n                    // and remove them from the branch's checks.\n                    Pattern::Variable { name } => {\n                        self.body.assign(name.clone(), check.var.clone());\n                        return false;\n                    }\n                    // A discard pattern always matches, but since the value is not\n                    // used we can just remove it without even adding an assignment\n                    // to the body!\n                    Pattern::Discard => return false,\n                    // Assigns are kind of special: they get turned into assignments\n                    // (shocking) but then we can't discard the pattern they wrap.\n                    // So we replace the assignment pattern with the one it's wrapping\n                    // and try again.\n                    Pattern::Assign { name, pattern } => {\n                        self.body.assign(name.clone(), check.var.clone());\n                        check.pattern = *pattern;\n                    }\n                    // There's a special case of assignments when it comes to string\n                    // prefix patterns. We can give a name to a literal prefix like this:\n                    // `\"0\" as digit <> rest`.\n                    // We also want to move this special case of an assignment to the\n                    // branch body!\n                    Pattern::StringPrefix {\n                        prefix,\n                        prefix_name,\n                        rest: _,\n                    } => {\n                        if let Some(variable) = std::mem::take(prefix_name) {\n                            self.body\n                                .assign_literal_string(variable.clone(), prefix.clone());\n                        }\n                        return true;\n                    }\n                    // There's a special case of assignments when it comes to bit\n                    // array patterns. We can give a name to one slice of the array and\n                    // bind it to a variable to be used by later steps of the pattern\n                    // like this: `<<len, payload:size(len)>>` (here we're binding\n                    // two variables! `len` and `payload`).\n                    //\n                    // This kind of slicing will always match if it's not guarded by\n                    // any size test, so if we find a `ReadAction` that is the first\n                    // test to perform in a bit array pattern we know it's always\n                    // going to match and can be safely moved into the branch's body.\n                    Pattern::BitArray { tests } => match tests.front_mut() {\n                        Some(BitArrayTest::Match(MatchTest {\n                            value: BitArrayMatchedValue::Variable(name),\n                            read_action,\n                        })) => {\n                            let bit_array = check.var.clone();\n                            self.body.assign_bit_array_slice(\n                                name.clone(),\n                                bit_array,\n                                read_action.clone(),\n                            );\n                            let _ = tests.pop_front();\n                        }\n\n                        Some(test) => match test {\n                            // If we have `_ as a` we treat that as a regular variable\n                            // assignment.\n                            BitArrayTest::Match(MatchTest {\n                                value: BitArrayMatchedValue::Assign { name, value },\n                                read_action,\n                            }) if value.is_discard() => {\n                                *test = BitArrayTest::Match(MatchTest {\n                                    value: BitArrayMatchedValue::Variable(name.clone()),\n                                    read_action: read_action.clone(),\n                                });\n                            }\n\n                            // Just like regular assigns, those patterns are unrefutable\n                            // and will become assignments in the branch's body.\n                            BitArrayTest::Match(MatchTest {\n                                value: BitArrayMatchedValue::Assign { name, value },\n                                read_action,\n                            }) => {\n                                self.body\n                                    .assign_segment_constant_value(name.clone(), value.as_ref());\n\n                                // We will still need to check the aliased value!\n                                *test = BitArrayTest::Match(MatchTest {\n                                    value: value.as_ref().clone(),\n                                    read_action: read_action.clone(),\n                                });\n                            }\n\n                            // Discards are removed directly without even binding them\n                            // in the branch's body.\n                            _ if test.is_discard() => {\n                                let _ = tests.pop_front();\n                            }\n\n                            // Otherwise there's no unconditional test to pop, we\n                            // keep the pattern without changing it.\n                            BitArrayTest::Size(_)\n                            | BitArrayTest::Match(_)\n                            | BitArrayTest::CatchAllIsBytes { .. }\n                            | BitArrayTest::ReadSizeIsNotNegative { .. }\n                            | BitArrayTest::SegmentIsFiniteFloat { .. } => return true,\n                        },\n\n                        // If a bit array pattern has no tests then it's always\n                        // going to match, no matter what. We just remove it.\n                        None => return false,\n                    },\n\n                    // All other patterns are not unconditional, so we just keep them.\n                    Pattern::Int { .. }\n                    | Pattern::Float { .. }\n                    | Pattern::String { .. }\n                    | Pattern::Tuple { .. }\n                    | Pattern::Variant { .. }\n                    | Pattern::NonEmptyList { .. }\n                    | Pattern::EmptyList => return true,\n                }\n            }\n        });\n    }\n}\n\n/// The body of a branch. It always starts with a series of variable assignments\n/// in the form: `let a = b`. As explained in `move_unconditional_patterns`' doc,\n/// each body starts with a series of assignments we keep track of as we're\n/// compiling each branch.\n///\n#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub struct Body {\n    /// Any variables to bind before running the code.\n    ///\n    /// The tuples are in the form `(name, value)`, so `(wibble, var)`\n    /// corresponds to `let wibble = var`.\n    ///\n    pub bindings: Vec<(EcoString, BoundValue)>,\n\n    /// The index of the clause in the case expression that should be run.\n    ///\n    pub clause_index: usize,\n}\n\n/// A value that can appear on the right hand side of one of the assignments we\n/// find at the top of a body.\n///\n#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub enum BoundValue {\n    /// `let a = variable`\n    ///\n    Variable(Variable),\n\n    /// `let a = \"a literal string\"`\n    ///\n    LiteralString(EcoString),\n\n    /// `let a = 123`\n    ///\n    LiteralInt(BigInt),\n\n    /// `let a = 12.2`\n    ///\n    LiteralFloat(EcoString),\n\n    /// `let a = sliceAsInt(bit_array, 0, 16, ...)`\n    ///\n    BitArraySlice {\n        bit_array: Variable,\n        read_action: ReadAction,\n    },\n}\n\nimpl Body {\n    pub fn new(clause_index: usize) -> Self {\n        Self {\n            bindings: vec![],\n            clause_index,\n        }\n    }\n\n    /// Adds a new assignment to the body, binding `let variable = value`\n    ///\n    pub fn assign(&mut self, variable: EcoString, value: Variable) {\n        self.bindings.push((variable, BoundValue::Variable(value)));\n    }\n\n    fn assign_literal_string(&mut self, variable: EcoString, value: EcoString) {\n        self.bindings\n            .push((variable, BoundValue::LiteralString(value)));\n    }\n\n    fn assign_bit_array_slice(\n        &mut self,\n        segment_name: EcoString,\n        bit_array: Variable,\n        value: ReadAction,\n    ) {\n        self.bindings.push((\n            segment_name,\n            BoundValue::BitArraySlice {\n                bit_array,\n                read_action: value,\n            },\n        ))\n    }\n\n    fn assign_segment_constant_value(&mut self, name: EcoString, value: &BitArrayMatchedValue) {\n        let value = match value {\n            BitArrayMatchedValue::LiteralFloat(value) => BoundValue::LiteralFloat(value.clone()),\n            BitArrayMatchedValue::LiteralInt { value, .. } => BoundValue::LiteralInt(value.clone()),\n            BitArrayMatchedValue::LiteralString { value, .. } => {\n                BoundValue::LiteralString(value.clone())\n            }\n            BitArrayMatchedValue::Variable(_)\n            | BitArrayMatchedValue::Discard(_)\n            | BitArrayMatchedValue::Assign { .. } => {\n                panic!(\"aliased non constant value: {value:#?}\")\n            }\n        };\n\n        self.bindings.push((name, value))\n    }\n}\n\n/// A user defined pattern such as `Some((x, 10))`.\n/// This is a bit simpler than the full fledged `TypedPattern` used for code analysis\n/// and only focuses on the relevant bits needed to perform exhaustiveness checking\n/// and code generation.\n///\n/// Using this simplified version of a pattern for the case compiler makes it a\n/// whole lot simpler and more efficient (patterns will have to be cloned, so\n/// we use an arena to allocate those and only store ids to make this operation\n/// extra cheap).\n///\n#[derive(Clone, Eq, PartialEq, Debug)]\npub enum Pattern {\n    Discard,\n    Int {\n        int_value: BigInt,\n    },\n    Float {\n        float_value: LiteralFloatValue,\n    },\n    String {\n        value: EcoString,\n    },\n    StringPrefix {\n        prefix: EcoString,\n        prefix_name: Option<EcoString>,\n        rest: Id<Pattern>,\n    },\n    Assign {\n        name: EcoString,\n        pattern: Id<Pattern>,\n    },\n    Variable {\n        name: EcoString,\n    },\n    Tuple {\n        elements: Vec<Id<Pattern>>,\n    },\n    Variant {\n        index: usize,\n        name: EcoString,\n        module: Option<EcoString>,\n        fields: Vec<Id<Pattern>>,\n    },\n    NonEmptyList {\n        first: Id<Pattern>,\n        rest: Id<Pattern>,\n    },\n    EmptyList,\n    BitArray {\n        tests: VecDeque<BitArrayTest>,\n    },\n}\n\nimpl Pattern {\n    /// Each pattern (with a couple exceptions) can be turned into a\n    /// simpler `RuntimeCheck`: that is a check that can be performed at runtime\n    /// to make sure a `PatternCheck` can succeed on a specific value.\n    ///\n    fn to_runtime_check_kind(&self) -> Option<RuntimeCheckKind> {\n        let kind = match self {\n            // These patterns are unconditional: they will always match and be moved\n            // out of a branch's checks. So there's no corresponding runtime check\n            // we can perform for them.\n            Pattern::Discard | Pattern::Variable { .. } | Pattern::Assign { .. } => return None,\n            Pattern::Int { int_value, .. } => RuntimeCheckKind::Int {\n                int_value: int_value.clone(),\n            },\n            Pattern::Float { float_value, .. } => RuntimeCheckKind::Float {\n                float_value: *float_value,\n            },\n            Pattern::String { value } => RuntimeCheckKind::String {\n                value: value.clone(),\n            },\n            Pattern::StringPrefix { prefix, .. } => RuntimeCheckKind::StringPrefix {\n                prefix: prefix.clone(),\n            },\n            Pattern::Tuple { elements } => RuntimeCheckKind::Tuple {\n                size: elements.len(),\n            },\n            Pattern::Variant { index, .. } => RuntimeCheckKind::Variant { index: *index },\n            Pattern::NonEmptyList { .. } => RuntimeCheckKind::NonEmptyList,\n            Pattern::EmptyList => RuntimeCheckKind::EmptyList,\n            // Bit arrays have no corresponding kind as they're dealt with in a\n            // completely different way.\n            Pattern::BitArray { .. } => return None,\n        };\n\n        Some(kind)\n    }\n\n    fn is_matching_on_unreachable_variant(&self, branch_mode: &BranchMode) -> bool {\n        match (self, branch_mode) {\n            (\n                Self::Variant { index, .. },\n                BranchMode::NamedType {\n                    inferred_variant: Some(variant),\n                    ..\n                },\n            ) if index != variant => true,\n            _ => false,\n        }\n    }\n\n    fn is_matching_on_impossible_segment(&self) -> Option<Vec<ImpossibleBitArraySegmentPattern>> {\n        match self {\n            Self::BitArray { tests } => {\n                let impossible_segments = tests\n                    .iter()\n                    .filter_map(|test| match test {\n                        BitArrayTest::Size(_)\n                        | BitArrayTest::CatchAllIsBytes { .. }\n                        | BitArrayTest::ReadSizeIsNotNegative { .. }\n                        | BitArrayTest::SegmentIsFiniteFloat { .. } => None,\n\n                        BitArrayTest::Match(MatchTest { value, read_action }) => {\n                            value.is_impossible_segment(read_action)\n                        }\n                    })\n                    .collect_vec();\n\n                if impossible_segments.is_empty() {\n                    None\n                } else {\n                    Some(impossible_segments)\n                }\n            }\n            Self::Discard\n            | Self::Int { .. }\n            | Self::Float { .. }\n            | Self::String { .. }\n            | Self::StringPrefix { .. }\n            | Self::Assign { .. }\n            | Self::Variable { .. }\n            | Self::Tuple { .. }\n            | Self::Variant { .. }\n            | Self::NonEmptyList { .. }\n            | Self::EmptyList => None,\n        }\n    }\n}\n\n/// A single check making up a branch, checking that a variable matches with a\n/// given pattern. For example, the following branch has 2 checks:\n///\n/// ```txt\n/// a is Some, b is 1 -> todo\n/// ┬    ─┬──\n/// │     ╰── This is the pattern being checked\n/// ╰── This is the variable being pattern matched on\n/// ─┬─────── ─┬────\n///  ╰─────────┴── Two `PatternCheck`s\n/// ```\n///\n#[derive(Clone, Eq, PartialEq, Debug)]\nstruct PatternCheck {\n    var: Variable,\n    pattern: Id<Pattern>,\n}\n\n/// This is one of the checks we can take at runtime to decide how to move\n/// forward in the decision tree.\n///\n/// After performing a successful check on a value we will discover something\n/// about its shape: it might be an int, an variant of a custom type, ...\n/// Some values (like variants and lists) might hold onto additional data we\n/// will have to pattern match on: in order to do that we need a name to refer\n/// to those new variables we've discovered after performing a check. That's\n/// what `args` is for.\n///\n/// Let's have a look at an example. Imagine we have a pattern like this one:\n/// `a is Wibble(1, _, [])`; after performing a runtime check to make sure `a`\n/// is indeed a `Wibble`, we'll need to perform additional checks on it's\n/// arguments: that pattern will be replaced by three new ones `a0 is 1`,\n/// `a1 is _` and `a2 is []`. Those new variables are the `args`.\n///\n#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum RuntimeCheck {\n    Int {\n        int_value: BigInt,\n    },\n    Float {\n        float_value: LiteralFloatValue,\n    },\n    String {\n        value: EcoString,\n    },\n    StringPrefix {\n        prefix: EcoString,\n        rest: Variable,\n    },\n    Tuple {\n        size: usize,\n        elements: Vec<Variable>,\n    },\n    BitArray {\n        test: BitArrayTest,\n    },\n    Variant {\n        match_: VariantMatch,\n        index: usize,\n        labels: HashMap<usize, EcoString>,\n        fields: Vec<Variable>,\n    },\n    NonEmptyList {\n        first: Variable,\n        rest: Variable,\n    },\n    EmptyList,\n}\n\nimpl RuntimeCheck {\n    fn kind(&self) -> Option<RuntimeCheckKind> {\n        let kind = match self {\n            RuntimeCheck::Int { int_value, .. } => RuntimeCheckKind::Int {\n                int_value: int_value.clone(),\n            },\n            RuntimeCheck::Float { float_value, .. } => RuntimeCheckKind::Float {\n                float_value: *float_value,\n            },\n            RuntimeCheck::String { value } => RuntimeCheckKind::String {\n                value: value.clone(),\n            },\n            RuntimeCheck::StringPrefix { prefix, rest: _ } => RuntimeCheckKind::StringPrefix {\n                prefix: prefix.clone(),\n            },\n            RuntimeCheck::Tuple { size, elements: _ } => RuntimeCheckKind::Tuple { size: *size },\n            RuntimeCheck::Variant { index, .. } => RuntimeCheckKind::Variant { index: *index },\n            RuntimeCheck::EmptyList => RuntimeCheckKind::EmptyList,\n            RuntimeCheck::NonEmptyList { first: _, rest: _ } => RuntimeCheckKind::NonEmptyList,\n            RuntimeCheck::BitArray { .. } => return None,\n        };\n        Some(kind)\n    }\n\n    pub(crate) fn is_ignored(&self) -> bool {\n        match self {\n            RuntimeCheck::Variant {\n                match_: VariantMatch::NeverExplicitlyMatchedOn { .. },\n                ..\n            } => true,\n            RuntimeCheck::Int { .. }\n            | RuntimeCheck::Float { .. }\n            | RuntimeCheck::String { .. }\n            | RuntimeCheck::StringPrefix { .. }\n            | RuntimeCheck::Tuple { .. }\n            | RuntimeCheck::BitArray { .. }\n            | RuntimeCheck::NonEmptyList { .. }\n            | RuntimeCheck::Variant { .. }\n            | RuntimeCheck::EmptyList => false,\n        }\n    }\n\n    /// Returns all the bit array segments referenced in this check.\n    /// For each segment it returns its name and the read action used to access\n    /// such segment.\n    ///\n    pub(crate) fn referenced_segment_patterns(&self) -> Vec<(&EcoString, &ReadAction)> {\n        match self {\n            RuntimeCheck::BitArray { test } => test.referenced_segment_patterns(),\n            RuntimeCheck::Int { .. }\n            | RuntimeCheck::Float { .. }\n            | RuntimeCheck::String { .. }\n            | RuntimeCheck::StringPrefix { .. }\n            | RuntimeCheck::Tuple { .. }\n            | RuntimeCheck::Variant { .. }\n            | RuntimeCheck::NonEmptyList { .. }\n            | RuntimeCheck::EmptyList => vec![],\n        }\n    }\n}\n\n#[derive(Eq, PartialEq, Clone, Hash, Debug)]\npub enum RuntimeCheckKind {\n    Int { int_value: BigInt },\n    Float { float_value: LiteralFloatValue },\n    String { value: EcoString },\n    StringPrefix { prefix: EcoString },\n    Tuple { size: usize },\n    Variant { index: usize },\n    EmptyList,\n    NonEmptyList,\n}\n\n/// All possible variant checks are automatically generated beforehand once we\n/// know we are matching on a value with a custom type.\n/// Then if the compiled case is explicitly matching on one of those, we update\n/// it to store additional information: for example how the variant is used\n/// (if qualified or unqualified and if it is aliased).\n///\n/// This way when we get to code generation we can clump all variants that were\n/// never explicitly matched on in a single `else` block without blowing up code\n/// size!\n///\n#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum VariantMatch {\n    ExplicitlyMatchedOn {\n        name: EcoString,\n        module: Option<EcoString>,\n    },\n    NeverExplicitlyMatchedOn {\n        name: EcoString,\n    },\n}\n\nimpl VariantMatch {\n    pub(crate) fn name(&self) -> EcoString {\n        match self {\n            VariantMatch::ExplicitlyMatchedOn { name, module: _ } => name.clone(),\n            VariantMatch::NeverExplicitlyMatchedOn { name } => name.clone(),\n        }\n    }\n\n    pub(crate) fn module(&self) -> Option<EcoString> {\n        match self {\n            VariantMatch::ExplicitlyMatchedOn { name: _, module } => module.clone(),\n            VariantMatch::NeverExplicitlyMatchedOn { name: _ } => None,\n        }\n    }\n}\n\n/// A variable that can be matched on in a branch.\n///\n#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]\npub struct Variable {\n    pub id: usize,\n    pub type_: Arc<Type>,\n}\n\nimpl Variable {\n    fn new(id: usize, type_: Arc<Type>) -> Self {\n        Self { id, type_ }\n    }\n\n    /// Builds a `PatternCheck` that checks this variable matches the given pattern.\n    /// So we can build pattern checks the same way we informally describe them:\n    /// ```txt\n    /// var is pattern\n    /// ```\n    /// With this builder method would become:\n    /// ```rs\n    /// var.is(pattern)\n    /// ```\n    ///\n    fn is(&self, pattern: Id<Pattern>) -> PatternCheck {\n        PatternCheck {\n            var: self.clone(),\n            pattern,\n        }\n    }\n}\n\n#[derive(Debug)]\n/// Different types need to be handled differently when compiling a case expression\n/// into a decision tree. There's some types that have infinite matching patterns\n/// (like ints, strings, ...) and thus will always need a fallback option.\n///\n/// Other types, like custom types, only have a well defined and finite number\n/// of patterns that could match: when matching on a `Result` we know that we can\n/// only have an `Ok(_)` and an `Error(_)`, anything else would end up being a\n/// type error!\n///\n/// So this enum is used to pick the correct strategy to compile a case that's\n/// performing a `PatternCheck` on a variable with a specific type.\n///\nenum BranchMode {\n    /// This covers numbers, functions, variables, strings, and bitarrays.\n    Infinite,\n    Tuple {\n        elements: Vec<Arc<Type>>,\n    },\n    List {\n        inner_type: Arc<Type>,\n    },\n    NamedType {\n        constructors: Vec<TypeValueConstructor>,\n        inferred_variant: Option<usize>,\n    },\n}\n\nimpl BranchMode {\n    /// Returns a heuristic estimate of the branching factor.\n    ///\n    /// This value is used by the pivot-selection to prefer splits\n    /// with fewer branches, which tends to produce smaller and shallower\n    /// decision trees.\n    fn branching_factor(&self) -> usize {\n        match self {\n            BranchMode::Infinite => usize::MAX,\n            BranchMode::Tuple { elements } => elements.len(),\n            BranchMode::List { .. } => 2,\n            BranchMode::NamedType { constructors, .. } => constructors.len(),\n        }\n    }\n\n    fn is_infinite(&self) -> bool {\n        match self {\n            BranchMode::Infinite => true,\n            BranchMode::Tuple { .. } | BranchMode::List { .. } | BranchMode::NamedType { .. } => {\n                false\n            }\n        }\n    }\n}\n\nimpl Variable {\n    fn branch_mode(&self, env: &Environment<'_>) -> BranchMode {\n        match collapse_links(self.type_.clone()).as_ref() {\n            Type::Fn { .. } | Type::Var { .. } => BranchMode::Infinite,\n            Type::Named { module, name, .. }\n                if is_prelude_module(module)\n                    && (name == \"Int\"\n                        || name == \"Float\"\n                        || name == \"BitArray\"\n                        || name == \"String\") =>\n            {\n                BranchMode::Infinite\n            }\n\n            Type::Named {\n                module,\n                name,\n                arguments,\n                ..\n            } if is_prelude_module(module) && name == \"List\" => BranchMode::List {\n                inner_type: arguments.first().expect(\"list has a type argument\").clone(),\n            },\n\n            Type::Tuple { elements } => BranchMode::Tuple {\n                elements: elements.clone(),\n            },\n\n            Type::Named {\n                module,\n                name,\n                arguments,\n                inferred_variant,\n                ..\n            } => {\n                let constructors = ConstructorSpecialiser::specialise_constructors(\n                    env.get_constructors_for_type(module, name)\n                        .expect(\"Custom type variants must exist\"),\n                    arguments.as_slice(),\n                    &env.current_module,\n                    module,\n                );\n\n                let inferred_variant = inferred_variant.map(|i| i as usize);\n                BranchMode::NamedType {\n                    constructors,\n                    inferred_variant,\n                }\n            }\n        }\n    }\n}\n\n/// When compiling a bit array pattern each segment is turned into a series of\n/// tests that all need to match in order for the pattern to succeed.\n/// Each segment might add some requirements on the total size of a bit array\n/// and/or on the value of some of its specific parts.\n///\n/// Let's look at a simple example to get started:\n///\n/// ```txt\n/// <<0:size(12), 1, rest:bits>>\n///   ─┬────────\n///    ╰── This first segment requires that the bit array must have at least\n///        12 bits and their value must be the Int `0`. So this first\n///        segment would be turned into the following series of tests:\n///        `Size(>=, 12)` and `Match(0, ReadAction(0, 12, int))`\n/// ```\n///\n/// However, the various sizes and offsets of the different segments might not\n/// always be known at compile time and depend on previous sections of the\n/// pattern. This is no big deal: as you'll discover in more detail in the\n/// `SizeExpression`'s doc we can also represent those variable sizes:\n///\n/// ```txt\n/// <<len, payload:size(len), rest:bits>>\n///   ─┬─  ─┬───────────────\n///    │    ╰── For this segment to match the bit array must have enough bits\n///    │        for the previous segment (8 bits) and for this one (`len` bits),\n///    │        so it will turn into the following series of tests:\n///    │        `Size(>=, 8 + len)` and `Match(len, ReadAction(8, len, int))`\n///    │\n///    ╰── This first segment is 8 bits and an int (it's the default Gleam picks\n///        if no options are supplied)\n/// ```\n///\n#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub enum BitArrayTest {\n    Size(SizeTest),\n    Match(MatchTest),\n\n    /// This is a special test to check that the remaining part of a bit array\n    /// has a whole number of bytes when using the `:bytes` option.\n    ///\n    CatchAllIsBytes {\n        size_so_far: Offset,\n    },\n\n    /// This test is made to ensure a given variable is positive: a segment\n    /// pattern where the size is a variable with a negative value will never\n    /// match. So we check this to make sure the test will fail.\n    ///\n    ReadSizeIsNotNegative {\n        size: ReadSize,\n    },\n\n    /// This test checks that the segment read by the given read action is a\n    /// finite Float and not a `NaN` or `Infinity`.\n    ///\n    /// We need this check as `NaN` and `Infinity` will not match with float\n    /// segments (like `<<_:32-float>>`) on the Erlang target and we must\n    /// replicate the same behaviours on the JavaScript target as well.\n    ///\n    SegmentIsFiniteFloat {\n        read_action: ReadAction,\n    },\n}\n\nimpl BitArrayTest {\n    fn is_discard(&self) -> bool {\n        match self {\n            BitArrayTest::Match(MatchTest {\n                value: BitArrayMatchedValue::Discard(_),\n                ..\n            }) => true,\n            BitArrayTest::Match(_)\n            | BitArrayTest::Size(_)\n            | BitArrayTest::CatchAllIsBytes { .. }\n            | BitArrayTest::ReadSizeIsNotNegative { .. }\n            | BitArrayTest::SegmentIsFiniteFloat { .. } => false,\n        }\n    }\n\n    pub(crate) fn referenced_segment_patterns(&self) -> Vec<(&EcoString, &ReadAction)> {\n        match self {\n            BitArrayTest::ReadSizeIsNotNegative { size } => {\n                let mut references = Vec::new();\n                size.referenced_segment_patterns(&mut references);\n                references\n            }\n\n            BitArrayTest::Size(SizeTest { operator: _, size })\n            | BitArrayTest::CatchAllIsBytes { size_so_far: size } => {\n                size.referenced_segment_patterns()\n            }\n\n            BitArrayTest::SegmentIsFiniteFloat {\n                read_action: ReadAction { from, size, .. },\n            }\n            | BitArrayTest::Match(MatchTest {\n                read_action: ReadAction { from, size, .. },\n                ..\n            }) => {\n                let mut references = vec![];\n                references.append(&mut from.referenced_segment_patterns());\n                size.referenced_segment_patterns(&mut references);\n\n                references\n            }\n        }\n    }\n}\n\n/// Test to make sure the bit array has a specific number of bits.\n///\n#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub struct SizeTest {\n    pub operator: SizeOperator,\n    pub size: Offset,\n}\n\nimpl SizeTest {\n    /// Tells us if this test is guaranteed to succeed given another test that\n    /// we know has already succeeded.\n    ///\n    /// For example, \">= 5\" is certainly going to succeed if \">= 6\" has already\n    /// succeeded.\n    ///\n    fn succeeds_if_succeeding(&self, succeeding: &SizeTest) -> Confidence {\n        match (succeeding.operator, self.operator) {\n            (SizeOperator::Equal, SizeOperator::Equal) if succeeding.size == self.size => {\n                Confidence::Certain\n            }\n            (_, SizeOperator::GreaterEqual) => succeeding.size.greater_equal(&self.size),\n            _ => Confidence::Uncertain,\n        }\n    }\n\n    /// Tells us if this test is guaranteed to fail given another test that\n    /// we know has already failed.\n    ///\n    /// For example, \">= 5\" is certainly going to fail if \">= 4\" has already\n    /// failed.\n    ///\n    fn fails_if_failing(&self, failing: &SizeTest) -> Confidence {\n        match (failing.operator, self.operator) {\n            (SizeOperator::GreaterEqual, _) => self.size.greater_equal(&failing.size),\n            (_, _) if self == failing => Confidence::Certain,\n            _ => Confidence::Uncertain,\n        }\n    }\n\n    /// Tells us if this test is guaranteed to fail given another test that\n    /// we know has already succeeded.\n    ///\n    /// For example, \"= 1\" is certainly going to fail if \"= 2\" has already\n    /// succeeded.\n    ///\n    fn fails_if_succeeding(&self, succeeding: &SizeTest) -> Confidence {\n        match (succeeding.operator, self.operator) {\n            (SizeOperator::GreaterEqual, SizeOperator::Equal) => {\n                succeeding.size.greater(&self.size)\n            }\n            (SizeOperator::Equal, SizeOperator::GreaterEqual) => {\n                self.size.greater(&succeeding.size)\n            }\n            (SizeOperator::Equal, SizeOperator::Equal) => succeeding.size.different(&self.size),\n            _ => Confidence::Uncertain,\n        }\n    }\n}\n\n/// Test to make sure the segment read by the specified `read_action` matches\n/// a given value.\n///\n#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub struct MatchTest {\n    pub value: BitArrayMatchedValue,\n    pub read_action: ReadAction,\n}\n\n#[derive(Debug)]\nstruct Interference {\n    interfering_bits_are_equal: bool,\n    first_encloses_second: bool,\n    second_encloses_first: bool,\n}\n\nimpl MatchTest {\n    /// If this match test interferes with the other one, this will return\n    /// information about how they interfere.\n    ///\n    ///\n    /// # What is interference used for?\n    ///\n    /// Interference analysis is an optimization that we can apply to segments\n    /// matching on a literal value with a known offset and size.\n    /// It allows discarding many overlapping checks that we can for sure tell\n    /// will never (or will always) match.\n    ///\n    /// This optimization is particularly important for network protocol\n    /// applications where it is typical to match on some fixed patterns at the\n    /// start of the bitarray:\n    ///\n    /// ```gleam\n    /// case packet {\n    ///   <<\"CONTENT_LENGTH\", 0, rest:bytes>> -> todo\n    ///   <<\"QUERY_STRING\", 0, rest:bytes>> -> todo\n    ///   // ...\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    ///\n    /// # What is interference?\n    ///\n    /// We say two read actions interfere with each other if:\n    /// - They're both matching against a statically known value, we will call\n    ///   them `v1` and `v2`\n    /// - They both start at a statically known offset, `o1` and `o2`\n    /// - They both have a statically known size, `s1` and `s2`\n    /// - `o1 <= o2 && o1 + s1 > o2`\n    ///\n    /// This is a lot of letters to say something actually quite simple, having\n    /// a look at a graphical example will make this easier to grasp. Let's\n    /// visualize each match action as a segment; each read action will match\n    /// against a portion of the bit array, starting at the given offset and\n    /// with the given number of bits (in the example I'm also showing the bits\n    /// that the read action matches against):\n    ///\n    /// ```txt\n    ///          o1         (o1+s1)\n    ///         ┄├0001010110┤┄\n    ///               ┄├1101000000111011┤┄\n    ///                o2               (o2+s2)\n    /// ```\n    ///\n    /// They interfere if the first one comes first (`o1 <= o2`) and the start\n    /// of the second one falls inside the range covered by the first one\n    /// (`o1 + s1 > p2`).\n    /// So the example above showcases two interfering read actions, here's an\n    /// example of two read actions that are not interfering with each other:\n    ///\n    /// ```txt\n    ///          o1      (o1+s1)\n    ///         ┄├0110101┤┄\n    ///                      ┄├0101110101┤┄\n    ///                       o2         (o2+s2)\n    /// ```\n    ///\n    ///\n    /// # How is interference useful\n    ///\n    /// Knowing that two read actions interfere is very useful because, knowing\n    /// if the first one matches or not can allow us to tell for certain if an\n    /// interfering match has no change of succeeding as well.\n    /// Let's look at the three cases:\n    ///\n    /// 1. We know the first action succeeded, so the binary has the expected\n    ///    bits in the matched segment\n    ///    ```txt\n    ///             o1         (o1+s1)\n    ///            ┄├0110101111┤┄  ← This check succeded!\n    ///                   ┄├0001110101┤┄\n    ///                    o2         (o2+s2)\n    ///    ```\n    ///    Can the second check ever succeed? No! Since the first check\n    ///    succeeded we know for certain that the first three bits the second\n    ///    check would match against are going to be `111`, so they surely won't\n    ///    match with `000`.\n    ///\n    /// 2. We know the first action succeeded, and the second action is fully\n    ///    contained inside it:\n    ///    ```txt\n    ///             o1              (o1+s1)\n    ///            ┄├011010000001111┤┄  ← This check succeded!\n    ///               ┄├0100000┤┄\n    ///                o2      (o2+s2)\n    ///    ```\n    ///    In that case we know for certain that the second check will succeed\n    ///    as well (and so can be skipped) if the overlapping bits being checked\n    ///    are exactly the same.\n    ///\n    /// 3. We know that the first action failed, and the second one is\n    ///    fully enclosing it:\n    ///    ```txt\n    ///             o1  (o1+s1)\n    ///            ┄├010┤┄  ← This check failed!\n    ///            ┄├01000001010000001111┤┄\n    ///             o2                   (o2+s2)\n    ///    ```\n    ///   Can the second check ever succeed? No! Since the first check failed we\n    ///   know for certain that the first bits are not `010`, so there's no\n    ///   chance for the second match to succeed as it requires those three bits\n    ///   to be `010` as well.\n    ///\n    ///\n    /// ## What information is returned by this function\n    ///\n    /// If the two actions are not interfering with each other this will return\n    /// `None`. Otherwise, it will return all the information needed by the\n    /// three examples above (check usages of this function to see how this is\n    /// used, hopefully it should be pretty straightforward!):\n    /// - whether the bits in the overlapping section are the same\n    /// - whether the first action fully encloses the second one\n    /// - whether the second action fully encloses the first one\n    ///\n    fn interfering_bits(&self, other: &Self) -> Option<Interference> {\n        // After reading the doc comment this should be pretty easy to follow:\n        // The first requirement for interference is: `o1 <= o2`\n        let offset_one = self.read_action.from.constant_bits()?.to_usize()?;\n        let offset_other = other.read_action.from.constant_bits()?.to_usize()?;\n        if offset_one > offset_other {\n            return None;\n        };\n\n        // The second requirement is that: `o1 + s1 > o2`\n        let size_one = self.read_action.size.constant_bits()?.to_usize()?;\n        let size_other = other.read_action.size.constant_bits()?.to_usize()?;\n        if offset_one + size_one <= offset_other {\n            return None;\n        };\n\n        // At this point we know that both are interfering, so we compare the\n        // overlapping slice of bits they're matching against.\n        // A little implementation note: we're storing the matched _bytes_, not\n        // bits, so we will be using the `view_bits` function to perform a\n        // comparison of slices of bits.\n        let bits_one = self.value.constant_bits()?;\n        let bits_other = other.value.constant_bits()?;\n        let end = (offset_other + size_other).min(offset_one + size_one);\n\n        let range_one = offset_one..=(offset_one + size_one);\n        let range_other = offset_other..=(offset_other + size_other);\n\n        Some(Interference {\n            interfering_bits_are_equal: bits_one[offset_other - offset_one..end - offset_one]\n                == bits_other[0..end - offset_other],\n            first_encloses_second: range_contains(&range_one, &range_other),\n            second_encloses_first: range_contains(&range_other, &range_one),\n        })\n    }\n}\n\n/// Returns true if the first range fully contains the other one.\nfn range_contains(\n    one: &std::ops::RangeInclusive<usize>,\n    other: &std::ops::RangeInclusive<usize>,\n) -> bool {\n    one.contains(other.start()) && one.contains(other.end())\n}\n\n/// A value that can be matched in a bit array pattern's segment. We do not use\n/// a `Pattern` directly since the allowed values are actually a subset of all\n/// the possible patterns: it can only contain literal floats, ints, strings,\n/// a variable name, and a discard.\n///\n#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub enum BitArrayMatchedValue {\n    LiteralFloat(EcoString),\n    LiteralInt {\n        value: BigInt,\n        /// This is carried around for better error reporting in case a segment\n        /// is deemed unreachable: it is the location this literal value comes\n        /// from in the whole pattern.\n        location: SrcSpan,\n        /// The bits representing the given literal int, with the correct\n        /// signed- and endianness as specified in the bit array segment.\n        bits: Result<BitVec<u8, Msb0>, IntToBitsError>,\n    },\n    LiteralString {\n        value: EcoString,\n        encoding: StringEncoding,\n        /// The bytes representing the given literal string, with the correct\n        /// encoding and endianness specified in the bit array segment.\n        bytes: Vec<u8>,\n    },\n    Variable(EcoString),\n    Discard(EcoString),\n    Assign {\n        name: EcoString,\n        value: Box<BitArrayMatchedValue>,\n    },\n}\n\nimpl BitArrayMatchedValue {\n    /// This is an arbitrary limit beyond which interference _may_ no longer be done.\n    /// This is necessary because people may write very silly segments like\n    /// `<<0:9_007_199_254_740_992>>`, which would allocate around a wee petabyte of memory.\n    /// Literal strings are already in memory, and thus ignore this limit.\n    const MAX_BITS_INTERFERENCE: u32 = u16::MAX as u32;\n\n    pub(crate) fn is_literal(&self) -> bool {\n        match self {\n            BitArrayMatchedValue::LiteralFloat(_)\n            | BitArrayMatchedValue::LiteralInt { .. }\n            | BitArrayMatchedValue::LiteralString { .. } => true,\n            BitArrayMatchedValue::Variable(..) | BitArrayMatchedValue::Discard(..) => false,\n            BitArrayMatchedValue::Assign { value, .. } => value.is_literal(),\n        }\n    }\n\n    /// If the matched value is a literal value for which we implement\n    /// interference pruning, this returns the bits representing it to be used\n    /// for interference.\n    ///\n    fn constant_bits(&self) -> Option<&BitSlice<u8, Msb0>> {\n        match self {\n            BitArrayMatchedValue::LiteralString { bytes, .. } => Some(bytes.view_bits::<Msb0>()),\n            BitArrayMatchedValue::Assign { value, .. } => value.constant_bits(),\n            BitArrayMatchedValue::LiteralInt { bits, .. } => bits.as_deref().ok(),\n\n            // TODO: We could also implement the interfering optimisation for\n            // literal floats as well, but the usefulness is questionable\n            BitArrayMatchedValue::LiteralFloat(_)\n            | BitArrayMatchedValue::Variable(_)\n            | BitArrayMatchedValue::Discard(_) => None,\n        }\n    }\n\n    /// If we can statically tell the segment will never match, this will return\n    /// the reason why it can't match. Otherwise it returns `None`.\n    ///\n    fn is_impossible_segment(\n        &self,\n        read_action: &ReadAction,\n    ) -> Option<ImpossibleBitArraySegmentPattern> {\n        match self {\n            BitArrayMatchedValue::Assign { value, .. } => value.is_impossible_segment(read_action),\n            BitArrayMatchedValue::LiteralInt {\n                value,\n                location,\n                bits,\n            } => match bits {\n                Err(IntToBitsError::Unrepresentable { size }) => {\n                    Some(ImpossibleBitArraySegmentPattern::UnrepresentableInteger {\n                        value: value.clone(),\n                        size: *size,\n                        location: *location,\n                        signed: read_action.signed,\n                    })\n                }\n                _ => None,\n            },\n\n            BitArrayMatchedValue::LiteralFloat(_)\n            | BitArrayMatchedValue::LiteralString { .. }\n            | BitArrayMatchedValue::Variable(_)\n            | BitArrayMatchedValue::Discard(_) => None,\n        }\n    }\n\n    /// Returns true if the two `MatchedValue`s are matching for the exact same\n    /// thing. Note how this doesn't automatically mean they will be matching\n    /// for the exact same thing in a whole bit array pattern as they could be\n    /// matching at different positions!\n    ///\n    /// ```gleam\n    /// <<1, _>>\n    /// <<_, 1>>\n    /// // Both are matching on the same value but at different positions!\n    /// ```\n    ///\n    fn checking_same_value(&self, other: &Self) -> bool {\n        match (self, other) {\n            // Ints need special care: they're carrying around information about\n            // where they come from. But as for equality is concerned for the\n            // pattern match compilation, they are considered equal as long as\n            // the two values are equal, no matter where the values come from.\n            (Self::LiteralInt { value: one, .. }, Self::LiteralInt { value: other, .. }) => {\n                one == other\n            }\n            (Self::LiteralInt { .. }, _) => false,\n\n            // All the other cases follow the standard equality implementation.\n            (Self::LiteralFloat(one), Self::LiteralFloat(other)) => one == other,\n            (Self::LiteralFloat(_), _) => false,\n\n            // Two literal string matches are the same if they match for the\n            // same bytes. No matter the original starting string and encoding.\n            (Self::LiteralString { bytes: one, .. }, Self::LiteralString { bytes: other, .. }) => {\n                one == other\n            }\n            (Self::LiteralString { .. }, _) => false,\n\n            (Self::Variable(one), Self::Variable(other)) => one == other,\n            (Self::Variable(_), _) => false,\n\n            (Self::Discard(_), Self::Discard(_)) => true,\n            (Self::Discard(_), _) => false,\n\n            (\n                Self::Assign {\n                    name: _,\n                    value: one,\n                },\n                Self::Assign {\n                    name: _,\n                    value: other,\n                },\n            ) => one.checking_same_value(other),\n            (Self::Assign { .. }, _) => false,\n        }\n    }\n}\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub enum StringEncoding {\n    Utf8,\n    Utf16,\n    Utf32,\n}\n\nimpl BitArrayMatchedValue {\n    pub fn is_discard(&self) -> bool {\n        match self {\n            BitArrayMatchedValue::Discard(_) => true,\n            BitArrayMatchedValue::LiteralFloat(_)\n            | BitArrayMatchedValue::LiteralInt { .. }\n            | BitArrayMatchedValue::LiteralString { .. }\n            | BitArrayMatchedValue::Variable(_)\n            | BitArrayMatchedValue::Assign { .. } => false,\n        }\n    }\n}\n\nimpl BitArrayTest {\n    /// Wether two bit array tests are equivalent, that is they are checking\n    /// for the same thing.\n    ///\n    fn equivalent_to(&self, other: &Self) -> bool {\n        match (self, other) {\n            (BitArrayTest::Size(one), BitArrayTest::Size(other)) => one == other,\n            (BitArrayTest::Size(_), _) => false,\n\n            (\n                BitArrayTest::Match(MatchTest { value, read_action }),\n                BitArrayTest::Match(MatchTest {\n                    value: other_value,\n                    read_action: other_read_action,\n                }),\n            ) => value.checking_same_value(other_value) && read_action == other_read_action,\n            (BitArrayTest::Match(_), _) => false,\n\n            (\n                BitArrayTest::CatchAllIsBytes { size_so_far: one },\n                BitArrayTest::CatchAllIsBytes { size_so_far: other },\n            ) => one == other,\n            (BitArrayTest::CatchAllIsBytes { .. }, ..) => false,\n\n            (\n                BitArrayTest::ReadSizeIsNotNegative { size: one },\n                BitArrayTest::ReadSizeIsNotNegative { size: other },\n            ) => one == other,\n            (BitArrayTest::ReadSizeIsNotNegative { .. }, _) => false,\n\n            (\n                BitArrayTest::SegmentIsFiniteFloat { read_action: one },\n                BitArrayTest::SegmentIsFiniteFloat { read_action: other },\n            ) => one == other,\n            (BitArrayTest::SegmentIsFiniteFloat { .. }, _) => false,\n        }\n    }\n\n    /// Tells us if this test is guaranteed to succeed given another test that\n    /// we know has already succeeded.\n    ///\n    /// For example, \"size >= 5\" is certainly going to succeed if \"size >= 6\"\n    /// has already succeeded.\n    ///\n    #[must_use]\n    fn succeeds_if_succeeding(&self, succeeding: &BitArrayTest) -> Confidence {\n        match (succeeding, self) {\n            (one, other) if one.equivalent_to(other) => Confidence::Certain,\n            (BitArrayTest::Size(succeeding), BitArrayTest::Size(test)) => {\n                test.succeeds_if_succeeding(succeeding)\n            }\n            (BitArrayTest::Match(succeeding), BitArrayTest::Match(test)) => {\n                // This is example 2. in the doc comment of `interfering_bits`:\n                // if the bits are the same and the second one is fully enclosed\n                // in the first one, then the second one will succeed as well!\n                if let Some(Interference {\n                    interfering_bits_are_equal: true,\n                    first_encloses_second: true,\n                    ..\n                }) = succeeding.interfering_bits(test)\n                {\n                    Confidence::Certain\n                } else {\n                    Confidence::Uncertain\n                }\n            }\n            // The tests are not comparable, we can't deduce any new information.\n            _ => Confidence::Uncertain,\n        }\n    }\n\n    /// Tells us if this test is guaranteed to fail given another test that\n    /// we know has already failed.\n    ///\n    /// For example, \"size >= 5\" is certainly going to fail if \"size >= 4\"\n    /// has already failed.\n    ///\n    #[must_use]\n    fn fails_if_failing(&self, failing: &BitArrayTest) -> Confidence {\n        match (failing, self) {\n            (one, other) if one.equivalent_to(other) => Confidence::Certain,\n            (BitArrayTest::Size(failing), BitArrayTest::Size(test)) => {\n                test.fails_if_failing(failing)\n            }\n            (BitArrayTest::Match(succeeding), BitArrayTest::Match(test)) => {\n                // This is example 3. in the doc comment of `interfering_bits`:\n                // if the bits are the same and the second one is fully\n                // enclosing the first one, then the second one will fail as\n                // well!\n                if let Some(Interference {\n                    interfering_bits_are_equal: true,\n                    second_encloses_first: true,\n                    ..\n                }) = succeeding.interfering_bits(test)\n                {\n                    Confidence::Certain\n                } else {\n                    Confidence::Uncertain\n                }\n            }\n            // The tests are not comparable, we can't deduce any new information.\n            _ => Confidence::Uncertain,\n        }\n    }\n\n    /// Tells us if this test is guaranteed to fail given another test that\n    /// we know has already succeeded.\n    ///\n    /// For example, \"size = 1\" is certainly going to fail if \"size = 2\" has already\n    /// succeeded.\n    ///\n    #[must_use]\n    fn fails_if_succeeding(&self, succeeding: &BitArrayTest) -> Confidence {\n        match (succeeding, self) {\n            // This is an implementation of Table 6 (a) of the bit array pattern\n            // matching paper linked at the top of this module's documentation!\n            (BitArrayTest::Size(succeeding), BitArrayTest::Size(test)) => {\n                test.fails_if_succeeding(succeeding)\n            }\n            (BitArrayTest::Match(succeeding), BitArrayTest::Match(test)) => {\n                // This is example 1. in the doc comment of `interfering_bits`:\n                // if the bits are the different and the first one is succeeding\n                // then we know the second one will fail.\n                if let Some(Interference {\n                    interfering_bits_are_equal: false,\n                    ..\n                }) = succeeding.interfering_bits(test)\n                {\n                    Confidence::Certain\n                } else {\n                    Confidence::Uncertain\n                }\n            }\n            // The tests are not comparable, we can't deduce any new information.\n            _ => Confidence::Uncertain,\n        }\n    }\n}\n\n/// When performing a size test it could require that a size is exactly some\n/// specific number of bits (for example if we're matching the last segment\n/// of a bit array) or that it has at least some number of bits. For example:\n///\n/// ```txt\n/// <<0:size(12), 1:size(8)>>\n///   ─┬────────  ─┬───────\n///    │           ╰── For this segment to successfully match the bit array must\n///    │               have exactly 20 bits: because it will need to read 8 bits\n///    │               from bit 13 where the previous one ends: `Size(=, 20)`\n///    │\n///    ╰── For this segment to successfully match, the bit array must have at\n///        least 12 bits: `Size(>, 12)`\n/// ```\n///\n#[derive(Clone, Eq, PartialEq, Debug, Copy, serde::Serialize, serde::Deserialize)]\npub enum SizeOperator {\n    GreaterEqual,\n    Equal,\n}\n\n/// Represents the action of reading a certain number of bits from a bit array\n/// at a given position, returning a value with the given type.\n///\n/// Notice how the starting position and number of bits to read might not be\n/// known at compile time but also include variables! For example here:\n///\n/// ```txt\n// <<len, payload:size(len), rest:bits>>\n///  ─┬─  ─┬───────────────\n///   │    ╰── Here payload has a variable size, given by the `len` variable\n///   │\n///   ╰── While this segment has a constant size of 8 bits\n/// ```\n///\n#[derive(Clone, Eq, PartialEq, Debug, Hash, serde::Serialize, serde::Deserialize)]\npub struct ReadAction {\n    /// The offset to start reading the bits from.\n    ///\n    pub from: Offset,\n    /// Number of _bits_ to read.\n    ///\n    pub size: ReadSize,\n    /// The type of the read value.\n    ///\n    pub type_: ReadType,\n    /// Endianness of the read value.\n    ///\n    pub endianness: Endianness,\n    /// Signedness of the read value.\n    ///\n    pub signed: bool,\n}\n\n/// Only a subset of all the possible Gleam types can be used for a pattern\n/// segment. We enumerate those out explicitly here.\n///\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]\npub enum ReadType {\n    Float,\n    Int,\n    String,\n    BitArray,\n    UtfCodepoint,\n}\n\nimpl ReadType {\n    pub(crate) fn is_int(&self) -> bool {\n        match self {\n            ReadType::Int => true,\n            ReadType::Float | ReadType::String | ReadType::BitArray | ReadType::UtfCodepoint => {\n                false\n            }\n        }\n    }\n\n    pub(crate) fn is_float(&self) -> bool {\n        match self {\n            ReadType::Float => true,\n            ReadType::Int | ReadType::String | ReadType::BitArray | ReadType::UtfCodepoint => false,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum Confidence {\n    Certain,\n    Uncertain,\n}\n\nimpl Confidence {\n    fn is_certain(&self) -> bool {\n        match self {\n            Confidence::Certain => true,\n            Confidence::Uncertain => false,\n        }\n    }\n\n    fn or_else(&self, fun: impl Fn() -> Confidence) -> Confidence {\n        match self {\n            Confidence::Certain => Confidence::Certain,\n            Confidence::Uncertain => fun(),\n        }\n    }\n}\n\n/// An offset, in bits, into a bit array. An offset contains three parts. For\n/// example, in the following pattern:\n/// ```txt\n/// <<a, b:size(a), c:size(b - 1), payload:size(c)>>\n/// ```\n///\n/// The start of the `payload` segment is the sum of the length of `a` (which we\n/// know is 1 byte), plus the size of `b`, which is the value of `a`, plus the\n/// size of `c`, which is 1 less than the value of `b`.\n///\n/// Here, `constant` would be `8`; `variables` would map `a` to `1`, because it\n/// is referenced once, in a segment with unit `1`; `calculations` would contain\n/// `b - 1`.\n///\n#[derive(Clone, Eq, PartialEq, Debug, Hash, serde::Serialize, serde::Deserialize)]\npub struct Offset {\n    pub constant: BigInt,\n    pub variables: im::HashMap<VariableUsage, usize>,\n    pub calculations: im::Vector<OffsetCalculation>,\n}\n\n#[derive(Clone, Eq, PartialEq, Debug, Hash, serde::Serialize, serde::Deserialize)]\npub struct OffsetCalculation {\n    pub left: Offset,\n    pub right: Offset,\n    pub operator: IntOperator,\n}\n\nimpl Offset {\n    pub fn constant(value: impl Into<BigInt>) -> Self {\n        Self {\n            constant: value.into(),\n            variables: im::HashMap::new(),\n            calculations: im::Vector::new(),\n        }\n    }\n\n    fn from_size(size: &ReadSize) -> Self {\n        Self::constant(0).add_size(size)\n    }\n\n    fn add_size(mut self, size: &ReadSize) -> Offset {\n        match size {\n            ReadSize::ConstantBits(value) => Self {\n                constant: self.constant + value,\n                variables: self.variables,\n                calculations: self.calculations,\n            },\n            ReadSize::VariableBits { variable, unit } => Self {\n                constant: self.constant,\n                variables: self.variables.alter(\n                    |value| match value {\n                        Some(value) => Some(value + (*unit as usize)),\n                        None => Some(*unit as usize),\n                    },\n                    variable.as_ref().clone(),\n                ),\n                calculations: self.calculations,\n            },\n            ReadSize::RemainingBits | ReadSize::RemainingBytes => self,\n\n            ReadSize::BinaryOperator {\n                left,\n                right,\n                operator,\n            } => match operator {\n                IntOperator::Add => self.add_size(left).add_size(right),\n                IntOperator::Subtract\n                | IntOperator::Multiply\n                | IntOperator::Divide\n                | IntOperator::Remainder => {\n                    self.calculations.push_back(OffsetCalculation {\n                        left: Self::from_size(left),\n                        right: Self::from_size(right),\n                        operator: *operator,\n                    });\n                    self\n                }\n            },\n        }\n    }\n\n    pub fn add_constant(&self, constant: impl Into<BigInt>) -> Offset {\n        Offset {\n            constant: self.constant.clone() + constant.into(),\n            variables: self.variables.clone(),\n            calculations: self.calculations.clone(),\n        }\n    }\n\n    /// Returns `true` if we can tell for certain this offset is greater than\n    /// another one.\n    ///\n    fn greater(&self, other: &Offset) -> Confidence {\n        // We can't easily tell if one calculation is greater than another, so\n        // we can only be certain about one being greater if there are no calculations\n        if self.constant > other.constant\n            && self.calculations.is_empty()\n            && other.calculations.is_empty()\n            && superset(&self.variables, &other.variables)\n        {\n            Confidence::Certain\n        } else {\n            Confidence::Uncertain\n        }\n    }\n\n    /// Returns `true` if we can tell for certain this offset is greater or equal\n    /// to another one.\n    ///\n    fn greater_equal(&self, other: &Offset) -> Confidence {\n        // Like `greater`, we can only be certain if there are no calculations\n        if self == other\n            || (self.constant >= other.constant\n                && self.calculations.is_empty()\n                && other.calculations.is_empty()\n                && superset(&self.variables, &other.variables))\n        {\n            Confidence::Certain\n        } else {\n            Confidence::Uncertain\n        }\n    }\n\n    /// Returns `true` if we can tell for certain this offset is different from\n    /// another one.\n    ///\n    fn different(&self, other: &Offset) -> Confidence {\n        self.greater(other).or_else(|| other.greater(self))\n    }\n\n    pub(crate) fn is_zero(&self) -> bool {\n        self.constant == BigInt::ZERO && self.variables.is_empty() && self.calculations.is_empty()\n    }\n\n    /// If this offset has a constant size, returns its size in bits.\n    ///\n    pub(crate) fn constant_bits(&self) -> Option<BigInt> {\n        if self.variables.is_empty() && self.calculations.is_empty() {\n            Some(self.constant.clone())\n        } else {\n            None\n        }\n    }\n\n    /// If this offset has a constant size that's a whole number of bytes,\n    /// returns its size in bytes.\n    ///\n    pub(crate) fn constant_bytes(&self) -> Option<BigInt> {\n        let bits = self.constant_bits()?;\n        if bits.clone() % 8 == BigInt::ZERO {\n            Some(bits / 8)\n        } else {\n            None\n        }\n    }\n\n    fn referenced_segment_patterns(&self) -> Vec<(&EcoString, &ReadAction)> {\n        let mut references = Vec::new();\n\n        for variable_usage in self.variables.keys() {\n            match variable_usage {\n                VariableUsage::PatternSegment(segment_name, read_action) => {\n                    references.push((segment_name, read_action));\n                }\n                VariableUsage::OutsideVariable(..) => {}\n            }\n        }\n\n        for calculation in self.calculations.iter() {\n            references.extend(calculation.left.referenced_segment_patterns());\n            references.extend(calculation.right.referenced_segment_patterns());\n        }\n\n        references\n    }\n}\n\n/// The number of bits to read in a read action when reading a segment.\n///\n#[derive(Clone, Eq, PartialEq, Debug, Hash, serde::Serialize, serde::Deserialize)]\npub enum ReadSize {\n    /// Read a constant, compile-time-known number of bits.\n    ///\n    /// ```txt\n    /// <<tag:size(8)>>\n    ///   ─┬─────────\n    ///    ╰─ Here we know that we have to read exactly 8 bits\n    /// ```\n    ///\n    ConstantBits(BigInt),\n    /// Read a variable number of bits.\n    ///\n    /// ```txt\n    /// <<len, payload:size(len)>>\n    ///        ─┬───────────────\n    ///         ╰─ Here we will know how many bits to read only at runtime since\n    ///            the length is a variable\n    /// ```\n    ///\n    VariableBits {\n        variable: Box<VariableUsage>,\n        unit: u8,\n    },\n\n    /// A maths expression calculating the read size from one or more variables.\n    ///\n    /// ```txt\n    /// <<len, payload:size(len * 8)>>\n    ///        ─┬───────────────────\n    ///         ╰─ Here we have to calculate the length by performing the\n    ///            multiplication at runtime\n    /// ```\n    BinaryOperator {\n        left: Box<ReadSize>,\n        right: Box<ReadSize>,\n        operator: IntOperator,\n    },\n\n    /// Read all the remaining bits in the bit array when using a catch all\n    /// pattern.\n    ///\n    /// ```txt\n    /// <<_, rest:bits>>\n    ///      ─┬───────\n    ///       ╰─ We take all the remaining bits from the bit array\n    /// ```\n    ///\n    RemainingBits,\n    RemainingBytes,\n}\n\nimpl ReadSize {\n    /// If this is a constant number of bits returns it wrapped in `Some`.\n    pub(crate) fn constant_bits(&self) -> Option<BigInt> {\n        match self {\n            ReadSize::ConstantBits(value) => Some(value.clone()),\n            ReadSize::VariableBits { .. }\n            | ReadSize::BinaryOperator { .. }\n            | ReadSize::RemainingBits\n            | ReadSize::RemainingBytes => None,\n        }\n    }\n\n    /// If this is a constant number of bytes returns it wrapped in `Some`.\n    pub(crate) fn constant_bytes(&self) -> Option<BigInt> {\n        let bits = self.constant_bits()?;\n        if bits.clone() % 8 == BigInt::ZERO {\n            Some(bits / 8)\n        } else {\n            None\n        }\n    }\n\n    fn referenced_segment_patterns<'a>(\n        &'a self,\n        references: &mut Vec<(&'a EcoString, &'a ReadAction)>,\n    ) {\n        match self {\n            ReadSize::VariableBits { variable, unit: _ } => match variable.as_ref() {\n                VariableUsage::PatternSegment(segment_value, read_action) => {\n                    references.push((segment_value, read_action));\n                }\n                VariableUsage::OutsideVariable(..) => (),\n            },\n\n            ReadSize::BinaryOperator { left, right, .. } => {\n                left.referenced_segment_patterns(references);\n                right.referenced_segment_patterns(references);\n            }\n\n            ReadSize::ConstantBits(..) | ReadSize::RemainingBits | ReadSize::RemainingBytes => (),\n        };\n    }\n\n    fn can_be_negative(&self) -> bool {\n        match self {\n            ReadSize::ConstantBits(value) => *value < BigInt::ZERO,\n            ReadSize::VariableBits { variable, .. } => match variable.as_ref() {\n                VariableUsage::PatternSegment(_, read_action) => read_action.signed,\n                VariableUsage::OutsideVariable(_) => true,\n            },\n            ReadSize::BinaryOperator {\n                left,\n                right,\n                operator,\n            } => {\n                *operator == IntOperator::Subtract\n                    || left.can_be_negative()\n                    || right.can_be_negative()\n            }\n            ReadSize::RemainingBits | ReadSize::RemainingBytes => false,\n        }\n    }\n}\n\n#[derive(Clone, Eq, PartialEq, Debug, Hash, serde::Serialize, serde::Deserialize)]\npub enum VariableUsage {\n    /// A bit array named segment that was brought into scope in the bit array\n    /// pattern itself and might be referenced by later segments.\n    PatternSegment(EcoString, ReadAction),\n    /// A variable defined somewhere else\n    OutsideVariable(EcoString),\n}\n\nimpl VariableUsage {\n    pub fn name(&self) -> &EcoString {\n        match self {\n            VariableUsage::PatternSegment(name, _) | VariableUsage::OutsideVariable(name) => name,\n        }\n    }\n}\n\n/// This is the decision tree that a pattern matching expression gets turned\n/// into: it's a tree-like structure where each path to a root node contains a\n/// series of checks to perform at runtime to understand if a value matches with\n/// a given pattern.\n///\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Decision {\n    /// This is the final node of the tree, once we get to this one we know we\n    /// have a body to run because a given pattern matched.\n    ///\n    Run { body: Body },\n\n    /// We have to make this decision when we run into a branch that also has a\n    /// guard: if it is true we can finally run the body of the branch, stored in\n    /// `if_true`.\n    /// If it is false we might still have to take other decisions and so we might\n    /// have another `DecisionTree` to traverse, stored in `if_false`.\n    ///\n    Guard {\n        guard: usize,\n        if_true: Body,\n        if_false: Box<Decision>,\n    },\n\n    /// When reaching this node we'll have to see if any of the possible checks\n    /// in `choices` will succeed on `var`. If it does, we know that's the path\n    /// we have to go down to. If none of the checks matches, then we'll have to\n    /// go down the `fallback` branch.\n    ///\n    /// The type system guarantees that all switches will always have at least\n    /// one last choice that acts as a fallback to pick if none of the others\n    /// matches; no matter the value we're matching on.\n    ///\n    /// In case we're dealing with exhaustive cases (for example on lists/custom\n    /// types) we also keep track of the final check associated with the final\n    /// branch: keep in mind, we don't actually have to run that check because\n    /// we know that the type system guarantees it will always match; but it\n    /// can hold useful informations for type generation so we keep it around.\n    /// You can read the doc for `FallbackCheck` to find out a more in depth\n    /// explanation and some examples!\n    ///\n    Switch {\n        var: Variable,\n        choices: Vec<(RuntimeCheck, Decision)>,\n        fallback: Box<Decision>,\n        fallback_check: Box<FallbackCheck>,\n    },\n\n    /// This is a special node: it represents a missing pattern. If a tree\n    /// contains such a node, then we know that the patterns it was compiled\n    /// from are not exhaustive and the path leading to this node will describe\n    /// what kind of pattern doesn't match!\n    ///\n    Fail,\n}\n\n/// When we have a swith in the decision tree we know there's always going to be\n/// at least one choice that comes last and we know is going to match no matter\n/// what. This might fall under three different categories.\n///\n#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]\npub enum FallbackCheck {\n    /// This corresponds to the catch all added at the end of a case expression\n    /// matching on an infinite type.\n    ///\n    /// ```txt\n    /// case todo {\n    ///   1 -> todo\n    ///   _ -> todo\n    ///   ─┬───────\n    //     ╰── when matching on an infinite type there's going to be a catch all\n    /// }\n    ///\n    InfiniteCatchAll,\n\n    /// This happens when we're matching on a variant whose checks are all\n    /// explicitly written down:\n    ///\n    /// ```txt\n    /// case todo {\n    ///   Ok(_) -> todo\n    ///   Error(Nil) -> todo\n    ///   ─┬────────────────\n    //     ╰── when matching on a custom type (or list!) we'll have to write all\n    //         variants down, so there's always going to be a last one.\n    /// }\n    /// ```\n    ///\n    /// The type system will make sure that this last check will always match,\n    /// no matter what, if none of the other checks matches. We still keep the\n    /// corresponding runtime check around because it's useful for code generation!\n    ///\n    RuntimeCheck { check: RuntimeCheck },\n\n    /// This is a special case for a catch all! It happens when we're matching\n    /// on a variant and use a catch all pattern:\n    ///\n    /// ```txt\n    /// case todo {\n    ///   Ok(_) -> todo\n    ///   _ -> todo\n    ///   ─┬───────\n    ///    ╰── here we know we're just skipping over the `Error` variant with\n    ///       this catch all.\n    /// }\n    /// ```\n    ///\n    /// We know exactly which variants we're skipping, so we keep track of\n    /// those skipped checks (they will end up being useful for reporting\n    /// missing patterns!)\n    ///\n    CatchAll { ignored_checks: Vec<RuntimeCheck> },\n}\n\nimpl Decision {\n    pub fn run(body: Body) -> Self {\n        Decision::Run { body }\n    }\n\n    pub fn guard(guard: usize, if_true: Body, if_false: Self) -> Self {\n        Decision::Guard {\n            guard,\n            if_true,\n            if_false: Box::new(if_false),\n        }\n    }\n}\n\n/// The `case` compiler itself (shocking, I know).\n///\n#[derive(Debug)]\nstruct Compiler<'a> {\n    environment: &'a Environment<'a>,\n    patterns: Arena<Pattern>,\n    variable_id: usize,\n    diagnostics: Diagnostics,\n}\n\n/// The result of compiling a pattern match expression.\n///\n#[derive(Debug)]\npub struct CompileCaseResult {\n    pub compiled_case: CompiledCase,\n    pub diagnostics: Diagnostics,\n}\n\nimpl CompileCaseResult {\n    pub fn is_reachable(&self, clause: usize, pattern_index: usize) -> Reachability {\n        if self\n            .diagnostics\n            .reachable\n            .contains(&(clause, pattern_index))\n        {\n            Reachability::Reachable\n        } else if self\n            .diagnostics\n            .match_impossible_variants\n            .contains(&(clause, pattern_index))\n        {\n            Reachability::Unreachable(UnreachablePatternReason::ImpossibleVariant)\n        } else if let Some(segments) = self\n            .diagnostics\n            .match_impossible_segments\n            .get(&(clause, pattern_index))\n        {\n            Reachability::Unreachable(UnreachablePatternReason::ImpossibleSegments(\n                segments.clone(),\n            ))\n        } else {\n            Reachability::Unreachable(UnreachablePatternReason::DuplicatePattern)\n        }\n    }\n\n    pub fn missing_patterns(&self, environment: &Environment<'_>) -> Vec<EcoString> {\n        missing_patterns::missing_patterns(self, environment)\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]\npub struct CompiledCase {\n    pub tree: Decision,\n    pub subject_variables: Vec<Variable>,\n}\n\nimpl CompiledCase {\n    pub fn failure() -> Self {\n        Self {\n            tree: Decision::Fail,\n            subject_variables: vec![],\n        }\n    }\n\n    /// The decision tree for simple variable assignment, such as in the following\n    /// assignment:\n    /// ```gleam\n    /// let x = 10\n    /// ```\n    pub fn simple_variable_assignment(name: EcoString, type_: Arc<Type>) -> Self {\n        let variable = Variable::new(0, type_);\n        let mut body = Body::new(0);\n        body.assign(name, variable.clone());\n        Self {\n            tree: Decision::Run { body },\n            subject_variables: vec![variable],\n        }\n    }\n}\n\n/// Whether a pattern is reachable, or why it is unreachable.\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Reachability {\n    Reachable,\n    Unreachable(UnreachablePatternReason),\n}\n\n/// A type for storing diagnostics produced by the decision tree compiler.\n///\n#[derive(Debug)]\npub struct Diagnostics {\n    /// A flag indicating the match is missing one or more pattern.\n    pub missing: bool,\n\n    /// The patterns that are reachable. If a pattern isn't in this list it\n    /// means it is redundant.\n    /// Each entry is a pair of indices: The index of the clause the pattern\n    /// belongs to, followed by the index of the pattern itself within the\n    /// clause. For example, in this case expression:\n    /// ```gleam\n    /// case x {\n    ///   1 -> todo\n    ///   2 | 3 -> todo\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    /// The `3` pattern would be `(1, 1)`, because it is the second pattern of\n    /// the second clause, and both are zero-indexed.\n    ///\n    pub reachable: HashSet<(usize, usize)>,\n\n    /// Patterns which match on variants of a type which the compiler\n    /// can tell will never be present, due to variant inference.\n    ///\n    /// See `reachable` for an explanation of its structure.\n    ///\n    pub match_impossible_variants: HashSet<(usize, usize)>,\n\n    /// Patterns that are matching on bit array segments the compiler can tell\n    /// for sure will never match.\n    ///\n    pub match_impossible_segments: HashMap<(usize, usize), Vec<ImpossibleBitArraySegmentPattern>>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum ImpossibleBitArraySegmentPattern {\n    UnrepresentableInteger {\n        value: BigInt,\n        size: u32,\n        location: SrcSpan,\n        signed: bool,\n    },\n}\n\nimpl ImpossibleBitArraySegmentPattern {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            ImpossibleBitArraySegmentPattern::UnrepresentableInteger { location, .. } => *location,\n        }\n    }\n}\n\nimpl<'a> Compiler<'a> {\n    fn new(environment: &'a Environment<'a>, variable_id: usize, patterns: Arena<Pattern>) -> Self {\n        Self {\n            environment,\n            patterns,\n            variable_id,\n            diagnostics: Diagnostics {\n                missing: false,\n                reachable: HashSet::new(),\n                match_impossible_variants: HashSet::new(),\n                match_impossible_segments: HashMap::new(),\n            },\n        }\n    }\n\n    fn pattern(&mut self, pattern_id: Id<Pattern>) -> &mut Pattern {\n        self.patterns\n            .get_mut(pattern_id)\n            .expect(\"unknown pattern id\")\n    }\n\n    /// Returns a new fresh variable (i.e. guaranteed to have a unique `variable_id`)\n    /// with the given type.\n    ///\n    fn fresh_variable(&mut self, type_: Arc<Type>) -> Variable {\n        let var = Variable::new(self.variable_id, type_);\n        self.variable_id += 1;\n        var\n    }\n\n    fn mark_as_reached(&mut self, branch: &Branch) {\n        let _ = self\n            .diagnostics\n            .reachable\n            .insert((branch.clause_index, branch.alternative_index));\n    }\n\n    fn mark_as_matching_impossible_variant(&mut self, branch: &Branch) {\n        let _ = self\n            .diagnostics\n            .reachable\n            .remove(&(branch.clause_index, branch.alternative_index));\n        let _ = self\n            .diagnostics\n            .match_impossible_variants\n            .insert((branch.clause_index, branch.alternative_index));\n    }\n\n    fn mark_as_matching_impossible_segment(\n        &mut self,\n        branch: &Branch,\n        segments: Vec<ImpossibleBitArraySegmentPattern>,\n    ) {\n        let _ = self\n            .diagnostics\n            .reachable\n            .remove(&(branch.clause_index, branch.alternative_index));\n        let _ = self\n            .diagnostics\n            .match_impossible_segments\n            .insert((branch.clause_index, branch.alternative_index), segments);\n    }\n\n    fn compile(&mut self, mut branches: VecDeque<Branch>) -> Decision {\n        branches\n            .iter_mut()\n            .for_each(|branch| branch.move_unconditional_patterns(self));\n\n        let Some(first_branch) = branches.front() else {\n            // If there's no branches, that means we have a pattern that is not\n            // exhaustive as there's nothing that could match!\n            self.diagnostics.missing = true;\n            return Decision::Fail;\n        };\n\n        self.mark_as_reached(first_branch);\n\n        // In order to compile the branches, we need to pick a `PatternCheck` from\n        // the first branch, and use the variable it's pattern matching on to create\n        // a new node in the tree. All the branches will be split into different\n        // possible paths of this tree.\n        match find_pivot_check(first_branch, &branches, self.environment) {\n            Some(PatternCheck { var, .. }) => self.split_and_compile_with_pivot_var(var, branches),\n\n            // If the branch has no remaining checks, it means that we've moved all\n            // its variable patterns as assignments into the body and there's no\n            // additional checks remaining. So the only thing left that could result\n            // in the match failing is the additional guard.\n            None => match first_branch.guard {\n                // If there's no guard we're in the following situation:\n                // `∅ -> body`. It means that this branch will always match no\n                // matter what, all the remaining branches are just discarded and\n                // we can produce a terminating node to run the body\n                // unconditionally.\n                None => Decision::run(first_branch.body.clone()),\n                // If we have a guard we're in this scenario:\n                // `∅ if condition -> body`. We can produce a `Guard` node:\n                // if the condition evaluates to `True` we can run its body.\n                // Otherwise, we'll have to keep looking at the remaining branches\n                // to know what to do if this branch doesn't match.\n                Some(guard) => {\n                    let if_true = first_branch.body.clone();\n                    // All the remaining branches will be compiled and end up\n                    // in the path of the tree to choose if the guard is false.\n                    let _ = branches.pop_front();\n                    let if_false = self.compile(branches);\n                    Decision::guard(guard, if_true, if_false)\n                }\n            },\n        }\n    }\n\n    fn split_and_compile_with_pivot_var(\n        &mut self,\n        pivot_var: Variable,\n        branches: VecDeque<Branch>,\n    ) -> Decision {\n        // We first try and come up with a list of all the runtime checks we might\n        // have to perform on the variable at runtime. In most cases it's a limited\n        // number of checks that we know before hand (for example, when matching\n        // on a list, or on a custom type).\n        let branch_mode = pivot_var.branch_mode(self.environment);\n        let known_checks = match &branch_mode {\n            // If the type being matched on is infinite there's no known runtime\n            // check we could come up with in advance. So we'll build them as\n            // we go.\n            BranchMode::Infinite => vec![],\n\n            // If the type is a tuple there's only one runtime check we could\n            // perform that actually makes sense.\n            BranchMode::Tuple { elements } => vec![self.is_tuple_check(elements)],\n\n            // If the type being matched on is a list we know the resulting\n            // decision tree node is only ever going to have two different paths:\n            // one to follow if the list is empty, and one to follow if it's not.\n            BranchMode::List { inner_type } => {\n                vec![\n                    RuntimeCheck::EmptyList,\n                    self.is_list_check(inner_type.clone()),\n                ]\n            }\n\n            // If we know that a specific variant is inferred we will require just\n            // that one and not all the other ones we know for sure are not going to\n            // be there.\n            BranchMode::NamedType {\n                constructors,\n                inferred_variant: Some(index),\n            } => {\n                let constructor = constructors\n                    .get(*index)\n                    .expect(\"wrong index for inferred variant\");\n                vec![self.is_variant_check(*index, constructor)]\n            }\n\n            // Otherwise we know we'll need a check for each of its possible variants.\n            BranchMode::NamedType { constructors, .. } => constructors\n                .iter()\n                .enumerate()\n                .map(|(index, constructor)| self.is_variant_check(index, constructor))\n                .collect_vec(),\n        };\n\n        // We then split all the branches using these checks and compile the\n        // choices they've been split up into.\n        let mut splitter = BranchSplitter::from_checks(known_checks);\n        self.split_branches(&mut splitter, branches, pivot_var.clone(), &branch_mode);\n        if branch_mode.is_infinite() {\n            // If the branching is infinite, that means we always need to also have\n            // a fallback (imagine you're pattern matching on an `Int` and put no\n            // `_` at the end of the case expression).\n            self.splitter_to_switch(pivot_var, splitter)\n        } else if splitter.choices.is_empty() {\n            // If the branching doesn't need any fallback but we ended up with no\n            // checks it means we're trying to pattern match on an external type\n            // but haven't provided a catch-all case.\n            // That's never going to match, so we produce a failure node.\n            self.diagnostics.missing = true;\n            Decision::Fail\n        } else {\n            // Otherwise we know that one of the possible runtime checks is always\n            // going to succeed and there's no need to also have a fallback branch.\n            self.splitter_to_exhaustive_switch(pivot_var, splitter)\n        }\n    }\n\n    fn split_branches(\n        &mut self,\n        splitter: &mut BranchSplitter,\n        branches: VecDeque<Branch>,\n        pivot_var: Variable,\n        branch_mode: &BranchMode,\n    ) {\n        for mut branch in branches {\n            let Some(pattern_check) = branch.pop_check_on_var(&pivot_var) else {\n                // If the branch doesn't perform any check on the pivot variable, it means\n                // it could still match no matter what shape `pivot_var` has. So we must\n                // add it as a fallback branch, that is a branch that is still relevant\n                // for all possible paths in the decision tree.\n                splitter.add_fallback_branch(branch);\n                continue;\n            };\n\n            let checked_pattern = self.pattern(pattern_check.pattern);\n\n            if checked_pattern.is_matching_on_unreachable_variant(branch_mode) {\n                self.mark_as_matching_impossible_variant(&branch);\n                continue;\n            } else if let Some(unreachable_segments) =\n                checked_pattern.is_matching_on_impossible_segment()\n            {\n                self.mark_as_matching_impossible_segment(&branch, unreachable_segments);\n                continue;\n            }\n\n            splitter.add_checked_branch(pattern_check, branch, branch_mode, self);\n        }\n    }\n\n    /// Compiles the branches in a splitter down to a switch matching on a type\n    /// with infinite variants (like ints, floats and strings). With a fallaback\n    /// branch.\n    ///\n    fn splitter_to_switch(&mut self, var: Variable, splitter: BranchSplitter) -> Decision {\n        let choices = self.compile_all_choices(splitter.choices);\n        let last_choice = self.compile(splitter.fallback);\n        Decision::Switch {\n            var,\n            choices,\n            fallback: Box::new(last_choice),\n            fallback_check: Box::new(FallbackCheck::InfiniteCatchAll),\n        }\n    }\n\n    /// Compiles the branches in a splitter down to a switch matching on a type\n    /// with a finite known number of variants.\n    ///\n    fn splitter_to_exhaustive_switch(\n        &mut self,\n        var: Variable,\n        splitter: BranchSplitter,\n    ) -> Decision {\n        let mut choices = splitter.choices;\n        let (choices, fallback, fallback_check) =\n            if choices.iter().any(|(check, _)| check.is_ignored()) {\n                // If there's any check that is ignored and not explicitly being\n                // matched on then we want to ignore all of those and clump them\n                // into a single \"fallback\" branch to avoid bloating the generated\n                // tree.\n                let mut ignored_checks = vec![];\n                let mut remaining_choices = vec![];\n                for choice in choices.into_iter() {\n                    if choice.0.is_ignored() {\n                        ignored_checks.push(choice.0)\n                    } else {\n                        remaining_choices.push(choice)\n                    }\n                }\n\n                let fallback_check = FallbackCheck::CatchAll { ignored_checks };\n                (remaining_choices, splitter.fallback, fallback_check)\n            } else {\n                // Otherwise we just use the last check as the final one that\n                // can be outright skipped.\n                let (last_check, last_choice) = choices.pop().expect(\"at least one choice\");\n                let fallback_check = FallbackCheck::RuntimeCheck { check: last_check };\n                (choices, last_choice, fallback_check)\n            };\n\n        let choices = self.compile_all_choices(choices);\n        let fallback = Box::new(self.compile(fallback));\n        Decision::Switch {\n            var,\n            choices,\n            fallback,\n            fallback_check: Box::new(fallback_check),\n        }\n    }\n\n    fn compile_all_choices(\n        &mut self,\n        choices: Vec<(RuntimeCheck, VecDeque<Branch>)>,\n    ) -> Vec<(RuntimeCheck, Decision)> {\n        choices\n            .into_iter()\n            .map(|(check, branches)| (check, self.compile(branches)))\n            .collect_vec()\n    }\n\n    /// Turns a `RuntimeCheckKind` into a new `RuntimeCheck` by coming up with\n    /// the needed new fresh variables.\n    /// All the type information needed to create these variables is in the\n    /// `branch_mode` arg.\n    ///\n    fn fresh_runtime_check(\n        &mut self,\n        kind: RuntimeCheckKind,\n        branch_mode: &BranchMode,\n    ) -> RuntimeCheck {\n        match (kind, branch_mode) {\n            (RuntimeCheckKind::Int { int_value }, _) => RuntimeCheck::Int {\n                int_value: int_value.clone(),\n            },\n            (RuntimeCheckKind::Float { float_value }, _) => RuntimeCheck::Float { float_value },\n            (RuntimeCheckKind::String { value }, _) => RuntimeCheck::String {\n                value: value.clone(),\n            },\n            (RuntimeCheckKind::StringPrefix { prefix }, _) => RuntimeCheck::StringPrefix {\n                prefix: prefix.clone(),\n                rest: self.fresh_variable(string()),\n            },\n            (RuntimeCheckKind::Tuple { .. }, BranchMode::Tuple { elements }) => {\n                self.is_tuple_check(elements)\n            }\n            (RuntimeCheckKind::Variant { index }, BranchMode::NamedType { constructors, .. }) => {\n                self.is_variant_check(\n                    index,\n                    constructors.get(index).expect(\"unknown variant index\"),\n                )\n            }\n            (RuntimeCheckKind::EmptyList, _) => RuntimeCheck::EmptyList,\n            (RuntimeCheckKind::NonEmptyList, BranchMode::List { inner_type }) => {\n                self.is_list_check(inner_type.clone())\n            }\n            (_, _) => unreachable!(\"type checking should make this impossible\"),\n        }\n    }\n\n    /// Comes up with new pattern cecks that have to match in case a given\n    /// runtime check succeeds for the given pattern.\n    ///\n    /// Let's make an example: when we have a pattern - say `a is Wibble(1, [])` -\n    /// we come up with a runtime check to perform on it. For our example the\n    /// runtime check is to make sure that `a` is indeed a `Wibble` variant.\n    /// However, after successfully performing that check we're left with much to\n    /// do! We know that `a` is `Wibble` but now we'll have to make sure that its\n    /// inner arguments also match the given patterns. So the new additional checks\n    /// we have to add are `a0 is 1, a1 is []` (where `a0` and `a1` are the fresh\n    /// variable names we use to refer to the constructor's arguments).\n    ///\n    fn new_checks(\n        &mut self,\n        for_pattern: &Pattern,\n        after_succeding_check: &RuntimeCheck,\n    ) -> Vec<PatternCheck> {\n        match (for_pattern, after_succeding_check) {\n            // These patterns never result in adding new checks. After a runtime\n            // check matches on them there's nothing else to discover.\n            (\n                Pattern::Discard\n                | Pattern::Assign { .. }\n                | Pattern::Variable { .. }\n                | Pattern::Int { .. }\n                | Pattern::Float { .. }\n                | Pattern::BitArray { .. }\n                | Pattern::EmptyList,\n                _,\n            )\n            | (Pattern::String { .. }, RuntimeCheck::String { .. }) => vec![],\n\n            // After making sure a value is not an empty list we'll have to perform\n            // additional checks on its first item and on the tail.\n            (\n                Pattern::NonEmptyList {\n                    first: first_pattern,\n                    rest: rest_pattern,\n                },\n                RuntimeCheck::NonEmptyList {\n                    first: first_variable,\n                    rest: rest_variable,\n                },\n            ) => vec![\n                first_variable.is(*first_pattern),\n                rest_variable.is(*rest_pattern),\n            ],\n\n            // After making sure a value is a specific variant we'll have to check each\n            // of its arguments respects the given patterns (as shown in the doc example for\n            // this function!)\n            (\n                Pattern::Variant {\n                    fields: patterns, ..\n                },\n                RuntimeCheck::Variant {\n                    fields: variables, ..\n                },\n            ) => (variables.iter().zip(patterns))\n                .map(|(field, pattern)| field.is(*pattern))\n                .collect_vec(),\n\n            // Tuples are exactly the same as variants: after making sure we're dealing with\n            // a tuple, we will have to check that each of its elements matches the given\n            // pattern: `a is #(1, _)` will result in the following checks\n            // `a0 is 1, a1 is _` (where `a0` and `a1` are fresh variable names we use to\n            // refer to each of the tuple's elements).\n            (\n                Pattern::Tuple { elements: patterns },\n                RuntimeCheck::Tuple {\n                    elements: variables,\n                    ..\n                },\n            ) => (variables.iter().zip(patterns))\n                .map(|(element, pattern)| element.is(*pattern))\n                .collect_vec(),\n\n            // Strings are quite fun: if we've checked at runtime a string starts with a given\n            // prefix and we want to check that it's some overlapping literal value we'll still\n            // have some amount of work to perform.\n            //\n            // Let's have a look at an example: the pattern we care about is `a is \"wibble\"`\n            // and we've just successfully ran the runtime check for `a is \"wib\" <> rest`.\n            // So we know the string already starts with `\"wib\"` what we have to check now\n            // is that the remaining part `rest` is `\"ble\"`.\n            (Pattern::String { value }, RuntimeCheck::StringPrefix { prefix, rest, .. }) => {\n                let remaining = value.strip_prefix(prefix.as_str()).unwrap_or(value);\n                vec![rest.is(self.string_pattern(remaining))]\n            }\n\n            // String prefixes are similar to strings, but a bit more involved. Let's say we're\n            // checking the pattern:\n            //\n            // ```txt\n            // \"wibblest\" <> rest1\n            // ─┬────────\n            //  ╰── We will refer to this as `prefix1`\n            // ```\n            //\n            // And we know that the following overlapping runtime check has already succeeded:\n            //\n            // ```txt\n            // \"wibble\" <> rest0\n            // ─┬──────\n            //  ╰── We will refer to this as `prefix0`\n            // ```\n            //\n            // We're lucky because we now know quite a bit about the shape of the string. Since\n            // we know it already starts with `\"wibble\"` we can just check that the remaining\n            // part after that starts with the missing part of the prefix:\n            // `prefix0 is \"st\" <> rest1`.\n            (\n                Pattern::StringPrefix {\n                    prefix: prefix1,\n                    prefix_name: _,\n                    rest: rest1,\n                },\n                RuntimeCheck::StringPrefix {\n                    prefix: prefix0,\n                    rest: rest0,\n                },\n            ) => {\n                let remaining = prefix1.strip_prefix(prefix0.as_str()).unwrap_or(prefix1);\n                // If the prefixes are exactly the same then the only remaining check\n                // is for the two remaining bits to be the same.\n                if remaining.is_empty() {\n                    vec![rest0.is(*rest1)]\n                } else {\n                    vec![rest0.is(self.string_prefix_pattern(remaining, *rest1))]\n                }\n            }\n\n            (_, _) => unreachable!(\"invalid pattern overlapping\"),\n        }\n    }\n\n    /// Builds an `IsVariant` runtime check, coming up with new fresh variable names\n    /// for its arguments.\n    ///\n    fn is_variant_check(\n        &mut self,\n        index: usize,\n        constructor: &TypeValueConstructor,\n    ) -> RuntimeCheck {\n        RuntimeCheck::Variant {\n            index,\n            match_: VariantMatch::NeverExplicitlyMatchedOn {\n                name: constructor.name.clone(),\n            },\n            labels: constructor\n                .parameters\n                .iter()\n                .enumerate()\n                .filter_map(|(i, parameter)| Some((i, parameter.label.clone()?)))\n                .collect(),\n            fields: constructor\n                .parameters\n                .iter()\n                .map(|parameter| parameter.type_.clone())\n                .map(|type_| self.fresh_variable(type_))\n                .collect_vec(),\n        }\n    }\n\n    /// Builds an `IsNonEmptyList` runtime check, coming up with fresh variable\n    /// names for its arguments.\n    ///\n    fn is_list_check(&mut self, inner_type: Arc<Type>) -> RuntimeCheck {\n        RuntimeCheck::NonEmptyList {\n            first: self.fresh_variable(inner_type.clone()),\n            rest: self.fresh_variable(Arc::new(Type::list(inner_type))),\n        }\n    }\n\n    /// Builds an `IsTuple` runtime check, coming up with fresh variable\n    /// names for its arguments.\n    ///\n    fn is_tuple_check(&mut self, elements: &[Arc<Type>]) -> RuntimeCheck {\n        RuntimeCheck::Tuple {\n            size: elements.len(),\n            elements: elements\n                .iter()\n                .map(|type_| self.fresh_variable(type_.clone()))\n                .collect_vec(),\n        }\n    }\n\n    /// Allocates a new `StringPattern` with the given value.\n    ///\n    fn string_pattern(&mut self, value: &str) -> Id<Pattern> {\n        self.patterns.alloc(Pattern::String {\n            value: EcoString::from(value),\n        })\n    }\n\n    fn bit_array_pattern(&mut self, tests: VecDeque<BitArrayTest>) -> Id<Pattern> {\n        self.patterns.alloc(Pattern::BitArray { tests })\n    }\n\n    /// Allocates a new `StringPrefix` pattern with the given prefix and pattern\n    /// for the rest of the string.\n    ///\n    fn string_prefix_pattern(&mut self, prefix: &str, rest: Id<Pattern>) -> Id<Pattern> {\n        self.patterns.alloc(Pattern::StringPrefix {\n            prefix: EcoString::from(prefix),\n            prefix_name: None,\n            rest,\n        })\n    }\n}\n\n/// Returns a pattern check from `first_branch` to be used as a pivot to split all\n/// the `branches`.\n///\nfn find_pivot_check(\n    first_branch: &Branch,\n    branches: &VecDeque<Branch>,\n    env: &Environment<'_>,\n) -> Option<PatternCheck> {\n    // To try and minimise code duplication, we use the following heuristic: we\n    // choose the check matching on the variable that is referenced the most\n    // across all checks in all branches.\n    let mut var_references = HashMap::new();\n    for branch in branches {\n        for check in &branch.checks {\n            let _ = var_references\n                .entry(check.var.id)\n                .and_modify(|references| *references += 1)\n                .or_insert(0);\n        }\n    }\n\n    // We want to picke the variable that has the smallest branching factor\n    // possible, this tends to yield smaller, shallower decision trees.\n    // So, for example, we will pick a list (branching factor of 2 `[]` and\n    // `[_, ..]`) over an integer (infinitely many choices).\n    //\n    // In case two variables are tied we break the tie by choosing the subject\n    // that appears in the most clauses (i.e. a test that will pay off for more\n    // rows).\n    //\n    // Both parts mirror standard guidance for good match trees (small branching\n    // factor; prioritize columns that are widely useful):\n    // https://www.cs.tufts.edu/~nr/cs257/archive/luc-maranget/jun08.pdf\n    first_branch\n        .checks\n        .iter()\n        .min_by_key(|check| {\n            let branching_factor = check.var.branch_mode(env).branching_factor();\n            let references = var_references.get(&check.var.id).cloned().unwrap_or(0);\n\n            // Notice how we're using `-references`: we want to favour the one\n            // that has the most references, so the one were `-references` is\n            // the smallest.\n            (branching_factor, -references)\n        })\n        .cloned()\n}\n\n/// A handy data structure we use to split branches in different possible paths\n/// based on a check.\n///\nstruct BranchSplitter {\n    pub choices: Vec<(RuntimeCheck, VecDeque<Branch>)>,\n    pub fallback: VecDeque<Branch>,\n\n    /// This is used to allow quickly looking up a choice in the `choices`\n    /// vector, without loosing track of the checks' order.\n    indices: HashMap<RuntimeCheckKind, usize>,\n\n    /// This is used to store the indices of just the prefix checks as they have\n    /// different rules from all the other `RuntimeCheckKinds` whose indices are\n    /// instead stored in the `indices` field.\n    ///\n    /// We discuss this in more detail in the `index_of_overlapping_runtime_check`\n    /// function!\n    prefix_indices: Trie<String, usize>,\n}\n\nimpl BranchSplitter {\n    /// Creates a new splitter with the given starting checks.\n    ///\n    fn from_checks(checks: Vec<RuntimeCheck>) -> Self {\n        let mut choices = Vec::with_capacity(checks.len());\n        let mut indices = HashMap::new();\n\n        for (index, runtime_check) in checks.into_iter().enumerate() {\n            let Some(kind) = runtime_check.kind() else {\n                continue;\n            };\n            let _ = indices.insert(kind, index);\n            choices.push((runtime_check, VecDeque::new()));\n        }\n\n        Self {\n            fallback: VecDeque::new(),\n            choices,\n            indices,\n            prefix_indices: Trie::new(),\n        }\n    }\n\n    /// Add a fallback branch: this is a branch that is relevant to all possible\n    /// paths as it could still run, no matter the result of any of the `Check`s\n    /// we've stored!\n    ///\n    fn add_fallback_branch(&mut self, branch: Branch) {\n        self.choices\n            .iter_mut()\n            .for_each(|(_, branches)| branches.push_back(branch.clone()));\n        self.fallback.push_back(branch);\n    }\n\n    /// Given a branch and the pattern its using to check on the pivot variable,\n    /// adds it to the paths where it's relevant, that is where we know from\n    /// previous checks that this pattern has a chance of matching.\n    ///\n    fn add_checked_branch(\n        &mut self,\n        pattern_check: PatternCheck,\n        mut branch: Branch,\n        branch_mode: &BranchMode,\n        compiler: &mut Compiler<'_>,\n    ) {\n        let pattern = compiler.pattern(pattern_check.pattern).clone();\n\n        // Bit array patterns are split in a different way that requires special\n        // handling. Instead of reasoning on overlapping checks what we do it we\n        // always split the decision tree in two distinct paths based on one of\n        // the bit array pattern's tests.\n        if let Pattern::BitArray { tests } = pattern {\n            self.add_checked_bit_array_branch(pattern_check, tests, branch, compiler);\n            return;\n        };\n\n        let kind = pattern\n            .to_runtime_check_kind()\n            .expect(\"no unconditional patterns left\");\n\n        let indices_of_overlapping_checks = self.indices_of_overlapping_checks(&kind);\n        if indices_of_overlapping_checks.is_empty() {\n            // This is a new choice we haven't yet discovered as it is not overlapping\n            // with any of the existing ones. So we add it as a possible new path\n            // we might have to go down to in the decision tree.\n            self.save_index_of_new_choice(kind.clone());\n\n            let check = compiler.fresh_runtime_check(kind, branch_mode);\n            for new_check in compiler.new_checks(&pattern, &check) {\n                branch.add_check(new_check);\n            }\n            let mut branches = self.fallback.clone();\n            branches.push_back(branch);\n\n            self.choices.push((check, branches));\n        } else {\n            // Otherwise, we know that the check for this branch overlaps with\n            // (possibly more than one) existing checks and so is relevant only\n            // as part of those existing paths.\n            // We'll add the branch with its newly discovered checks only to those\n            // paths.\n            for index in indices_of_overlapping_checks.iter() {\n                let (overlapping_check, branches) = self\n                    .choices\n                    .get_mut(*index)\n                    .expect(\"check to already be a choice\");\n\n                let mut branch = branch.clone();\n                for new_check in compiler.new_checks(&pattern, overlapping_check) {\n                    branch.add_check(new_check);\n                }\n                branches.push_back(branch);\n            }\n        }\n\n        // Then we have to update all variant checks with any new name/module\n        // we might have discovered from the pattern to make sure we're using\n        // the correct qualification to refer to each constructor.\n        if let Pattern::Variant { name, module, .. } = pattern {\n            for index in indices_of_overlapping_checks {\n                let (check, _) = self\n                    .choices\n                    .get_mut(index)\n                    .expect(\"check to already be a choice\");\n                if let RuntimeCheck::Variant { match_, .. } = check {\n                    *match_ = VariantMatch::ExplicitlyMatchedOn {\n                        module: module.clone(),\n                        name: name.clone(),\n                    }\n                }\n            }\n        }\n    }\n\n    /// When we work with bit array patterns the splitter follows a different\n    /// strategy to split branches: instead of trying to create a multiway\n    /// decision tree with possibly many branches, we create only two branches\n    /// based on the first segment test we run into.\n    /// One path is going to be for the branches that can match if the test is\n    /// successful, and the other one is going to be the usual fallback to go\n    /// down to if it's not successful.\n    ///\n    /// > \"And now for the tricky bit...\"\n    /// > <https://youtu.be/lKXe3HUG2l4?si=i1thYB-kjfMU8NSe&t=645>\n    ///\n    fn add_checked_bit_array_branch(\n        &mut self,\n        pattern_check: PatternCheck,\n        tests: VecDeque<BitArrayTest>,\n        mut branch: Branch,\n        compiler: &mut Compiler<'_>,\n    ) {\n        // If we haven't found a test yet we just use the first one we find\n        // as the pivot to split all the branches.\n        let pivot_test = match self.choices.as_slice() {\n            [] => {\n                let test = tests.front().expect(\"empty bit array test\").clone();\n                self.choices.push((\n                    RuntimeCheck::BitArray { test: test.clone() },\n                    VecDeque::new(),\n                ));\n                test\n            }\n            [(RuntimeCheck::BitArray { test }, _)] => test.clone(),\n            _ => unreachable!(\"non bit array check when splitting bit array patterns\"),\n        };\n\n        let pattern_fails_if_test_succeeds = tests\n            .iter()\n            .any(|test| test.fails_if_succeeding(&pivot_test).is_certain());\n\n        let pattern_fails_if_test_fails = tests\n            .iter()\n            .any(|test| test.fails_if_failing(&pivot_test).is_certain());\n\n        // The branch is still relevant for the if_true path if it still has a\n        // chance of matching knowing that the pivot test has matched.\n        // So if we know for certain that the pattern would fail, we don't even\n        // bother adding it to the if_true path.\n        if !pattern_fails_if_test_succeeds {\n            // If the branch is relevant we can further simplify it by removing\n            // all those tests that are guaranteed to succeed. For example,\n            // if the succeeding pivot test is `size >= 20` there's no point\n            // in checking that `size >= 10`, we know that's always true in this\n            // path of the decision tree!\n            let tests = tests\n                .into_iter()\n                .filter(|test| test.succeeds_if_succeeding(&pivot_test) == Confidence::Uncertain)\n                .collect::<VecDeque<_>>();\n\n            let mut branch = branch.clone();\n            let variable = &pattern_check.var;\n            branch.add_check(variable.is(compiler.bit_array_pattern(tests)));\n\n            // We know that there's always going to be a single choice for the\n            // successful check, so we get that and add the branch to it.\n            let (_, if_true_branches) = self\n                .choices\n                .get_mut(0)\n                .expect(\"bit array compilation with no choice\");\n            if_true_branches.push_back(branch);\n        }\n\n        // Same goes for the if_false branch: knowing the pivot test has failed\n        // we only want to keep those branches with a pattern that still have a\n        // chance to match.\n        if !pattern_fails_if_test_fails {\n            // The main difference with the if true case is that we have no way\n            // of pruning the number of needed tests, so we add this check back\n            // exactly as it is.\n            branch.add_check(pattern_check);\n            self.fallback.push_back(branch);\n        }\n    }\n\n    fn save_index_of_new_choice(&mut self, kind: RuntimeCheckKind) {\n        let _ = match kind {\n            RuntimeCheckKind::Int { .. }\n            | RuntimeCheckKind::Float { .. }\n            | RuntimeCheckKind::String { .. }\n            | RuntimeCheckKind::Tuple { .. }\n            | RuntimeCheckKind::Variant { .. }\n            | RuntimeCheckKind::EmptyList\n            | RuntimeCheckKind::NonEmptyList => self.indices.insert(kind, self.choices.len()),\n\n            RuntimeCheckKind::StringPrefix { prefix } => self\n                .prefix_indices\n                .insert(prefix.to_string(), self.choices.len()),\n        };\n    }\n\n    fn indices_of_overlapping_checks(&self, kind: &RuntimeCheckKind) -> Vec<usize> {\n        match kind {\n            // All these checks will only overlap with a check that is exactly the\n            // same, so we just look up their index in the `indices` map using the\n            // kind as the lookup.\n            RuntimeCheckKind::Int { .. }\n            | RuntimeCheckKind::Float { .. }\n            | RuntimeCheckKind::Tuple { .. }\n            | RuntimeCheckKind::Variant { .. }\n            | RuntimeCheckKind::EmptyList\n            | RuntimeCheckKind::NonEmptyList => {\n                self.indices.get(kind).cloned().into_iter().collect_vec()\n            }\n\n            // String patterns are a bit more tricky as they might end up overlapping\n            // even if they're not exactly the same kind of check! Let's have a look\n            // at an example. Say we're compiling these branches:\n            //\n            // ```\n            // a is \"wibble\" <> rest -> todo\n            // a is \"wibbler\" <> rest -> todo\n            // ```\n            //\n            // We use the first (and only) check in the first branch as the pivot and\n            // now we have to decide where to put the next branch. Is it matching with\n            // the first one or completely unrelated?\n            // Since `\"wibbler\"` starts with `\"wibble\"` we know it's overlapping and\n            // it cannot possibly match if the previous one doesn't!\n            //\n            // So when we find a `String`/`StringPrefix` pattern we look for a prefix\n            // among the ones we have discovered so far that could match with it.\n            // That is, we look for a prefix of the pattern we're checking in the prefix\n            // trie.\n            RuntimeCheckKind::StringPrefix { prefix: value } => {\n                ancestors_values(&self.prefix_indices, value).collect_vec()\n            }\n\n            // Strings are almost exactly the same, except they could also have an exact\n            // match with other string patterns. So a string pattern could overlap with\n            // another string pattern (if they're matching on the same value), or with\n            // one or more string prefix patterns with a matching prefix.\n            RuntimeCheckKind::String { value } => {\n                let first_index = self.indices.get(kind).cloned();\n                first_index\n                    .into_iter()\n                    .chain(ancestors_values(&self.prefix_indices, value))\n                    .collect_vec()\n            }\n        }\n    }\n}\n\nfn ancestors_values(trie: &Trie<String, usize>, key: &str) -> impl Iterator<Item = usize> {\n    trie.get_ancestor(key)\n        .into_iter()\n        .flat_map(|ancestor| ancestor.values().copied())\n}\n\n#[derive(Debug)]\npub struct ConstructorSpecialiser {\n    specialised_types: HashMap<u64, Arc<Type>>,\n}\n\nimpl ConstructorSpecialiser {\n    fn specialise_constructors(\n        constructors: &TypeVariantConstructors,\n        type_arguments: &[Arc<Type>],\n        current_module: &EcoString,\n        type_module: &EcoString,\n    ) -> Vec<TypeValueConstructor> {\n        match constructors.opaque {\n            // If the type is opaque and we are not in the definition module of\n            // that type, we don't have access to any constructors so we treat\n            // it the same as an external type.\n            Opaque::Opaque if current_module != type_module => return Vec::new(),\n            Opaque::Opaque | Opaque::NotOpaque => {}\n        };\n\n        let specialiser = Self::new(constructors.type_parameters_ids.as_slice(), type_arguments);\n        constructors\n            .variants\n            .iter()\n            .map(|v| specialiser.specialise_type_value_constructor(v))\n            .collect_vec()\n    }\n\n    fn new(parameters: &[u64], type_arguments: &[Arc<Type>]) -> Self {\n        let specialised_types = parameters\n            .iter()\n            .copied()\n            .zip(type_arguments.iter().cloned())\n            .collect();\n        Self { specialised_types }\n    }\n\n    fn specialise_type_value_constructor(&self, v: &TypeValueConstructor) -> TypeValueConstructor {\n        let TypeValueConstructor {\n            name,\n            parameters,\n            documentation,\n        } = v;\n        let parameters = parameters\n            .iter()\n            .map(|p| TypeValueConstructorField {\n                type_: self.specialise_type(p.type_.as_ref()),\n                label: p.label.clone(),\n                documentation: p.documentation.clone(),\n            })\n            .collect_vec();\n        TypeValueConstructor {\n            name: name.clone(),\n            parameters,\n            documentation: documentation.clone(),\n        }\n    }\n\n    fn specialise_type(&self, type_: &Type) -> Arc<Type> {\n        Arc::new(match type_ {\n            Type::Named {\n                publicity,\n                package,\n                module,\n                name,\n                arguments,\n                inferred_variant,\n            } => Type::Named {\n                publicity: *publicity,\n                package: package.clone(),\n                module: module.clone(),\n                name: name.clone(),\n                arguments: arguments\n                    .iter()\n                    .map(|argument| self.specialise_type(argument))\n                    .collect(),\n                inferred_variant: *inferred_variant,\n            },\n\n            Type::Fn { arguments, return_ } => Type::Fn {\n                arguments: arguments\n                    .iter()\n                    .map(|argument| self.specialise_type(argument))\n                    .collect(),\n                return_: return_.clone(),\n            },\n\n            Type::Var { type_ } => Type::Var {\n                type_: Arc::new(RefCell::new(self.specialise_var(type_))),\n            },\n\n            Type::Tuple { elements } => Type::Tuple {\n                elements: elements\n                    .iter()\n                    .map(|element| self.specialise_type(element))\n                    .collect(),\n            },\n        })\n    }\n\n    fn specialise_var(&self, type_: &RefCell<TypeVar>) -> TypeVar {\n        match &*type_.borrow() {\n            TypeVar::Unbound { id } => TypeVar::Unbound { id: *id },\n\n            TypeVar::Link { type_ } => TypeVar::Link {\n                type_: self.specialise_type(type_.as_ref()),\n            },\n\n            TypeVar::Generic { id } => match self.specialised_types.get(id) {\n                Some(type_) => TypeVar::Link {\n                    type_: type_.clone(),\n                },\n                None => TypeVar::Generic { id: *id },\n            },\n        }\n    }\n}\n\n/// Intermiate data structure that's used to set up everything that's needed by\n/// the pattern matching compiler and get a case expression ready to be compiled,\n/// while hiding the intricacies of handling an arena to record different patterns.\n///\n#[derive(Debug)]\npub struct CaseToCompile {\n    patterns: Arena<Pattern>,\n    branches: Vec<Branch>,\n    subject_variables: Vec<Variable>,\n    /// The number of clauses in this case to compile.\n    number_of_clauses: usize,\n    variable_id: usize,\n}\n\nimpl CaseToCompile {\n    pub fn new(subject_types: &[Arc<Type>]) -> Self {\n        let mut variable_id = 0;\n        let subject_variables = subject_types\n            .iter()\n            .map(|type_| {\n                let id = variable_id;\n                variable_id += 1;\n                Variable::new(id, type_.clone())\n            })\n            .collect_vec();\n\n        Self {\n            patterns: Arena::new(),\n            branches: vec![],\n            number_of_clauses: 0,\n            subject_variables,\n            variable_id,\n        }\n    }\n\n    /// Registers a `TypedClause` as one of the branches to be compiled.\n    ///\n    /// If you don't have a clause and just have a simple `TypedPattern` you want\n    /// to generate a decision tree for you can use `add_pattern`.\n    ///\n    pub fn add_clause(&mut self, branch: &TypedClause) {\n        let all_patterns =\n            std::iter::once(&branch.pattern).chain(branch.alternative_patterns.iter());\n\n        for (alternative_index, patterns) in all_patterns.enumerate() {\n            let mut checks = Vec::with_capacity(patterns.len());\n\n            // We're doing the zipping ourselves instead of using iters.zip as the\n            // borrow checker would complain and the only workaround would be to\n            // allocate an entire new vector each time.\n            for i in 0..patterns.len() {\n                let pattern = self.register(patterns.get(i).expect(\"pattern index\"));\n                let var = self\n                    .subject_variables\n                    .get(i)\n                    .expect(\"wrong number of subjects\");\n                checks.push(var.is(pattern))\n            }\n\n            let has_guard = branch.guard.is_some();\n            let branch = Branch::new(self.number_of_clauses, alternative_index, checks, has_guard);\n            self.branches.push(branch);\n        }\n\n        self.number_of_clauses += 1;\n    }\n\n    /// Add a single pattern as a branch to be compiled.\n    ///\n    /// This is useful in case one wants to check exhaustiveness of a single\n    /// pattern without having a fully fledged `TypedClause` to pass to the `add_clause`\n    /// method. For example, in `let` destructurings.\n    ///\n    pub fn add_pattern(&mut self, pattern: &TypedPattern) {\n        let pattern = self.register(pattern);\n        let var = self\n            .subject_variables\n            .first()\n            .expect(\"wrong number of subject variables for pattern\");\n        let branch = Branch::new(self.number_of_clauses, 0, vec![var.is(pattern)], false);\n        self.number_of_clauses += 1;\n        self.branches.push(branch);\n    }\n\n    pub fn compile(self, env: &Environment<'_>) -> CompileCaseResult {\n        let mut compiler = Compiler::new(env, self.variable_id, self.patterns);\n\n        let decision = if self.branches.is_empty() {\n            let var = self\n                .subject_variables\n                .first()\n                .expect(\"case with no subjects\")\n                .clone();\n\n            compiler.split_and_compile_with_pivot_var(var, VecDeque::new())\n        } else {\n            compiler.compile(self.branches.into())\n        };\n\n        CompileCaseResult {\n            diagnostics: compiler.diagnostics,\n            compiled_case: CompiledCase {\n                tree: decision,\n                subject_variables: self.subject_variables,\n            },\n        }\n    }\n\n    /// Registers a typed pattern (and all its sub-patterns) into this\n    /// `CaseToCompile`'s pattern arena, returning an id to get the pattern back.\n    ///\n    fn register(&mut self, pattern: &TypedPattern) -> Id<Pattern> {\n        match pattern {\n            TypedPattern::Invalid { .. } => self.insert(Pattern::Discard),\n            TypedPattern::Discard { .. } => self.insert(Pattern::Discard),\n\n            TypedPattern::Int { int_value, .. } => {\n                let int_value = int_value.clone();\n                self.insert(Pattern::Int { int_value })\n            }\n\n            TypedPattern::Float { float_value, .. } => {\n                let float_value = *float_value;\n                self.insert(Pattern::Float { float_value })\n            }\n\n            TypedPattern::String { value, .. } => {\n                let value = value.clone();\n                self.insert(Pattern::String { value })\n            }\n\n            TypedPattern::Variable { name, .. } => {\n                let name = name.clone();\n                self.insert(Pattern::Variable { name })\n            }\n\n            TypedPattern::Assign { name, pattern, .. } => {\n                let name = name.clone();\n                let pattern = self.register(pattern);\n                self.insert(Pattern::Assign { name, pattern })\n            }\n\n            TypedPattern::Tuple { elements, .. } => {\n                let elements = elements\n                    .iter()\n                    .map(|element| self.register(element))\n                    .collect_vec();\n                self.insert(Pattern::Tuple { elements })\n            }\n\n            TypedPattern::List { elements, tail, .. } => {\n                let mut list = match tail {\n                    Some(tail) => self.register(&tail.pattern),\n                    None => self.insert(Pattern::EmptyList),\n                };\n                for element in elements.iter().rev() {\n                    let first = self.register(element);\n                    list = self.insert(Pattern::NonEmptyList { first, rest: list });\n                }\n                list\n            }\n\n            TypedPattern::Constructor {\n                arguments,\n                constructor,\n                name,\n                module,\n                ..\n            } => {\n                let index = constructor.expect_ref(\"must be inferred\").constructor_index as usize;\n                let module = module.as_ref().map(|(module, _)| module.clone());\n                let fields = arguments\n                    .iter()\n                    .map(|argument| self.register(&argument.value))\n                    .collect_vec();\n                self.insert(Pattern::Variant {\n                    name: name.clone(),\n                    module,\n                    index,\n                    fields,\n                })\n            }\n\n            TypedPattern::BitArray { segments, .. } => {\n                let tests = self.bit_array_to_tests(segments);\n                self.insert(Pattern::BitArray { tests })\n            }\n\n            TypedPattern::StringPrefix {\n                left_side_string,\n                left_side_assignment,\n                right_side_assignment,\n                ..\n            } => {\n                let prefix = left_side_string.clone();\n                let prefix_name = left_side_assignment\n                    .as_ref()\n                    .map(|(label, _)| label.clone());\n                let rest_pattern = match right_side_assignment {\n                    AssignName::Variable(name) => Pattern::Variable { name: name.clone() },\n                    AssignName::Discard(_) => Pattern::Discard,\n                };\n                let rest = self.insert(rest_pattern);\n                self.insert(Pattern::StringPrefix {\n                    prefix,\n                    prefix_name,\n                    rest,\n                })\n            }\n\n            TypedPattern::BitArraySize { .. } => {\n                unreachable!(\"Cannot convert BitArraySize to exhaustiveness pattern\")\n            }\n        }\n    }\n\n    fn insert(&mut self, pattern: Pattern) -> Id<Pattern> {\n        self.patterns.alloc(pattern)\n    }\n\n    fn bit_array_to_tests(\n        &mut self,\n        segments: &[TypedPatternBitArraySegment],\n    ) -> VecDeque<BitArrayTest> {\n        // If there's no segments then we just add a single check to make sure\n        // the bit array is empty.\n        if segments.is_empty() {\n            let mut test = VecDeque::new();\n            test.push_front(BitArrayTest::Size(SizeTest {\n                operator: SizeOperator::Equal,\n                size: Offset::constant(0),\n            }));\n            return test;\n        }\n\n        let mut previous_end = Offset::constant(0);\n        let mut tests = VecDeque::with_capacity(segments.len() * 2);\n        let mut pattern_variables = HashMap::new();\n\n        let segments_count = segments.len();\n        for (i, segment) in segments.iter().enumerate() {\n            let segment_size = segment_size(segment, &pattern_variables, None);\n\n            // If we're reading a variable number of bits we need to make sure\n            // that that variable is not negative!\n            if segment_size.can_be_negative() {\n                tests.push_back(BitArrayTest::ReadSizeIsNotNegative {\n                    size: segment_size.clone(),\n                });\n            }\n\n            // All segments but the last will require the original bit array to\n            // have a minimum number of bits for the pattern to succeed. The\n            // final segment is special as it could require a specific size, or\n            // be a catch all that matches with any number of remaining bits.\n            let is_last_segment = i + 1 == segments_count;\n            match &segment_size {\n                ReadSize::RemainingBits => (),\n                ReadSize::RemainingBytes => tests.push_back(BitArrayTest::CatchAllIsBytes {\n                    size_so_far: previous_end.clone(),\n                }),\n                ReadSize::ConstantBits(_)\n                | ReadSize::VariableBits { .. }\n                | ReadSize::BinaryOperator { .. } => {\n                    let size = previous_end.clone().add_size(&segment_size);\n                    let operator = if is_last_segment {\n                        SizeOperator::Equal\n                    } else {\n                        SizeOperator::GreaterEqual\n                    };\n                    tests.push_back(BitArrayTest::Size(SizeTest { operator, size }));\n                }\n            };\n\n            let type_ = match &segment.type_ {\n                type_ if type_.is_int() => ReadType::Int,\n                type_ if type_.is_float() => ReadType::Float,\n                type_ if type_.is_string() => ReadType::String,\n                type_ if type_.is_bit_array() => ReadType::BitArray,\n                type_ if type_.is_utf_codepoint() => ReadType::UtfCodepoint,\n                x => panic!(\"invalid segment type in exhaustiveness {x:?}\"),\n            };\n\n            let read_action = ReadAction {\n                size: segment_size.clone(),\n                from: previous_end.clone(),\n                type_,\n                endianness: segment.endianness(),\n                signed: segment.signed(),\n            };\n\n            // Each segment is also turned into a match test, checking the\n            // selected bits match with the pattern's value.\n            let value = segment_matched_value(segment, None, &read_action);\n\n            // Then if the matched value is a variable that is in scope for the\n            // rest of the pattern we keep track of it, so it can be used in the\n            // following read actions as a valid size.\n            match &value {\n                BitArrayMatchedValue::LiteralFloat(_)\n                | BitArrayMatchedValue::LiteralInt { .. }\n                | BitArrayMatchedValue::LiteralString { .. }\n                | BitArrayMatchedValue::Discard(_) => {}\n                BitArrayMatchedValue::Variable(name)\n                | BitArrayMatchedValue::Assign { name, .. } => {\n                    let _ = pattern_variables.insert(name.clone(), read_action.clone());\n                }\n            }\n\n            // If we are matching on a float segment that is not a literal we want\n            // to add an additional check to make sure that we won't match with\n            // `NaN` and `Infinity`!\n            if type_.is_float() && !value.is_literal() {\n                tests.push_back(BitArrayTest::SegmentIsFiniteFloat {\n                    read_action: read_action.clone(),\n                });\n            }\n            tests.push_back(BitArrayTest::Match(MatchTest { value, read_action }));\n\n            previous_end = previous_end.add_size(&segment_size);\n        }\n        tests\n    }\n}\n\nfn segment_matched_value(\n    segment: &TypedPatternBitArraySegment,\n    // If we are compiling an assignment pattern, we still need access to the\n    // `type_` and `options` fields of the `segment`, so we must still pass that\n    // in above. However, we need to check the correct sub-pattern of the original\n    // pattern, so if they are different we set this argument to `Some`.\n    pattern: Option<&TypedPattern>,\n    read_action: &ReadAction,\n) -> BitArrayMatchedValue {\n    let pattern = pattern.unwrap_or(&segment.value);\n    match pattern {\n        ast::Pattern::Int {\n            int_value,\n            location,\n            ..\n        } => BitArrayMatchedValue::LiteralInt {\n            value: int_value.clone(),\n            location: *location,\n            bits: int_to_bits(\n                int_value,\n                &read_action.size,\n                read_action.endianness,\n                read_action.signed,\n            ),\n        },\n        ast::Pattern::Float { value, .. } => BitArrayMatchedValue::LiteralFloat(value.clone()),\n        ast::Pattern::String { value, .. } if segment.has_utf16_option() => {\n            BitArrayMatchedValue::LiteralString {\n                value: value.clone(),\n                encoding: StringEncoding::Utf16,\n                bytes: string_to_utf16_bytes(\n                    &convert_string_escape_chars(value),\n                    read_action.endianness,\n                ),\n            }\n        }\n        ast::Pattern::String { value, .. } if segment.has_utf32_option() => {\n            BitArrayMatchedValue::LiteralString {\n                value: value.clone(),\n                encoding: StringEncoding::Utf32,\n                bytes: string_to_utf32_bytes(\n                    &convert_string_escape_chars(value),\n                    read_action.endianness,\n                ),\n            }\n        }\n        ast::Pattern::String { value, .. } => BitArrayMatchedValue::LiteralString {\n            value: value.clone(),\n            encoding: StringEncoding::Utf8,\n            bytes: convert_string_escape_chars(value).as_bytes().into(),\n        },\n        ast::Pattern::Variable { name, .. } => BitArrayMatchedValue::Variable(name.clone()),\n        ast::Pattern::Discard { name, .. } => BitArrayMatchedValue::Discard(name.clone()),\n        ast::Pattern::Assign { name, pattern, .. } => BitArrayMatchedValue::Assign {\n            name: name.clone(),\n            value: Box::new(segment_matched_value(segment, Some(pattern), read_action)),\n        },\n        ast::Pattern::BitArraySize(_)\n        | ast::Pattern::List { .. }\n        | ast::Pattern::Constructor { .. }\n        | ast::Pattern::Tuple { .. }\n        | ast::Pattern::BitArray { .. }\n        | ast::Pattern::StringPrefix { .. }\n        | ast::Pattern::Invalid { .. } => panic!(\"unexpected segment value pattern {pattern:?}\"),\n    }\n}\n\nfn int_to_bits(\n    value: &BigInt,\n    read_size: &ReadSize,\n    endianness: Endianness,\n    signed: bool,\n) -> Result<BitVec<u8, Msb0>, IntToBitsError> {\n    let size = read_size\n        .constant_bits()\n        .ok_or(IntToBitsError::NonConstantSize)?\n        .to_u32()\n        .ok_or(IntToBitsError::ExceedsMaximumSize)?;\n\n    if !representable_with_bits(value, size, signed) {\n        return Err(IntToBitsError::Unrepresentable { size });\n    } else if size > BitArrayMatchedValue::MAX_BITS_INTERFERENCE {\n        return Err(IntToBitsError::ExceedsMaximumSize);\n    }\n\n    // Pad negative numbers with 1s (true) and non-negative numbers with 0s (false)\n    let pad_digit = value.sign() == Sign::Minus;\n    let size = size as usize;\n    let mut bytes = int_to_bytes(value, endianness, signed);\n    let bytes_size = bytes.len() * 8;\n\n    let bits = match (endianness, bytes_size.cmp(&size)) {\n        (_, Ordering::Equal) => BitVec::from_vec(bytes),\n\n        // Even though we return an error if `value` cannot be represented in `size` bits,\n        // we may need to slice off up a couple bits if the read size is not a multiple of 8.\n        // <3:4> yields the bytes [0b0000_0011]. We slice off 4 bits and get 0011\n        (Endianness::Big, Ordering::Greater) => {\n            BitVec::from_bitslice(&bytes.view_bits()[bytes_size - size..])\n        }\n        // If the number needs fewer bits than the read size, we pad it.\n        // <3:9> yields the bytes [0b0000_0011]. We add one digit and get 0_0000_0011\n        (Endianness::Big, Ordering::Less) => {\n            let mut bits = BitVec::repeat(pad_digit, size - bytes_size);\n            bits.extend_from_raw_slice(&bytes);\n            bits\n        }\n\n        (Endianness::Little, Ordering::Greater) => {\n            // If the difference is greater than a byte, we returned an Error earlier\n            let remainder = size % 8;\n            if remainder == 0 {\n                BitVec::from_vec(bytes)\n            } else {\n                // If the size is not a multiple of 8, we need to truncate the most significant bits.\n                // As they are in the last byte, we leftshift by the appropriate amount and\n                // truncate the final bits after conversion\n                let last_byte = bytes.last_mut().expect(\"bytes must not be empty\");\n                *last_byte <<= 8 - remainder;\n\n                let mut bits = BitVec::from_vec(bytes);\n                bits.truncate(size);\n                bits\n            }\n        }\n        (Endianness::Little, Ordering::Less) => {\n            let mut bits = BitVec::from_vec(bytes);\n            let padding: BitVec<u8, Msb0> = BitVec::repeat(pad_digit, size - bytes_size);\n            bits.extend_from_bitslice(padding.as_bitslice());\n            bits\n        }\n    };\n    Ok(bits)\n}\n\nfn int_to_bytes(value: &BigInt, endianness: Endianness, signed: bool) -> Vec<u8> {\n    match (endianness, signed) {\n        (Endianness::Big, false) => value.to_bytes_be().1,\n        (Endianness::Big, true) => value.to_signed_bytes_be(),\n        (Endianness::Little, false) => value.to_bytes_le().1,\n        (Endianness::Little, true) => value.to_signed_bytes_le(),\n    }\n}\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]\npub enum IntToBitsError {\n    Unrepresentable { size: u32 },\n    ExceedsMaximumSize,\n    NonConstantSize,\n}\n\nfn segment_size(\n    segment: &TypedPatternBitArraySegment,\n    pattern_variables: &HashMap<EcoString, ReadAction>,\n    // If we are compiling an assignment pattern, we still need access to the\n    // `type_` and `options` fields of the `segment`, so we must still pass that\n    // in above. However, we need to check the correct sub-pattern of the original\n    // pattern, so if they are different we set this argument to `Some`.\n    pattern: Option<&TypedPattern>,\n) -> ReadSize {\n    let pattern = pattern.unwrap_or(&segment.value);\n\n    match segment.size() {\n        // The size of a segment must be a `BitArraySize` pattern.\n        Some(ast::Pattern::BitArraySize(size)) => {\n            bit_array_size(segment.unit(), pattern_variables, size)\n        }\n        Some(x) => panic!(\"invalid pattern size made it to code generation {x:?}\"),\n\n        // If a segment has the `bits`/`bytes` option and has no size, that\n        // means it's the final catch all segment: we'll have to read any number\n        // of bits.\n        _ if segment.has_bits_option() => ReadSize::RemainingBits,\n        _ if segment.has_bytes_option() => ReadSize::RemainingBytes,\n\n        // If there's no size option we go for a default: 8 bits for int\n        // segments, and 64 for anything else.\n        None if segment.type_.is_int() => ReadSize::ConstantBits(8.into()),\n        None => match pattern {\n            ast::Pattern::Assign { pattern, .. } => {\n                segment_size(segment, pattern_variables, Some(pattern))\n            }\n\n            ast::Pattern::String { value, .. } if segment.has_utf16_option() => {\n                ReadSize::ConstantBits(\n                    // Each utf16 code unit is 16 bits\n                    length_utf16(&convert_string_escape_chars(value)) * BigInt::from(16),\n                )\n            }\n            ast::Pattern::String { value, .. } if segment.has_utf32_option() => {\n                // Each utf32 code unit is 32 bits\n                ReadSize::ConstantBits(\n                    length_utf32(&convert_string_escape_chars(value)) * BigInt::from(32),\n                )\n            }\n            // If the segment is a literal string then it has an automatic size\n            // given by its number of bytes.\n            ast::Pattern::String { value, .. } => {\n                ReadSize::ConstantBits(convert_string_escape_chars(value).len() * BigInt::from(8))\n            }\n            // In all other cases the segment is considered to be 64 bits\n            ast::Pattern::Int { .. }\n            | ast::Pattern::Float { .. }\n            | ast::Pattern::Variable { .. }\n            | ast::Pattern::BitArraySize(_)\n            | ast::Pattern::Discard { .. }\n            | ast::Pattern::List { .. }\n            | ast::Pattern::Constructor { .. }\n            | ast::Pattern::Tuple { .. }\n            | ast::Pattern::BitArray { .. }\n            | ast::Pattern::StringPrefix { .. }\n            | ast::Pattern::Invalid { .. } => ReadSize::ConstantBits(64.into()),\n        },\n    }\n}\n\nfn bit_array_size(\n    unit: u8,\n    pattern_variables: &HashMap<EcoString, ReadAction>,\n    size: &TypedBitArraySize,\n) -> ReadSize {\n    match size {\n        BitArraySize::Int { int_value, .. } => ReadSize::ConstantBits(int_value * unit),\n        BitArraySize::Variable { name, .. } => {\n            let variable = match pattern_variables.get(name) {\n                Some(read_action) => {\n                    VariableUsage::PatternSegment(name.clone(), read_action.clone())\n                }\n                None => VariableUsage::OutsideVariable(name.clone()),\n            };\n            ReadSize::VariableBits {\n                variable: Box::new(variable),\n                unit,\n            }\n        }\n        BitArraySize::BinaryOperator {\n            operator,\n            left,\n            right,\n            ..\n        } => {\n            let size = ReadSize::BinaryOperator {\n                left: Box::new(bit_array_size(1, pattern_variables, left)),\n                right: Box::new(bit_array_size(1, pattern_variables, right)),\n                operator: *operator,\n            };\n\n            if unit == 1 {\n                size\n            } else {\n                ReadSize::BinaryOperator {\n                    left: Box::new(size),\n                    right: Box::new(ReadSize::ConstantBits(unit.into())),\n                    operator: IntOperator::Multiply,\n                }\n            }\n        }\n        BitArraySize::Block { inner, .. } => bit_array_size(unit, pattern_variables, inner),\n    }\n}\n\n/// Returns `true` if one bag is a superset of the other: that is it contains\n/// all the keys of `other` in a quantity that's greater or equal.\n///\n#[must_use]\nfn superset(\n    one: &im::HashMap<VariableUsage, usize>,\n    other: &im::HashMap<VariableUsage, usize>,\n) -> bool {\n    other\n        .iter()\n        .all(|(key, other_occurrences)| match one.get(key) {\n            Some(occurrences) => occurrences >= other_occurrences,\n            None => false,\n        })\n}\n\n#[must_use]\nfn representable_with_bits(value: &BigInt, bits: u32, signed: bool) -> bool {\n    // No number is representable in 0 bits.\n    if bits == 0 {\n        return false;\n    };\n\n    let required_bits = match (value.sign(), signed) {\n        // Zero always needs one bit.\n        (Sign::NoSign, _) => 1,\n\n        // `BigInt::bits` does not consider the sign!\n        (Sign::Plus, false) => value.bits(),\n        // Therefore we need to add the sign bit here: `10` -> `010`\n        (Sign::Plus, true) => value.bits() + 1,\n\n        // A negative number must be signed\n        (Sign::Minus, false) => return false,\n        (Sign::Minus, true) => {\n            let bits_unsigned = value.bits();\n            let trailing_zeros = value\n                .trailing_zeros()\n                .expect(\"trailing_zeros to return a value for non-zero numbers\");\n            let is_power_of_2 = trailing_zeros == bits_unsigned - 1;\n\n            // Negative powers of two don't need an extra sign bit. E.g. `-2 == 0b10`\n            if is_power_of_2 {\n                bits_unsigned\n            } else {\n                bits_unsigned + 1\n            }\n        }\n    };\n\n    match required_bits.to_u32() {\n        Some(required_bits) => bits >= required_bits,\n        None => false,\n    }\n}\n\n#[cfg(test)]\nmod representable_with_bits_test {\n    use crate::exhaustiveness::representable_with_bits;\n    use num_bigint::BigInt;\n\n    #[test]\n    fn positive_number_representable_with_bits_test() {\n        // 9 can be represented as a >=4 bits unsigned number.\n        assert!(representable_with_bits(&9.into(), 4, false));\n        assert!(representable_with_bits(&9.into(), 5, false));\n        // But not in <=3 bits as an unsigned number.\n        assert!(!representable_with_bits(&9.into(), 3, false));\n        assert!(!representable_with_bits(&9.into(), 2, false));\n\n        // It can be represented as a >=5 bit signed number.\n        assert!(representable_with_bits(&9.into(), 5, true));\n        assert!(representable_with_bits(&9.into(), 6, true));\n        // But not in <= 4 bits as a signed number.\n        assert!(!representable_with_bits(&9.into(), 4, true));\n        assert!(!representable_with_bits(&9.into(), 3, true));\n    }\n\n    #[test]\n    fn negative_number_representable_with_bits_test() {\n        // A negative number will never be representable as an unsigned number,\n        // no matter the number of bits!\n        assert!(!representable_with_bits(&BigInt::from(-9), 1, false));\n        assert!(!representable_with_bits(&BigInt::from(-9), 500, false));\n\n        // -9 can be represented in >=5 bits as a signed number.\n        assert!(representable_with_bits(&BigInt::from(-9), 5, true));\n        assert!(representable_with_bits(&BigInt::from(-9), 6, true));\n        // But not in <= 4 bits as a signed number.\n        assert!(!representable_with_bits(&BigInt::from(-9), 4, true));\n        assert!(!representable_with_bits(&BigInt::from(-9), 3, true));\n    }\n\n    #[test]\n    fn zero_representable_with_bits_test() {\n        for i in 0..12 {\n            println!(\"{i}: {}\", BigInt::from(i).bits());\n        }\n        assert!(!representable_with_bits(&BigInt::ZERO, 0, false));\n        assert!(!representable_with_bits(&BigInt::ZERO, 0, true));\n\n        assert!(representable_with_bits(&BigInt::ZERO, 1, false));\n        assert!(representable_with_bits(&BigInt::ZERO, 1, true));\n    }\n\n    #[test]\n    fn number_representable_with_sign_test() {\n        // Sign needs one additional bit\n        assert!(representable_with_bits(&8.into(), 4, false));\n        assert!(!representable_with_bits(&8.into(), 4, true));\n        assert!(representable_with_bits(&8.into(), 5, true));\n\n        // Negative number must be signed\n        assert!(!representable_with_bits(&BigInt::from(-8), 100, false));\n\n        // Negative powers of two don't need an extra sign bit\n        assert!(!representable_with_bits(&BigInt::from(-8), 3, true));\n        assert!(representable_with_bits(&BigInt::from(-8), 4, true));\n\n        assert!(!representable_with_bits(&BigInt::from(-9), 4, true));\n        assert!(representable_with_bits(&BigInt::from(-9), 5, true));\n    }\n}\n\n#[cfg(test)]\nmod int_to_bits_test {\n    use std::assert_eq;\n\n    use crate::{\n        ast::Endianness,\n        exhaustiveness::{BitArrayMatchedValue, IntToBitsError, ReadSize, int_to_bits},\n    };\n    use bitvec::{bitvec, order::Msb0, vec::BitVec};\n    use num_bigint::BigInt;\n\n    fn read_size(size: u32) -> ReadSize {\n        ReadSize::ConstantBits(BigInt::from(size))\n    }\n\n    #[test]\n    fn int_to_bits_size_too_big() {\n        assert_eq!(\n            int_to_bits(\n                &BigInt::ZERO,\n                &read_size(BitArrayMatchedValue::MAX_BITS_INTERFERENCE + 1),\n                Endianness::Big,\n                true,\n            ),\n            Err(IntToBitsError::ExceedsMaximumSize),\n        );\n    }\n\n    #[test]\n    fn int_to_bits_zero() {\n        let expect = Ok(bitvec![u8, Msb0; 0; 3]);\n        assert_eq!(\n            int_to_bits(&BigInt::ZERO, &read_size(3), Endianness::Big, false),\n            expect\n        );\n        assert_eq!(\n            int_to_bits(&BigInt::ZERO, &read_size(3), Endianness::Little, false),\n            expect\n        );\n\n        let expect = Ok(bitvec![u8, Msb0; 0; 10]);\n        assert_eq!(\n            int_to_bits(&BigInt::ZERO, &read_size(10), Endianness::Big, false),\n            expect\n        );\n        assert_eq!(\n            int_to_bits(&BigInt::ZERO, &read_size(10), Endianness::Little, false),\n            expect\n        );\n    }\n\n    #[test]\n    fn int_to_bits_positive() {\n        // Exact match\n        assert_eq!(\n            int_to_bits(\n                &BigInt::from(0xff00),\n                &read_size(16),\n                Endianness::Big,\n                false\n            ),\n            Ok(BitVec::<u8, Msb0>::from_vec(vec![0xff, 0x00])),\n        );\n        assert_eq!(\n            int_to_bits(\n                &BigInt::from(0xff00),\n                &read_size(16),\n                Endianness::Little,\n                false\n            ),\n            Ok(BitVec::<u8, Msb0>::from_vec(vec![0x00, 0xff])),\n        );\n\n        assert_eq!(\n            int_to_bits(\n                &BigInt::from(0b11_1111_0000),\n                &read_size(10),\n                Endianness::Big,\n                false\n            ),\n            Ok(bitvec![u8, Msb0; 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]),\n        );\n        assert_eq!(\n            int_to_bits(\n                &BigInt::from(0b11_1111_0000),\n                &read_size(10),\n                Endianness::Little,\n                false\n            ),\n            Ok(bitvec![u8, Msb0; 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]),\n        );\n\n        // Too few bits in int\n        assert_eq!(\n            int_to_bits(&BigInt::from(0xff), &read_size(12), Endianness::Big, false),\n            Ok(bitvec![u8, Msb0; 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]),\n        );\n        assert_eq!(\n            int_to_bits(\n                &BigInt::from(0xff),\n                &read_size(12),\n                Endianness::Little,\n                false\n            ),\n            Ok(bitvec![u8, Msb0; 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]),\n        );\n    }\n\n    #[test]\n    fn int_to_bits_signed() {\n        assert_eq!(\n            int_to_bits(&BigInt::from(-128), &read_size(12), Endianness::Big, true),\n            Ok(bitvec![u8, Msb0; 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]),\n        );\n        assert_eq!(\n            int_to_bits(\n                &BigInt::from(-128),\n                &read_size(12),\n                Endianness::Little,\n                true\n            ),\n            Ok(bitvec![u8, Msb0; 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]),\n        );\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/fix.rs",
    "content": "use crate::{\n    Error, Result,\n    format::{Formatter, Intermediate},\n    warning::WarningEmitter,\n};\nuse camino::Utf8Path;\nuse ecow::EcoString;\n\npub fn parse_fix_and_format(src: &EcoString, path: &Utf8Path) -> Result<String> {\n    // Parse\n    let parsed = crate::parse::parse_module(path.to_owned(), src, &WarningEmitter::null())\n        .map_err(|error| Error::Parse {\n            path: path.to_path_buf(),\n            src: src.clone(),\n            error: Box::new(error),\n        })?;\n    let intermediate = Intermediate::from_extra(&parsed.extra, src);\n    let module = parsed.module;\n\n    // Fix\n    // let module = some_fixer_module::Fixer::fix(module);\n\n    // Format\n    let mut buffer = String::new();\n    Formatter::with_comments(&intermediate)\n        .module(&module)\n        .pretty_print(80, &mut buffer)?;\n\n    Ok(buffer)\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/asignments.rs",
    "content": "use crate::assert_format;\n\n// https://github.com/gleam-lang/gleam/issues/2095\n#[test]\nfn comment() {\n    assert_format!(\n        r#\"pub fn main() {\n  // Hello\n  let x = 1\n  x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2095\n#[test]\nfn assert_comment() {\n    assert_format!(\n        r#\"pub fn main() {\n  // Hello\n  let assert x = 1\n  x\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/binary_operators.rs",
    "content": "use crate::assert_format;\n\n// https://github.com/gleam-lang/gleam/issues/835\n#[test]\npub fn long_binary_operation_sequence() {\n    assert_format!(\n        r#\"pub fn main() {\n  int.to_string(color.red)\n  <> \", \"\n  <> int.to_string(color.green)\n  <> \", \"\n  <> int.to_string(color.blue)\n  <> \", \"\n  <> float.to_string(color.alpha)\n}\n\"#\n    );\n}\n\n#[test]\npub fn long_comparison_chain() {\n    assert_format!(\n        r#\"pub fn main() {\n  trying_a_comparison(this, is, a, function) > with_ints\n  && trying_other_comparisons < with_ints\n  || trying_other_comparisons <= with_ints\n  && trying_other_comparisons >= with_ints\n  || and_now_an_equality_check == with_a_function(wibble, wobble)\n  && trying_other_comparisons >. with_floats\n  || trying_other_comparisons <. with_floats(wobble)\n  && trying_other_comparisons <=. with_floats\n  || trying_other_comparisons(wibble, wobble) >=. with_floats\n  && wibble <> wobble\n}\n\"#\n    );\n}\n\n#[test]\npub fn long_chain_mixing_operators() {\n    assert_format!(\n        r#\"pub fn main() {\n  variable + variable - variable * variable / variable\n  == variable * variable / variable - variable + variable\n  || wibble * wobble > 11\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  variable +. variable -. variable *. variable /. variable\n  == variable *. variable /. variable -. variable +. variable\n  || wibble *. wobble >=. 11\n}\n\"#\n    );\n}\n\n// Thanks Hayleigh for pointing this out!\n#[test]\nfn case_branch_is_not_broken_if_can_fit_on_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  case remainder {\n    _ if remainder >=. 0.5 && x >=. 0.0 ->\n      float_sign(x) *. truncate_float(xabs +. 1.0) /. p\n    _ -> float_sign(x) *. xabs_truncated /. p\n  }\n}\n\"#\n    );\n}\n\n// https://discord.com/channels/768594524158427167/1187508793945378847/1187508793945378847\n#[test]\nfn binary_operation_in_assignment_that_is_almost_80_chars() {\n    assert_format!(\n        r#\"pub fn main() {\n  let is_vr_implicit =\n    dicom_read_context.transfer_syntax == transfer_syntax.ImplicitVrLittleEndian\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2480\n#[test]\nfn labelled_field_with_binary_operators_are_not_broken_if_they_can_fit() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(Lesson(\n    name: names.name,\n    text: text,\n    code: code,\n    path: chapter_path <> \"/\",\n    previous: None,\n    next: None,\n  ))\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(Lesson(\n    name: names.name,\n    text:,\n    code:,\n    path: chapter_path\n      <> \"/\"\n      <> this_one_doesnt_fit\n      <> \"and ends up on multiple lines\",\n    previous: None,\n    next: None,\n  ))\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(wibble(\n    name: names.name,\n    text:,\n    code:,\n    path: chapter_path <> \"/\",\n    previous: None,\n    next: None,\n  ))\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(wibble(\n    name: names.name,\n    text:,\n    code:,\n    path: chapter_path\n      <> \"/\"\n      <> this_one_doesnt_fit\n      <> \"and ends up on multiple lines\",\n    previous: None,\n    next: None,\n  ))\n}\n\"#\n    );\n}\n\n#[test]\nfn math_binops_kept_on_a_single_line_in_pipes() {\n    assert_format!(\n        r#\"pub fn main() {\n  1 + 2 * 3 / 4 - 5\n  |> wibble\n  |> wobble\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  1 +. 2 *. 3 /. 4 -. 5\n  |> wibble\n  |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_used_as_function_arguments_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    a_variable_with_a_long_name\n      <> another_variable_with_a_long_name\n      <> yet_another_variable_with_a_long_name,\n    wobble,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_is_not_nested_if_the_only_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    a_variable_with_a_long_name\n    <> another_variable_with_a_long_name\n    <> yet_another_variable_with_a_long_name,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_inside_list_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    wibble,\n    a_variable_with_a_long_name\n      <> another_variable_with_a_long_name\n      <> yet_another_variable_with_a_long_name,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_inside_list_is_not_nested_if_only_item() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    a_variable_with_a_long_name\n    <> another_variable_with_a_long_name\n    <> yet_another_variable_with_a_long_name,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_inside_tuple_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    wibble,\n    a_variable_with_a_long_name\n      <> another_variable_with_a_long_name\n      <> yet_another_variable_with_a_long_name,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn binop_inside_tuple_is_not_nested_if_only_item() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    a_variable_with_a_long_name\n    <> another_variable_with_a_long_name\n    <> yet_another_variable_with_a_long_name,\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2624\n#[test]\nfn binop_as_argument_in_variant_with_spread_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  Wibble(\n    ..wibble,\n    label: string\n      <> \"a long string that is making things go on multiple lines\"\n      <> \"another string\",\n  )\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/bit_array.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn construction() {\n    assert_format!(\n        \"fn main() {\n  let a = 1\n  let x = <<1, a, 2:bytes>>\n  let size = <<3:2, 4:size(3), 5:bytes-size(4), 6:size(a)>>\n  let unit = <<7:unit(1), 8:bytes-unit(2)>>\n  x\n}\n\",\n    );\n}\n\n#[test]\nfn pattern() {\n    assert_format!(\n        \"fn main() {\n  let a = 1\n  let <<b, c, d:bytes>> = <<1, a, 2:bytes>>\n  b\n}\n\",\n    );\n}\n\n#[test]\nfn long() {\n    assert_format!(\n        \"fn main() {\n  let some_really_long_variable_name_to_force_wrapping = 1\n  let bits = <<\n    some_really_long_variable_name_to_force_wrapping,\n    some_really_long_variable_name_to_force_wrapping,\n  >>\n  bits\n}\n\",\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2932\n#[test]\nfn tight_empty() {\n    assert_format!(\n        \"fn main() {\n  let some_really_really_really_really_really_really_really_long_variable_name_to_force_wrapping = <<>>\n  some_really_really_really_really_really_really_really_long_variable_name_to_force_wrapping\n}\n\"\n    );\n}\n\n#[test]\nfn comments_are_not_moved_out_of_empty_bit_array() {\n    assert_format!(\n        r#\"pub fn main() {\n  // This is an empty bit array!\n  <<\n    // Nothing here...\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn empty_bit_arrays_with_comment_inside_are_indented_properly() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    <<\n      // Nothing here...\n    >>,\n    wibble_wobble_wibble_wobble_wibble_wobble_wibble_wobble,\n    <<\n      // Nothing here as well!\n    >>,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_non_empty_bit_arrays_are_not_moved() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    <<\n      // One is below me.\n      1, 2,\n      // Three is below me.\n      3,\n    >>,\n    wibble_wobble_wibble_wobble_wibble_wobble_wibble_wobble,\n    <<\n      // Three is below me.\n      3,\n    >>,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_bit_arrays() {\n    assert_format!(\n        \"pub fn main() {\n  <<\n    100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400,\n    1500, 1600, 1700, 1800, 1900, 2000,\n  >>\n}\n\"\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_bit_arrays1() {\n    assert_format!(\n        \"pub fn main() {\n  <<\n    1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 11.0, 12.0, 13.0, 14.0,\n    15.0, 16.0, 17.0, 18.0, 19.0, 2.0,\n  >>\n}\n\"\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_bit_arrays2() {\n    assert_format!(\n        r#\"pub fn main() {\n  <<\n    \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\",\n    \"ten\", \"eleven\", \"twelve\",\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_bit_arrays3() {\n    assert_format!(\n        \"const values = <<\n  100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400,\n  1500, 1600, 1700, 1800, 1900, 2000,\n>>\n\"\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_bit_arrays4() {\n    assert_format!(\n        \"const values = <<\n  1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 11.0, 12.0, 13.0, 14.0, 15.0,\n  16.0, 17.0, 18.0, 19.0, 2.0,\n>>\n\"\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_bit_arrays5() {\n    assert_format!(\n        r#\"const values = <<\n  \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\", \"ten\",\n  \"eleven\", \"twelve\",\n>>\n\"#\n    );\n}\n\n#[test]\nfn binop_value() {\n    assert_format!(\n        r#\"pub fn main() {\n  <<{ 1 + 1 }>>\n}\n\"#\n    );\n}\n\n#[test]\nfn block_value() {\n    assert_format!(\n        r#\"pub fn main() {\n  <<\n    {\n      io.println(\"hi\")\n      1\n    },\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn operator_in_pattern_size() {\n    assert_format!(\n        \"pub fn main() {\n  let assert <<len, payload:size({ len + 1 } * 8 + 1)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/4792#issuecomment-3096177213\nfn bit_array_segments_are_kept_one_per_line() {\n    assert_format!(\n        \"pub fn main() {\n  <<\n    1:1,\n    1:1,\n    0:2,\n    opcode:4,\n    masked:1,\n    length_section:bits,\n    mask_key:bits,\n    data:bits,\n  >>\n  |> bytes_tree.from_bit_array\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_with_trailing_comma_is_broken() {\n    assert_format_rewrite!(\n        \"pub fn main() { <<1, 2, a,>> }\",\n        r#\"pub fn main() {\n  <<\n    1,\n    2,\n    a,\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_bit_array_with_trailing_comma_is_broken() {\n    assert_format_rewrite!(\n        \"const bit_array = <<1, 2, a,>>\",\n        r#\"const bit_array = <<\n  1,\n  2,\n  a,\n>>\n\"#\n    );\n}\n\n#[test]\nfn bit_array_with_trailing_comma_is_kept_broken() {\n    assert_format!(\n        r#\"pub fn main() {\n  <<\n    1,\n    2,\n    a,\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_bit_array_with_trailing_comma_is_kept_broken() {\n    assert_format!(\n        r#\"const bit_array = <<\n  1,\n  2,\n  a,\n>>\n\"#\n    );\n}\n\n#[test]\nfn bit_array_with_no_trailing_comma_is_packed_on_a_single_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  <<\n    1,\n    2,\n    a\n  >>\n}\n\"#,\n        r#\"pub fn main() {\n  <<1, 2, a>>\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_bit_array_with_no_trailing_comma_is_packed_on_a_single_line() {\n    assert_format_rewrite!(\n        r#\"const bit_array = <<\n  1,\n  2,\n  a\n>>\"#,\n        \"const bit_array = <<1, 2, a>>\\n\"\n    );\n}\n\n#[test]\nfn bit_array_with_no_comma_is_packed_on_a_single_line_or_split_one_item_per_line() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  <<\n    1,\n    a,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    b,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312\n  >>\n}\n\",\n        \"pub fn main() {\n  <<\n    1,\n    a,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    b,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n  >>\n}\n\"\n    );\n}\n\n#[test]\nfn constant_bit_array_with_no_comma_is_packed_on_a_single_line_or_split_one_item_per_line() {\n    assert_format_rewrite!(\n        \"const bit_array = <<\n  1,\n  a,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  b,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312\n>>\n\",\n        \"const bit_array = <<\n  1,\n  a,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  b,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n>>\n\"\n    );\n}\n\n#[test]\nfn simple_bit_array_with_no_comma_is_packed_on_a_single_line_or_split_one_item_per_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  <<\n    \"hello\",\n    \"wibble wobble\",\n    \"these are all simple strings\",\n    \"but the bitarray won't be packed\",\n    \"the formatter will keep\",\n    \"one item\",\n    \"per line\",\n    \"since there's no trailing comma here ->\"\n  >>\n}\n\"#,\n        r#\"pub fn main() {\n  <<\n    \"hello\",\n    \"wibble wobble\",\n    \"these are all simple strings\",\n    \"but the bitarray won't be packed\",\n    \"the formatter will keep\",\n    \"one item\",\n    \"per line\",\n    \"since there's no trailing comma here ->\",\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_bit_array_with_trailing_comma_and_multiple_items_per_line_is_packed() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  <<\n    \"hello\",\n    \"wibble wobble\",\n    \"these are all simple strings\",\n    \"and the bit array will be packed since the following strings are\",\n    \"on the same\", \"line\", \"and there's a trailing comma ->\",\n  >>\n}\n\"#,\n        r#\"pub fn main() {\n  <<\n    \"hello\", \"wibble wobble\", \"these are all simple strings\",\n    \"and the bit array will be packed since the following strings are\",\n    \"on the same\", \"line\", \"and there's a trailing comma ->\",\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_constant_bit_array_with_trailing_comma_and_multiple_items_per_line_is_packed() {\n    assert_format_rewrite!(\n        r#\"pub const bit_array = <<\n  \"hello\",\n  \"wibble wobble\",\n  \"these are all simple strings\",\n  \"and the bit array will be packed since the following strings are\",\n  \"on the same\", \"line\", \"and there's a trailing comma ->\",\n>>\n\"#,\n        r#\"pub const bit_array = <<\n  \"hello\", \"wibble wobble\", \"these are all simple strings\",\n  \"and the bit array will be packed since the following strings are\",\n  \"on the same\", \"line\", \"and there's a trailing comma ->\",\n>>\n\"#\n    );\n}\n\n#[test]\nfn simple_packed_bit_array_with_trailing_comma_is_kept_with_multiple_items_per_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  <<\n    \"hello\", \"wibble wobble\", \"these are all simple strings\",\n    \"and the bit array will be kept packed since it ends with a trailing comma\",\n    \"right here! ->\",\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_single_line_bit_array_with_trailing_comma_is_split_one_item_per_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  <<\"these are all simple strings\", \"but the bit array won't be packed\", \"since it ends with a trailing comma ->\",>>\n}\n\"#,\n        r#\"pub fn main() {\n  <<\n    \"these are all simple strings\",\n    \"but the bit array won't be packed\",\n    \"since it ends with a trailing comma ->\",\n  >>\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_single_line_bit_array_with_no_trailing_comma_is_split_one_item_per_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  <<\"these are all simple strings\", \"but the bit array won't be packed\", \"even if it doesn't end with a trailing comma!\">>\n}\n\"#,\n        r#\"pub fn main() {\n  <<\n    \"these are all simple strings\",\n    \"but the bit array won't be packed\",\n    \"even if it doesn't end with a trailing comma!\",\n  >>\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/blocks.rs",
    "content": "use crate::assert_format;\n\n// https://github.com/gleam-lang/gleam/issues/2119\n#[test]\nfn assignment() {\n    assert_format!(\n        r#\"fn main() {\n  let greeting = {\n    \"Hello\"\n  }\n\n  greeting\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2131\n#[test]\nfn comment() {\n    assert_format!(\n        r#\"fn main() {\n  wibble(\n    // Hello\n    { Nil },\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn block_comment() {\n    assert_format!(\n        r#\"fn main() {\n  testbldr.demonstrate(\n    named: \"Hello, this argument is longer to make it all wrap\",\n    with: {\n      // Comment!\n      Nil\n      Nil\n    },\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn last_comments_are_not_moved_out_of_blocks() {\n    assert_format!(\n        r#\"fn main() {\n  {\n    hello\n    // Hope I'm not yeeted out of this block!\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  {\n    hello\n    {\n      { hi }\n      // Some nested comments\n    }\n    // At the end of multiple blocks\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case wibble {\n    wobble -> {\n      1\n      // Hope I can stay inside this clause\n    }\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/cases.rs",
    "content": "use crate::assert_format;\n\n#[test]\nfn case_with_two_long_subjects() {\n    assert_format!(\n        r#\"pub fn main() {\n  case\n    wibble(one_long_argument, something_else),\n    wobble(another_argument, this_is_long)\n  {\n    _ -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_patterns_get_split_one_on_each_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  case wibble, wobble, wubble {\n    Wibble(one_thing, something_else, wibble),\n      Wobble(\n        this_will_go_over_the_line_limit,\n        and_the_arguments_get_broken_as_well,\n        wobble,\n      ),\n      Wubble(this_will_go_over_the_line_limit, wubble)\n    -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_patterns_with_guard_get_split_one_on_each_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  case wibble, wobble, wubble {\n    Wibble(one_thing, something_else, wibble),\n      Wobble(this_will_go_over_the_line_limit, wobble),\n      Wubble(this_will_go_over_the_line_limit, wubble)\n      if wibble && wobble || wubble\n    -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_patterns_with_long_guard_get_split_one_on_each_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  case wibble, wobble, wubble {\n    Wibble(one_thing, something_else, wibble),\n      Wobble(this_will_go_over_the_line_limit, wobble),\n      Wubble(this_will_go_over_the_line_limit, wubble)\n      if { wibble || wobble }\n      && { wibble || wobble && wibble > 10 }\n      || wobble < 10_000_000\n    -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_patterns_and_alternative_patterns_mixed_together() {\n    assert_format!(\n        r#\"pub fn main() {\n  case wibble, wobble, wubble {\n    Wibble(one_thing, something_else, wibble),\n      Wobble(this_will_go_over_the_line_limit, wobble),\n      Wubble(this_will_go_over_the_line_limit, wubble)\n    | Wibble(a), Wobble(b), Wubble(c)\n    | Wibble(one_thing, something_else, wibble),\n      Wobble(this_will_go_over_the_line_limit, wobble),\n      Wubble(this_will_go_over_the_line_limit, wubble)\n      if { wibble || wobble }\n      && { wibble || wobble && wibble > 10 }\n      || wobble < 10_000_000\n    -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn case_pattern_split_on_multiple_lines_is_not_needlessly_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  case thing {\n    CannotSaveNewSnapshot(\n      reason: reason,\n      title: title,\n      destination: destination,\n    ) -> todo\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3140\n#[test]\nfn long_comment_before_case_with_multiple_subjects_doesnt_force_a_break() {\n    assert_format!(\n        r#\"fn main() {\n  case a, b {\n    // a very long comment a very long comment a very long comment a very long comment\n    _, _ -> True\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn alternatives_are_not_split_if_not_necessary() {\n    assert_format!(\n        r#\"fn main() {\n  case thing {\n    Wibble | Wobble -> {\n      todo\n      todo\n    }\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn alternatives_are_not_split_if_not_necessary_2() {\n    assert_format!(\n        r#\"fn main() {\n  case thing {\n    Wibble | Wobble | Wabble ->\n      loooooooong_function_call_that_barely_goes_over_the_limit()\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn subjects_are_not_split_if_not_necessary() {\n    assert_format!(\n        r#\"fn main() {\n  case\n    is_all_uppercase(remark),\n    string.ends_with(remark, \"?\"),\n    string.trim(remark) == \"\"\n  {\n    _, _, _ -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn case_in_call_gets_broken_if_it_goes_over_the_limit_with_subject() {\n    assert_format!(\n        r#\"fn main() {\n  do_diff_attributes(\n    dict.delete(prev, attr.name),\n    rest,\n    case attr.value == old.value {\n      True -> added\n      False -> [attr, ..added]\n    },\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn case_in_call_is_not_broken_if_it_goes_over_the_limit_with_branches() {\n    assert_format!(\n        r#\"fn main() {\n  do_diff_attributes(rest, case attr.value == old.value {\n    True -> added\n    False -> [attr, ..added]\n  })\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/conditional_compilation.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn multiple() {\n    assert_format!(\n        \"type X\n\n@target(erlang)\ntype Y {\n  Y\n}\n\n@target(javascript)\ntype Z {\n  Z\n}\n\"\n    );\n}\n\n#[test]\nfn formatter_removes_target_shorthand_erlang() {\n    assert_format_rewrite!(\n        \"@target(erl)\nfn wibble() {\n  todo\n}\",\n        \"@target(erlang)\nfn wibble() {\n  todo\n}\n\"\n    );\n}\n\n#[test]\nfn formatter_removes_target_shorthand_javascript() {\n    assert_format_rewrite!(\n        \"@target(js)\nfn wibble() {\n  todo\n}\",\n        \"@target(javascript)\nfn wibble() {\n  todo\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/constant.rs",
    "content": "use crate::assert_format;\n\n// https://github.com/gleam-lang/gleam/issues/5143\n#[test]\npub fn constant_with_deprecated_attribute() {\n    assert_format!(\n        r#\"@deprecated(\"Use tau instead\")\npub const pi = 3.14\n\"#\n    );\n}\n\n#[test]\nfn const_record_update_simple() {\n    assert_format!(\n        r#\"pub type Counter {\n  Counter(a: Int, b: Int)\n}\n\npub const c = Counter(0, 0)\n\npub const c2 = Counter(..c, a: 1, b: 2)\n\"#\n    );\n}\n\n#[test]\nfn const_record_update_long() {\n    assert_format!(\n        r#\"pub type Counter {\n  Counter(loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: Int)\n}\n\npub const c = Counter(0)\n\npub const c2 = Counter(\n  ..c,\n  loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: 1,\n)\n\"#\n    );\n}\n\n#[test]\nfn const_record_update_with_module() {\n    assert_format!(\n        r#\"pub type Counter {\n  Counter(a: Int, b: Int)\n}\n\npub const c = Counter(0, 0)\n\npub const c2 = mod.Counter(..c, a: 1)\n\"#\n    );\n}\n\n#[test]\nfn const_list_prepend() {\n    assert_format!(\n        \"pub const wibble = [2, 3, 4]\n\npub const wobble = [0, 1, ..wibble]\n\"\n    );\n}\n\n#[test]\nfn const_list_prepend_multiline() {\n    assert_format!(\n        r#\"pub const wibble = [\"Hello\", \"world\"]\n\npub const wobble = [\n  \"Some really long message that causes the line to wrap\",\n  \"Something else\",\n  ..wibble\n]\n\"#\n    );\n}\n\n#[test]\nfn const_list_prepend_multiline_with_comments() {\n    assert_format!(\n        r#\"pub const wibble = [\"Hello\", \"world\"]\n\npub const wobble = [\n  \"Some really long message that causes the line to wrap\",\n  // Some comment\n  \"Something else\",\n  // Prepend the values to `wibble`\n  ..wibble\n  // End of list\n]\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/custom_type.rs",
    "content": "use crate::assert_format;\n\n#[test]\nfn custom_type_0() {\n    assert_format!(\n        \"type WowThisTypeHasJustTheLongestName(\n  some_long_type_variable,\n  and_another,\n  and_another_again,\n) {\n  Make\n}\n\"\n    );\n}\n#[test]\nfn custom_type_1() {\n    assert_format!(\n        \"type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\"\n    );\n}\n#[test]\nfn custom_type_2() {\n    assert_format!(\n        \"type Result(a, e) {\n  Ok(value: a)\n  Error(error: e)\n}\n\"\n    );\n}\n#[test]\nfn custom_type_3() {\n    assert_format!(\n        \"type SillyResult(a, e) {\n  Ok(\n    first_value_with_really_long_name: a,\n    second_value_with_really_long_name: a,\n  )\n  Error(error: e)\n}\n\"\n    );\n}\n#[test]\nfn custom_type_4() {\n    assert_format!(\n        \"type SillyResult(a, e) {\n  Ok(\n    first_value_with_really_long_name: a,\n    second_value_with_really_long_name: List(\n      #(Int, fn(a, a, a, a, a, a, a) -> List(a)),\n    ),\n  )\n  Error(error: e)\n}\n\"\n    );\n}\n#[test]\nfn custom_type_5() {\n    assert_format!(\n        \"type X {\n  X(\n    start: fn() -> a_reall_really_long_name_goes_here,\n    stop: fn() -> a_reall_really_long_name_goes_here,\n  )\n}\n\"\n    );\n}\n#[test]\nfn custom_type_6() {\n    assert_format!(\n        \"pub opaque type X {\n  X\n}\n\"\n    );\n}\n#[test]\nfn custom_type_7() {\n    assert_format!(\n        \"///\npub type Option(a) {\n  None\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1757\n#[test]\nfn multiple_line_custom_type_constructor_field_doc_comments() {\n    assert_format!(\n        r#\"pub type Thingy {\n  Thingy(\n    /// One?\n    /// One!\n    one: One,\n    /// Two?\n    /// Two!\n    two: Two,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_custom_type() {\n    assert_format!(\n        r#\"@deprecated(\"Deprecated type\")\npub type One {\n  One\n}\n\"#\n    );\n}\n\n#[test]\nfn doc_comments_7_test() {\n    assert_format!(\n        r#\"import one\n\n/// one\n///two\ntype Whatever {\n  Whatever\n}\n\"#\n    );\n}\n\n#[test]\nfn comments1() {\n    assert_format!(\n        r#\"import one\n\n// one\n//two\ntype Whatever {\n  Whatever\n}\n\"#\n    );\n}\n\n#[test]\nfn comments2() {\n    assert_format!(\n        r#\"import one\n\n// one\n//two\n/// three\ntype Whatever {\n  Whatever\n}\n\"#\n    );\n}\n\n#[test]\nfn comments6() {\n    assert_format!(\n        r#\"// one\n//two\ntype Thingy\n\"#\n    );\n}\n\n#[test]\nfn comments7() {\n    assert_format!(\n        r#\"// one\n//two\ntype Thingy\n\"#\n    );\n}\n\n#[test]\nfn comments8() {\n    assert_format!(\n        r#\"// one\n//two\ntype Whatever {\n  Whatever\n}\n\"#\n    );\n}\n\n#[test]\nfn comments10() {\n    assert_format!(\n        r#\"// zero\nimport one\n\n// one\n//two\ntype Whatever {\n  Whatever\n}\n\"#\n    );\n}\n\n#[test]\nfn comments11() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  \\\"world\\\"\n}\n\"\n    );\n}\n\n#[test]\nfn comment21() {\n    assert_format!(\n        \"pub type Spec {\n  Spec(\n    // Hello\n    hello: Int,\n    // World\n    world: Int,\n  )\n}\n\"\n    );\n}\n\n#[test]\nfn commented_constructors() {\n    assert_format!(\n        \"pub type Number {\n  // 1\n  One\n  // 2\n  Two\n  // 3\n  Three\n  // ???\n  More\n}\n\"\n    );\n}\n\n#[test]\nfn commented_constructors1() {\n    assert_format!(\n        \"pub type Number {\n  /// 1\n  One\n  /// 2\n  Two\n  /// 3\n  Three\n  /// ???\n  More\n}\n\"\n    );\n}\n\n#[test]\nfn commented_constructors2() {\n    assert_format!(\n        \"pub type Number {\n  // a\n  /// 1\n  One\n  // b\n  /// 2\n  Two\n  // c\n  /// 3\n  Three\n  // defg\n  /// ???\n  More\n}\n\"\n    );\n}\n\n#[test]\nfn commented_constructors3() {\n    assert_format!(\n        \"pub type Number {\n  /// 1\n  One(value: Int)\n  /// > 1\n  Many(value: Int)\n}\n\"\n    );\n}\n\n#[test]\nfn deprecated_variant_1() {\n    assert_format!(\n        r#\"pub type One {\n  @deprecated(\"Deprecated type\")\n  One\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_variant_2() {\n    assert_format!(\n        r#\"pub type One {\n  @deprecated(\"Deprecated type\")\n  One(Int, Int, Int, Int, Int, Int, Int)\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_variant_3() {\n    assert_format!(\n        r#\"pub type One {\n  @deprecated(\"Deprecated type with a very long message\")\n  One(Int, Int, Int, Int, Int, Int, Int)\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_variant_4() {\n    assert_format!(\n        r#\"pub type One {\n  @deprecated(\"Deprecated type with a very long message\n\nIt even has multiple lines!\n\")\n  One(Int, Int, Int, Int, Int, Int, Int)\n}\n\"#\n    );\n}\n\n#[test]\nfn external_custom_type() {\n    assert_format!(\n        r#\"@external(erlang, \"erlang\", \"map\")\n@external(javascript, \"../dict.d.mts\", \"Dict\")\npub type Dict(key, value)\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/echo.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn echo() {\n    assert_format!(\n        \"fn main() {\n  echo\n}\n\"\n    );\n}\n\n#[test]\nfn echo_with_value() {\n    assert_format!(\n        r#\"fn main() {\n  echo value\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_with_big_value_that_needs_to_be_split() {\n    assert_format!(\n        r#\"fn main() {\n  echo [\n    this_is_a_long_list_and_requires_splitting,\n    wibble_wobble_woo,\n    multiple_lines,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_inside_a_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble\n  |> echo\n  |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_inside_a_single_line_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble |> echo |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_last_item_of_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble |> wobble |> echo\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_last_item_of_multiline_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble\n  |> wobble\n  |> echo\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_with_related_expression_on_following_line() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  panic as echo\n  \"wibble\"\n}\n\"#,\n        r#\"fn main() {\n  panic as echo \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_with_following_value_in_a_pipeline() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  []\n  |> echo wibble\n  |> wobble\n}\n\"#,\n        r#\"fn main() {\n  []\n  |> echo\n  wibble\n  |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_printing_multiline_pipeline() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  echo first\n  |> wibble\n  |> wobble\n}\n\"#,\n        r#\"fn main() {\n  echo first\n    |> wibble\n    |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_printing_one_line_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  echo first |> wibble |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as() {\n    assert_format!(\n        \"fn main() {\n  echo as hello\n}\n\"\n    );\n}\n\n#[test]\nfn echo_as_with_value() {\n    assert_format!(\n        r#\"fn main() {\n  echo value as message\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_big_value_that_needs_to_be_split() {\n    assert_format!(\n        r#\"fn main() {\n  echo call([\n    this_is_a_long_list_and_requires_splitting,\n    wibble_wobble_woo,\n    multiple_lines,\n  ])\n    as \"tag!\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_inside_a_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble\n  |> echo as \"echooo o o\"\n  |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_inside_a_single_line_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble |> echo as string |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_as_last_item_of_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble |> wobble |> echo as end\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_as_last_item_of_multiline_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  wibble\n  |> wobble\n  |> echo as message\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_related_expression_on_following_line() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  panic as echo\n  \"wibble\"\n  as wobble\n}\n\"#,\n        r#\"fn main() {\n  panic as echo \"wibble\" as wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_following_value_in_a_pipeline() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  []\n  |> echo as wibble wibble\n  |> wobble\n}\n\"#,\n        r#\"fn main() {\n  []\n  |> echo as wibble\n  wibble\n  |> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_printing_multiline_pipeline() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  echo first\n  |> wibble\n  |> wobble\n  as \"pipeline\"\n}\n\"#,\n        r#\"fn main() {\n  echo first\n    |> wibble\n    |> wobble\n    as \"pipeline\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_printing_one_line_pipeline() {\n    assert_format!(\n        r#\"fn main() {\n  echo first |> wibble |> wobble as \"pipeline\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_multiline_message() {\n    assert_format!(\n        r#\"fn main() {\n  echo [wibble, wobble]\n    as {\n      // Force this block to split\n      \"wibble\" <> wobble()\n    }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/external_fn.rs",
    "content": "use crate::assert_format;\n\n#[test]\nfn no_body_erlang() {\n    assert_format!(\n        r#\"@external(erlang, \"one\", \"one\")\nfn one(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn no_body_javascript() {\n    assert_format!(\n        r#\"@external(javascript, \"one\", \"one\")\nfn one(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn no_body_body() {\n    assert_format!(\n        r#\"@external(erlang, \"two\", \"two\")\n@external(javascript, \"one\", \"one\")\nfn one(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn erlang() {\n    assert_format!(\n        r#\"@external(erlang, \"one\", \"one\")\nfn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript() {\n    assert_format!(\n        r#\"@external(javascript, \"one\", \"one\")\nfn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn body() {\n    assert_format!(\n        r#\"@external(erlang, \"two\", \"two\")\n@external(javascript, \"one\", \"one\")\nfn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2259\n#[test]\nfn break_external_fn_arguments() {\n    assert_format!(\n        r#\"@external(erlang, \"ffi\", \"improper_list_append\")\nfn improper_list_append(\n  a: item_a,\n  b: item_b,\n  c: improper_tail,\n) -> List(anything)\n\"#\n    );\n}\n\n// Bug found by Hayleigh\n#[test]\nfn long_long_external() {\n    assert_format!(\n        r#\"@external(javascript, \"./client-component.ffi.mjs\", \"register\")\npub fn register(\n  _app: App(WebComponent, Nil, model, msg),\n  _name: String,\n) -> Result(Nil, Error) {\n  Error(NotABrowser)\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/external_types.rs",
    "content": "use crate::assert_format;\n\n#[test]\nfn example1() {\n    assert_format!(\"type Private\\n\");\n}\n\n#[test]\nfn example2() {\n    assert_format!(\"type Box(a)\\n\");\n}\n\n#[test]\nfn example3() {\n    assert_format!(\"type Box(a, b, zero)\\n\");\n}\n\n#[test]\nfn example4() {\n    assert_format!(\"pub type Private\\n\");\n}\n\n#[test]\nfn example5() {\n    assert_format!(\"pub type Box(a)\\n\");\n}\n\n#[test]\nfn example6() {\n    assert_format!(\"pub type Box(a, b, zero)\\n\");\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/function.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn capture_with_single_argument() {\n    assert_format_rewrite!(\n        \"pub fn main() -> Nil {\n  wibble([], wobble(_))\n}\n\",\n        \"pub fn main() -> Nil {\n  wibble([], wobble)\n}\n\"\n    );\n}\n\n#[test]\nfn deprecated() {\n    assert_format!(\n        r#\"@deprecated(\"use something else instead\")\npub fn main() -> Nil {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_external() {\n    assert_format!(\n        r#\"@deprecated(\"use something else instead\")\n@external(erlang, \"thing\", \"main\")\npub fn main() -> Nil\n\"#\n    );\n}\n\n#[test]\nfn anonymous_function_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, fn(x) {\n    let y = x + 1\n    y\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn anonymous_function_with_single_line_body_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, fn(x) { x })\n}\n\"#\n    );\n}\n\n#[test]\nfn anonymous_function_with_multi_line_unbreakable_body_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, fn(x) {\n    call_to_other_function(a, b, c, d, e, f, g, h)\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn anonymous_function_with_multi_line_breakable_body_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, fn(x) {\n    call_to_other_function(a, b, c, d, e, f, g, { x + x })\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn anonymous_function_with_multi_line_long_breakable_body_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, fn(x) {\n    call_to_other_function(a, b, c, d, e, f, g, case wibble {\n      Wibble -> 1\n      Wobble -> 2\n    })\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_as_final_function_argument_goes_on_its_own_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function_with_a_long_name(\n    123,\n    456,\n    another_function_being_called(123, 456),\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, #(\n    \"Here is a very long string which causes the formatter to wrap it\",\n  ))\n}\n\"#\n    );\n}\n\n#[test]\nfn list_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, [\n    \"Here is a very long string which causes the formatter to wrap it\",\n  ])\n}\n\"#\n    );\n}\n\n#[test]\nfn case_expression_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, case my_var {\n    True -> True\n    False -> False\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn block_as_final_function_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(123, 456, {\n    let days = 7\n    days * 24 * 60 * 60\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn when_all_arguments_are_too_long_each_one_is_on_its_own_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  some_function(\n    variable_with_really_long_name,\n    whoah_this_is_getting_out_of_hand,\n    [\"Here is a very long string which causes the formatter to wrap it\"],\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_breakable_lists_in_function_calls() {\n    assert_format!(\n        r#\"pub fn main() {\n  html([attribute(\"lang\", \"en\")], [\n    head([attribute(\"wibble\", \"wobble\")], [\n      title([], [text(\"Hello this is some HTML\")]),\n    ]),\n    body([], [h1([], [text(\"Hello, world!\")])]),\n  ])\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_breakable_tuples_in_function_calls() {\n    assert_format!(\n        r#\"pub fn main() {\n  html(#(attribute(\"lang\", \"en\")), #(\n    head(#(attribute(\"wibble\", \"wobble\")), #(\n      title(#(), #(text(\"Hello this is some HTML\"))),\n      body(#(), #(text(\"Hello this is some HTML\"))),\n    )),\n    body(#(), #(h1(#(), #(text(\"Hello, lisp!\"))))),\n  ))\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2435\n#[test]\nfn only_last_argument_can_be_broken() {\n    assert_format!(\n        r#\"pub fn main() {\n  tbd.workbook(for: \"my_project\")\n  |> task(\n    doc: \"Run the project tests\",\n    tags: list.concat([[\"test\", \"ci\"], gleam, typescript]),\n    action: fn(_, _) { tbd.command(run: \"gleam\", with: [\"test\"]) },\n  )\n  |> run\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  Theme(\n    flag: styler([32]),\n    heading: styler([1, 95]),\n    highlight: styler([1, 36]),\n    parameter: styler([34]),\n    tag: styler([33]),\n    given_tag: styler([3]),\n    first_tag: styler([1]),\n    tab: \"    \",\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn function_that_is_a_little_over_the_limit() {\n    assert_format!(\n        r#\"pub fn handle_request(\n  handler: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n) -> Nil {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2571\n#[test]\nfn expr_function_as_last_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  Builder(\n    accumulator: \"\",\n    update: fn(accum, val) { accum <> val },\n    final: fn(accum) { accum },\n  )\n}\n\"#\n    );\n\n    // We want to make sure that, if it goes over the limit NOT with its\n    // arguments' list the body is still the first thing that gets split.\n    assert_format!(\n        r#\"pub fn main() {\n  Builder(accumulator: \"\", update: fn(accum, val) { accum }, final: fn(accum) {\n    accum\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn comment_at_start_of_inline_function_body() {\n    assert_format!(\n        r#\"pub fn main() {\n  let add = fn(x: Int, y: Int) {\n    // This is a comment\n    x + y\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn comment_at_start_of_top_level_function_body() {\n    assert_format!(\n        r#\"pub fn add(x: Int, y: Int) {\n  // This is a comment\n  x + y\n}\n\"#\n    );\n}\n\n#[test]\nfn comment_at_end_of_inline_function_args() {\n    assert_format!(\n        r#\"pub fn main() {\n  let add = fn(\n    x: Int,\n    y: Int,\n    // This is a comment\n  ) {\n    x + y\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn comment_middle_of_inline_function_body() {\n    assert_format!(\n        r#\"pub fn main() {\n  let add = fn(x: Int, y: Int, z: Int) {\n    let a = x + y\n    // This is a comment\n    a + z\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5004\n#[test]\nfn comment_in_tuple_return_type() {\n    assert_format_rewrite!(\n        r#\"pub fn main() -> #(\n  // This is a string\n  String, // This is an awesome string\n) {\n  todo\n}\n\"#,\n        r#\"pub fn main() -> #(\n  String,\n  // This is a string\n  // This is an awesome string\n) {\n  todo\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/guards.rs",
    "content": "use crate::assert_format;\n\n#[test]\nfn field_access() {\n    assert_format!(\n        r#\"pub fn main() {\n  case x {\n    _ if a.b -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_field_access() {\n    assert_format!(\n        r#\"pub fn main() {\n  case x {\n    _ if a.b.c.d -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn operators_in_guard() {\n    assert_format!(\n        r#\"pub fn main() {\n  case list.map(codepoints, string.utf_codepoint_to_int) {\n    [drive, colon, slash]\n      if { slash == 47 || slash == 92 }\n      && colon == 58\n      && drive >= 65\n      && drive <= 90\n      || drive >= 97\n      && drive <= 122\n    -> {\n      1\n      |> 2\n    }\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn a_comment_before_a_guard_doesnt_force_it_to_break() {\n    assert_format!(\n        r#\"pub fn main() {\n  case wibble {\n    // Apparently this comment breaks everything\n    _ if wobble -> Ok(state.newest)\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn long_guard_with_alternative_patterns() {\n    assert_format!(\n        r#\"pub fn main() {\n  case wibble {\n    Wibble(first_one)\n      | Wibble(another_one)\n      | Wibble(\n        this_is_extra_long_to_go_over_the_line_limit,\n        this_gets_broken_as_well,\n      )\n      if True\n    -> Ok(wibble)\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn guard_block_is_not_removed_even_if_redundant() {\n    assert_format!(\n        r#\"pub fn main() {\n  case todo {\n    _ if { True && True } && True -> 1\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_guard_block_is_not_removed_even_if_redundant() {\n    assert_format!(\n        r#\"pub fn main() {\n  case todo {\n    _ if { True && { True && False } } && True -> 1\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/imports.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn types_and_values() {\n    assert_format!(\n        \"import one/two.{type Abc, type Bcd, Abc, Bcd, abc, bcd}\n\"\n    );\n}\n\n#[test]\nfn discarded_import() {\n    assert_format!(\n        \"import one/two as _three\n\"\n    );\n}\n\n#[test]\nfn discarded_import_with_unqualified() {\n    assert_format!(\n        \"import one/two.{type Abc, Bcd, abc} as _three\n\"\n    );\n}\n\n#[test]\nfn redundant_as_name_is_removed() {\n    assert_format_rewrite!(\"import wibble/wobble as wobble\", \"import wibble/wobble\\n\");\n    assert_format_rewrite!(\"import wibble as wibble\", \"import wibble\\n\");\n}\n\n#[test]\nfn imports_are_sorted_alphabetically() {\n    assert_format_rewrite!(\n        \"import c import a/a import a/c import b import a/ab import a\",\n        \"import a\nimport a/a\nimport a/ab\nimport a/c\nimport b\nimport c\n\"\n    );\n}\n\n#[test]\nfn import_groups_are_respected() {\n    assert_format_rewrite!(\n        \"import group_one/a\nimport group_one/b\n// another group\nimport group_two/wobble\nimport group_two/wibble\n// yet another group\nimport group_three/b\nimport group_three/c\nimport group_three/a\n\",\n        \"import group_one/a\nimport group_one/b\n\n// another group\nimport group_two/wibble\nimport group_two/wobble\n\n// yet another group\nimport group_three/a\nimport group_three/b\nimport group_three/c\n\"\n    );\n}\n\n#[test]\nfn empty_lines_define_different_groups() {\n    assert_format_rewrite!(\n        \"import c\n@target(javascript)\nimport b\n\nimport a\n\nimport gleam/string\nimport gleam/list\",\n        \"@target(javascript)\nimport b\nimport c\n\nimport a\n\nimport gleam/list\nimport gleam/string\n\"\n    );\n}\n\n#[test]\nfn import_groups_with_empty_lines_and_comments() {\n    assert_format_rewrite!(\n        \"import c\n@target(javascript)\nimport b\n\nimport a\n// third group\nimport gleam/string\nimport gleam/list\n\nimport wobble\nimport wibble\n\",\n        \"@target(javascript)\nimport b\nimport c\n\nimport a\n\n// third group\nimport gleam/list\nimport gleam/string\n\nimport wibble\nimport wobble\n\"\n    );\n}\n\n#[test]\nfn type_definition_in_between_imports() {\n    assert_format!(\n        r#\"import a\nimport b\n\npub type Wibble(a) {\n  Wobble\n}\n\nimport c\nimport d\n\nimport e\n\npub type Wabble\n\nimport f\n\"#\n    );\n}\n\n#[test]\nfn function_definition_in_between_imports() {\n    assert_format!(\n        r#\"import a\nimport b\n\npub fn wibble() {\n  todo\n}\n\nimport c\nimport d\n\nimport e\n\npub fn wobble() -> Int {\n  todo\n}\n\nimport f\n\"#\n    );\n}\n\n#[test]\nfn constant_definition_in_between_imports() {\n    assert_format!(\n        r#\"import a\nimport b\n\npub const wibble = Wibble\n\nimport c\nimport d\n\nimport e\n\nconst wobble = 1\n\nimport f\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2915\n#[test]\nfn white_lines_between_comments_in_import_groups_are_preserved() {\n    assert_format!(\n        r#\"import a\n\n// comment\n\nimport b\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2915\n#[test]\nfn import_sorting_doesnt_add_spurious_white_line() {\n    assert_format!(\n        r#\"// comment\n\nimport filepath\nimport gleam/dynamic.{type Dynamic}\nimport gleam/io\nimport gleam/list\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/lists.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn list_with_trailing_comma_is_broken() {\n    assert_format_rewrite!(\n        \"pub fn main() { [ 1, 2, a, ] }\",\n        r#\"pub fn main() {\n  [\n    1,\n    2,\n    a,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_list_with_trailing_comma_is_broken() {\n    assert_format_rewrite!(\n        \"const list = [ 1, 2, a, ]\",\n        r#\"const list = [\n  1,\n  2,\n  a,\n]\n\"#\n    );\n}\n\n#[test]\nfn list_with_trailing_comma_is_kept_broken() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    1,\n    2,\n    a,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_list_with_trailing_comma_is_kept_broken() {\n    assert_format!(\n        r#\"const list = [\n  1,\n  2,\n  a,\n]\n\"#\n    );\n}\n\n#[test]\nfn list_with_no_trailing_comma_is_packed_on_a_single_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  [\n    1,\n    2,\n    a\n  ]\n}\n\"#,\n        r#\"pub fn main() {\n  [1, 2, a]\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_list_with_no_trailing_comma_is_packed_on_a_single_line() {\n    assert_format_rewrite!(\n        r#\"const list = [\n  1,\n  2,\n  a\n]\"#,\n        \"const list = [1, 2, a]\\n\"\n    );\n}\n\n#[test]\nfn list_with_no_comma_is_packed_on_a_single_line_or_split_one_item_per_line() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  [\n    1,\n    a,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    b,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312\n  ]\n}\n\",\n        \"pub fn main() {\n  [\n    1,\n    a,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    b,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n    12_312_312_312_312_312_312_312,\n  ]\n}\n\"\n    );\n}\n\n#[test]\nfn constant_list_with_no_comma_is_packed_on_a_single_line_or_split_one_item_per_line() {\n    assert_format_rewrite!(\n        \"const list = [\n  1,\n  a,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  b,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312\n]\n\",\n        \"const list = [\n  1,\n  a,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  b,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n  12_312_312_312_312_312_312_312,\n]\n\"\n    );\n}\n\n#[test]\nfn simple_list_with_no_comma_is_packed_on_a_single_line_or_split_one_item_per_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  [\n    \"hello\",\n    \"wibble wobble\",\n    \"these are all simple strings\",\n    \"but the list won't be packed\",\n    \"the formatter will keep\",\n    \"one item\",\n    \"per line\",\n    \"since there's no trailing comma here ->\"\n  ]\n}\n\"#,\n        r#\"pub fn main() {\n  [\n    \"hello\",\n    \"wibble wobble\",\n    \"these are all simple strings\",\n    \"but the list won't be packed\",\n    \"the formatter will keep\",\n    \"one item\",\n    \"per line\",\n    \"since there's no trailing comma here ->\",\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_list_with_trailing_comma_and_multiple_items_per_line_is_packed() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  [\n    \"hello\",\n    \"wibble wobble\",\n    \"these are all simple strings\",\n    \"and the list will be packed since the following strings are\",\n    \"on the same\", \"line\", \"and there's a trailing comma ->\",\n  ]\n}\n\"#,\n        r#\"pub fn main() {\n  [\n    \"hello\", \"wibble wobble\", \"these are all simple strings\",\n    \"and the list will be packed since the following strings are\", \"on the same\",\n    \"line\", \"and there's a trailing comma ->\",\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_constant_list_with_trailing_comma_and_multiple_items_per_line_is_packed() {\n    assert_format_rewrite!(\n        r#\"pub const list = [\n  \"hello\",\n  \"wibble wobble\",\n  \"these are all simple strings\",\n  \"and the list will be packed since the following strings are\",\n  \"on the same\", \"line\", \"and there's a trailing comma ->\",\n]\n\"#,\n        r#\"pub const list = [\n  \"hello\", \"wibble wobble\", \"these are all simple strings\",\n  \"and the list will be packed since the following strings are\", \"on the same\",\n  \"line\", \"and there's a trailing comma ->\",\n]\n\"#\n    );\n}\n\n#[test]\nfn simple_packed_list_with_trailing_comma_is_kept_with_multiple_items_per_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    \"hello\", \"wibble wobble\", \"these are all simple strings\",\n    \"and the list will be kept packed since it ends with a trailing comma\",\n    \"right here! ->\",\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_single_line_list_with_trailing_comma_is_split_one_item_per_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  [\"these are all simple strings\", \"but the list won't be packed\", \"since it ends with a trailing comma ->\",]\n}\n\"#,\n        r#\"pub fn main() {\n  [\n    \"these are all simple strings\",\n    \"but the list won't be packed\",\n    \"since it ends with a trailing comma ->\",\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn simple_single_line_list_with_no_trailing_comma_is_split_one_item_per_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  [\"these are all simple strings\", \"but the list won't be packed\", \"even if it doesn't end with a trailing comma!\"]\n}\n\"#,\n        r#\"pub fn main() {\n  [\n    \"these are all simple strings\",\n    \"but the list won't be packed\",\n    \"even if it doesn't end with a trailing comma!\",\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn empty_lines_in_list_are_not_ignored() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  [1, 2,\n\n  3\n  ]\n}\n\",\n        \"pub fn main() {\n  [\n    1,\n    2,\n\n    3,\n  ]\n}\n\"\n    );\n}\n\n#[test]\nfn empty_lines_in_const_list_are_not_ignored() {\n    assert_format_rewrite!(\n        \"const list =\n  [1, 2,\n\n  3\n  ]\n\",\n        \"const list = [\n  1,\n  2,\n\n  3,\n]\n\"\n    );\n}\n\n#[test]\nfn lists_with_empty_lines_are_always_broken() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  [\n    1,\n    2,\n\n    3, 4, 5\n  ]\n}\n\",\n        \"pub fn main() {\n  [\n    1,\n    2,\n\n    3,\n    4,\n    5,\n  ]\n}\n\"\n    );\n}\n\n#[test]\nfn const_lists_with_empty_lines_are_always_broken() {\n    assert_format_rewrite!(\n        \"const list =\n  [\n    1,\n    2,\n\n    3, 4, 5\n  ]\n\",\n        \"const list = [\n  1,\n  2,\n\n  3,\n  4,\n  5,\n]\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/pipeline.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\npub fn single_line_pipeline_longer_than_line_limit_gets_split() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  wibble |> wobble |> loooooooooooooooooooooooooooooooooooooooooooong_function_name\n}\n\"#,\n        r#\"pub fn main() {\n  wibble\n  |> wobble\n  |> loooooooooooooooooooooooooooooooooooooooooooong_function_name\n}\n\"#,\n    );\n}\n\n#[test]\npub fn single_line_pipeline_shorter_than_line_limit_is_kept_on_a_single_line() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(1) |> wobble\n}\n\"#\n    );\n}\n\n#[test]\npub fn multi_line_pipeline_is_split_no_matter_the_length() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(1)\n  |> wobble\n}\n\"#\n    );\n}\n\n#[test]\npub fn adding_a_newline_to_a_pipeline_splits_all() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  wibble |> wobble\n  |> wabble\n}\n\"#,\n        r#\"pub fn main() {\n  wibble\n  |> wobble\n  |> wabble\n}\n\"#,\n    );\n}\n\n#[test]\npub fn multiline_function_inside_pipeline_function_argument_is_indented_properly() {\n    assert_format!(\n        r#\"pub fn main() {\n  function(\n    arg0,\n    thing\n      |> string.replace(\n        \"{something something}\",\n        date.month_to_string(month, config.l10n.context),\n      ),\n  )\n}\n\"#,\n    );\n}\n\n#[test]\npub fn multiline_function_inside_pipeline_in_list_is_indented_properly() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    item1,\n    thing\n      |> string.replace(\n        \"{something something}\",\n        date.month_to_string(month, config.l10n.context),\n      ),\n  ]\n}\n\"#,\n    );\n}\n\n#[test]\npub fn multiline_function_inside_pipeline_in_tuple_is_indented_properly() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    item1,\n    thing\n      |> string.replace(\n        \"{something something}\",\n        date.month_to_string(month, config.l10n.context),\n      ),\n  )\n}\n\"#,\n    );\n}\n\n#[test]\nfn pipe_with_labelled_first_argument_capture() {\n    assert_format!(\n        \"fn wibble(label1 a, label2 b, lots c, of d, labels e) {\n  a + b * c - d / e\n}\n\nfn main() {\n  1 |> wibble(label1: _, label2: 2, lots: 3, of: 4, labels: 5)\n}\n\"\n    );\n}\n\n#[test]\nfn pipe_with_labelled_only_argument_capture() {\n    assert_format!(\n        \"fn wibble(descriptive_label value) {\n  value\n}\n\nfn main() {\n  42 |> wibble(descriptive_label: _)\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/record_update.rs",
    "content": "use crate::assert_format;\n\n#[test]\nfn one() {\n    assert_format!(\n        \"pub type Counter {\n  Counter(a: Int, b: Int)\n}\n\nfn main() {\n  let c = Counter(0, 0)\n  let c = Counter(..c, a: c.a + 1, b: c.a + c.b)\n  c\n}\n\"\n    );\n}\n\n#[test]\nfn two() {\n    // Long record updates are split onto multiple lines\n    assert_format!(\n        \"pub type Counter {\n  Counter(loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: Int)\n}\n\nfn main() {\n  let c = Counter(0)\n  let c =\n    Counter(\n      ..c,\n      loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: 1,\n    )\n  c\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1872\n#[test]\nfn comment_before_spread() {\n    assert_format!(\n        r#\"fn main() {\n  Thingy(\n    // Def?\n    // Def!\n    ..thingy.defaults,\n    one: One,\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1872\n#[test]\nfn comment_before_update_label() {\n    assert_format!(\n        r#\"fn main() {\n  Thingy(\n    ..thingy.defaults,\n    // Def?\n    // Def!\n    one: One,\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1872\n#[test]\nfn multiple_line_custom_type_field_comments() {\n    assert_format!(\n        r#\"fn main() {\n  Thingy(\n    // Def?\n    // Def!\n    ..thingy.defaults,\n    // One?\n    // One!\n    one: One,\n    // Two?\n    // Two!\n    two: Two,\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4120\n#[test]\nfn record_update_gets_formatted_like_a_function_call() {\n    assert_format!(\n        r#\"pub fn example() {\n  Record(..record, field: {\n    use _ <- list.map(record.field)\n    io.print(\"Example\")\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn record_with_record_and_spread_field_is_not_needlessly_broken() {\n    assert_format!(\n        \"pub fn main() {\n  case todo {\n    Wibble(\n      some_field: Wobble(something: 1, ..),\n      other_field_1:,\n      other_field_2:,\n      other_field_3:,\n      ..,\n    ) -> todo\n  }\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/tuple.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n// https://github.com/gleam-lang/gleam/issues/2083\n#[test]\nfn nested_index_block() {\n    assert_format!(\n        r#\"pub fn main() {\n  { #(1, 2).1 }.1\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2083\n#[test]\nfn index_block() {\n    assert_format!(\n        r#\"pub fn main() {\n  {\n    1\n    #(1, 2)\n  }.1\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_with_last_splittable_arg() {\n    assert_format!(\n        r#\"fn on_attribute_change() -> Dict(String, Decoder(Msg)) {\n  dict.from_list([\n    #(\"value\", fn(attr) {\n      attr\n      |> dynamic.int\n      |> result.map(Value)\n      |> result.map(AttributeChanged)\n    }),\n  ])\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  #(\"value\", [\n    \"a long list that needs to be split on multiple lines\",\n    \"another long string\",\n  ])\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3070\n#[test]\nfn constant_long_list_of_tuples() {\n    assert_format!(\n        r#\"const wibble = [\n  #(1, 2),\n  #(3, 4),\n  #(5, 6),\n  #(7, 8),\n  #(9, 10),\n  #(11, 12),\n  #(1, 2),\n  #(3, 4),\n  #(5, 6),\n  #(7, 8),\n  #(9, 10),\n  #(11, 12),\n]\n\npub fn main() {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_tuple_access() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble.1.0\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_tuple_with_needless_block() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  { wibble.1 }.0\n}\n\"#,\n        r#\"pub fn main() {\n  wibble.1.0\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_literal_tuple_with_needless_block_is_not_changed() {\n    assert_format!(\n        r#\"pub fn main() {\n  { #(wibble, wobble).1 }.0\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests/use_.rs",
    "content": "use crate::{assert_format, assert_format_rewrite};\n\n#[test]\nfn use_1() {\n    assert_format!(\n        r#\"pub fn main() {\n  use <- benchmark(\"thingy\")\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn use_2() {\n    assert_format!(\n        r#\"pub fn main() {\n  use user <- login()\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn use_3() {\n    assert_format!(\n        r#\"pub fn main() {\n  use one, two, three, four <- get_multiple_things()\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn use_4() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    one,\n    two,\n    three,\n    four,\n    five,\n    six,\n    seven,\n    eight,\n    nine,\n    ten,\n    eleven,\n    twelve,\n    thirteen\n  <- get_multiple_things_with_a_longer_function\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn use_5() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    one,\n    two,\n    three,\n    four,\n    five,\n    six,\n    seven,\n    eight,\n    nine,\n    ten,\n    eleven,\n    twelve,\n    thirteen\n  <- get_multiple_things_with_a_longer_function(a, b, c, d)\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn use_6() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    one,\n    two,\n    three,\n    four,\n    five,\n    six,\n    seven,\n    eight,\n    nine,\n    ten,\n    eleven,\n    twelve,\n    thirteen\n  <- get_multiple_things_with_a_longer_function(\n    \"one\",\n    \"two\",\n    \"three\",\n    \"four\",\n    \"five\",\n    \"six\",\n    \"seven\",\n    \"eight\",\n  )\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn pipe_call() {\n    assert_format!(\n        r#\"pub fn main() {\n  use <-\n    a\n    |> b\n  c\n}\n\"#\n    );\n}\n\n#[test]\nfn use_pipe_everything() {\n    assert_format!(\n        r#\"pub fn main() {\n  {\n    use <- a\n    todo\n  }\n  |> b\n  c\n}\n\"#\n    );\n}\n\n#[test]\nfn long_right_hand_side_0_arguments() {\n    assert_format!(\n        r#\"pub fn main() {\n  use <- some_really_long_function_call(\n    \"one\",\n    \"two\",\n    \"three\",\n    \"four\",\n    \"five\",\n    \"six\",\n    \"seven\",\n    \"eight\",\n  )\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn long_right_hand_side_1_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  use x <- some_really_long_function_call(\n    \"one\",\n    \"two\",\n    \"three\",\n    \"four\",\n    \"five\",\n    \"six\",\n    \"seven\",\n    \"eight\",\n  )\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn long_right_hand_side_2_arguments() {\n    assert_format!(\n        r#\"pub fn main() {\n  use x, y <- some_really_long_function_call(\n    \"one\",\n    \"two\",\n    \"three\",\n    \"four\",\n    \"five\",\n    \"six\",\n    \"seven\",\n    \"eight\",\n  )\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn arity_1_var_call() {\n    assert_format!(\n        r#\"pub fn main() {\n  use x, y <- await(\n    file.read()\n    |> promise.map(something),\n  )\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn arity_1_access_call() {\n    assert_format!(\n        r#\"pub fn main() {\n  use x, y <- promise.await(\n    file.read()\n    |> promise.map(something),\n  )\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn patterns() {\n    assert_format!(\n        r#\"pub fn main() {\n  use Box(x) <- apply(Box(1))\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn patterns_with_annotation() {\n    assert_format!(\n        r#\"pub fn main() {\n  use Box(x): Box(Int) <- apply(Box(1))\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn long_patterns() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    Box(\n      xxxxxxxxxxxxxxxxxxxxxxx,\n      yyyyyyyyyyyyyyyyyyyyyyyyyyy,\n      zzzzzzzzzzzzzzzzzzzzzzzzzzzz,\n    )\n  <- apply(Box(1))\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_long_patterns() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    Box(\n      xxxxxxxxxxxxxxxxxxxxxxx,\n      yyyyyyyyyyyyyyyyyyyyyyyyyyy,\n      zzzzzzzzzzzzzzzzzzzzzzzzzzzz,\n    ),\n    Box(_),\n    Box(_),\n    Box(_)\n  <- apply(Box(1))\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_long_patterns_with_annotations() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    Box(\n      xxxxxxxxxxxxxxxxxxxxxxx,\n      yyyyyyyyyyyyyyyyyyyyyyyyyyy,\n      zzzzzzzzzzzzzzzzzzzzzzzzzzzz,\n    ): Box(Int, Bool, String),\n    Box(_)\n  <- apply(Box(1))\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_long_annotations() {\n    assert_format!(\n        r#\"pub fn main() {\n  use\n    Box(_, _): Box(\n      Xxzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,\n      Yyyyyyyyyyyyyyyyyyyyyyyy,\n    ),\n    Box(_)\n  <- apply(Box(1))\n  x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2114\n#[test]\nfn comment() {\n    assert_format!(\n        r#\"fn main() {\n  // comment\n  use x <- result.then(y)\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3605\n#[test]\nfn use_with_empty_callback_body_is_rewritten_to_have_a_todo() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  use wibble, wobble <- woo\n}\n\"#,\n        r#\"fn main() {\n  use wibble, wobble <- woo\n  todo\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format/tests.rs",
    "content": "use itertools::Itertools;\nuse pretty_assertions::assert_eq;\n\nmod asignments;\nmod binary_operators;\nmod bit_array;\nmod blocks;\nmod cases;\nmod conditional_compilation;\nmod constant;\nmod custom_type;\nmod echo;\nmod external_fn;\nmod external_types;\nmod function;\nmod guards;\nmod imports;\nmod lists;\nmod pipeline;\nmod record_update;\nmod tuple;\nmod use_;\n\n#[macro_export]\nmacro_rules! assert_format {\n    ($src:expr $(,)?) => {\n        let mut writer = String::new();\n        $crate::format::pretty(&mut writer, &$src.into(), camino::Utf8Path::new(\"<stdin>\"))\n            .unwrap();\n        assert_eq!($src, writer);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_format_rewrite {\n    ($src:expr, $expected:expr  $(,)?) => {\n        let mut writer = String::new();\n        $crate::format::pretty(&mut writer, &$src.into(), camino::Utf8Path::new(\"<stdin>\"))\n            .unwrap();\n        assert_eq!(writer, $expected);\n    };\n}\n\n#[test]\nfn imports() {\n    assert_format!(\"\\n\");\n    assert_format!(\"import one\\n\");\n    assert_format!(\"import one\\nimport two\\n\");\n    assert_format!(\"import one/two/three\\n\");\n    assert_format!(\"import four/five\\nimport one/two/three\\n\");\n    assert_format!(\"import one.{fun, fun2, fun3}\\n\");\n    assert_format!(\"import one.{One, Two, fun1, fun2}\\n\");\n    assert_format!(\"import one.{main as entrypoint}\\n\");\n    assert_format!(\"import one/two/three as free\\n\");\n    assert_format!(\"import one/two/three.{thunk} as free\\n\");\n    assert_format!(\"import one/two/three.{thunk as funky} as free\\n\");\n    assert_format!(\n        \"import my/cool/module.{\n  Ane, Bwo, Chree, Dour, Eive, Fix, Geven, Hight, Iine, Jen, Kleven, Lwelve,\n  Mhirteen, Nifteen, Oixteen,\n}\n\"\n    );\n    assert_format!(\n        \"import gleam/result.{\n  Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, Abcde,\n  End,\n}\n\"\n    );\n}\n\n#[test]\nfn multiple_statements_test() {\n    assert_format!(\n        r#\"import one\nimport three\nimport two\n\npub type One\n\npub type Two\n\npub type Three\n\npub type Four\n\"#\n    );\n}\n\n#[test]\nfn type_alias() {\n    assert_format!(\n        \"type Option(a) =\n  Result(a, Nil)\n\"\n    );\n\n    assert_format!(\n        \"pub type Option(a) =\n  Result(a, Nil)\n\"\n    );\n\n    assert_format!(\n        \"pub type Pair(a, b) =\n  #(a, b)\n\"\n    );\n\n    assert_format!(\n        \"pub type Sixteen(element) =\n  #(\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n  )\n\"\n    );\n\n    assert_format!(\n        \"pub type Sixteen(element) =\n  fn(\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n    element,\n  ) ->\n    #(\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n      element,\n    )\n\"\n    );\n\n    //    assert_format!(\n    //        \"pub type Curried(element) =\n    //  fn() ->\n    //  elementttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt\n    //\"\n    //    );\n\n    //    assert_format!(\n    //        \"pub type Sixteen(element) =\n    //  fn(element) ->\n    //  #(\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //    element,\n    //  )\n    //\"\n    //    );\n\n    assert_format!(\n        \"pub type Curried(element) =\n  fn(element) -> fn(element) -> element\n\"\n    );\n\n    //    assert_format!(\n    //        \"pub type Curried(element) =\n    //  fn(element)\n    //  -> fn(element)\n    //  -> fn(element)\n    //  -> fn(element)\n    //  -> fn(element)\n    //  -> element\n    //\"\n    //    );\n\n    assert_format!(\n        \"type WowThisTypeHasJustTheLongestName =\n  WowThisTypeHasAnEvenLongerNameHowIsThatPossible\n\"\n    );\n\n    assert_format!(\n        \"type WowThisTypeHasJustTheLongestName =\n  Container(\n    Int,\n    String,\n    List(a),\n    SomethingElse,\n    WowThisTypeHasJustTheLongestName,\n  )\n\"\n    );\n\n    assert_format!(\n        \"type WowThisTypeHasJustTheLongestName(\n  some_long_type_variable,\n  and_another,\n  and_another_again,\n) =\n  Container(\n    Int,\n    String,\n    List(a),\n    SomethingElse,\n    WowThisTypeHasJustTheLongestName,\n  )\n\"\n    );\n\n    assert_format!(\n        \"///\ntype Many(a) =\n  List(a)\n\"\n    );\n}\n\n#[test]\nfn expr_fn() {\n    assert_format!(\n        r#\"fn main() {\n  fn(x) { x }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn(_) { x }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn(_discarded) { x }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn() {\n    1\n    2\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn() {\n    let y = x\n    y\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn() {\n    let x: Int = 1\n    x\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn() {\n    let x: Box(_) = call()\n    x\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn() {\n    let x: Box(_whatever) = call()\n    x\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn(_) {\n    1\n    2\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn(_) -> Int {\n    1\n    2\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn(_: Int) -> Int { 2 }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  fn(x) {\n    case x {\n      Ok(i) -> i + 1\n      Error(_) -> 0\n    }\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_call() {\n    assert_format!(\n        r#\"fn main() {\n  run()\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  run(1)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  run(with: 1)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  run(\n    with: 1,\n    loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: 1,\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  run(\n    with: something(1, 2, 3),\n    loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: 1,\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  run(\n    with: something(\n      loooooooooooooooooooooooooooooooooooooooong: 1,\n      looooooooooooooooooooooooooooooooooooooooong: 2,\n    ),\n    loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: 1,\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        \"fn main() {\n  succ(1)\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  add(1)(2)(3)\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  Ok(1)\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  Ok(1, {\n    1\n    2\n  })\n}\n\"\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  Person(\"Al\", is_cool: VeryTrue)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  Person(name: \"Al\", is_cool: VeryTrue)\n}\n\"#\n    );\n}\n\n#[test]\nfn compact_single_argument_call() {\n    assert_format!(\n        r#\"fn main() {\n  thingy(fn(x) {\n    1\n    2\n  })\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy([\n    // ok!\n    one(),\n    two(),\n  ])\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy(<<\n    // ok!\n    one(),\n    two(),\n  >>)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy(#(\n    // ok!\n    one(),\n    two(),\n  ))\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy(\n    wiggle(my_function(\n      // ok!\n      one(),\n      two(),\n    )),\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy(case x {\n    1 -> 1\n    _ -> 0\n  })\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy({\n    1\n    2\n    3\n  })\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  thingy({\n    let x = 1\n    x\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_tuple() {\n    assert_format!(\n        r#\"fn main(one, two, three) {\n  #(1, {\n    1\n    2\n  })\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(\n    atom.create_from_string(\"module\"),\n    atom.create_from_string(\"gleam@otp@actor\"),\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #()\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(1)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(1, 2)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(1, 2, 3)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn() {\n    assert_format!(\n        r#\"fn main(one, two, three) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn1() {\n    assert_format!(\n        r#\"fn main(label_one one, label_two two, label_three three) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn2() {\n    assert_format!(\n        r#\"fn main(label_one one: One, label_two two: Two) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn3() {\n    assert_format!(\n        r#\"fn main(\n  label_one one: One,\n  label_two two: Two,\n  label_three three: Three,\n  label_four four: Four,\n) {\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main(_discarded) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn4() {\n    assert_format!(\n        r#\"fn main(label _discarded) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn5() {\n    // https://github.com/gleam-lang/gleam/issues/613\n    assert_format!(\n        r#\"fn main() {\n  Nil\n  // Done\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn6() {\n    //\n    // Module function return annotations\n    //\n\n    assert_format!(\n        r#\"fn main() -> Nil {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn7() {\n    assert_format!(\n        r#\"fn main() -> Loooooooooooooooooooong(\n  Looooooooooooooong,\n  Looooooooooooooooooong,\n  Loooooooooooooooooooooong,\n  Looooooooooooooooooooooooong,\n) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn8() {\n    assert_format!(\n        r#\"fn main() -> Loooooooooooooooooooong(\n  Loooooooooooooooooooooooooooooooooooooooooong,\n) {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn9() {\n    assert_format!(\n        r#\"fn main() -> program.Exit {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn statement_fn10() {\n    assert_format!(\n        \"fn order(\n  first: Set(member),\n  second: Set(member),\n) -> #(Set(member), Set(member), a) {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn statement_fn11() {\n    assert_format!(\n        \"///\npub fn try_map(\n  over list: List(a),\n  with fun: fn(a) -> Result(b, e),\n) -> Result(List(b), e) {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn binary_operators() {\n    assert_format!(\n        r#\"fn main() {\n  True && False\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  True || False\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 < 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 <= 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 <. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 <=. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 == 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 != 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 >= 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 > 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 >=. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 >. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 + 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 +. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 - 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 -. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 * 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 *. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 / 1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1.0 /. 1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1 % 1\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_int() {\n    assert_format!(\n        r#\"fn i() {\n  1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  121_234_345_989_000\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -12_928_347_925\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  1_234_567_890\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  123_456_789\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  12_345_678\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  1_234_567\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  123_456\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  12_345\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  1234\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  123\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  12\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  1\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -1_234_567_890\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -123_456_789\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -12_345_678\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -1_234_567\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -123_456\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -12_345\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -1234\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -123\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -12\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn i() {\n  -1\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  1_234\n}\n\"#,\n        r#\"fn i() {\n  1234\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  12_34\n}\n\"#,\n        r#\"fn i() {\n  1234\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  123_4\n}\n\"#,\n        r#\"fn i() {\n  1234\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  1234_5\n}\n\"#,\n        r#\"fn i() {\n  12_345\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  12345_6\n}\n\"#,\n        r#\"fn i() {\n  123_456\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  123456_7\n}\n\"#,\n        r#\"fn i() {\n  1_234_567\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  1234567_8\n}\n\"#,\n        r#\"fn i() {\n  12_345_678\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -1_234\n}\n\"#,\n        r#\"fn i() {\n  -1234\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -12_34\n}\n\"#,\n        r#\"fn i() {\n  -1234\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -123_4\n}\n\"#,\n        r#\"fn i() {\n  -1234\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -1234_5\n}\n\"#,\n        r#\"fn i() {\n  -12_345\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -12345_6\n}\n\"#,\n        r#\"fn i() {\n  -123_456\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -123456_7\n}\n\"#,\n        r#\"fn i() {\n  -1_234_567\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  -1234567_8\n}\n\"#,\n        r#\"fn i() {\n  -12_345_678\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn i() {\n  let #(1_234, _) = #(1_234, Nil)\n}\n\"#,\n        r#\"fn i() {\n  let #(1234, _) = #(1234, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn i() {\n  let #(12_34, _) = #(12_34, Nil)\n}\n\"#,\n        r#\"fn i() {\n  let #(1234, _) = #(1234, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn i() {\n  let #(1234567_8, _) = #(1234567_8, Nil)\n}\n\"#,\n        r#\"fn i() {\n  let #(12_345_678, _) = #(12_345_678, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn i() {\n  let #(-1_234, _) = #(-1_234, Nil)\n}\n\"#,\n        r#\"fn i() {\n  let #(-1234, _) = #(-1234, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn i() {\n  let #(-12_34, _) = #(-12_34, Nil)\n}\n\"#,\n        r#\"fn i() {\n  let #(-1234, _) = #(-1234, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn i() {\n  let #(-1234567_8, _) = #(-1234567_8, Nil)\n}\n\"#,\n        r#\"fn i() {\n  let #(-12_345_678, _) = #(-12_345_678, Nil)\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"const an_int = 1_234\n\"#,\n        r#\"const an_int = 1234\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const an_int = 12_34\n\"#,\n        r#\"const an_int = 1234\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const an_int = 1234567_8\n\"#,\n        r#\"const an_int = 12_345_678\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const an_int = -1_234\n\"#,\n        r#\"const an_int = -1234\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const an_int = -12_34\n\"#,\n        r#\"const an_int = -1234\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const an_int = -1234567_8\n\"#,\n        r#\"const an_int = -12_345_678\n\"#\n    );\n\n    assert_format!(\"fn n() {\\n  1_234_567\\n}\\n\");\n    assert_format!(\"fn h() {\\n  0xCAB005E\\n}\\n\");\n    assert_format!(\"fn h() {\\n  0xC_AB_00_5E\\n}\\n\");\n    assert_format!(\"fn h() {\\n  0xCA_B0_05_E\\n}\\n\");\n    assert_format!(\"fn b() {\\n  0b10100001\\n}\\n\");\n    assert_format!(\"fn b() {\\n  0b_1010_0001\\n}\\n\");\n    assert_format!(\"fn o() {\\n  0o1234567\\n}\\n\");\n    assert_format!(\"fn o() {\\n  0o1_234_567\\n}\\n\");\n    assert_format!(\"fn o() {\\n  0o_123_456_7\\n}\\n\");\n}\n\n#[test]\nfn expr_float() {\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.\n}\n\"#,\n        r#\"fn f() {\n  1.0\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.00\n}\n\"#,\n        r#\"fn f() {\n  1.0\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.00100\n}\n\"#,\n        r#\"fn f() {\n  1.001\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.001001\n}\n\"#,\n        r#\"fn f() {\n  1.001001\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.00e100_100\n}\n\"#,\n        r#\"fn f() {\n  1.0e100_100\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.00100e100_100\n}\n\"#,\n        r#\"fn f() {\n  1.001e100_100\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1.001001e100_100\n}\n\"#,\n        r#\"fn f() {\n  1.001001e100_100\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn f() {\n  1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn f() {\n  -1.0\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn f() {\n  9999.6666\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567_890.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567_890.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123_456_789.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12_345_678.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123_456.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12_345.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1234.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -0.0\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567_890.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123_456_789.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12_345_678.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123_456.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12_345.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1234.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -0.1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567_890.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123_456_789.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12_345_678.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1_234_567.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123_456.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12_345.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1234.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -123.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -12.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.123456\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -0.123456\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1_234.0\n}\n\"#,\n        r#\"fn f() {\n  1234.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  12_34.0\n}\n\"#,\n        r#\"fn f() {\n  1234.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  123_4.0\n}\n\"#,\n        r#\"fn f() {\n  1234.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1234_5.0\n}\n\"#,\n        r#\"fn f() {\n  12_345.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  12345_6.0\n}\n\"#,\n        r#\"fn f() {\n  123_456.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  123456_7.0\n}\n\"#,\n        r#\"fn f() {\n  1_234_567.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  1234567_8.0\n}\n\"#,\n        r#\"fn f() {\n  12_345_678.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -1_234.0\n}\n\"#,\n        r#\"fn f() {\n  -1234.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -12_34.0\n}\n\"#,\n        r#\"fn f() {\n  -1234.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -123_4.0\n}\n\"#,\n        r#\"fn f() {\n  -1234.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -1234_5.0\n}\n\"#,\n        r#\"fn f() {\n  -12_345.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -12345_6.0\n}\n\"#,\n        r#\"fn f() {\n  -123_456.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -123456_7.0\n}\n\"#,\n        r#\"fn f() {\n  -1_234_567.0\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  -1234567_8.0\n}\n\"#,\n        r#\"fn f() {\n  -12_345_678.0\n}\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"fn f() {\n  let #(1_234.0, _) = #(1_234.0, Nil)\n}\n\"#,\n        r#\"fn f() {\n  let #(1234.0, _) = #(1234.0, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  let #(12_34.0, _) = #(12_34.0, Nil)\n}\n\"#,\n        r#\"fn f() {\n  let #(1234.0, _) = #(1234.0, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  let #(1234567_8.0, _) = #(1234567_8.0, Nil)\n}\n\"#,\n        r#\"fn f() {\n  let #(12_345_678.0, _) = #(12_345_678.0, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  let #(-1_234.0, _) = #(-1_234.0, Nil)\n}\n\"#,\n        r#\"fn f() {\n  let #(-1234.0, _) = #(-1234.0, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  let #(-12_34.0, _) = #(-12_34.0, Nil)\n}\n\"#,\n        r#\"fn f() {\n  let #(-1234.0, _) = #(-1234.0, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"fn f() {\n  let #(-1234567_8.0, _) = #(-1234567_8.0, Nil)\n}\n\"#,\n        r#\"fn f() {\n  let #(-12_345_678.0, _) = #(-12_345_678.0, Nil)\n}\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = 1_234.0\n\"#,\n        r#\"const a_float = 1234.0\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = 12_34.0\n\"#,\n        r#\"const a_float = 1234.0\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = 1234567_8.0\n\"#,\n        r#\"const a_float = 12_345_678.0\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = -1_234.0\n\"#,\n        r#\"const a_float = -1234.0\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = -12_34.0\n\"#,\n        r#\"const a_float = -1234.0\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = -1234567_8.0\n\"#,\n        r#\"const a_float = -12_345_678.0\n\"#\n    );\n\n    assert_format_rewrite!(\n        r#\"const a_float = 1234.00\n\"#,\n        r#\"const a_float = 1234.0\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = 1234.00100\n\"#,\n        r#\"const a_float = 1234.001\n\"#\n    );\n    assert_format_rewrite!(\n        r#\"const a_float = 1234.001001\n\"#,\n        r#\"const a_float = 1234.001001\n\"#\n    );\n\n    assert_format!(\n        r#\"fn f() {\n  1.0e1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e-1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.0e1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.0e-1\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e10\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e-10\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.0e10\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -11.0e-10\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e-100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -1.0e100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  -11.0e-100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e100_100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.0e100_100\n}\n\"#\n    );\n    assert_format!(\n        r#\"fn f() {\n  1.001e100_100\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_string() {\n    assert_format!(\n        r#\"fn main() {\n  \"Hello\"\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  \"Hello\n\nWorld\"\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  \"\\\\n\\\\t\"\n}\n\"#\n    );\n}\n#[test]\nfn expr_seq() {\n    assert_format!(\n        r#\"fn main() {\n  1\n  2\n  3\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  first(1)\n  1\n}\n\"#\n    );\n}\n#[test]\nfn expr_lists() {\n    assert_format!(\n        \"fn main() {\n  []\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [1]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [\n    {\n      1\n      2\n    },\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [1, 2, 3]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [\n    1,\n    {\n      2\n      3\n    },\n    3,\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    [1, 2, 3],\n    really_long_variable_name,\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    [\n      really_long_variable_name,\n      really_long_variable_name,\n      really_long_variable_name,\n      2,\n      3,\n      [1, 2, 3, 4],\n    ],\n    really_long_variable_name,\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [1, 2, 3, ..x]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    ..tail\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  [\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    [\n      really_long_variable_name,\n      really_long_variable_name,\n      really_long_variable_name,\n      2,\n      3,\n      [1, 2, 3, 4],\n      ..tail\n    ],\n    really_long_variable_name,\n  ]\n}\n\"\n    );\n}\n\n#[test]\nfn expr_pipe() {\n    assert_format!(\n        r#\"fn main() {\n  1\n  |> really_long_variable_name\n  |> really_long_variable_name\n  |> really_long_variable_name\n  |> really_long_variable_name\n  |> really_long_variable_name\n  |> really_long_variable_name\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(\n    1\n      |> succ\n      |> succ,\n    2,\n    3,\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  some_call(\n    1\n      |> succ\n      |> succ,\n    2,\n    3,\n  )\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  [\n    1\n      |> succ\n      |> succ,\n    2,\n    3,\n  ]\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let x =\n    1\n    |> succ\n    |> succ\n  x\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(1, 2)\n  |> pair.first\n  |> should.equal(1)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  #(1, 2)\n  |> pair.first(1, 2, 4)\n  |> should.equal(1)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1\n  // 1\n  |> func1\n  // 2\n  |> func2\n}\n\"#\n    );\n\n    // https://github.com/gleam-lang/gleam/issues/618\n\n    assert_format!(\n        r#\"fn main() {\n  {\n    1\n    2\n  }\n  |> func\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  1\n  |> {\n    1\n    2\n  }\n}\n\"#\n    );\n\n    // https://github.com/gleam-lang/gleam/issues/658\n    assert_format!(\n        r#\"fn main() {\n  { os.system_time(os.Millisecond) < june_12_2020 * 1_000_000 }\n  |> should.equal(True)\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  { os.system_time(os.Millisecond) < june_12_2020 * 1_000_000 }\n  |> transform\n  |> should.equal(True)\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let() {\n    assert_format!(\n        r#\"fn main() {\n  let x = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let1() {\n    assert_format!(\n        r#\"fn main() {\n  let assert x = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let2() {\n    assert_format!(\n        r#\"fn main() {\n  let x = {\n    let y = 1\n    y\n  }\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let3() {\n    assert_format!(\n        r#\"fn main() {\n  let x = {\n    1\n    2\n  }\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let4() {\n    assert_format!(\n        r#\"fn main() {\n  let y = case x {\n    1 -> 1\n    _ -> 0\n  }\n  y\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let5() {\n    assert_format!(\n        r#\"fn main() {\n  let y = case x {\n    1 -> 1\n\n    _ -> 0\n  }\n  y\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let6() {\n    assert_format!(\n        r#\"fn main() {\n  let x = fn(x) { x }\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let7() {\n    assert_format!(\n        r#\"fn main() {\n  let x = fn() {\n    1\n    2\n  }\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let8() {\n    assert_format!(\n        r#\"fn main() {\n  let x = fn(\n    state: state,\n    acc: visitor_acc,\n    visitor: fn(visitor_acc, Pid(a)) -> new_visitor_acc,\n  ) {\n    1\n    2\n  }\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let9() {\n    assert_format!(\n        r#\"fn main() {\n  let x = fn(\n    state: state,\n    acc: visitor_acc,\n    visitor: fn(visitor_acc, Pid(a)) -> new_visitor_acc,\n  ) {\n    2\n  }\n  x\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_let10() {\n    assert_format!(\n        r#\"fn main() {\n  let dict = map.from_list([#(\"a\", 0), #(\"b\", 1), #(\"c\", 2), #(\"d\", 3)])\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_simple() {\n    // Pattern::Float\n    assert_format!(\n        r#\"fn main() {\n  let 1 = 1\n  Nil\n}\n\"#\n    );\n\n    // Pattern::String\n    assert_format!(\n        r#\"fn main() {\n  let 1.0 = 1\n  Nil\n}\n\"#\n    );\n\n    // Pattern::Var\n    assert_format!(\n        r#\"fn main() {\n  let x = 1\n  let y = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn breakable_pattern() {\n    assert_format!(\n        r#\"fn main() {\n  let Ok(Thingybob(\n    one: _one,\n    two: _two,\n    three: _three,\n    four: _four,\n    five: _five,\n    six: _six,\n  )) = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_let() {\n    assert_format!(\n        r#\"fn main() {\n  let x as y = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let #(x, y, 123 as z) = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_discard() {\n    assert_format!(\n        r#\"fn main() {\n  let _ = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let _wibble = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_lists() {\n    assert_format!(\n        r#\"fn main() {\n  let [] = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let [1] = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let [1, 2, 3, 4] = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let [1, 2, 3, 4, ..x] = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let [\n    really_long_variable_name,\n    really_long_variable_name,\n    really_long_variable_name,\n    [1, 2, 3, 4, xyz],\n    ..thingy\n  ] = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_constructor() {\n    assert_format!(\n        r#\"fn main() {\n  let True = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let False = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let Ok(1) = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let Person(name, age: the_age) = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let Person(name: the_name, age: the_age) = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let Person(age: age, name: name) = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let Person(age: really_long_variable_name, name: really_long_variable_name) =\n    1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_tuple() {\n    assert_format!(\n        r#\"fn main() {\n  let #() = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let #(x) = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let #(x, y) = 1\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let #(x, y, z) = 1\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 -> {\n      1\n      2\n    }\n    1 -> 1\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 -> {\n      let x = 1\n      x\n    }\n    1 -> 1\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn do() {\n  case list {\n    [x, ..xs] -> {\n      let x = 1\n      x\n    }\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn do() {\n  case list {\n    [x, ..xs] -> {\n      let x = 1\n      x\n      1\n      2\n      3\n      4\n    }\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        \"fn main() {\n  case x {\n    1 -> 2\n\n    2 -> 3\n\n    _ -> 0\n  }\n}\n\"\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case bool {\n    True -> {\n      \"Wibble\"\n      |> io.println\n\n      \"Wobble\"\n      |> io.println\n\n      Nil\n    }\n    False -> Nil\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case_nested() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 ->\n      case x {\n        1 -> 1\n        _ -> 0\n      }\n    1 -> 1\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case list {\n    [x] ->\n      case x {\n        _ -> 1\n      }\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case_then_fn() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 -> fn(x) { x }\n    1 -> 1\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 -> fn() {\n      1\n      2\n    }\n    1 -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case_multiple_subjects() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 -> 1\n    1 -> 1\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1, 2, 3, 4 {\n    1, 2, 3, 4 -> 1\n    1, 2, 3, 4 -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case_alternative_patterns() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    1 | 2 | 3 -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1, 2 {\n    1, 1 | 2, 2 | 3, 3 -> Nil\n    1, 1 | 2, 2 | 3, 3 -> Nil\n    1, 1 | 2, 2 | 3, 3 -> Nil\n    1, 1 | 2, 2 | 3, 3 -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case pat {\n    pat.Typeof(\"Boolean\", pat)\n    | pat.Typeof(\"Number\", pat)\n    | pat.Typeof(\"String\", pat) -> Nil\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case_clause_guards() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    _ if x == y -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case \"x\" {\n    _ if x == \"x\" -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case #(1, 2, 3) {\n    _ if x == #(1, 2, 3) -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"type Test {\n  Test(x: Int, y: Float)\n}\n\npub fn main() {\n  let x = Test(1, 3.0)\n  case x {\n    _ if x == Test(1, 1.0) -> 1\n    _ if x == Test(y: 2.0, x: 2) -> 2\n    _ if x != Test(2, 3.0) -> 2\n    _ -> 0\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    _ if x != y -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    _ if x || y -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    _ if x && y -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    _ if x != y && x == z -> Nil\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_case_clause_comments() {\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    // Hello Louis!\n    1 | 2 | 3 -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    // Hello José!\n    1 | 2 -> Nil\n    // Hello Louis!\n    n -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case 1 {\n    // Hello Joe!\n    1 | 2 -> Nil\n\n    // Hello Louis!\n    n -> Nil\n  }\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  case pat {\n    // Hello Ada\n    pat.Typeof(\"Boolean\", pat) | pat.Typeof(\"Number\", pat) -> True\n\n    // Hello Alan\n    pat.Typeof(\"Boolean\", pat)\n    | pat.Typeof(\"Number\", pat)\n    | pat.Typeof(\"String\", pat) -> False\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn field_access() {\n    assert_format!(\n        r#\"fn main() {\n  one.two\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  one.two.three.four\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_access() {\n    assert_format!(\n        r#\"fn main() {\n  tup.0\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_access1() {\n    assert_format!(\n        r#\"fn main() {\n  tup.1\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_access2() {\n    assert_format!(\n        r#\"fn main() {\n  tup.777\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_access3() {\n    assert_format!(\n        r#\"fn main() {\n  tup.1.2\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_panic() {\n    assert_format!(\n        \"fn main() {\n  panic\n}\n\"\n    );\n}\n\n#[test]\nfn expr_panic_as() {\n    assert_format!(\n        r#\"fn main() {\n  panic as \"panicking\"\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_panic_as_value() {\n    assert_format!(\n        r#\"fn main() {\n  let x = \"panicking\" <> \"with a value\"\n  panic as x\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_todo_as_value() {\n    assert_format!(\n        r#\"fn main() {\n  let x = \"Need to\" <> \"do this\"\n  todo as x\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_todo() {\n    assert_format!(\n        \"fn main() {\n  todo\n}\n\"\n    );\n}\n\n#[test]\nfn expr_todo_with_label() {\n    assert_format!(\n        r#\"fn main() {\n  todo as \"todo with a label\"\n}\n\"#\n    );\n}\n\n#[test]\nfn expr_todo1() {\n    assert_format_rewrite!(\n        r#\"fn main() {\n  fn() {}\n}\n\"#,\n        r#\"fn main() {\n  fn() { todo }\n}\n\"#\n    );\n}\n\n#[test]\nfn doc_comments_test() {\n    assert_format!(\n        \"/// one\nfn main() {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn doc_comments_1_test() {\n    assert_format!(\n        \"/// one\n///two\nfn main() {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn doc_comments_2_test() {\n    assert_format!(\n        r#\"/// one\n///two\n@external(javascript, \"\", \"\")\nfn whatever() -> Nil\n\"#\n    );\n}\n\n#[test]\nfn doc_comments_3_test() {\n    assert_format!(\n        r#\"/// one\n///two\ntype Thingy\n\"#\n    );\n}\n\n#[test]\nfn doc_comments_4_test() {\n    assert_format!(\n        r#\"/// one\n///two\ntype Thingy\n\"#\n    );\n}\n\n#[test]\nfn doc_comments_5_test() {\n    assert_format!(\n        r#\"/// one\n///two\ntype Whatever {\n  Whatever\n}\n\"#\n    );\n}\n\n#[test]\nfn doc_comments_6_test() {\n    assert_format!(\n        r#\"/// one\n///two\ntype Whatever =\n  Int\n\"#\n    );\n}\n\n#[test]\nfn comments3() {\n    assert_format!(\n        \"// one\nfn main() {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn comments4() {\n    assert_format!(\n        \"// one\n//two\nfn main() {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn comments5() {\n    assert_format!(\n        r#\"// one\n//two\n@external(javascript, \"\", \"\")\nfn whatever() -> Nil\n\"#\n    );\n}\n\n#[test]\nfn comments9() {\n    assert_format!(\n        r#\"// one\n//two\ntype Whatever =\n  Int\n\"#\n    );\n}\n\n#[test]\nfn comment23() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  1\n}\n\"\n    );\n}\n\n#[test]\nfn comment24() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  1.0\n}\n\"\n    );\n}\n\n#[test]\nfn comment25() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn comment14() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  []\n}\n\"\n    );\n}\n\n#[test]\nfn comment15() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  [\n    // One\n    1,\n    // Two\n    2,\n  ]\n}\n\"\n    );\n}\n\n#[test]\nfn comment16() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  [\n    // One\n    1,\n    // Two\n    2,\n    [\n      // Five\n      3,\n      [\n        // Four\n        4,\n      ],\n    ],\n  ]\n}\n\"\n    );\n}\n\n#[test]\nfn comment17() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  // world\n  one(\n    // One\n    1,\n    // Two\n    2,\n    two(\n      // Five\n      3,\n      three(\n        // Four\n        4,\n      ),\n    ),\n  )\n}\n\"\n    );\n}\n\n#[test]\nfn comment18() {\n    assert_format!(\n        \"fn main() {\n  // Hello\n  1\n  // world\n  2\n}\n\"\n    );\n}\n\n#[test]\nfn comment19() {\n    assert_format!(\n        \"fn main() {\n  let // hello\n  x = 1\n  x\n}\n\"\n    );\n}\n\n#[test]\nfn comment20() {\n    assert_format!(\n        \"fn main() {\n  let [\n    // 1\n    1,\n    // 2\n    2,\n  ] = xs\n  x\n}\n\"\n    );\n}\n\n#[test]\nfn comment21() {\n    assert_format!(\n        \"pub type Spec {\n  Spec(\n    // Hello\n    hello: Int,\n    // World\n    world: Int,\n  )\n}\n\"\n    );\n}\n\n#[test]\nfn comment22() {\n    assert_format!(\n        \"/// ß↑e̊\n///\npub fn one() {\n  1\n}\n\npub fn two() {\n  2\n}\n\",\n    );\n}\n\n#[test]\nfn trailing_comments() {\n    assert_format!(\n        \"fn main() {\n  x\n}\n// Hello world\n// ok!\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  x\n}\n/// Hello world\n/// ok!\n\"\n    );\n    assert_format!(\n        \"fn main() {\n  x\n}\n/// Hello world\n/// ok!\n// Hello world\n// ok!\n\"\n    );\n}\n\n#[test]\nfn commented_fn_arguments() {\n    assert_format!(\n        \"fn main(\n  // comment\n  label argument: Type,\n) {\n  x\n}\n\"\n    );\n}\n\n#[test]\nfn commented_fn_arguments1() {\n    assert_format!(\n        \"fn main(\n  // comment1\n  label argument1: Type,\n  // comment2\n  label argument2: Type,\n) {\n  x\n}\n\"\n    );\n}\n\n#[test]\nfn commented_fn_arguments2() {\n    assert_format!(\n        \"@external(erlang, \\\"\\\", \\\"\\\")\npub fn main(\n  // comment1\n  argument1: Type,\n  // comment2\n  argument2: Type,\n) -> Int\n\"\n    );\n}\n\n#[test]\nfn commented_binop() {\n    assert_format!(\n        \"fn main() {\n  1\n  // hello\n  + 2\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  // one\n  1\n  // two\n  + 2\n  // three\n  + 3\n}\n\"\n    );\n}\n\n#[test]\nfn commented_constructors() {\n    assert_format!(\n        \"pub type Number {\n  // 1\n  One\n  // 2\n  Two\n  // 3\n  Three\n  // ???\n  More\n}\n\"\n    );\n\n    assert_format!(\n        \"pub type Number {\n  /// 1\n  One\n  /// 2\n  Two\n  /// 3\n  Three\n  /// ???\n  More\n}\n\"\n    );\n\n    assert_format!(\n        \"pub type Number {\n  // a\n  /// 1\n  One\n  // b\n  /// 2\n  Two\n  // c\n  /// 3\n  Three\n  // defg\n  /// ???\n  More\n}\n\"\n    );\n\n    assert_format!(\n        \"pub type Number {\n  /// 1\n  One(value: Int)\n  /// > 1\n  Many(value: Int)\n}\n\"\n    );\n}\n\n#[test]\nfn function_captures_test() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  run(_)\n}\n\",\n        \"pub fn main() {\n  run\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  run(1, 2, _, 4, 5)\n}\n\"\n    );\n\n    assert_format_rewrite!(\n        \"pub fn main() {\n  run(1, 2, _, 4, 5)(_)\n}\n\",\n        \"pub fn main() {\n  run(1, 2, _, 4, 5)\n}\n\"\n    );\n}\n\n#[test]\nfn pattern_record_spread() {\n    assert_format!(\n        \"type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\nfn main() {\n  let triple = Triple(1, 2, 3)\n  let Triple(the_a, c: the_c, ..) = triple\n  the_c\n}\n\"\n    );\n\n    // Formats the operator spread syntax with long names\n    assert_format!(\n        \"type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\nfn main() {\n  let triple = Triple(1, 2, 3)\n  let Triple(\n    really_really_long_variable_name_a,\n    c: really_really_long_variable_name_c,\n    ..,\n  ) = triple\n  really_really_long_variable_name_c\n}\n\"\n    );\n\n    // https://github.com/gleam-lang/gleam/issues/776\n    assert_format!(\n        \"fn main() {\n  let Triple(..) = triple()\n  1\n}\n\"\n    );\n}\n\n#[test]\nfn empty_lines() {\n    assert_format!(\n        \"pub fn main() {\n  1\n\n  2\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  // one\n  1\n\n  // two\n  2\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  // one\n  1\n\n  // two\n  2\n\n  // three\n  3\n}\n\"\n    );\n\n    assert_format!(\n        \"pub type Number {\n  One\n\n  Two\n\n  Three\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  let x = 1\n\n  x\n}\n\"\n    );\n\n    // Lines with only spaces are treated as empty\n    assert_format_rewrite!(\n        \"pub fn main() {\n  let x = 1\\n    \\n  x\n}\n\",\n        \"pub fn main() {\n  let x = 1\n\n  x\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n}\n\"\n    );\n}\n\n#[test]\nfn modules_docs() {\n    assert_format!(\n        \"//// One\n//// Two\n//// Three\n\npub fn main() {\n  let x = 1\n\n  x\n}\n\"\n    );\n\n    assert_format!(\n        \"////\n////\n////\n////\n////\n\ntype X {\n  X\n}\n// Hello\n\"\n    );\n}\n\n#[test]\nfn binary_operator_precedence() {\n    assert_format!(\n        \"fn main() {\n  { 1 + 2 } * 3\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  3 * { 1 + 2 }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  3\n  * {\n    1\n    |> inc\n  }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  {\n    1\n    |> inc\n  }\n  * 3\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  1\n  |> { a || b }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  { a || b }\n  |> go\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/868\n#[test]\nfn precedence_rhs() {\n    assert_format!(\n        \"fn main() {\n  True != { a == b }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  True != { a == { b != c } }\n}\n\"\n    );\n}\n\n#[test]\nfn module_constants() {\n    assert_format!(\n        \"pub const str = \\\"a string\\\"\n\nconst my_constant: String = \\\"Hello\\\"\n\npub const int = 4\n\npub const float = 3.14\n\"\n    );\n}\n\n#[test]\nfn concise_wrapping_of_simple_lists() {\n    assert_format!(\n        \"pub fn main() {\n  [\n    100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400,\n    1500, 1600, 1700, 1800, 1900, 2000,\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  [\n    1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 11.0, 12.0, 13.0, 14.0,\n    15.0, 16.0, 17.0, 18.0, 19.0, 2.0,\n  ]\n}\n\"\n    );\n\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\",\n    \"ten\", \"eleven\", \"twelve\",\n  ]\n}\n\"#\n    );\n\n    assert_format!(\n        \"const values = [\n  100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400,\n  1500, 1600, 1700, 1800, 1900, 2000,\n]\n\"\n    );\n\n    assert_format!(\n        \"const values = [\n  1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 11.0, 12.0, 13.0, 14.0, 15.0,\n  16.0, 17.0, 18.0, 19.0, 2.0,\n]\n\"\n    );\n\n    assert_format!(\n        r#\"const values = [\n  \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\", \"ten\",\n  \"eleven\", \"twelve\",\n]\n\"#\n    );\n}\n\n#[test]\nfn commented_labelled_arguments() {\n    assert_format!(\n        \"fn main() {\n  Emulator(\n    // one\n    one: 1,\n    // two\n    two: 1,\n  )\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  my_func(\n    // one\n    one: 1,\n    // two\n    two: 1,\n  )\n}\n\"\n    );\n}\n\n#[test]\nfn module_rewrites_test() {\n    // Module comments are moved to the top\n    assert_format_rewrite!(\n        \"//// One\n\n//// Two\n\nfn main() {\n  1\n}\n//// Three\n\n//// Four\n\",\n        \"//// One\n//// Two\n//// Three\n//// Four\n\nfn main() {\n  1\n}\n\",\n    );\n\n    // Superfluous function captures are removed from pipe expressions\n    assert_format_rewrite!(\n        \"fn main() {\n  1\n  |> run(_, 1)\n}\n\",\n        \"fn main() {\n  1\n  |> run(1)\n}\n\",\n    );\n\n    assert_format_rewrite!(\n        \"fn main() {\n  1\n  |> run(_)\n}\n\",\n        \"fn main() {\n  1\n  |> run\n}\n\",\n    );\n\n    assert_format_rewrite!(\n        \"fn main() {\n  let some_really_long_variable_name_to_force_wrapping = 1\n  let bits = <<\n      some_really_long_variable_name_to_force_wrapping,\n      some_really_long_variable_name_to_force_wrapping,\n    >>\n  bits\n}\n\",\n        \"fn main() {\n  let some_really_long_variable_name_to_force_wrapping = 1\n  let bits = <<\n    some_really_long_variable_name_to_force_wrapping,\n    some_really_long_variable_name_to_force_wrapping,\n  >>\n  bits\n}\n\",\n    );\n}\n\n// TODO: improve. This is too wide\n#[test]\n// https://github.com/gleam-lang/gleam/issues/748\nfn assignments_break_value_first_test() {\n    assert_format!(\n        r#\"fn main() {\n  let assert Ok(1) = [\n    10_000_000_000_000_000_000_000_000_001,\n    20_000_000_000_000_000_000_000_000_001,\n    30_000_000_000_000_000_000_000_000_001,\n    40_000_000_000_000_000_000_000_000_001,\n  ]\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let assert Ok(1) = [\n    1_000_000_000_000_000_000_000_000_000, 2_000_000_000_000_000_000_000_000_000,\n    3_000_000_000_000_000_000_000_000_000, 4_000_000_000_000_000_000_000_000_000,\n  ]\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let assert <<11, 2, 4, 5, 6>> = [\n    10_000_000_000_000_000_000_000_000_001,\n    20_000_000_000_000_000_000_000_000_001,\n    30_000_000_000_000_000_000_000_000_001,\n    40_000_000_000_000_000_000_000_000_001,\n  ]\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let assert <<11, 2, 4, 5, 6>> = [\n    1_000_000_000_000_000_000_000_000_000, 2_000_000_000_000_000_000_000_000_000,\n    3_000_000_000_000_000_000_000_000_000, 4_000_000_000_000_000_000_000_000_000,\n  ]\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let assert [11, 2, 4, 5, 6] = [\n    10_000_000_000_000_000_000_000_000_001,\n    20_000_000_000_000_000_000_000_000_001,\n    30_000_000_000_000_000_000_000_000_001,\n    40_000_000_000_000_000_000_000_000_001,\n  ]\n  Nil\n}\n\"#\n    );\n\n    assert_format!(\n        r#\"fn main() {\n  let assert [11, 2, 4, 5, 6] = [\n    1_000_000_000_000_000_000_000_000_000, 2_000_000_000_000_000_000_000_000_000,\n    3_000_000_000_000_000_000_000_000_000, 4_000_000_000_000_000_000_000_000_000,\n  ]\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn function_type_type() {\n    assert_format!(\n        \"type F =\n  fn(some, really, long, set, of, arguments) ->\n    #(some, really, long, set, of, arguments)\n\"\n    );\n}\n\n#[test]\nfn tuple_constant() {\n    assert_format!(\n        \"const x: #(Int, Int) = #(1, 2)\n\"\n    );\n}\n\n#[test]\nfn var_constant() {\n    assert_format!(\n        r#\"const x = 1\n\nconst x_alias = x\n\nfn f(i: Int) -> Int {\n  i\n}\n\nconst f_alias: fn(Int) -> Int = f\n\"#\n    );\n}\n\n#[test]\nfn let_as_expression() {\n    assert_format!(\n        \"pub fn main() {\n  let x = 1\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  let x = {\n    let y = 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn assert_as_expression() {\n    assert_format!(\n        \"pub fn main() {\n  let assert x = 1\n}\n\"\n    );\n\n    assert_format!(\n        \"pub fn main() {\n  let assert x = {\n    let assert y = 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn case_in_call() {\n    assert_format!(\n        \"fn clause_guard_tests(_fns) -> List(Test) {\n  example(fn() {\n    assert_equal(0, case Nil {\n      _ if yes -> 0\n      _ -> 1\n    })\n  })\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1390\n#[test]\nfn list_spread_pattern() {\n    assert_format!(\n        \"pub fn main(x) {\n  case x {\n    [y, ..] -> y\n    _ -> 0\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1431\n#[test]\nfn first_argument_capture_special_case_list() {\n    assert_format!(\n        r#\"pub fn main(x) {\n  wibble(_, [\n    \"one argument that is both breakable and long enough to cause it to wrap\",\n  ])\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1431\n#[test]\nfn first_argument_capture_special_case_fn() {\n    assert_format!(\n        r#\"pub fn main(x) {\n  wibble(_, fn() {\n    \"one argument that is both breakable and long enough to cause it to wrap\"\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn negation() {\n    assert_format!(\n        \"pub fn negate(x) {\n  !x\n}\n\"\n    );\n}\n\n#[test]\nfn negation_block() {\n    assert_format!(\n        \"pub fn negate(x) {\n  !{\n    123\n    x\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn empty_lines_work_with_trailing_space() {\n    let src = \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  // Comment\n\n  1\n\n\n  // Comment\n\n\n  2\n}\n\";\n    let expected = \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  // Comment\n\n  1\n\n  // Comment\n\n  2\n}\n\";\n    // We first make extra sure we've not messed up the expected output and\n    // check it's well formatted.\n    assert_format!(expected);\n\n    assert_format_rewrite!(src, expected);\n}\n\n#[test]\nfn empty_lines_work_with_eol_normalisation() {\n    let src = \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  // Comment\n\n  1\n\n\n  // Comment\n\n\n  2\n}\n\";\n    let expected = \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  // Comment\n\n  1\n\n  // Comment\n\n  2\n}\n\";\n\n    // We first make extra sure we've not messed up the expected output and\n    // check it's well formatted.\n    assert_format!(expected);\n\n    assert_format_rewrite!(&src.replace('\\n', \"\\r\\n\"), expected);\n    assert_format_rewrite!(&src.replace('\\n', \"\\r\"), expected);\n}\n\n#[test]\nfn empty_lines_work_with_trailing_space_and_eol_normalisation() {\n    let src = \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  // Comment\n\n  1\n\n\n  // Comment\n\n\n  2\n}\n\";\n    let expected = \"pub fn main() {\n  let inc = fn(a) { a + 1 }\n\n  pair.map_first(#(1, 2), inc)\n  |> should.equal(#(2, 2))\n\n  // Comment\n\n  1\n\n  // Comment\n\n  2\n}\n\";\n\n    // We first make extra sure we've not messed up the expected output and\n    // check it's well formatted.\n    assert_format!(expected);\n\n    assert_format_rewrite!(src.replace('\\n', \"\\r\\n\"), expected);\n    assert_format_rewrite!(&src.replace('\\n', \"\\r\"), expected);\n}\n#[test]\nfn single_empty_line_between_comments() {\n    // empty line isn't added if it's not already present\n    assert_format!(\n        \"pub fn wibble() {\n  // wibble\n  // wobble\n  123\n}\n\"\n    );\n}\n\n#[test]\nfn single_empty_line_between_comments1() {\n    // single empty line between comments/statement preserved\n    assert_format!(\n        \"pub fn wibble() {\n  // wibble\n\n  // wobble\n\n  123\n}\n\"\n    );\n}\n\n#[test]\nfn single_empty_line_between_comments2() {\n    // multiple consecutive empty lines condensed into one\n    assert_format_rewrite!(\n        \"pub fn wibble() {\n  // wibble\n\n\n  // wobble\n\n\n  123\n}\n\",\n        \"pub fn wibble() {\n  // wibble\n\n  // wobble\n\n  123\n}\n\"\n    );\n}\n\n#[test]\nfn single_empty_line_between_comments3() {\n    // freestanding comments keep empty lines\n    assert_format!(\n        \"// wibble\n\n// wobble\n\"\n    );\n}\n\n#[test]\nfn single_empty_line_between_comments4() {\n    // freestanding comments condense consecutive empty lines\n    assert_format_rewrite!(\n        \"// wibble\n\n\n// wobble\n\",\n        \"// wibble\n\n// wobble\n\",\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1640\n#[test]\nfn no_newline_before_comments() {\n    assert_format!(\n        \"// wibble\n// wobble\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1647\n#[test]\nfn list_at_end_of_long_expr_line() {\n    assert_format!(\n        \"pub fn example() {\n  Ok(\n    RecordConstructorWithALongName(\n      a_field: RecordConstructorWithALongName(a_field: Record(a_field: [])),\n    ),\n  )\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1647\n#[test]\nfn list_at_end_of_long_pattern_line() {\n    assert_format!(\n        \"pub fn example() {\n  let assert LongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLong([]) =\n    1\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1647\n#[test]\nfn list_at_end_of_long_constant_line() {\n    assert_format!(\n        \"const longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong = []\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1649\n#[test]\nfn dont_remove_braces_when_accessing_tuple() {\n    assert_format!(\n        r#\"fn main() {\n  { typed.0 }.type_\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1681\n#[test]\nfn wrap_case_subjects() {\n    assert_format!(\n        r#\"fn main() {\n  case\n    \"This is a really really long string to force wrapping\",\n    \"This is a really really long string to force wrapping\",\n    \"This is a really really long string to force wrapping\",\n    \"This is a really really long string to force wrapping\"\n  {\n    _, _, _, _ -> Nil\n  }\n}\n\"#\n    );\n}\n\n// A bug reported on Discord. This would cause a compiler crash.\n#[test]\nfn multiple_empty_line_collapse_bug() {\n    assert_format_rewrite!(\n        r#\"// Comment\n\n\n\nconst x = 1\n\"#,\n        r#\"// Comment\n\nconst x = 1\n\"#\n    );\n}\n\n#[test]\nfn do_not_remove_required_braces_case_guard() {\n    assert_format!(\n        \"fn main() {\n  let is_enabled = False\n  let is_confirmed = False\n  let is_admin = True\n  case is_enabled, is_confirmed, is_admin {\n    is_enabled, is_confirmed, is_admin\n      if is_enabled && { is_confirmed || is_admin }\n    -> Nil\n    _, _, _ -> Nil\n  }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  let wibble = True\n  case wibble {\n    wibble if True != { 1 == 2 } -> Nil\n    _ -> Nil\n  }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    wibble if True != { 1 == { wobble == wibble } } -> Nil\n    _ -> Nil\n  }\n}\n\"\n    );\n\n    assert_format!(\n        \"fn main() {\n  let wibble = #(10, [0])\n  case wibble {\n    wibble if True && { wibble.0 == 10 || wibble.0 == 1 } -> Nil\n    _ -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_remove_braces_from_case_guard() {\n    assert_format!(\n        \"fn main() {\n  let is_enabled = False\n  let is_confirmed = False\n  let is_admin = True\n  case is_enabled, is_confirmed, is_admin {\n    is_enabled, is_confirmed, is_admin\n      if { is_enabled && is_confirmed } || is_admin\n    -> Nil\n    _, _, _ -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_remove_braces_from_case_guard_2() {\n    assert_format!(\n        \"fn main() {\n  let wibble = #(10, [0])\n  case wibble {\n    wibble if True && { wibble.0 == 10 } -> Nil\n    _ -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn const_multi_line_string_breaks() {\n    assert_format!(\n        r#\"const string = [\n  \"hello\nworld\",\n]\n\"#\n    );\n}\n\n#[test]\nfn expr_multi_line_string_breaks() {\n    assert_format!(\n        r#\"pub fn main() {\n  let string = [\n    \"hello\nworld\",\n  ]\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1724\n#[test]\nfn case_subject_block() {\n    assert_format!(\n        r#\"pub fn main() {\n  case\n    {\n      let assert Ok(x) = thing()\n      let assert Ok(y) = thing()\n      x + y\n    }\n  {\n    _ -> Nil\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn qualified_const_fn() {\n    assert_format!(\n        r#\"import other\n\nconst x = other.function\n\"#\n    );\n}\n\n#[test]\nfn qualified_const_fn_fn_after() {\n    assert_format!(\n        r#\"import other\n\nconst x = other.function\n\npub fn main() {\n  io.println(\"Hello, Joe!\")\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1872\n#[test]\nfn multiple_line_spread_list_comments() {\n    assert_format!(\n        r#\"fn main() {\n  [\n    // First!\n    // First?\n    1,\n    // Spread!\n    // Spread?\n    ..[2, 3]\n  ]\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1872\n#[test]\nfn list_spread_comment_pattern() {\n    assert_format!(\n        r#\"fn main() {\n  let assert [\n    1,\n    // Spread!\n    // Spread?\n    ..rest\n  ] = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1872\n#[test]\nfn list_spread_discard_comment_pattern() {\n    assert_format!(\n        r#\"fn main() {\n  let assert [\n    1,\n    // Spread!\n    // Spread?\n    ..\n  ] = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1786\n#[test]\nfn multiple_line_documentation_comment_statement_grouping() {\n    assert_format!(\n        r#\"/// This is the first line of the documentation comment.\n/// This is the second line of the documentation comment.\n/// This is the third line of the documentation comment.\npub type Map(key, value)\n\"#\n    );\n}\n\n#[test]\nfn not_and() {\n    assert_format!(\n        r#\"pub fn main() {\n  !{ True && False }\n}\n\"#\n    );\n}\n\n#[test]\nfn not_or() {\n    assert_format!(\n        r#\"pub fn main() {\n  !{ True || False }\n}\n\"#\n    );\n}\n\n#[test]\nfn not_add() {\n    assert_format!(\n        r#\"pub fn main() {\n  !{ 1 + 3 }\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_assert() {\n    assert_format_rewrite!(\n        r#\"fn main(x) {\n  let assert True = x\n}\n\"#,\n        r#\"fn main(x) {\n  let assert True = x\n}\n\"#\n    );\n}\n\n#[test]\nfn negate() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = -        a\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = -a\n}\n\"#\n    );\n}\n\n#[test]\nfn double_negate() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = --a\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = a\n}\n\"#\n    );\n}\n\n#[test]\nfn triple_negate() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = -  -   - a\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = -a\n}\n\"#\n    );\n}\n\n#[test]\nfn binary_negate() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = -{a+3}\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = -{ a + 3 }\n}\n\"#\n    );\n}\n\n#[test]\nfn binary_double_negate() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = --{a + 3}\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = { a + 3 }\n}\n\"#\n    );\n}\n\n#[test]\nfn even_repeated_negate_after_subtract() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = 4\n  let c = a-------b\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = 4\n  let c = a - b\n}\n\"#\n    );\n}\n\n#[test]\nfn odd_repeated_negate_after_subtract() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = 4\n  let c = a--------b\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b = 4\n  let c = a - -b\n}\n\"#\n    );\n}\n\n#[test]\nfn double_negation_on_bools_is_removed() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  !!True\n}\n\"#,\n        \"pub fn main() {\n  True\n}\n\"\n    );\n}\n\n#[test]\nfn wrap_long_line_with_int_negation() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 3\n  let b = a * a * a * a * a * a * a * a * a * a * a * a * a *   { a * a * a * a * a * a * a * a * a * a }\n  let c = c * c * c * c * c * c * c * c * c * c * c * c * c * - { c * c * c * c * c * c * c * c * c * c }\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 3\n  let b =\n    a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * a\n    * { a * a * a * a * a * a * a * a * a * a }\n  let c =\n    c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * c\n    * -{ c * c * c * c * c * c * c * c * c * c }\n}\n\"#\n    );\n}\n\n#[test]\nfn wrap_long_line_with_bool_negation() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = True\n  let b = a || a || a || a || a || a || a || a || a || a || a || a || a ||   { a || a || a || a || a || a || a || a || a || a }\n  let c = c || c || c || c || c || c || c || c || c || c || c || c || c || ! { c || c || c || c || c || c || c || c || c || c }\n}\n\"#,\n        r#\"pub fn main() {\n  let a = True\n  let b =\n    a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || a\n    || { a || a || a || a || a || a || a || a || a || a }\n  let c =\n    c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || c\n    || !{ c || c || c || c || c || c || c || c || c || c }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1977\n#[test]\nfn preserve_single_expression_blocks() {\n    assert_format!(\n        r#\"pub fn main(x) {\n  case x {\n    1 -> {\n      1\n    }\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn calling_pipeline0() {\n    assert_format!(\n        r#\"pub fn main() {\n  {\n    one\n    |> two\n  }()\n}\n\"#\n    );\n}\n\n#[test]\nfn calling_pipeline1() {\n    assert_format!(\n        r#\"pub fn main() {\n  {\n    one\n    |> two\n  }(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn calling_pipeline2() {\n    assert_format!(\n        r#\"pub fn main() {\n  {\n    one\n    |> two\n  }(1, 2)\n}\n\"#\n    );\n}\n\n#[test]\nfn calling_pipeline_1_list() {\n    assert_format!(\n        r#\"pub fn main() {\n  {\n    one\n    |> two\n  }([1, 2, 3])\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2119\n#[test]\nfn empty_line_after_fn_with_return_annotation() {\n    assert_format!(\n        r#\"fn main() {\n  fn() -> String { \"\" }\n\n  0\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2174\n#[test]\nfn empty_line_after_crash() {\n    assert_format_rewrite!(\n        r#\"pub type One {\n  One // Comment\n\n}\n\n\"#,\n        r#\"pub type One {\n  One\n  // Comment\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2196\n#[test]\nfn comment_at_end_of_type() {\n    assert_format!(\n        r#\"pub type X {\n  X\n  // Afterwards\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_type_alias() {\n    assert_format!(\n        r#\"@deprecated(\"Deprecated type\")\npub type Tiger =\n  Nil\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2423\n#[test]\nfn prefix_as() {\n    assert_format!(\n        r#\"pub fn main(x) {\n  case x {\n    \"0\" as digit <> rest | \"1\" as digit <> rest -> rest\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn case_splits_function_on_newline() {\n    assert_format!(\n        r#\"pub fn main() {\n  case x {\n    1 ->\n      some_module.some_long_name_function([\n        some_module.some_long_name_function(),\n      ])\n    _ -> todo\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2442\n#[test]\nfn single_argument_list() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok([\n    some_long_variable_name_to_force_wrapping,\n    some_long_variable_name_to_force_wrapping,\n    some_long_variable_name_to_force_wrapping,\n  ])\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2442\n#[test]\nfn single_argument_function() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(fn() {\n    some_long_variable_name_to_force_wrapping()\n    some_long_variable_name_to_force_wrapping()\n    some_long_variable_name_to_force_wrapping()\n  })\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2442\n#[test]\nfn single_argument_tuple() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(#(\n    some_long_variable_name_to_force_wrapping,\n    some_long_variable_name_to_force_wrapping,\n    some_long_variable_name_to_force_wrapping,\n  ))\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2442\n#[test]\nfn single_argument_call() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(do_something(\n    some_long_variable_name_to_force_wrapping,\n    some_long_variable_name_to_force_wrapping,\n    some_long_variable_name_to_force_wrapping,\n  ))\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2442\n#[test]\nfn single_argument_call_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(\n    do_something(do_something_else(\n      some_long_variable_name_to_force_wrapping,\n      some_long_variable_name_to_force_wrapping,\n      some_long_variable_name_to_force_wrapping,\n    )),\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2442\n#[test]\nfn single_argument_call_nested_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  Ok(\n    do_something(\n      do_something_else(do_a_last_thing(\n        some_long_variable_name_to_force_wrapping,\n        some_long_variable_name_to_force_wrapping,\n        some_long_variable_name_to_force_wrapping,\n      )),\n    ),\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2512\n#[test]\nfn list_with_pipe_format() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    \"Success!\"\n      |> ansi(apply: [1, 31]),\n    \"\",\n    \"Wrote `\" <> bin <> \"`, `\" <> pwsh_bin <> \"`\",\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_close_to_line_limit() {\n    assert_format!(\n        r#\"pub fn main() {\n  function_call(\n    that,\n    is,\n    super,\n    close,\n    to,\n    the,\n    max,\n    line,\n    limit,\n    of,\n    80,\n    chars,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn multiline_string_are_not_broken_with_string_concatenation_if_they_fit() {\n    assert_format!(\n        r#\"pub fn main() {\n  \"pub fn wibble(\" <> arg <> \") ->\" <> type_ <> \"{\n    body\n}\"\n}\n\"#\n    );\n}\n\n#[test]\nfn nesting_goes_back_to_normal_after_multiline_string() {\n    assert_format!(\n        r#\"pub fn main() {\n  let x = {\n    \"\n1\n2\n\" <> long_name_function_call(\n      1_111_111_111_111_111,\n      222_222_222_222,\n      3_333_333_333_333_333,\n    )\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn multiline_string_get_broken_on_newlines_as_function_arguments() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    wobble,\n    \"wobble\n  wibble\n       wobble\",\n    wibble,\n    wobble,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_used_as_function_arguments_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    a_variable_with_a_long_name\n      |> another_variable_with_a_long_name\n      |> yet_another_variable_with_a_long_name,\n    wobble,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_used_as_function_arguments_is_not_nested_if_it_is_the_only_argument() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    a_variable_with_a_long_name\n    |> another_variable_with_a_long_name\n    |> yet_another_variable_with_a_long_name,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_inside_list_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    wibble,\n    a_variable_with_a_long_name\n      |> another_variable_with_a_long_name\n      |> yet_another_variable_with_a_long_name,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_inside_list_is_not_nested_if_only_item() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    a_variable_with_a_long_name\n    |> another_variable_with_a_long_name\n    |> yet_another_variable_with_a_long_name,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_inside_tuple_gets_nested() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    wibble,\n    a_variable_with_a_long_name\n      |> another_variable_with_a_long_name\n      |> yet_another_variable_with_a_long_name,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_inside_tuple_is_not_nested_if_only_item() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    a_variable_with_a_long_name\n    |> another_variable_with_a_long_name\n    |> yet_another_variable_with_a_long_name,\n  )\n}\n\"#\n    );\n}\n\n// github.com/gleam-lang/gleam/issues/2608\n#[test]\nfn comments_are_not_moved_out_of_list_of_literals() {\n    assert_format!(\n        r#\"fn main() {\n  [\n    1, 2,\n    // list\n  ]\n}\n\"#\n    );\n}\n\n// github.com/gleam-lang/gleam/issues/2608\n#[test]\nfn comments_are_not_moved_out_of_list() {\n    assert_format!(\n        r#\"fn main() {\n  [\n    wibble,\n    wobble,\n    // list\n  ]\n}\n\"#\n    );\n}\n\n// github.com/gleam-lang/gleam/issues/2608\n#[test]\nfn comments_are_not_moved_out_of_case_expressions() {\n    assert_format!(\n        r#\"fn main() {\n  case True {\n    _ -> Nil\n    // case\n  }\n}\n\"#\n    );\n}\n\n// github.com/gleam-lang/gleam/issues/2608\n#[test]\nfn comments_are_not_moved_out_of_tuples() {\n    assert_format!(\n        r#\"fn main() {\n  #(\n    1,\n    2,\n    // tuple\n  )\n}\n\"#\n    );\n}\n\n// github.com/gleam-lang/gleam/issues/2608\n#[test]\nfn comments_are_not_moved_out_of_function_calls() {\n    assert_format!(\n        r#\"fn main() {\n  call(\n    1,\n    2,\n    // function call\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2607\n#[test]\nfn function_arguments_after_comment_are_not_indented() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    // Wobble\n    1 + 1,\n    \"wibble\",\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2607\n#[test]\nfn tuple_items_after_comment_are_not_indented() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    // Wobble\n    1 + 1,\n    \"wibble\",\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2607\n#[test]\nfn list_items_after_comment_are_not_indented() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    // Wobble\n    1 + 1,\n    \"wibble\",\n  ]\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2990\n#[test]\nfn comments_are_not_moved_out_of_empty_list() {\n    assert_format!(\n        r#\"pub fn main() {\n  // This is an empty list!\n  [\n    // Nothing here...\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn empty_lists_with_comment_inside_are_indented_properly() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    [\n      // Nothing here...\n    ],\n    wibble_wobble_wibble_wobble_wibble_wobble_wibble_wobble,\n    [\n      // Nothing here as well!\n    ],\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2890\n#[test]\nfn piped_blocks_are_not_needlessly_indented() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    1,\n    {\n      \"long enough to need to wrap. blah blah blah blah blah blah blah blah blah\"\n    }\n      |> wibble,\n    3,\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2924\n#[test]\nfn record_update_fields_are_not_needlessly_broken() {\n    assert_format!(\n        r#\"pub fn main() {\n  Model(\n    ..model,\n    wibble: wibble_wobble_wibble_wobble + 1,\n    wobble: Some(wibble_wobble_wibble_wobble),\n  )\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2890\n#[test]\nfn piped_lists_are_not_needlessly_indented() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    [\n      [\"wibble wobble\", \"wibble\", \"wobble\"],\n      [\"long enough to go over\", \"line limit\"],\n    ]\n      |> list.concat,\n    todo,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_nested_pipe_chain() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    thing\n      // A comment\n      |> wibble\n      // Another comment\n      |> wobble,\n    thing,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_nested_binop_chain() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    thing\n      // A comment\n      <> wibble\n      // Another comment\n      <> wobble,\n    thing,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_binop_chain() {\n    assert_format!(\n        r#\"pub fn main() {\n  thing\n  // A comment\n  <> wibble\n  // Another comment\n  <> wobble\n}\n\"#\n    );\n}\n\n#[test]\nfn internal_attribute_on_function() {\n    assert_format!(\n        r#\"@internal\npub fn main() {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn internal_attribute_on_type() {\n    assert_format!(\n        r#\"@internal\npub type Type\n\"#\n    );\n}\n\n#[test]\nfn internal_attribute_on_const() {\n    assert_format!(\n        r#\"@internal\npub const wibble = 1\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_contant_list() {\n    assert_format!(\n        r#\"const wibble = [\n  // A comment\n  1, 2,\n  // Another comment\n  3,\n  // One last comment\n]\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_contant_empty_list() {\n    assert_format!(\n        r#\"const wibble = [\n  // A comment\n]\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_contant_tuple() {\n    assert_format!(\n        r#\"const wibble = #(\n  // A comment\n  1,\n  2,\n  // Another comment\n  3,\n  // One last comment\n)\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_contant_empty_tuple() {\n    assert_format!(\n        r#\"const wibble = #(\n  // A comment\n)\n\"#\n    );\n}\n\n#[test]\nfn comments_inside_empty_tuple() {\n    assert_format!(\n        r#\"pub fn main() {\n  #(\n    // A comment!\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_at_the_end_of_anonymous_function() {\n    assert_format!(\n        r#\"pub fn main() {\n  fn() {\n    1\n    // a final comment\n\n    // another final comment\n    // at the end of the block\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_in_anonymous_function_args() {\n    assert_format!(\n        r#\"pub fn main() {\n  fn(\n    // A comment 1\n    // A comment 2\n  ) {\n    1\n  }\n}\n\"#\n    );\n    assert_format!(\n        r#\"pub fn main() {\n  fn(\n    // A comment 1\n    a,\n    // A comment 2\n  ) {\n    1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn comments_after_last_argument_of_record_constructor() {\n    assert_format!(\n        r#\"type Record {\n  Record(\n    field: String,\n    // comment_line_1: String,\n    // comment_line_2: String,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn only_comments_in_record_constructor() {\n    assert_format!(\n        r#\"type Record {\n  Record(\n    // comment_line_1: String,\n    // comment_line_2: String,\n  )\n}\n\"#\n    );\n}\n#[test]\nfn comment_after_spread_operator() {\n    assert_format!(\n        \"type Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\nfn main() {\n  let triple = Triple(1, 2, 3)\n  let Triple(\n    really_really_long_variable_name_a,\n    c: really_really_long_variable_name_c,\n    ..,\n    // comment\n  ) = triple\n  really_really_long_variable_name_c\n}\n\"\n    );\n}\n\n#[test]\nfn multiline_comment_in_case_block() {\n    assert_format!(\n        r#\"pub fn do_len(list, acc) {\n  case list {\n    [] -> acc\n    [_, ..rest] -> rest |> do_len(acc + 1)\n    // Even the opposite wouldn't be optimised:\n    // { acc + 1 } |> do_len(rest, _)\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3190\n#[test]\nfn trailing_comments_inside_non_empty_bit_arrays_are_not_moved() {\n    assert_format!(\n        r#\"pub fn main() {\n  <<\n    1, 2,\n    // One and two are above me.\n  >>\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3210\n#[test]\nfn newlines_are_not_stripped_if_two_consecutive_anonymous_function_are_passed_as_arguments() {\n    assert_format!(\n        r#\"pub fn main() {\n  fun(\n    fn() {\n      wibble\n\n      wobble\n    },\n    fn() { wibble },\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn const_long_concat_string() {\n    assert_format_rewrite!(\n        r#\"const long_string = \"some\" <> \" very\" <> \" long\" <> \" string\" <> \" indeed\" <> \" please\" <> \" break\"\n\"#,\n        r#\"const long_string = \"some\"\n  <> \" very\"\n  <> \" long\"\n  <> \" string\"\n  <> \" indeed\"\n  <> \" please\"\n  <> \" break\"\n\"#\n    );\n}\n\n#[test]\nfn const_concat_short_unbroken() {\n    assert_format!(\n        r#\"const x = \"some\" <> \"short\" <> \"string\"\n\"#\n    );\n}\n\n#[test]\nfn const_concat_long_including_list() {\n    assert_format_rewrite!(\n        r#\"const x = \"some long string 1\" <> \"some long string 2\" <> [\"here is a list\", \"with several elements\", \"in order to make it be too long to fit on one line\", \"so we can see how it breaks\", \"onto multiple lines\"] <> \"and a last string\"\n\"#,\n        r#\"const x = \"some long string 1\"\n  <> \"some long string 2\"\n  <> [\n    \"here is a list\",\n    \"with several elements\",\n    \"in order to make it be too long to fit on one line\",\n    \"so we can see how it breaks\",\n    \"onto multiple lines\",\n  ]\n  <> \"and a last string\"\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3397\n#[test]\nfn comment_after_case_branch() {\n    assert_format!(\n        r#\"pub fn main() {\n  case x {\n    _ ->\n      // comment\n      [123]\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3397\n#[test]\nfn comment_after_case_branch_case() {\n    assert_format!(\n        r#\"pub fn main() {\n  case x {\n    _ ->\n      // comment\n      case y {\n        _ -> todo\n      }\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn label_shorthand_call_arg_is_split_like_regular_labelled_args() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    a_punned_arg_that_is_super_long:,\n    another_punned_arg:,\n    yet_another_pun:,\n    ok_thats_enough: wibble,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn commented_label_shorthand_call_arg_is_split_like_regular_labelled_args() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(\n    // A comment here\n    a_punned_arg_that_is_super_long:,\n    another_punned_arg:,\n    // And a comment there\n    yet_another_pun:,\n    ok_thats_enough: wibble,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn label_shorthand_pattern_arg_is_split_like_regular_labelled_patterns() {\n    assert_format!(\n        r#\"pub fn main() {\n  let Wibble(\n    a_punned_arg_that_is_super_long:,\n    another_punned_arg:,\n    yet_another_pun:,\n    ok_thats_enough: wibble,\n  ) = todo\n}\n\"#\n    );\n}\n\n#[test]\nfn record_pattern_with_no_label_shorthand() {\n    assert_format!(\n        r#\"pub fn main() {\n  let Wibble(x: x) = todo\n}\n\"#\n    );\n}\n\n#[test]\nfn record_with_no_label_shorthand() {\n    assert_format!(\n        r#\"pub fn main() {\n  Wibble(x: x)\n}\n\"#\n    );\n}\n\n#[test]\nfn function_without_label_shorthand() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble(x: x)\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2015\n#[test]\nfn doc_comments_are_split_by_regular_comments() {\n    assert_format!(\n        r#\"/// Doc comment\n// Commented function\n// fn wibble() {}\n\n/// Other doc comment\npub fn main() {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2015\n#[test]\nfn it_is_easy_to_tell_two_different_doc_comments_apart_when_a_regular_comment_is_separating_those()\n{\n    assert_format_rewrite!(\n        r#\"/// Doc comment\n// regular comment\n/// Other doc comment\npub fn main() {\n  todo\n}\n\"#,\n        r#\"/// Doc comment\n// regular comment\n\n/// Other doc comment\npub fn main() {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2015\n#[test]\nfn multiple_commented_definitions_in_a_row_2() {\n    assert_format!(\n        r#\"/// Stray comment\n// regular comment\n\n/// Stray comment\n// regular comment\n\n/// Doc comment\npub fn wibble() {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2015\n#[test]\nfn only_stray_comments_and_definition_with_no_doc_comments() {\n    assert_format!(\n        r#\"/// Stray comment\n// regular comment\n\n/// Stray comment\n// regular comment\n\npub fn wibble() {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2015\n#[test]\nfn only_stray_comments_and_definition_with_no_doc_comments_2() {\n    assert_format_rewrite!(\n        r#\"/// Stray comment\n// regular comment\npub fn wibble () {\n  todo\n}\n\"#,\n        r#\"/// Stray comment\n// regular comment\n\npub fn wibble() {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_in_pipe_is_not_turned_into_shorthand_label() {\n    assert_format!(\n        r#\"pub fn main() {\n  wibble |> wobble(one: 1, label: _, two: 2)\n}\n\"#\n    );\n}\n\n// Bug found by Louis\n#[test]\nfn internal_attribute_does_not_change_formatting_of_a_function() {\n    assert_format!(\n        r#\"@internal\npub fn init(\n  start: #(SupervisorFlags, List(ChildSpecification)),\n) -> Result(#(Dynamic, Dynamic), never) {\n  todo\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3627\n#[test]\nfn big_grapheme_cluster() {\n    assert_format!(\n        r#\"pub fn main() {\n  sw(\"👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦\", [])\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3720\n#[test]\nfn record_inside_const_list() {\n    assert_format_rewrite!(\n        r#\"const commands = [\n  Command(\n    \"dev\",\n    \"Start a file watcher that automatically re-compiles your app on all file changes.\",\n  ), Command(\"help\", \"Show this help text.\"),\n]\n\"#,\n        r#\"const commands = [\n  Command(\n    \"dev\",\n    \"Start a file watcher that automatically re-compiles your app on all file changes.\",\n  ),\n  Command(\"help\", \"Show this help text.\"),\n]\n\"#\n    );\n}\n\n#[test]\nfn formatter_adds_todo_inside_empty_block() {\n    assert_format_rewrite!(\n        \"pub fn main() {{}}\",\n        r#\"pub fn main() {\n  { todo }\n}\n\"#\n    );\n}\n\n#[test]\nfn let_assert_as() {\n    assert_format!(\n        r#\"pub fn main() {\n  let assert 10 = 10 as \"10 == 10\"\n}\n\"#\n    );\n}\n\n#[test]\nfn let_assert_as_long_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  let assert Ok(10) = Ok(10)\n    as \"It's pretty obvious that this will never fail, but just in case, here is why.\"\n}\n\"#\n    );\n}\n\n#[test]\nfn let_assert_as_long_message_and_value() {\n    assert_format!(\n        r#\"pub fn main() {\n  let assert Ok(something) =\n    some_very_long_variable_which_always_represents_a_successful_result\n    as \"As you can see by the incredibly descriptive variable name, this operation never fails.\"\n}\n\"#\n    );\n}\n\n#[test]\nfn let_assert_as_concatenated_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  let assert 1 = 2 as { \"This will\" <> \" \" <> \"crash\" }\n}\n\"#\n    );\n}\n\n#[test]\nfn let_assert_as_variable_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  let message = \"Hi :)\"\n  let assert 1 = 2 as message\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4121\n#[test]\nfn function_capture_formatted_like_regular_calls() {\n    assert_format!(\n        r#\"pub fn main() {\n  capture(a, _, [\n    really_long_thing_that_can_be_broken,\n    something_else_for_good_measure,\n  ])\n}\n\"#\n    );\n}\n\n#[test]\nfn function_capture_formatted_like_regular_calls_2() {\n    assert_format!(\n        r#\"pub fn main() {\n  capture(\n    a,\n    _,\n    really_long_thing_that_cannot_be_broken,\n    something_else_for_good_measure,\n  )\n}\n\"#\n    );\n}\n\n#[test]\nfn function_capture_formatted_like_regular_calls_3() {\n    assert_format!(\n        r#\"pub fn main() {\n  list.fold(my_list, _, fn(a) {\n    io.print(\"Meh\")\n    io.print(\"Meh\")\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn function_capture_formatted_like_regular_calls_inside_a_long_list() {\n    assert_format!(\n        r#\"pub fn main() {\n  [\n    capture(a, _, [\n      really_long_thing_that_can_be_broken,\n      something_else_for_good_measure,\n    ]),\n    regular_call(a, [\n      really_long_thing_that_can_be_broken,\n      something_else_for_good_measure,\n    ]),\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn function_capture_formatted_like_regular_calls_in_a_pipe() {\n    assert_format!(\n        r#\"pub fn main() {\n  [1, 2, 3]\n  |> list.fold(from: 1, over: _, with: fn(a, b) {\n    // a comment!\n    a + b\n  })\n}\n\"#\n    );\n}\n\n#[test]\nfn assert() {\n    assert_format!(\n        \"pub fn main() {\n  assert True\n}\n\"\n    );\n}\n\n#[test]\nfn assert_with_long_expression() {\n    assert_format!(\n        \"pub fn main() {\n  assert some_function_with_a_very_long_name_that_exceeds_the_eighty_character_limit()\n}\n\"\n    );\n}\n\n#[test]\nfn assert_with_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  assert True as \"This is always true\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_with_long_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  assert True\n    as \"This should never panic, because it is a literal True value, and so will always be true.\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_with_long_expression_and_long_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  assert some_long_function_name_which_if_everything_is_right_should_always_be_true\n    as \"This should never panic, because the function only ever returns true.\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_with_long_binary_expression() {\n    assert_format!(\n        r#\"pub fn main() {\n  echo wibble_wobble_wibble_wobble_wibble_wobble_wibble\n    >= wibble_wobble_wibble_wobble_wibble_wobble_wibble\n\n  echo wibble_wobble_wibble_wobble_wibble_wobble_wibble\n    + wibble_wobble_wibble_wobble_wibble_wobble_wibble\n\n  echo wibble_wobble_wibble_wobble_wibble_wobble_wibble\n    == wibble_wobble_wibble_wobble_wibble_wobble_wibble\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_with_long_binary_expression() {\n    assert_format!(\n        r#\"pub fn main() {\n  assert wibble_wobble_wibble_wobble_wibble_wobble_wibble\n    >= wibble_wobble_wibble_wobble_wibble_wobble_wibble\n\n  assert wibble_wobble_wibble_wobble_wibble_wobble_wibble\n    + wibble_wobble_wibble_wobble_wibble_wobble_wibble\n\n  assert wibble_wobble_wibble_wobble_wibble_wobble_wibble\n    == wibble_wobble_wibble_wobble_wibble_wobble_wibble\n}\n\"#\n    );\n}\n\n#[test]\nfn comment_is_not_moved_after_assert() {\n    assert_format!(\n        \"pub fn main() {\n  // Wibble!\n  assert True\n}\n\"\n    );\n}\n\n#[test]\nfn todo_as_with_comment() {\n    assert_format!(\n        r#\"pub fn main() {\n  todo as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn todo_as_with_comment_on_the_same_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  todo as // A little comment explaining something\n    \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  todo as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn todo_as_with_comment_before_the_as() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  todo // A little comment explaining something\n    as \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  todo as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn panic_as_with_comment() {\n    assert_format!(\n        r#\"pub fn main() {\n  panic as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn panic_as_with_comment_on_the_same_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  panic as // A little comment explaining something\n    \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  panic as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn panic_as_with_comment_before_the_as() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  panic // A little comment explaining something\n    as \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  panic as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_comment() {\n    assert_format!(\n        r#\"pub fn main() {\n  echo 1 as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_comment_on_the_same_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  echo 1 as // A little comment explaining something\n    \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  echo 1 as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_as_with_comment_before_the_as() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  echo 1 // A little comment explaining something\n    as \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  echo 1 as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_as_with_comment() {\n    assert_format!(\n        r#\"pub fn main() {\n  assert True as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_as_with_comment_on_the_same_line() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  assert True as // A little comment explaining something\n    \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  assert True as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_as_with_comment_before_the_as() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  assert True // A little comment explaining something\n    as \"wibble\"\n}\n\"#,\n        r#\"pub fn main() {\n  assert True as\n    // A little comment explaining something\n    \"wibble\"\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4664\n#[test]\nfn pattern_unused_discard() {\n    assert_format_rewrite!(\n        r#\"pub fn main() {\n  let a = 10\n  let _ = case a {\n    _ as b -> b\n  }\n}\n\"#,\n        r#\"pub fn main() {\n  let a = 10\n  let _ = case a {\n    b -> b\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4929\n#[test]\nfn format_panic_as_with_block_message() {\n    assert_format!(\n        r#\"pub fn main() {\n  panic as {\n    // b\n    a\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5056\n#[test]\nfn remove_redundant_negation_from_literal_int_1() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  --1\n}\n\",\n        \"pub fn main() {\n  1\n}\n\"\n    );\n}\n\n#[test]\nfn remove_redundant_negation_from_literal_int_2() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  ---1\n}\n\",\n        \"pub fn main() {\n  -1\n}\n\"\n    );\n}\n\n#[test]\nfn remove_redundant_negation_from_literal_int_3() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  ----1\n}\n\",\n        \"pub fn main() {\n  1\n}\n\"\n    );\n}\n\n#[test]\nfn call_with_single_call_argument_and_trailing_comment() {\n    assert_format!(\n        \"pub fn main() {\n  call(\n    wibble(wobble),\n    // ...\n  )\n}\n\"\n    );\n}\n\n#[test]\nfn call_with_single_call_argument_and_trailing_comment_2() {\n    assert_format_rewrite!(\n        \"pub fn main() {\n  call(wibble(wobble) // ...\n  )\n}\n\",\n        \"pub fn main() {\n  call(\n    wibble(wobble),\n    // ...\n  )\n}\n\"\n    );\n}\n\n#[test]\nfn can_format_big_list_without_stack_overflowing() {\n    let items = std::iter::repeat_n(\"    1,\", 10_000).join(\"\\n\");\n\n    assert_format!(format!(\n        \"pub fn main() {{\n  [\n{items}\n  ]\n}}\n\"\n    ));\n}\n\n// https://github.com/gleam-lang/gleam/issues/5323\n#[test]\nfn internal_const_list_is_kept_on_multiple_lines() {\n    assert_format!(\n        \"@internal\npub const list = [\n  LeftToRight,\n  RightToLeft,\n]\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5401\n#[test]\nfn multiple_field_access_are_not_put_in_a_block() {\n    assert_format!(\n        \"pub fn main() {\n  a.wib.wob\n}\n\"\n    );\n}\n\n#[test]\nfn multiple_tuple_field_access_are_not_put_in_a_block() {\n    assert_format!(\n        \"pub fn main() {\n  #(1, 2).1.2\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/format.rs",
    "content": "#[cfg(test)]\nmod tests;\n\nuse crate::{\n    Error, Result,\n    ast::{\n        CustomType, Import, ModuleConstant, TypeAlias, TypeAstConstructor, TypeAstFn, TypeAstHole,\n        TypeAstTuple, TypeAstVar, *,\n    },\n    build::Target,\n    docvec,\n    io::Utf8Writer,\n    parse::extra::{Comment, ModuleExtra},\n    pretty::{self, *},\n    warning::WarningEmitter,\n};\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse std::cmp::Ordering;\nuse vec1::Vec1;\n\nuse crate::type_::Deprecation;\nuse camino::Utf8Path;\n\nconst INDENT: isize = 2;\n\npub fn pretty(writer: &mut impl Utf8Writer, src: &EcoString, path: &Utf8Path) -> Result<()> {\n    let parsed = crate::parse::parse_module(path.to_owned(), src, &WarningEmitter::null())\n        .map_err(|error| Error::Parse {\n            path: path.to_path_buf(),\n            src: src.clone(),\n            error: Box::new(error),\n        })?;\n    let intermediate = Intermediate::from_extra(&parsed.extra, src);\n    Formatter::with_comments(&intermediate)\n        .module(&parsed.module)\n        .pretty_print(80, writer)\n}\n\npub(crate) struct Intermediate<'a> {\n    comments: Vec<Comment<'a>>,\n    doc_comments: Vec<Comment<'a>>,\n    module_comments: Vec<Comment<'a>>,\n    empty_lines: &'a [u32],\n    new_lines: &'a [u32],\n    trailing_commas: &'a [u32],\n}\n\nimpl<'a> Intermediate<'a> {\n    pub fn from_extra(extra: &'a ModuleExtra, src: &'a EcoString) -> Intermediate<'a> {\n        Intermediate {\n            comments: extra\n                .comments\n                .iter()\n                .map(|span| Comment::from((span, src)))\n                .collect(),\n            doc_comments: extra\n                .doc_comments\n                .iter()\n                .map(|span| Comment::from((span, src)))\n                .collect(),\n            empty_lines: &extra.empty_lines,\n            module_comments: extra\n                .module_comments\n                .iter()\n                .map(|span| Comment::from((span, src)))\n                .collect(),\n            new_lines: &extra.new_lines,\n            trailing_commas: &extra.trailing_commas,\n        }\n    }\n}\n\n#[derive(Debug)]\nenum FnCapturePosition {\n    RightHandSideOfPipe,\n    EverywhereElse,\n}\n\n#[derive(Debug)]\n/// One of the pieces making a record update arg list: it could be the starting\n/// record being updated, or one of the subsequent arguments.\n///\nenum RecordUpdatePiece<'a, A> {\n    Record(&'a RecordBeingUpdated<A>),\n    Argument(&'a RecordUpdateArg<A>),\n}\n\nimpl<A> HasLocation for RecordUpdatePiece<'_, A> {\n    fn location(&self) -> SrcSpan {\n        match self {\n            RecordUpdatePiece::Record(record) => record.location,\n            RecordUpdatePiece::Argument(arg) => arg.location,\n        }\n    }\n}\n\ntype UntypedRecordUpdatePiece<'a> = RecordUpdatePiece<'a, UntypedExpr>;\n\n/// Hayleigh's bane\n#[derive(Debug, Clone, Default)]\npub struct Formatter<'a> {\n    comments: &'a [Comment<'a>],\n    doc_comments: &'a [Comment<'a>],\n    module_comments: &'a [Comment<'a>],\n    empty_lines: &'a [u32],\n    new_lines: &'a [u32],\n    trailing_commas: &'a [u32],\n}\n\nimpl<'comments> Formatter<'comments> {\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    pub(crate) fn with_comments(extra: &'comments Intermediate<'comments>) -> Self {\n        Self {\n            comments: &extra.comments,\n            doc_comments: &extra.doc_comments,\n            module_comments: &extra.module_comments,\n            empty_lines: extra.empty_lines,\n            new_lines: extra.new_lines,\n            trailing_commas: extra.trailing_commas,\n        }\n    }\n\n    /// Returns true if there's any comment that comes before the given\n    /// position.\n    ///\n    fn any_comments(&self, limit: u32) -> bool {\n        self.comments\n            .first()\n            .is_some_and(|comment| comment.start < limit)\n    }\n\n    /// Returns true if there's any comment that appears inside the given span.\n    ///\n    fn any_comment_between(&self, start: u32, end: u32) -> bool {\n        self.comments\n            .binary_search_by(|comment| {\n                if comment.start < start {\n                    Ordering::Less\n                } else if comment.start > end {\n                    Ordering::Greater\n                } else {\n                    Ordering::Equal\n                }\n            })\n            .is_ok()\n    }\n\n    fn any_empty_lines(&self, limit: u32) -> bool {\n        self.empty_lines.first().is_some_and(|line| *line < limit)\n    }\n\n    /// Pop comments that occur before a byte-index in the source, consuming\n    /// and retaining any empty lines contained within.\n    /// Returns an iterator of comments with their start position.\n    fn pop_comments_with_position(\n        &mut self,\n        limit: u32,\n    ) -> impl Iterator<Item = (u32, Option<&'comments str>)> + use<'comments> {\n        let (popped, rest, empty_lines) =\n            comments_before(self.comments, self.empty_lines, limit, true);\n        self.comments = rest;\n        self.empty_lines = empty_lines;\n        popped\n    }\n\n    /// Pop comments that occur before a byte-index in the source, consuming\n    /// and retaining any empty lines contained within.\n    fn pop_comments(\n        &mut self,\n        limit: u32,\n    ) -> impl Iterator<Item = Option<&'comments str>> + use<'comments> {\n        self.pop_comments_with_position(limit)\n            .map(|(_position, comment)| comment)\n    }\n\n    /// Pop doc comments that occur before a byte-index in the source, consuming\n    /// and dropping any empty lines contained within.\n    fn pop_doc_comments(\n        &mut self,\n        limit: u32,\n    ) -> impl Iterator<Item = Option<&'comments str>> + use<'comments> {\n        let (popped, rest, empty_lines) =\n            comments_before(self.doc_comments, self.empty_lines, limit, false);\n        self.doc_comments = rest;\n        self.empty_lines = empty_lines;\n        popped.map(|(_position, comment)| comment)\n    }\n\n    /// Remove between 0 and `limit` empty lines following the current position,\n    /// returning true if any empty lines were removed.\n    fn pop_empty_lines(&mut self, limit: u32) -> bool {\n        let mut end = 0;\n        for (i, &position) in self.empty_lines.iter().enumerate() {\n            if position > limit {\n                break;\n            }\n            end = i + 1;\n        }\n\n        self.empty_lines = self\n            .empty_lines\n            .get(end..)\n            .expect(\"Pop empty lines slicing\");\n        end != 0\n    }\n\n    fn targeted_definition<'a>(&mut self, definition: &'a TargetedDefinition) -> Document<'a> {\n        let target = definition.target;\n        let definition = &definition.definition;\n        let start = definition.location().start;\n\n        let comments = self.pop_comments_with_position(start);\n        let comments = self.printed_documented_comments(comments);\n        let document = self.documented_definition(definition);\n        let document = match target {\n            None => document,\n            Some(Target::Erlang) => docvec![\"@target(erlang)\", line(), document],\n            Some(Target::JavaScript) => docvec![\"@target(javascript)\", line(), document],\n        };\n\n        comments.to_doc().append(document.group())\n    }\n\n    pub(crate) fn module<'a>(&mut self, module: &'a UntypedModule) -> Document<'a> {\n        let mut documents = vec![];\n        let mut previous_was_a_definition = false;\n\n        // Here we take consecutive groups of imports so that they can be sorted\n        // alphabetically.\n        for (is_import_group, definitions) in &module\n            .definitions\n            .iter()\n            .chunk_by(|definition| definition.definition.is_import())\n        {\n            if is_import_group {\n                if previous_was_a_definition {\n                    documents.push(lines(2));\n                }\n                documents.append(&mut self.imports(definitions.collect_vec()));\n                previous_was_a_definition = false;\n            } else {\n                for definition in definitions {\n                    if !documents.is_empty() {\n                        documents.push(lines(2));\n                    }\n                    documents.push(self.targeted_definition(definition));\n                }\n                previous_was_a_definition = true;\n            }\n        }\n\n        let definitions = concat(documents);\n\n        // Now that definitions has been collected, only freestanding comments (//)\n        // and doc comments (///) remain. Freestanding comments aren't associated\n        // with any statement, and are moved to the bottom of the module.\n        let doc_comments = join(\n            self.doc_comments\n                .iter()\n                .map(|comment| \"///\".to_doc().append(EcoString::from(comment.content))),\n            line(),\n        );\n\n        let comments = match printed_comments(self.pop_comments(u32::MAX), false) {\n            Some(comments) => comments,\n            None => nil(),\n        };\n\n        let module_comments = if !self.module_comments.is_empty() {\n            let comments = self\n                .module_comments\n                .iter()\n                .map(|s| \"////\".to_doc().append(EcoString::from(s.content)));\n            join(comments, line()).append(line())\n        } else {\n            nil()\n        };\n\n        let non_empty = vec![module_comments, definitions, doc_comments, comments]\n            .into_iter()\n            .filter(|doc| !doc.is_empty());\n\n        join(non_empty, line()).append(line())\n    }\n\n    /// Separates the imports in groups delimited by comments or empty lines and\n    /// sorts each group alphabetically.\n    ///\n    /// The formatter needs to play nicely with import groups defined by the\n    /// programmer. If one puts a comment before an import then that's a clue\n    /// for the formatter that it has run into a gorup of related imports.\n    ///\n    /// So we can't just sort `imports` and format each one, we have to be a\n    /// bit smarter and see if each import is preceded by a comment.\n    /// Once we find a comment we know we're done with the current import\n    /// group and a new one has started.\n    ///\n    /// ```gleam\n    /// // This is an import group.\n    /// import gleam/int\n    /// import gleam/string\n    ///\n    /// // This marks the beginning of a new import group that can't\n    /// // be mushed together with the previous one!\n    /// import wibble\n    /// import wobble\n    /// ```\n    fn imports<'a>(&mut self, imports: Vec<&'a TargetedDefinition>) -> Vec<Document<'a>> {\n        let mut import_groups_docs = vec![];\n        let mut current_group = vec![];\n        let mut current_group_delimiter = nil();\n\n        for import in imports {\n            let start = import.definition.location().start;\n\n            // We need to start a new group if the `import` is preceded by one or\n            // more empty lines or a `//` comment.\n            let start_new_group = self.any_comments(start) || self.any_empty_lines(start);\n            if start_new_group {\n                // First we print the previous group and clear it out to start a\n                // new empty group containing the import we've just ran into.\n                if !current_group.is_empty() {\n                    import_groups_docs.push(docvec![\n                        current_group_delimiter,\n                        self.sorted_import_group(&current_group)\n                    ]);\n                    current_group.clear();\n                }\n\n                // Now that we've taken care of the previous group we can start\n                // the new one. We know it's preceded either by an empty line or\n                // some comments se we have to be a bit more precise and save the\n                // actual delimiter that we're going to put at the top of this\n                // group.\n\n                let comments = self.pop_comments(start);\n                let _ = self.pop_empty_lines(start);\n                current_group_delimiter = printed_comments(comments, true).unwrap_or(nil());\n            }\n            // Lastly we add the import to the group.\n            current_group.push(import);\n        }\n\n        // Let's not forget about the last import group!\n        if !current_group.is_empty() {\n            import_groups_docs.push(docvec![\n                current_group_delimiter,\n                self.sorted_import_group(&current_group)\n            ]);\n        }\n\n        // We want all consecutive import groups to be separated by an empty line.\n        // This should really be `.intersperse(line())` but I can't do that\n        // because of https://github.com/rust-lang/rust/issues/48919.\n        Itertools::intersperse(import_groups_docs.into_iter(), lines(2)).collect_vec()\n    }\n\n    /// Prints the imports as a single sorted group of import statements.\n    ///\n    fn sorted_import_group<'a>(&mut self, imports: &[&'a TargetedDefinition]) -> Document<'a> {\n        let imports = imports\n            .iter()\n            .sorted_by(|one, other| match (&one.definition, &other.definition) {\n                (Definition::Import(one), Definition::Import(other)) => {\n                    one.module.cmp(&other.module)\n                }\n                // It shouldn't really be possible for a non import to be here so\n                // we just return a default value.\n                _ => Ordering::Equal,\n            })\n            .map(|import| self.targeted_definition(import));\n\n        // This should really be `.intersperse(line())` but I can't do that\n        // because of https://github.com/rust-lang/rust/issues/48919.\n        Itertools::intersperse(imports, line())\n            .collect_vec()\n            .to_doc()\n    }\n\n    fn definition<'a>(&mut self, statement: &'a UntypedDefinition) -> Document<'a> {\n        match statement {\n            Definition::Function(function) => self.statement_fn(function),\n\n            Definition::TypeAlias(alias) => self.type_alias(alias),\n\n            Definition::CustomType(ct) => self.custom_type(ct),\n\n            Definition::Import(Import {\n                module,\n                as_name,\n                unqualified_values,\n                unqualified_types,\n                ..\n            }) => {\n                let second = if unqualified_values.is_empty() && unqualified_types.is_empty() {\n                    nil()\n                } else {\n                    let unqualified_types = unqualified_types\n                        .iter()\n                        .sorted_by(|a, b| a.name.cmp(&b.name))\n                        .map(|type_| docvec![\"type \", type_]);\n                    let unqualified_values = unqualified_values\n                        .iter()\n                        .sorted_by(|a, b| a.name.cmp(&b.name))\n                        .map(|value| value.to_doc());\n                    let unqualified = join(\n                        unqualified_types.chain(unqualified_values),\n                        flex_break(\",\", \", \"),\n                    );\n                    let unqualified = break_(\"\", \"\")\n                        .append(unqualified)\n                        .nest(INDENT)\n                        .append(break_(\",\", \"\"))\n                        .group();\n                    \".{\".to_doc().append(unqualified).append(\"}\")\n                };\n\n                let doc = docvec![\"import \", module.as_str(), second];\n                let default_module_access_name = module.split('/').next_back().map(EcoString::from);\n                match (default_module_access_name, as_name) {\n                    // If the `as name` is the same as the module name that would be\n                    // used anyways we won't render it. For example:\n                    // ```gleam\n                    // import gleam/int as int\n                    //                  ^^^^^^ this is redundant and removed\n                    // ```\n                    (Some(module_name), Some((AssignName::Variable(name), _)))\n                        if &module_name == name =>\n                    {\n                        doc\n                    }\n                    (_, None) => doc,\n                    (_, Some((AssignName::Variable(name) | AssignName::Discard(name), _))) => {\n                        doc.append(\" as \").append(name)\n                    }\n                }\n            }\n\n            Definition::ModuleConstant(ModuleConstant {\n                publicity,\n                name,\n                annotation,\n                value,\n                deprecation,\n                documentation: _,\n                location: _,\n                name_location: _,\n                type_: _,\n                implementations: _,\n            }) => {\n                let attributes = AttributesPrinter::new()\n                    .set_internal(*publicity)\n                    .set_deprecation(deprecation)\n                    .to_doc();\n                let head = attributes\n                    .append(pub_(*publicity))\n                    .append(\"const \")\n                    .append(name.as_str());\n                let head = match annotation {\n                    None => head,\n                    Some(t) => head.append(\": \").append(self.type_ast(t)),\n                };\n                head.append(\" = \").append(self.const_expr(value).group())\n            }\n        }\n    }\n\n    fn const_expr<'a, A, B>(&mut self, value: &'a Constant<A, B>) -> Document<'a> {\n        let comments = self.pop_comments(value.location().start);\n        let document = match value {\n            Constant::Int { value, .. } => self.int(value),\n\n            Constant::Float { value, .. } => self.float(value),\n\n            Constant::String { value, .. } => self.string(value),\n\n            Constant::List {\n                elements,\n                location,\n                tail,\n                ..\n            } => self.const_list(elements, location, tail),\n\n            Constant::Tuple {\n                elements, location, ..\n            } => self.const_tuple(elements, location),\n\n            Constant::BitArray {\n                segments, location, ..\n            } => {\n                let segment_docs = segments\n                    .iter()\n                    .map(|segment| bit_array_segment(segment, |e| self.const_expr(e)))\n                    .collect_vec();\n\n                let packing = self.items_sequence_packing(\n                    segments,\n                    None,\n                    |segment| segment.value.can_have_multiple_per_line(),\n                    *location,\n                );\n\n                self.bit_array(segment_docs, packing, location)\n            }\n\n            Constant::Record {\n                name,\n                arguments,\n                module: None,\n                ..\n            } if arguments.is_empty() => name.to_doc(),\n\n            Constant::Record {\n                name,\n                arguments,\n                module: Some((m, _)),\n                ..\n            } if arguments.is_empty() => m.to_doc().append(\".\").append(name.as_str()),\n\n            Constant::Record {\n                name,\n                arguments,\n                module: None,\n                location,\n                ..\n            } => {\n                let arguments = arguments\n                    .iter()\n                    .map(|argument| self.constant_call_arg(argument))\n                    .collect_vec();\n                name.to_doc()\n                    .append(self.wrap_arguments(arguments, location.end))\n                    .group()\n            }\n\n            Constant::Record {\n                name,\n                arguments,\n                module: Some((m, _)),\n                location,\n                ..\n            } => {\n                let arguments = arguments\n                    .iter()\n                    .map(|argument| self.constant_call_arg(argument))\n                    .collect_vec();\n                m.to_doc()\n                    .append(\".\")\n                    .append(name.as_str())\n                    .append(self.wrap_arguments(arguments, location.end))\n                    .group()\n            }\n\n            Constant::Var {\n                name, module: None, ..\n            } => name.to_doc(),\n\n            Constant::Var {\n                name,\n                module: Some((module, _)),\n                ..\n            } => docvec![module, \".\", name],\n\n            Constant::StringConcatenation { left, right, .. } => self\n                .const_expr(left)\n                .append(break_(\"\", \" \").append(\"<>\".to_doc()))\n                .nest(INDENT)\n                .append(\" \")\n                .append(self.const_expr(right)),\n\n            Constant::RecordUpdate {\n                module,\n                name,\n                record,\n                arguments,\n                location,\n                ..\n            } => self.const_record_update(module, name, record, arguments, location),\n\n            Constant::Invalid { .. } => panic!(\"invalid constants can not be in an untyped ast\"),\n        };\n        commented(document, comments)\n    }\n\n    fn const_list<'a, A, B>(\n        &mut self,\n        elements: &'a [Constant<A, B>],\n        location: &SrcSpan,\n        tail: &'a Option<Box<Constant<A, B>>>,\n    ) -> Document<'a> {\n        if elements.is_empty() {\n            // We take all comments that come _before_ the end of the list,\n            // that is all comments that are inside \"[\" and \"]\", if there's\n            // any comment we want to put it inside the empty list!\n            return match printed_comments(self.pop_comments(location.end), false) {\n                None => \"[]\".to_doc(),\n                Some(comments) => \"[\"\n                    .to_doc()\n                    .append(break_(\"\", \"\").nest(INDENT))\n                    .append(comments)\n                    .append(break_(\"\", \"\"))\n                    .append(\"]\")\n                    // vvv We want to make sure the comments are on a separate\n                    //     line from the opening and closing brackets so we\n                    //     force the breaks to be split on newlines.\n                    .force_break(),\n            };\n        }\n\n        let list_packing = self.items_sequence_packing(\n            elements,\n            tail.as_deref(),\n            |element| element.can_have_multiple_per_line(),\n            *location,\n        );\n        let comma = match list_packing {\n            ItemsPacking::FitMultiplePerLine => flex_break(\",\", \", \"),\n            ItemsPacking::FitOnePerLine | ItemsPacking::BreakOnePerLine => break_(\",\", \", \"),\n        };\n\n        let mut elements_doc = nil();\n        for element in elements.iter() {\n            let empty_lines = self.pop_empty_lines(element.location().start);\n            let element_doc = self.const_expr(element);\n\n            elements_doc = if elements_doc.is_empty() {\n                element_doc\n            } else if empty_lines {\n                // If there's empty lines before the list item we want to add an\n                // empty line here. Notice how we're making sure no nesting is\n                // added after the comma, otherwise we would be adding needless\n                // whitespace in the empty line!\n                docvec![\n                    elements_doc,\n                    comma.clone().set_nesting(0),\n                    line(),\n                    element_doc\n                ]\n            } else {\n                docvec![elements_doc, comma.clone(), element_doc]\n            };\n        }\n        elements_doc = elements_doc.next_break_fits(NextBreakFitsMode::Disabled);\n\n        let doc = break_(\"[\", \"[\").append(elements_doc);\n        let (doc, final_break) = match tail {\n            None => (doc.nest(INDENT), break_(\",\", \"\")),\n            Some(tail) => {\n                let comments = self.pop_comments(tail.location().start);\n\n                let tail = commented(docvec![\"..\", self.const_expr(tail)], comments);\n                (\n                    doc.append(break_(\",\", \", \")).append(tail).nest(INDENT),\n                    break_(\"\", \"\"),\n                )\n            }\n        };\n\n        // We get all remaining comments that come before the list's closing\n        // square bracket.\n        // If there's any we add those before the closing square bracket instead\n        // of moving those out of the list.\n        // Otherwise those would be moved out of the list.\n        let comments = self.pop_comments(location.end);\n        let doc = match printed_comments(comments, false) {\n            None => doc.append(final_break).append(\"]\"),\n            Some(comment) => doc\n                .append(final_break.nest(INDENT))\n                // ^ See how here we're adding the missing indentation to the\n                //   final break so that the final comment is as indented as the\n                //   list's items.\n                .append(comment)\n                .append(line())\n                .append(\"]\")\n                .force_break(),\n        };\n\n        match list_packing {\n            ItemsPacking::FitOnePerLine | ItemsPacking::FitMultiplePerLine => doc.group(),\n            ItemsPacking::BreakOnePerLine => doc.force_break(),\n        }\n    }\n\n    pub fn const_tuple<'a, A, B>(\n        &mut self,\n        elements: &'a [Constant<A, B>],\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        if elements.is_empty() {\n            // We take all comments that come _before_ the end of the tuple,\n            // that is all comments that are inside \"#(\" and \")\", if there's\n            // any comment we want to put it inside the empty list!\n            return match printed_comments(self.pop_comments(location.end), false) {\n                None => \"#()\".to_doc(),\n                Some(comments) => \"#(\"\n                    .to_doc()\n                    .append(break_(\"\", \"\").nest(INDENT))\n                    .append(comments)\n                    .append(break_(\"\", \"\"))\n                    .append(\")\")\n                    // vvv We want to make sure the comments are on a separate\n                    //     line from the opening and closing parentheses so we\n                    //     force the breaks to be split on newlines.\n                    .force_break(),\n            };\n        }\n\n        let arguments_docs = elements.iter().map(|element| self.const_expr(element));\n        let tuple_doc = break_(\"#(\", \"#(\")\n            .append(\n                join(arguments_docs, break_(\",\", \", \"))\n                    .next_break_fits(NextBreakFitsMode::Disabled),\n            )\n            .nest(INDENT);\n\n        let comments = self.pop_comments(location.end);\n        match printed_comments(comments, false) {\n            None => tuple_doc.append(break_(\",\", \"\")).append(\")\").group(),\n            Some(comments) => tuple_doc\n                .append(break_(\",\", \"\").nest(INDENT))\n                .append(comments)\n                .append(line())\n                .append(\")\")\n                .force_break(),\n        }\n    }\n\n    fn documented_definition<'a>(&mut self, s: &'a UntypedDefinition) -> Document<'a> {\n        let comments = self.doc_comments(s.location().start);\n        comments.append(self.definition(s).group()).group()\n    }\n\n    fn doc_comments<'a>(&mut self, limit: u32) -> Document<'a> {\n        let mut comments = self.pop_doc_comments(limit).peekable();\n        match comments.peek() {\n            None => nil(),\n            Some(_) => join(\n                comments.map(|c| match c {\n                    Some(c) => \"///\".to_doc().append(EcoString::from(c)),\n                    None => unreachable!(\"empty lines dropped by pop_doc_comments\"),\n                }),\n                line(),\n            )\n            .append(line())\n            .force_break(),\n        }\n    }\n\n    fn type_ast_constructor<'a>(\n        &mut self,\n        module: &'a Option<(EcoString, SrcSpan)>,\n        name: &'a str,\n        arguments: &'a [TypeAst],\n        location: &SrcSpan,\n        _name_location: &SrcSpan,\n    ) -> Document<'a> {\n        let head = module\n            .as_ref()\n            .map(|(qualifier, _)| qualifier.to_doc().append(\".\").append(name))\n            .unwrap_or_else(|| name.to_doc());\n\n        if arguments.is_empty() {\n            head\n        } else {\n            head.append(self.type_arguments(arguments, location))\n        }\n    }\n\n    fn type_ast<'a>(&mut self, t: &'a TypeAst) -> Document<'a> {\n        match t {\n            TypeAst::Hole(TypeAstHole { name, .. }) => name.to_doc(),\n\n            TypeAst::Constructor(TypeAstConstructor {\n                name,\n                arguments,\n                module,\n                location,\n                name_location,\n                start_parentheses: _,\n            }) => self.type_ast_constructor(module, name, arguments, location, name_location),\n\n            TypeAst::Fn(TypeAstFn {\n                arguments,\n                return_,\n                location,\n            }) => \"fn\"\n                .to_doc()\n                .append(self.type_arguments(arguments, location))\n                .group()\n                .append(\" ->\")\n                .append(break_(\"\", \" \").append(self.type_ast(return_)).nest(INDENT)),\n\n            TypeAst::Var(TypeAstVar { name, .. }) => name.to_doc(),\n\n            TypeAst::Tuple(TypeAstTuple { elements, location }) => {\n                \"#\".to_doc().append(self.type_arguments(elements, location))\n            }\n        }\n        .group()\n    }\n\n    fn type_arguments<'a>(&mut self, arguments: &'a [TypeAst], location: &SrcSpan) -> Document<'a> {\n        let arguments = arguments\n            .iter()\n            .map(|type_| self.type_ast(type_))\n            .collect_vec();\n        self.wrap_arguments(arguments, location.end)\n    }\n\n    pub fn type_alias<'a, A>(&mut self, alias: &'a TypeAlias<A>) -> Document<'a> {\n        let TypeAlias {\n            alias: name,\n            parameters: arguments,\n            type_ast: type_,\n            publicity,\n            deprecation,\n            location,\n            name_location: _,\n            type_: _,\n            documentation: _,\n        } = alias;\n\n        let attributes = AttributesPrinter::new()\n            .set_deprecation(deprecation)\n            .set_internal(*publicity)\n            .to_doc();\n\n        let head = docvec![attributes, pub_(*publicity), \"type \", name];\n        let head = if arguments.is_empty() {\n            head\n        } else {\n            let arguments = arguments.iter().map(|(_, e)| e.to_doc()).collect_vec();\n            head.append(self.wrap_arguments(arguments, location.end).group())\n        };\n\n        head.append(\" =\")\n            .append(line().append(self.type_ast(type_)).group().nest(INDENT))\n    }\n\n    fn fn_arg<'a, A>(&mut self, arg: &'a Arg<A>) -> Document<'a> {\n        let comments = self.pop_comments(arg.location.start);\n        let doc = match &arg.annotation {\n            None => arg.names.to_doc(),\n            Some(a) => arg.names.to_doc().append(\": \").append(self.type_ast(a)),\n        }\n        .group();\n        commented(doc, comments)\n    }\n\n    fn statement_fn<'a>(&mut self, function: &'a UntypedFunction) -> Document<'a> {\n        let Function {\n            location,\n            body_start: _,\n            end_position,\n            name,\n            arguments,\n            body,\n            publicity,\n            deprecation,\n            return_annotation,\n            return_type: _,\n            documentation: _,\n            external_erlang,\n            external_javascript,\n            implementations: _,\n            purity: _,\n        } = function;\n\n        let attributes = AttributesPrinter::new()\n            .set_deprecation(deprecation)\n            .set_internal(*publicity)\n            .set_external_erlang(external_erlang)\n            .set_external_javascript(external_javascript)\n            .to_doc();\n\n        // Fn name and args\n        let arguments = arguments\n            .iter()\n            .map(|argument| self.fn_arg(argument))\n            .collect_vec();\n        let signature = pub_(*publicity)\n            .append(\"fn \")\n            .append(\n                &name\n                    .as_ref()\n                    .expect(\"Function in a statement must be named\")\n                    .1,\n            )\n            .append(\n                self.wrap_arguments(\n                    arguments,\n                    // Calculate end location of arguments to not consume comments in\n                    // return annotation\n                    return_annotation\n                        .as_ref()\n                        .map_or(location.end, |ann| ann.location().start),\n                ),\n            );\n\n        // Add return annotation\n        let signature = match &return_annotation {\n            Some(anno) => signature.append(\" -> \").append(self.type_ast(anno)),\n            None => signature,\n        }\n        .group();\n\n        if body.is_empty() {\n            return attributes.append(signature);\n        }\n\n        let head = attributes.append(signature);\n\n        // Format body\n\n        let body = self.statements(body);\n\n        // Add any trailing comments\n        let body = match printed_comments(self.pop_comments(*end_position), false) {\n            Some(comments) => body.append(line()).append(comments),\n            None => body,\n        };\n\n        // Stick it all together\n        head.append(\" {\")\n            .append(line().append(body).nest(INDENT).group())\n            .append(line())\n            .append(\"}\")\n    }\n\n    fn expr_fn<'a>(\n        &mut self,\n        arguments: &'a [UntypedArg],\n        return_annotation: Option<&'a TypeAst>,\n        body: &'a Vec1<UntypedStatement>,\n        location: &SrcSpan,\n        end_of_head_byte_index: &u32,\n    ) -> Document<'a> {\n        let arguments_docs = arguments\n            .iter()\n            .map(|argument| self.fn_arg(argument))\n            .collect_vec();\n        let arguments = self\n            .wrap_arguments(arguments_docs, *end_of_head_byte_index)\n            .group()\n            .next_break_fits(NextBreakFitsMode::Disabled);\n        //   ^^^ We add this so that when an expression function is passed as\n        //       the last argument of a function and it goes over the line\n        //       limit with just its arguments we don't get some strange\n        //       splitting.\n        //       See https://github.com/gleam-lang/gleam/issues/2571\n        //\n        // There's many ways we could be smarter than this. For example:\n        //  - still split the arguments like it did in the example shown in the\n        //    issue if the expr_fn has more than one argument\n        //  - make sure that an anonymous function whose body is made up of a\n        //    single expression doesn't get split (I think that could boil down\n        //    to wrapping the body with a `next_break_fits(Disabled)`)\n        //\n        // These are some of the ways we could tweak the look of expression\n        // functions in the future if people are not satisfied with it.\n\n        let header = \"fn\".to_doc().append(arguments);\n\n        let header = match return_annotation {\n            None => header,\n            Some(t) => header.append(\" -> \").append(self.type_ast(t)),\n        };\n\n        let statements = self.statements(body.as_vec());\n        let body = match printed_comments(self.pop_comments(location.end), false) {\n            None => statements,\n            Some(comments) => statements.append(line()).append(comments).force_break(),\n        };\n\n        header.append(\" \").append(wrap_block(body)).group()\n    }\n\n    fn statements<'a>(&mut self, statements: &'a [UntypedStatement]) -> Document<'a> {\n        let mut previous_position = 0;\n        let count = statements.len();\n        let mut documents = Vec::with_capacity(count * 2);\n        for (i, statement) in statements.iter().enumerate() {\n            let preceding_newline = self.pop_empty_lines(previous_position + 1);\n            if i != 0 && preceding_newline {\n                documents.push(lines(2));\n            } else if i != 0 {\n                documents.push(line());\n            }\n            previous_position = statement.location().end;\n            documents.push(self.statement(statement).group());\n\n            // If the last statement is a use we make sure it's followed by a\n            // todo to make it explicit it has an unimplemented callback.\n            if statement.is_use() && i == count - 1 {\n                documents.push(line());\n                documents.push(\"todo\".to_doc());\n            }\n        }\n\n        if count == 1\n            && statements\n                .first()\n                .is_some_and(|statement| statement.is_expression())\n        {\n            documents.to_doc()\n        } else {\n            documents.to_doc().force_break()\n        }\n    }\n\n    fn assignment<'a>(&mut self, assignment: &'a UntypedAssignment) -> Document<'a> {\n        let comments = self.pop_comments(assignment.location.start);\n        let Assignment {\n            pattern,\n            value,\n            kind,\n            annotation,\n            ..\n        } = assignment;\n\n        let _ = self.pop_empty_lines(pattern.location().end);\n\n        let (keyword, message) = match kind {\n            AssignmentKind::Let | AssignmentKind::Generated => (\"let \", None),\n            AssignmentKind::Assert { message, .. } => (\"let assert \", message.as_ref()),\n        };\n\n        let pattern = self.pattern(pattern);\n\n        let annotation = annotation\n            .as_ref()\n            .map(|a| \": \".to_doc().append(self.type_ast(a)));\n\n        let doc = keyword\n            .to_doc()\n            .append(pattern.append(annotation).group())\n            .append(\" =\")\n            .append(self.assigned_value(value));\n\n        commented(\n            self.append_as_message(doc, PrecedingAs::Expression, message),\n            comments,\n        )\n    }\n\n    fn expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {\n        let comments = self.pop_comments(expr.start_byte_index());\n\n        let document = match expr {\n            UntypedExpr::Panic { message, .. } => {\n                self.append_as_message(\"panic\".to_doc(), PrecedingAs::Keyword, message.as_deref())\n            }\n\n            UntypedExpr::Todo { message, .. } => {\n                self.append_as_message(\"todo\".to_doc(), PrecedingAs::Keyword, message.as_deref())\n            }\n\n            UntypedExpr::Echo {\n                expression,\n                location: _,\n                keyword_end: _,\n                message,\n            } => self.echo(expression, message),\n\n            UntypedExpr::PipeLine { expressions, .. } => self.pipeline(expressions, false),\n\n            UntypedExpr::Int { value, .. } => self.int(value),\n\n            UntypedExpr::Float { value, .. } => self.float(value),\n\n            UntypedExpr::String { value, .. } => self.string(value),\n\n            UntypedExpr::Block {\n                statements,\n                location,\n                ..\n            } => self.block(location, statements, false),\n\n            UntypedExpr::Var { name, .. } if name == CAPTURE_VARIABLE => \"_\".to_doc(),\n\n            UntypedExpr::Var { name, .. } => name.to_doc(),\n\n            UntypedExpr::TupleIndex { tuple, index, .. } => self.tuple_index(tuple, *index),\n\n            UntypedExpr::NegateInt { value, .. } => self.negate_int(value),\n\n            UntypedExpr::NegateBool { value, .. } => self.negate_bool(value),\n\n            UntypedExpr::Fn { kind, body, .. } if kind.is_capture() => {\n                self.fn_capture(body, FnCapturePosition::EverywhereElse)\n            }\n\n            UntypedExpr::Fn {\n                return_annotation,\n                arguments,\n                body,\n                location,\n                end_of_head_byte_index,\n                ..\n            } => self.expr_fn(\n                arguments,\n                return_annotation.as_ref(),\n                body,\n                location,\n                end_of_head_byte_index,\n            ),\n\n            UntypedExpr::List {\n                elements,\n                tail,\n                location,\n            } => self.list(elements, tail.as_deref(), location),\n\n            UntypedExpr::Call {\n                fun,\n                arguments,\n                location,\n                ..\n            } => self.call(fun, arguments, location),\n\n            UntypedExpr::BinOp {\n                name, left, right, ..\n            } => self.bin_op(name, left, right, false),\n\n            UntypedExpr::Case {\n                subjects,\n                clauses,\n                location,\n            } => self.case(subjects, clauses.as_deref().unwrap_or_default(), location),\n\n            UntypedExpr::FieldAccess {\n                label, container, ..\n            } => self.expr(container).append(\".\").append(label.as_str()),\n\n            UntypedExpr::Tuple { elements, location } => self.tuple(elements, location),\n\n            UntypedExpr::BitArray {\n                segments, location, ..\n            } => {\n                let segment_docs = segments\n                    .iter()\n                    .map(|segment| bit_array_segment(segment, |e| self.bit_array_segment_expr(e)))\n                    .collect_vec();\n\n                let packing = self.items_sequence_packing(\n                    segments,\n                    None,\n                    |segment| segment.value.can_have_multiple_per_line(),\n                    *location,\n                );\n\n                self.bit_array(segment_docs, packing, location)\n            }\n            UntypedExpr::RecordUpdate {\n                constructor,\n                record,\n                arguments,\n                location,\n                ..\n            } => self.record_update(constructor, record, arguments, location),\n        };\n        commented(document, comments)\n    }\n\n    fn string<'a>(&self, string: &'a EcoString) -> Document<'a> {\n        let doc = string.to_doc().surround(\"\\\"\", \"\\\"\");\n        if string.contains('\\n') {\n            doc.force_break()\n        } else {\n            doc\n        }\n    }\n\n    fn bin_op_string<'a>(&self, string: &'a EcoString) -> Document<'a> {\n        let lines = string.split('\\n').collect_vec();\n        match lines.as_slice() {\n            [] | [_] => string.to_doc().surround(\"\\\"\", \"\\\"\"),\n            [first_line, lines @ ..] => {\n                let mut doc = docvec![\"\\\"\", first_line];\n                for line in lines {\n                    doc = doc\n                        .append(pretty::line().set_nesting(0))\n                        .append(line.to_doc())\n                }\n                doc.append(\"\\\"\".to_doc()).group()\n            }\n        }\n    }\n\n    fn float<'a>(&self, value: &'a str) -> Document<'a> {\n        // Create parts\n        let mut parts = value.split('.');\n        let integer_part = parts.next().unwrap_or_default();\n        // floating point part\n        let fp_part = parts.next().unwrap_or_default();\n        let integer_doc = self.underscore_integer_string(integer_part);\n        let dot_doc = \".\".to_doc();\n\n        // Split fp_part into a regular fractional and maybe a scientific part\n        let (fp_part_fractional, fp_part_scientific) = fp_part.split_at(\n            fp_part\n                .chars()\n                .position(|ch| ch == 'e')\n                .unwrap_or(fp_part.len()),\n        );\n\n        // Trim right any consequtive '0's\n        let mut fp_part_fractional = fp_part_fractional.trim_end_matches('0').to_string();\n        // If there is no fractional part left, add a '0', thus that 1. becomes 1.0 etc.\n        if fp_part_fractional.is_empty() {\n            fp_part_fractional.push('0');\n        }\n        let fp_doc = fp_part_fractional.chars().collect::<EcoString>();\n\n        integer_doc\n            .append(dot_doc)\n            .append(fp_doc)\n            .append(fp_part_scientific)\n    }\n\n    fn int<'a>(&self, value: &'a str) -> Document<'a> {\n        if value.starts_with(\"0x\") || value.starts_with(\"0b\") || value.starts_with(\"0o\") {\n            return value.to_doc();\n        }\n\n        self.underscore_integer_string(value)\n    }\n\n    fn underscore_integer_string<'a>(&self, value: &'a str) -> Document<'a> {\n        let underscore_ch = '_';\n        let minus_ch = '-';\n\n        let len = value.len();\n        let underscore_ch_cnt = value.matches(underscore_ch).count();\n        let reformat_watershed = if value.starts_with(minus_ch) { 6 } else { 5 };\n        let insert_underscores = (len - underscore_ch_cnt) >= reformat_watershed;\n\n        let mut new_value = String::new();\n        let mut j = 0;\n        for (i, ch) in value.chars().rev().enumerate() {\n            if ch == '_' {\n                continue;\n            }\n\n            if insert_underscores && i != 0 && ch != minus_ch && i < len && j % 3 == 0 {\n                new_value.push(underscore_ch);\n            }\n            new_value.push(ch);\n\n            j += 1;\n        }\n\n        new_value.chars().rev().collect::<EcoString>().to_doc()\n    }\n\n    fn pattern_constructor<'a>(\n        &mut self,\n        name: &'a str,\n        arguments: &'a [CallArg<UntypedPattern>],\n        module: &'a Option<(EcoString, SrcSpan)>,\n        spread: Option<SrcSpan>,\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        fn is_breakable(expr: &UntypedPattern) -> bool {\n            match expr {\n                Pattern::Tuple { .. } | Pattern::List { .. } | Pattern::BitArray { .. } => true,\n                Pattern::Constructor { arguments, .. } => !arguments.is_empty(),\n                Pattern::Int { .. }\n                | Pattern::Float { .. }\n                | Pattern::String { .. }\n                | Pattern::Variable { .. }\n                | Pattern::BitArraySize(_)\n                | Pattern::Assign { .. }\n                | Pattern::Discard { .. }\n                | Pattern::StringPrefix { .. }\n                | Pattern::Invalid { .. } => false,\n            }\n        }\n\n        let name = match module {\n            Some((m, _)) => m.to_doc().append(\".\").append(name),\n            None => name.to_doc(),\n        };\n\n        if arguments.is_empty() && spread.is_some() {\n            name.append(\"(..)\")\n        } else if arguments.is_empty() {\n            name\n        } else if spread.is_some() {\n            let arguments = arguments\n                .iter()\n                .map(|argument| self.pattern_call_arg(argument))\n                .collect_vec();\n            name.append(self.wrap_arguments_with_spread(arguments, location.end))\n                .group()\n        } else {\n            match arguments {\n                [argument] if is_breakable(&argument.value) => name\n                    .append(\"(\")\n                    .append(self.pattern_call_arg(argument))\n                    .append(\")\")\n                    .group(),\n\n                _ => {\n                    let arguments = arguments\n                        .iter()\n                        .map(|argument| self.pattern_call_arg(argument))\n                        .collect_vec();\n                    name.append(self.wrap_arguments(arguments, location.end))\n                        .group()\n                }\n            }\n        }\n    }\n\n    fn call<'a>(\n        &mut self,\n        fun: &'a UntypedExpr,\n        arguments: &'a [CallArg<UntypedExpr>],\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        let expr = match fun {\n            UntypedExpr::PipeLine { .. } => break_block(self.expr(fun)),\n\n            UntypedExpr::BinOp { .. }\n            | UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => self.expr(fun),\n        };\n\n        let arity = arguments.len();\n        self.append_inlinable_wrapped_arguments(\n            expr,\n            arguments,\n            location,\n            |argument| &argument.value,\n            |self_, arg| self_.call_arg(arg, arity),\n        )\n    }\n\n    fn tuple<'a>(&mut self, elements: &'a [UntypedExpr], location: &SrcSpan) -> Document<'a> {\n        if elements.is_empty() {\n            // We take all comments that come _before_ the end of the tuple,\n            // that is all comments that are inside \"#(\" and \")\", if there's\n            // any comment we want to put it inside the empty tuple!\n            return match printed_comments(self.pop_comments(location.end), false) {\n                None => \"#()\".to_doc(),\n                Some(comments) => \"#(\"\n                    .to_doc()\n                    .append(break_(\"\", \"\").nest(INDENT))\n                    .append(comments)\n                    .append(break_(\"\", \"\"))\n                    .append(\")\")\n                    // vvv We want to make sure the comments are on a separate\n                    //     line from the opening and closing parentheses so we\n                    //     force the breaks to be split on newlines.\n                    .force_break(),\n            };\n        }\n\n        self.append_inlinable_wrapped_arguments(\n            \"#\".to_doc(),\n            elements,\n            location,\n            |e| e,\n            |self_, e| self_.comma_separated_item(e, elements.len()),\n        )\n    }\n\n    // Appends to the given docs a comma-separated list of documents wrapped by\n    // parentheses. If the last item of the argument list is splittable the\n    // resulting document will try to first split that before splitting all the\n    // other arguments.\n    // This is used for function calls and tuples.\n    fn append_inlinable_wrapped_arguments<'a, 'b, T, ToExpr, ToDoc>(\n        &mut self,\n        doc: Document<'a>,\n        values: &'b [T],\n        location: &SrcSpan,\n        to_expr: ToExpr,\n        to_doc: ToDoc,\n    ) -> Document<'a>\n    where\n        T: HasLocation,\n        T: std::fmt::Debug,\n        ToExpr: Fn(&T) -> &UntypedExpr,\n        ToDoc: Fn(&mut Self, &'b T) -> Document<'a>,\n    {\n        match init_and_last(values) {\n            Some((initial_values, last_value))\n                if is_breakable_argument(to_expr(last_value), values.len())\n                    && !self.any_comments(last_value.location().start)\n                    && !self.any_comment_between(last_value.location().end, location.end) =>\n            {\n                let mut docs = initial_values\n                    .iter()\n                    .map(|value| to_doc(self, value))\n                    .collect_vec();\n\n                let last_value_doc = to_doc(self, last_value)\n                    .group()\n                    .next_break_fits(NextBreakFitsMode::Enabled);\n\n                docs.append(&mut vec![last_value_doc]);\n\n                doc.append(self.wrap_function_call_arguments(docs, location))\n                    .next_break_fits(NextBreakFitsMode::Disabled)\n                    .group()\n            }\n\n            Some(_) | None => {\n                let docs = values.iter().map(|value| to_doc(self, value)).collect_vec();\n                doc.append(self.wrap_function_call_arguments(docs, location))\n                    .group()\n            }\n        }\n    }\n\n    pub fn case<'a>(\n        &mut self,\n        subjects: &'a [UntypedExpr],\n        clauses: &'a [UntypedClause],\n        location: &'a SrcSpan,\n    ) -> Document<'a> {\n        let subjects_doc = break_(\"case\", \"case \")\n            .append(join(\n                subjects.iter().map(|s| self.expr(s).group()),\n                break_(\",\", \", \"),\n            ))\n            .nest(INDENT)\n            .append(break_(\"\", \" \"))\n            .append(\"{\")\n            .next_break_fits(NextBreakFitsMode::Disabled)\n            .group();\n\n        let clauses_doc = concat(\n            clauses\n                .iter()\n                .enumerate()\n                .map(|(i, c)| self.clause(c, i as u32).group()),\n        );\n\n        // We get all remaining comments that come before the case's closing\n        // bracket. If there's any we add those before the closing bracket\n        // instead of moving those out of the case expression.\n        // Otherwise those would be moved out of the case expression.\n        let comments = self.pop_comments(location.end);\n        let closing_bracket = match printed_comments(comments, false) {\n            None => docvec![line(), \"}\"],\n            Some(comment) => docvec![line(), comment]\n                .nest(INDENT)\n                .append(line())\n                .append(\"}\"),\n        };\n\n        subjects_doc\n            .append(line().append(clauses_doc).nest(INDENT))\n            .append(closing_bracket)\n            .force_break()\n    }\n\n    pub fn record_update<'a>(\n        &mut self,\n        constructor: &'a UntypedExpr,\n        record: &'a RecordBeingUpdated<UntypedExpr>,\n        arguments: &'a [UntypedRecordUpdateArg],\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        let constructor_doc: Document<'a> = self.expr(constructor);\n        let pieces = std::iter::once(UntypedRecordUpdatePiece::Record(record))\n            .chain(arguments.iter().map(UntypedRecordUpdatePiece::Argument))\n            .collect_vec();\n\n        self.append_inlinable_wrapped_arguments(\n            constructor_doc,\n            &pieces,\n            location,\n            |arg| match arg {\n                UntypedRecordUpdatePiece::Argument(arg) => &arg.value,\n                UntypedRecordUpdatePiece::Record(record) => record.base.as_ref(),\n            },\n            |this, arg| match arg {\n                UntypedRecordUpdatePiece::Argument(arg) => this.record_update_arg(arg),\n                UntypedRecordUpdatePiece::Record(record) => {\n                    let comments = this.pop_comments(record.location.start);\n                    commented(\"..\".to_doc().append(this.expr(&record.base)), comments)\n                }\n            },\n        )\n    }\n\n    pub fn const_record_update<'a, A, B>(\n        &mut self,\n        module: &Option<(EcoString, SrcSpan)>,\n        name: &'a EcoString,\n        record: &'a RecordBeingUpdated<Constant<A, B>>,\n        arguments: &'a [RecordUpdateArg<Constant<A, B>>],\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        let constructor_doc = match module {\n            Some((m, _)) => m.to_doc().append(\".\").append(name.as_str()),\n            None => name.to_doc(),\n        };\n\n        let pieces = std::iter::once(RecordUpdatePiece::Record(record))\n            .chain(arguments.iter().map(RecordUpdatePiece::Argument))\n            .collect_vec();\n\n        let docs = pieces\n            .iter()\n            .map(|piece| match piece {\n                RecordUpdatePiece::Argument(arg) => {\n                    let comments = self.pop_comments(arg.location.start);\n                    let doc = match arg {\n                        _ if arg.uses_label_shorthand() => arg.label.as_str().to_doc().append(\":\"),\n                        _ => arg\n                            .label\n                            .as_str()\n                            .to_doc()\n                            .append(\": \")\n                            .append(self.const_expr(&arg.value))\n                            .group(),\n                    };\n                    commented(doc, comments)\n                }\n                RecordUpdatePiece::Record(record) => {\n                    let comments = self.pop_comments(record.location.start);\n                    commented(\n                        \"..\".to_doc().append(self.const_expr(&record.base)),\n                        comments,\n                    )\n                }\n            })\n            .collect_vec();\n\n        constructor_doc\n            .append(self.wrap_arguments(docs, location.end))\n            .group()\n    }\n\n    pub fn bin_op<'a>(\n        &mut self,\n        name: &'a BinOp,\n        left: &'a UntypedExpr,\n        right: &'a UntypedExpr,\n        nest_steps: bool,\n    ) -> Document<'a> {\n        let left_side = self.bin_op_side(name, left, nest_steps);\n\n        let comments = self.pop_comments(right.start_byte_index());\n        let name_doc = break_(\"\", \" \").append(commented(name.to_doc(), comments));\n\n        let right_side = self.bin_op_side(name, right, nest_steps);\n\n        left_side\n            .append(if nest_steps {\n                name_doc.nest(INDENT)\n            } else {\n                name_doc\n            })\n            .append(\" \")\n            .append(right_side)\n    }\n\n    fn bin_op_side<'a>(\n        &mut self,\n        operator: &'a BinOp,\n        side: &'a UntypedExpr,\n        nest_steps: bool,\n    ) -> Document<'a> {\n        let side_doc = match side {\n            UntypedExpr::String { value, .. } => self.bin_op_string(value),\n            UntypedExpr::BinOp {\n                name, left, right, ..\n            } => self.bin_op(name, left, right, nest_steps),\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => self.expr(side),\n        };\n        match side.bin_op_name() {\n            // In case the other side is a binary operation as well and it can\n            // be grouped together with the current binary operation, the two\n            // docs are simply concatenated, so that they will end up in the\n            // same group and the formatter will try to keep those on a single\n            // line.\n            Some(side_name) if side_name.can_be_grouped_with(operator) => side_doc,\n            // In case the binary operations cannot be grouped together the\n            // other side is treated as a group on its own so that it can be\n            // broken independently of other pieces of the binary operations\n            // chain.\n            _ => self.operator_side(\n                side_doc.group(),\n                operator.precedence(),\n                side.bin_op_precedence(),\n            ),\n        }\n    }\n\n    pub fn operator_side<'a>(&self, doc: Document<'a>, op: u8, side: u8) -> Document<'a> {\n        if op > side {\n            wrap_block(doc).group()\n        } else {\n            doc\n        }\n    }\n\n    fn spans_multiple_lines(&self, start: u32, end: u32) -> bool {\n        self.new_lines\n            .binary_search_by(|newline| {\n                if *newline <= start {\n                    Ordering::Less\n                } else if *newline >= end {\n                    Ordering::Greater\n                } else {\n                    // If the newline is in between the pipe start and end\n                    // then we've found it!\n                    Ordering::Equal\n                }\n            })\n            // If we couldn't find any newline between the start and end of\n            // the pipeline then we will try and keep it on a single line.\n            .is_ok()\n    }\n\n    /// Returns true if there's a trailing comma between `start` and `end`.\n    ///\n    fn has_trailing_comma(&self, start: u32, end: u32) -> bool {\n        self.trailing_commas\n            .binary_search_by(|comma| {\n                if *comma < start {\n                    Ordering::Less\n                } else if *comma > end {\n                    Ordering::Greater\n                } else {\n                    Ordering::Equal\n                }\n            })\n            .is_ok()\n    }\n\n    fn pipeline<'a>(\n        &mut self,\n        expressions: &'a Vec1<UntypedExpr>,\n        nest_pipe: bool,\n    ) -> Document<'a> {\n        let mut docs = Vec::with_capacity(expressions.len() * 3);\n        let first = expressions.first();\n        let first_precedence = first.bin_op_precedence();\n        let first = self.expr(first).group();\n        docs.push(self.operator_side(first, 5, first_precedence));\n\n        let pipeline_start = expressions.first().location().start;\n        let pipeline_end = expressions.last().location().end;\n        let try_to_keep_on_one_line = !self.spans_multiple_lines(pipeline_start, pipeline_end);\n\n        for expr in expressions.iter().skip(1) {\n            let comments = self.pop_comments(expr.location().start);\n            let doc = if let UntypedExpr::Fn { kind, body, .. } = expr\n                && kind.is_capture()\n            {\n                self.fn_capture(body, FnCapturePosition::RightHandSideOfPipe)\n            } else {\n                self.expr(expr)\n            };\n            let doc = if nest_pipe { doc.nest(INDENT) } else { doc };\n            let space = if try_to_keep_on_one_line {\n                break_(\"\", \" \")\n            } else {\n                line()\n            };\n            let pipe = space.append(commented(\"|> \".to_doc(), comments));\n            let pipe = if nest_pipe { pipe.nest(INDENT) } else { pipe };\n            docs.push(pipe);\n            docs.push(self.operator_side(doc, 4, expr.bin_op_precedence()));\n        }\n\n        if try_to_keep_on_one_line {\n            docs.to_doc()\n        } else {\n            docs.to_doc().force_break()\n        }\n    }\n\n    fn fn_capture<'a>(\n        &mut self,\n        call: &'a [UntypedStatement],\n        position: FnCapturePosition,\n    ) -> Document<'a> {\n        // The body of a capture being multiple statements shouldn't be possible...\n        if call.len() != 1 {\n            panic!(\"Function capture found not to have a single statement call\");\n        }\n\n        let Some(Statement::Expression(UntypedExpr::Call {\n            fun,\n            arguments,\n            location,\n        })) = call.first()\n        else {\n            // The body of a capture being not a fn shouldn't be possible...\n            panic!(\"Function capture body found not to be a call in the formatter\")\n        };\n\n        match (position, arguments.as_slice()) {\n            // The capture has a single unlabelled hole:\n            //\n            //     wibble |> wobble(_)\n            //     list.map([], wobble(_))\n            //\n            // We want these to become:\n            //\n            //     wibble |> wobble\n            //     list.map([], wobble)\n            //\n            (FnCapturePosition::RightHandSideOfPipe | FnCapturePosition::EverywhereElse, [arg])\n                if arg.is_capture_hole() && arg.label.is_none() =>\n            {\n                self.expr(fun)\n            }\n\n            // The capture is on the right hand side of a pipe and its first\n            // argument it an unlabelled capture hole:\n            //\n            //     wibble |> wobble(_, woo)\n            //\n            // We want it to become:\n            //\n            //     wibble |> wobble(woo)\n            //\n            (FnCapturePosition::RightHandSideOfPipe, [arg, rest @ ..])\n                if arg.is_capture_hole() && arg.label.is_none() =>\n            {\n                let expr = self.expr(fun);\n                let arity = rest.len();\n                self.append_inlinable_wrapped_arguments(\n                    expr,\n                    rest,\n                    location,\n                    |arg| &arg.value,\n                    |self_, arg| self_.call_arg(arg, arity),\n                )\n            }\n\n            // In all other cases we print it like a regular function call\n            // without changing it.\n            //\n            (\n                FnCapturePosition::RightHandSideOfPipe | FnCapturePosition::EverywhereElse,\n                arguments,\n            ) => {\n                let expr = self.expr(fun);\n                let arity = arguments.len();\n                self.append_inlinable_wrapped_arguments(\n                    expr,\n                    arguments,\n                    location,\n                    |arg| &arg.value,\n                    |self_, arg| self_.call_arg(arg, arity),\n                )\n            }\n        }\n    }\n\n    pub fn record_constructor<'a, A>(\n        &mut self,\n        constructor: &'a RecordConstructor<A>,\n    ) -> Document<'a> {\n        let comments = self.pop_comments(constructor.location.start);\n        let doc_comments = self.doc_comments(constructor.location.start);\n        let attributes = AttributesPrinter::new()\n            .set_deprecation(&constructor.deprecation)\n            .to_doc();\n\n        let doc = if constructor.arguments.is_empty() {\n            if self.any_comments(constructor.location.end) {\n                attributes\n                    .append(constructor.name.as_str().to_doc())\n                    .append(self.wrap_arguments(vec![], constructor.location.end))\n                    .group()\n            } else {\n                attributes.append(constructor.name.as_str().to_doc())\n            }\n        } else {\n            let arguments = constructor\n                .arguments\n                .iter()\n                .map(\n                    |RecordConstructorArg {\n                         label,\n                         ast,\n                         location,\n                         ..\n                     }| {\n                        let arg_comments = self.pop_comments(location.start);\n                        let arg = match label {\n                            Some((_, l)) => l.to_doc().append(\": \").append(self.type_ast(ast)),\n                            None => self.type_ast(ast),\n                        };\n\n                        commented(\n                            self.doc_comments(location.start).append(arg).group(),\n                            arg_comments,\n                        )\n                    },\n                )\n                .collect_vec();\n\n            attributes\n                .append(constructor.name.as_str().to_doc())\n                .append(\n                    self.wrap_arguments(arguments, constructor.location.end)\n                        .group(),\n                )\n        };\n\n        commented(doc_comments.append(doc).group(), comments)\n    }\n\n    pub fn custom_type<'a, A>(&mut self, type_: &'a CustomType<A>) -> Document<'a> {\n        let CustomType {\n            location,\n            end_position,\n            name,\n            name_location: _,\n            publicity,\n            constructors,\n            documentation: _,\n            deprecation,\n            opaque,\n            parameters,\n            typed_parameters: _,\n            external_erlang,\n            external_javascript,\n        } = type_;\n\n        let _ = self.pop_empty_lines(location.end);\n\n        let attributes = AttributesPrinter::new()\n            .set_deprecation(deprecation)\n            .set_internal(*publicity)\n            .set_external_erlang(external_erlang)\n            .set_external_javascript(external_javascript)\n            .to_doc();\n\n        let doc = attributes\n            .append(pub_(*publicity))\n            .append(if *opaque { \"opaque type \" } else { \"type \" })\n            .append(if parameters.is_empty() {\n                name.clone().to_doc()\n            } else {\n                let arguments = type_\n                    .parameters\n                    .iter()\n                    .map(|(_, e)| e.to_doc())\n                    .collect_vec();\n                type_\n                    .name\n                    .clone()\n                    .to_doc()\n                    .append(self.wrap_arguments(arguments, location.end))\n                    .group()\n            });\n\n        if constructors.is_empty() {\n            return doc;\n        }\n        let doc = doc.append(\" {\");\n\n        let inner = concat(constructors.iter().map(|c| {\n            if self.pop_empty_lines(c.location.start) {\n                lines(2)\n            } else {\n                line()\n            }\n            .append(self.record_constructor(c))\n        }));\n\n        // Add any trailing comments\n        let inner = match printed_comments(self.pop_comments(*end_position), false) {\n            Some(comments) => inner.append(line()).append(comments),\n            None => inner,\n        }\n        .nest(INDENT)\n        .group();\n\n        doc.append(inner).append(line()).append(\"}\")\n    }\n\n    fn call_arg<'a>(&mut self, arg: &'a CallArg<UntypedExpr>, arity: usize) -> Document<'a> {\n        self.format_call_arg(arg, expr_call_arg_formatting, |this, value| {\n            this.comma_separated_item(value, arity)\n        })\n    }\n\n    fn format_call_arg<'a, A, F, G>(\n        &mut self,\n        arg: &'a CallArg<A>,\n        figure_formatting: F,\n        format_value: G,\n    ) -> Document<'a>\n    where\n        F: Fn(&'a CallArg<A>) -> CallArgFormatting<'a, A>,\n        G: Fn(&mut Self, &'a A) -> Document<'a>,\n    {\n        match figure_formatting(arg) {\n            CallArgFormatting::Unlabelled(value) => format_value(self, value),\n            CallArgFormatting::ShorthandLabelled(label) => {\n                let comments = self.pop_comments(arg.location.start);\n                let label = label.as_ref().to_doc().append(\":\");\n                commented(label, comments)\n            }\n            CallArgFormatting::Labelled(label, value) => {\n                let comments = self.pop_comments(arg.location.start);\n                let label = label.as_ref().to_doc().append(\": \");\n                let value = format_value(self, value);\n                commented(label, comments).append(value)\n            }\n        }\n    }\n\n    fn record_update_arg<'a>(&mut self, arg: &'a UntypedRecordUpdateArg) -> Document<'a> {\n        let comments = self.pop_comments(arg.location.start);\n        match arg {\n            // Argument supplied with a label shorthand.\n            _ if arg.uses_label_shorthand() => {\n                commented(arg.label.as_str().to_doc().append(\":\"), comments)\n            }\n            // Labelled argument.\n            _ => {\n                let doc = arg\n                    .label\n                    .as_str()\n                    .to_doc()\n                    .append(\": \")\n                    .append(self.expr(&arg.value))\n                    .group();\n\n                if arg.value.is_binop() || arg.value.is_pipeline() {\n                    commented(doc, comments).nest(INDENT)\n                } else {\n                    commented(doc, comments)\n                }\n            }\n        }\n    }\n\n    fn tuple_index<'a>(&mut self, tuple: &'a UntypedExpr, index: u64) -> Document<'a> {\n        // In case we have a block with a single variable tuple access we\n        // remove that redundant wrapper:\n        //\n        //     {tuple.1}.0 becomes\n        //     tuple.1.0\n        //\n        if let UntypedExpr::Block { statements, .. } = tuple {\n            match statements.as_slice() {\n                [Statement::Expression(tuple @ UntypedExpr::TupleIndex { tuple: inner, .. })]\n                    // We can't apply this change if the inner thing is a\n                    // literal tuple because the compiler cannot currently parse\n                    // it:  `#(1, #(2, 3)).1.0` is a syntax error at the moment.\n                    if !inner.is_tuple() =>\n                {\n                    self.expr(tuple)\n                }\n                _ => self.expr(tuple),\n            }\n        } else {\n            self.expr(tuple)\n        }\n        .append(\".\")\n        .append(index)\n    }\n\n    fn case_clause_value<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {\n        match expr {\n            UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::BitArray { .. } => {\n                let expression_comments = self.pop_comments(expr.location().start);\n                let expression_doc = self.expr(expr);\n                match printed_comments(expression_comments, true) {\n                    Some(comments) => line().append(comments).append(expression_doc).nest(INDENT),\n                    None => \" \".to_doc().append(expression_doc),\n                }\n            }\n\n            UntypedExpr::Case { .. } => line().append(self.expr(expr)).nest(INDENT),\n\n            UntypedExpr::Block {\n                statements,\n                location,\n                ..\n            } => \" \".to_doc().append(self.block(location, statements, true)),\n\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::BinOp { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => {\n                break_(\"\", \" \").append(self.expr(expr).group()).nest(INDENT)\n            }\n        }\n        .next_break_fits(NextBreakFitsMode::Disabled)\n        .group()\n    }\n\n    fn assigned_value<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {\n        match expr {\n            UntypedExpr::Case { .. } => \" \".to_doc().append(self.expr(expr)).group(),\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::BinOp { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => self.case_clause_value(expr),\n        }\n    }\n\n    fn clause<'a>(&mut self, clause: &'a UntypedClause, index: u32) -> Document<'a> {\n        let space_before = self.pop_empty_lines(clause.location.start);\n        let comments = self.pop_comments(clause.location.start);\n\n        let clause_doc = match &clause.guard {\n            None => self.alternative_patterns(clause),\n            Some(guard) => self\n                .alternative_patterns(clause)\n                .append(break_(\"\", \" \").nest(INDENT))\n                .append(\"if \")\n                .append(self.clause_guard(guard).group().nest(INDENT)),\n        };\n\n        // In case there's a guard or multiple subjects, if we decide to break\n        // the patterns on multiple lines we also want the arrow to end up on\n        // its own line to improve legibility.\n        //\n        // This looks like this:\n        // ```gleam\n        // case wibble, wobble {\n        //   Wibble(_),  // pretend this goes over the line limit\n        //     Wobble(_)\n        //   -> todo\n        //   // Notice how the arrow is broken on its own line, the same goes\n        //   // for patterns with `if` guards.\n        // }\n        // ```\n\n        let has_guard = clause.guard.is_some();\n        let has_multiple_subjects = clause.pattern.len() > 1;\n        let arrow_break = if has_guard || has_multiple_subjects {\n            break_(\"\", \" \")\n        } else {\n            \" \".to_doc()\n        };\n\n        let clause_doc = clause_doc\n            .append(arrow_break)\n            .group()\n            .append(\"->\")\n            .append(self.case_clause_value(&clause.then).group())\n            .group();\n\n        let clause_doc = match printed_comments(comments, false) {\n            Some(comments) => comments.append(line()).append(clause_doc),\n            None => clause_doc,\n        };\n\n        if index == 0 {\n            clause_doc\n        } else if space_before {\n            lines(2).append(clause_doc)\n        } else {\n            line().append(clause_doc)\n        }\n    }\n\n    fn alternative_patterns<'a>(&mut self, clause: &'a UntypedClause) -> Document<'a> {\n        let has_guard = clause.guard.is_some();\n        let has_multiple_subjects = clause.pattern.len() > 1;\n\n        // In case there's an `if` guard but no multiple subjects we want to add\n        // additional indentation before the vartical bar separating alternative\n        // patterns `|`.\n        // We're not adding the indentation if there's multiple subjects as that\n        // would make things harder to read, aligning the vertical bar with the\n        // different subjects:\n        // ```\n        // case wibble, wobble {\n        //   Wibble,\n        //     Wobble\n        //     | Wibble, // <- we don't want this indentation!\n        //     Wobble -> todo\n        // }\n        // ```\n        let alternatives_separator = if has_guard && !has_multiple_subjects {\n            break_(\"\", \" \").nest(INDENT).append(\"| \")\n        } else {\n            break_(\"\", \" \").append(\"| \")\n        };\n\n        let alternative_patterns = std::iter::once(&clause.pattern)\n            .chain(&clause.alternative_patterns)\n            .enumerate()\n            .map(|(alternative_index, p)| {\n                // Here `p` is a single pattern that can be comprised of\n                // multiple subjects.\n                // ```gleam\n                // case wibble, wobble {\n                //   True, False\n                // //^^^^^^^^^^^ This is a single pattern with multiple subjects\n                //   | _, _ -> todo\n                // }\n                // ```\n                let is_first_alternative = alternative_index == 0;\n                let subject_docs = p.iter().enumerate().map(|(subject_index, subject)| {\n                    // There's a small catch in turning each subject into a document.\n                    // Sadly we can't simply call `self.pattern` on each subject and\n                    // then nest each one in case it gets broken.\n                    // The first ever pattern that appears in a case clause (that is\n                    // the first subject of the first alternative) must not be nested\n                    // further; otherwise, when broken, it would have 2 extra spaces\n                    // of indentation: https://github.com/gleam-lang/gleam/issues/2940.\n                    let is_first_subject = subject_index == 0;\n                    let is_first_pattern_of_clause = is_first_subject && is_first_alternative;\n                    let subject_doc = self.pattern(subject);\n                    if is_first_pattern_of_clause {\n                        subject_doc\n                    } else {\n                        subject_doc.nest(INDENT)\n                    }\n                });\n                // We join all subjects with a breakable comma (that's also\n                // going to be nested) and make the subjects into a group to\n                // make sure the formatter tries to keep them on a single line.\n                join(subject_docs, break_(\",\", \", \").nest(INDENT)).group()\n            });\n        // Last, we make sure that the formatter tries to keep each\n        // alternative on a single line by making it a group!\n        join(alternative_patterns, alternatives_separator).group()\n    }\n\n    fn list<'a>(\n        &mut self,\n        elements: &'a [UntypedExpr],\n        tail: Option<&'a UntypedExpr>,\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        if elements.is_empty() {\n            return match tail {\n                Some(tail) => self.expr(tail),\n                // We take all comments that come _before_ the end of the list,\n                // that is all comments that are inside \"[\" and \"]\", if there's\n                // any comment we want to put it inside the empty list!\n                None => match printed_comments(self.pop_comments(location.end), false) {\n                    None => \"[]\".to_doc(),\n                    Some(comments) => \"[\"\n                        .to_doc()\n                        .append(break_(\"\", \"\").nest(INDENT))\n                        .append(comments)\n                        .append(break_(\"\", \"\"))\n                        .append(\"]\")\n                        // vvv We want to make sure the comments are on a separate\n                        //     line from the opening and closing brackets so we\n                        //     force the breaks to be split on newlines.\n                        .force_break(),\n                },\n            };\n        }\n\n        let list_packing = self.items_sequence_packing(\n            elements,\n            tail,\n            UntypedExpr::can_have_multiple_per_line,\n            *location,\n        );\n\n        let comma = match list_packing {\n            ItemsPacking::FitMultiplePerLine => flex_break(\",\", \", \"),\n            ItemsPacking::FitOnePerLine | ItemsPacking::BreakOnePerLine => break_(\",\", \", \"),\n        };\n\n        let list_size = elements.len()\n            + match tail {\n                Some(_) => 1,\n                None => 0,\n            };\n\n        let mut elements_doc = nil();\n        for element in elements.iter() {\n            let empty_lines = self.pop_empty_lines(element.location().start);\n            let element_doc = self.comma_separated_item(element, list_size);\n\n            elements_doc = if elements_doc.is_empty() {\n                element_doc\n            } else if empty_lines {\n                // If there's empty lines before the list item we want to add an\n                // empty line here. Notice how we're making sure no nesting is\n                // added after the comma, otherwise we would be adding needless\n                // whitespace in the empty line!\n                docvec![\n                    elements_doc,\n                    comma.clone().set_nesting(0),\n                    line(),\n                    element_doc\n                ]\n            } else {\n                docvec![elements_doc, comma.clone(), element_doc]\n            };\n        }\n        elements_doc = elements_doc.next_break_fits(NextBreakFitsMode::Disabled);\n\n        let doc = break_(\"[\", \"[\").append(elements_doc);\n        // We need to keep the last break aside and do not add it immediately\n        // because in case there's a final comment before the closing square\n        // bracket we want to add indentation (to just that break). Otherwise,\n        // the final comment would be less indented than list's elements.\n        let (doc, last_break) = match tail {\n            None => (doc.nest(INDENT), break_(\",\", \"\")),\n\n            Some(tail) => {\n                let comments = self.pop_comments(tail.location().start);\n                let tail = commented(docvec![\"..\", self.expr(tail)], comments);\n                (\n                    doc.append(break_(\",\", \", \")).append(tail).nest(INDENT),\n                    break_(\"\", \"\"),\n                )\n            }\n        };\n\n        // We get all remaining comments that come before the list's closing\n        // square bracket.\n        // If there's any we add those before the closing square bracket instead\n        // of moving those out of the list.\n        // Otherwise those would be moved out of the list.\n        let comments = self.pop_comments(location.end);\n        let doc = match printed_comments(comments, false) {\n            None => doc.append(last_break).append(\"]\"),\n            Some(comment) => doc\n                .append(last_break.nest(INDENT))\n                // ^ See how here we're adding the missing indentation to the\n                //   final break so that the final comment is as indented as the\n                //   list's items.\n                .append(comment)\n                .append(line())\n                .append(\"]\")\n                .force_break(),\n        };\n\n        match list_packing {\n            ItemsPacking::FitOnePerLine | ItemsPacking::FitMultiplePerLine => doc.group(),\n            ItemsPacking::BreakOnePerLine => doc.force_break(),\n        }\n    }\n\n    fn items_sequence_packing<'a, T: HasLocation>(\n        &self,\n        items: &'a [T],\n        tail: Option<&'a T>,\n        can_have_multiple_per_line: impl Fn(&'a T) -> bool,\n        list_location: SrcSpan,\n    ) -> ItemsPacking {\n        let ends_with_trailing_comma = tail\n            .map(|tail| tail.location().end)\n            .or_else(|| items.last().map(|last| last.location().end))\n            .is_some_and(|last_element_end| {\n                self.has_trailing_comma(last_element_end, list_location.end)\n            });\n\n        let has_multiple_elements_per_line =\n            self.has_items_on_the_same_line(items.iter().chain(tail));\n\n        let has_empty_lines_between_elements = match (items.first(), items.last().or(tail)) {\n            (Some(first), Some(last)) => self.empty_lines.first().is_some_and(|empty_line| {\n                *empty_line >= first.location().end && *empty_line < last.location().start\n            }),\n            _ => false,\n        };\n\n        if has_empty_lines_between_elements {\n            // If there's any empty line between elements we want to force each\n            // item onto its own line to preserve the empty lines that were\n            // intentionally added.\n            ItemsPacking::BreakOnePerLine\n        } else if !ends_with_trailing_comma {\n            // If the list doesn't end with a trailing comma we try and pack it in\n            // a single line; if we can't we'll put one item per line, no matter\n            // the content of the list.\n            ItemsPacking::FitOnePerLine\n        } else if tail.is_none()\n            && items.iter().all(can_have_multiple_per_line)\n            && has_multiple_elements_per_line\n            && self.spans_multiple_lines(list_location.start, list_location.end)\n        {\n            // If there's a trailing comma, we can have multiple items per line,\n            // and there's already multiple items per line, we try and pack as\n            // many items as possible on each line.\n            //\n            // Note how we only ever try and pack lists where all items are\n            // unbreakable primitives. To pack a list we need to use put\n            // `flex_break`s between each item.\n            // If the items themselves had breaks we could end up in a situation\n            // where an item gets broken making it span multiple lines and the\n            // spaces are not, for example:\n            //\n            // ```gleam\n            // [Constructor(\"wibble\", \"lorem ipsum dolor sit amet something something\"), Other(1)]\n            // ```\n            //\n            // If we used flex breaks here the list would be formatted as:\n            //\n            // ```gleam\n            // [\n            //   Constructor(\n            //     \"wibble\",\n            //     \"lorem ipsum dolor sit amet something something\",\n            //   ), Other(1)\n            // ]\n            // ```\n            //\n            // The first item is broken, meaning that once we get to the flex\n            // space separating it from the following one the formatter is not\n            // going to break it since there's enough space in the current line!\n            ItemsPacking::FitMultiplePerLine\n        } else {\n            // If it ends with a trailing comma we will force the list on\n            // multiple lines, with one item per line.\n            ItemsPacking::BreakOnePerLine\n        }\n    }\n\n    fn has_items_on_the_same_line<'a, L: HasLocation + 'a, T: Iterator<Item = &'a L>>(\n        &self,\n        items: T,\n    ) -> bool {\n        let mut previous: Option<SrcSpan> = None;\n        for item in items {\n            let item_location = item.location();\n            // A list has multiple items on the same line if two consecutive\n            // ones do not span multiple lines.\n            if let Some(previous) = previous\n                && !self.spans_multiple_lines(previous.end, item_location.start)\n            {\n                return true;\n            }\n            previous = Some(item_location);\n        }\n        false\n    }\n\n    /// Pretty prints an expression to be used in a comma separated list; for\n    /// example as a list item, a tuple item or as an argument of a function call.\n    fn comma_separated_item<'a>(\n        &mut self,\n        expression: &'a UntypedExpr,\n        siblings: usize,\n    ) -> Document<'a> {\n        // If there's more than one item in the comma separated list and there's a\n        // pipeline or long binary chain, we want to indent those to make it\n        // easier to tell where one item ends and the other starts.\n        // Othewise we just print the expression as a normal expr.\n        match expression {\n            UntypedExpr::BinOp {\n                name, left, right, ..\n            } if siblings > 1 => {\n                let comments = self.pop_comments(expression.start_byte_index());\n                let doc = self.bin_op(name, left, right, true).group();\n                commented(doc, comments)\n            }\n            UntypedExpr::PipeLine { expressions } if siblings > 1 => {\n                let comments = self.pop_comments(expression.start_byte_index());\n                let doc = self.pipeline(expressions, true).group();\n                commented(doc, comments)\n            }\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::BinOp { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => self.expr(expression).group(),\n        }\n    }\n\n    fn pattern<'a>(&mut self, pattern: &'a UntypedPattern) -> Document<'a> {\n        let comments = self.pop_comments(pattern.location().start);\n        let doc = match pattern {\n            Pattern::Int { value, .. } => self.int(value),\n\n            Pattern::Float { value, .. } => self.float(value),\n\n            Pattern::String { value, .. } => self.string(value),\n\n            Pattern::Variable { name, .. } => name.to_doc(),\n\n            Pattern::BitArraySize(size) => self.bit_array_size(size),\n\n            Pattern::Assign { name, pattern, .. } => {\n                if pattern.is_discard() {\n                    name.to_doc()\n                } else {\n                    self.pattern(pattern).append(\" as \").append(name.as_str())\n                }\n            }\n\n            Pattern::Discard { name, .. } => name.to_doc(),\n\n            Pattern::List { elements, tail, .. } => self.list_pattern(elements, tail),\n\n            Pattern::Constructor {\n                name,\n                arguments,\n                module,\n                spread,\n                location,\n                ..\n            } => self.pattern_constructor(name, arguments, module, *spread, location),\n\n            Pattern::Tuple {\n                elements, location, ..\n            } => {\n                let arguments = elements\n                    .iter()\n                    .map(|element| self.pattern(element))\n                    .collect_vec();\n                \"#\".to_doc()\n                    .append(self.wrap_arguments(arguments, location.end))\n                    .group()\n            }\n\n            Pattern::BitArray {\n                segments, location, ..\n            } => {\n                let segment_docs = segments\n                    .iter()\n                    .map(|segment| bit_array_segment(segment, |pattern| self.pattern(pattern)))\n                    .collect_vec();\n\n                self.bit_array(segment_docs, ItemsPacking::FitOnePerLine, location)\n            }\n\n            Pattern::StringPrefix {\n                left_side_string: left,\n                right_side_assignment: right,\n                left_side_assignment: left_assign,\n                ..\n            } => {\n                let left = self.string(left);\n                let right = match right {\n                    AssignName::Variable(name) => name.to_doc(),\n                    AssignName::Discard(name) => name.to_doc(),\n                };\n                match left_assign {\n                    Some((name, _)) => docvec![left, \" as \", name, \" <> \", right],\n                    None => docvec![left, \" <> \", right],\n                }\n            }\n\n            Pattern::Invalid { .. } => panic!(\"invalid patterns can not be in an untyped ast\"),\n        };\n        commented(doc, comments)\n    }\n\n    fn bit_array_size<'a>(&mut self, size: &'a BitArraySize<()>) -> Document<'a> {\n        match size {\n            BitArraySize::Int { value, .. } => self.int(value),\n            BitArraySize::Variable { name, .. } => name.to_doc(),\n            BitArraySize::BinaryOperator {\n                left,\n                right,\n                operator,\n                ..\n            } => {\n                let operator = match operator {\n                    IntOperator::Add => \" + \",\n                    IntOperator::Subtract => \" - \",\n                    IntOperator::Multiply => \" * \",\n                    IntOperator::Divide => \" / \",\n                    IntOperator::Remainder => \" % \",\n                };\n\n                docvec![\n                    self.bit_array_size(left),\n                    operator,\n                    self.bit_array_size(right)\n                ]\n            }\n            BitArraySize::Block { inner, .. } => self.bit_array_size(inner).surround(\"{ \", \" }\"),\n        }\n    }\n\n    fn list_pattern<'a>(\n        &mut self,\n        elements: &'a [UntypedPattern],\n        tail: &'a Option<Box<UntypedTailPattern>>,\n    ) -> Document<'a> {\n        if elements.is_empty() {\n            return match tail {\n                Some(tail) => self.pattern(&tail.pattern),\n                None => \"[]\".to_doc(),\n            };\n        }\n        let elements = join(\n            elements.iter().map(|element| self.pattern(element)),\n            break_(\",\", \", \"),\n        );\n        let doc = break_(\"[\", \"[\").append(elements);\n        match tail {\n            None => doc.nest(INDENT).append(break_(\",\", \"\")),\n\n            Some(tail) => {\n                let tail = &tail.pattern;\n                let comments = self.pop_comments(tail.location().start);\n                let tail = if tail.is_discard() {\n                    \"..\".to_doc()\n                } else {\n                    docvec![\"..\", self.pattern(tail)]\n                };\n                let tail = commented(tail, comments);\n                doc.append(break_(\",\", \", \"))\n                    .append(tail)\n                    .nest(INDENT)\n                    .append(break_(\"\", \"\"))\n            }\n        }\n        .append(\"]\")\n        .group()\n    }\n\n    fn pattern_call_arg<'a>(&mut self, arg: &'a CallArg<UntypedPattern>) -> Document<'a> {\n        self.format_call_arg(arg, pattern_call_arg_formatting, |this, value| {\n            this.pattern(value)\n        })\n    }\n\n    pub fn clause_guard_bin_op<'a>(\n        &mut self,\n        name: &'a BinOp,\n        left: &'a UntypedClauseGuard,\n        right: &'a UntypedClauseGuard,\n    ) -> Document<'a> {\n        self.clause_guard_bin_op_side(name, left, left.precedence())\n            .append(break_(\"\", \" \"))\n            .append(name.to_doc())\n            .append(\" \")\n            .append(self.clause_guard_bin_op_side(name, right, right.precedence() - 1))\n    }\n\n    fn clause_guard_bin_op_side<'a>(\n        &mut self,\n        name: &BinOp,\n        side: &'a UntypedClauseGuard,\n        // As opposed to `bin_op_side`, here we take the side precedence as an\n        // argument instead of computing it ourselves. That's because\n        // `clause_guard_bin_op` will reduce the precedence of any right side to\n        // make sure the formatter doesn't remove any needed curly bracket.\n        side_precedence: u8,\n    ) -> Document<'a> {\n        let side_doc = self.clause_guard(side);\n        match side.bin_op_name() {\n            // In case the other side is a binary operation as well and it can\n            // be grouped together with the current binary operation, the two\n            // docs are simply concatenated, so that they will end up in the\n            // same group and the formatter will try to keep those on a single\n            // line.\n            Some(side_name) if side_name.can_be_grouped_with(name) => {\n                self.operator_side(side_doc, name.precedence(), side_precedence)\n            }\n            // In case the binary operations cannot be grouped together the\n            // other side is treated as a group on its own so that it can be\n            // broken independently of other pieces of the binary operations\n            // chain.\n            _ => self.operator_side(side_doc.group(), name.precedence(), side_precedence),\n        }\n    }\n\n    fn clause_guard<'a>(&mut self, clause_guard: &'a UntypedClauseGuard) -> Document<'a> {\n        match clause_guard {\n            ClauseGuard::BinaryOperator {\n                operator,\n                left,\n                right,\n                ..\n            } => self.clause_guard_bin_op(operator, left, right),\n\n            ClauseGuard::Var { name, .. } => name.to_doc(),\n\n            ClauseGuard::TupleIndex { tuple, index, .. } => {\n                self.clause_guard(tuple).append(\".\").append(*index).to_doc()\n            }\n\n            ClauseGuard::FieldAccess {\n                container, label, ..\n            } => self\n                .clause_guard(container)\n                .append(\".\")\n                .append(label)\n                .to_doc(),\n\n            ClauseGuard::ModuleSelect {\n                module_name, label, ..\n            } => module_name.to_doc().append(\".\").append(label).to_doc(),\n\n            ClauseGuard::Constant(constant) => self.const_expr(constant),\n\n            ClauseGuard::Not { expression, .. } => docvec![\"!\", self.clause_guard(expression)],\n\n            ClauseGuard::Block { value, .. } => wrap_block(self.clause_guard(value)).group(),\n        }\n    }\n\n    fn constant_call_arg<'a, A, B>(&mut self, arg: &'a CallArg<Constant<A, B>>) -> Document<'a> {\n        self.format_call_arg(arg, constant_call_arg_formatting, |this, value| {\n            this.const_expr(value)\n        })\n    }\n\n    fn negate_bool<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {\n        match expr {\n            UntypedExpr::NegateBool { value, .. } => self.expr(value),\n            UntypedExpr::BinOp { .. } => \"!\".to_doc().append(wrap_block(self.expr(expr))),\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateInt { .. } => docvec![\"!\", self.expr(expr)],\n        }\n    }\n\n    fn negate_int<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {\n        match expr {\n            UntypedExpr::NegateInt { value, .. } => self.expr(value),\n            UntypedExpr::Int { value, .. } if value.starts_with('-') => self.int(&value[1..]),\n            UntypedExpr::BinOp { .. } => \"- \".to_doc().append(self.expr(expr)),\n\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. } => docvec![\"-\", self.expr(expr)],\n        }\n    }\n\n    fn use_<'a>(&mut self, use_: &'a UntypedUse) -> Document<'a> {\n        let comments = self.pop_comments(use_.location.start);\n\n        let call = if use_.call.is_call() {\n            docvec![\" \", self.expr(&use_.call)]\n        } else {\n            docvec![break_(\"\", \" \"), self.expr(&use_.call)].nest(INDENT)\n        }\n        .group();\n\n        let doc = if use_.assignments.is_empty() {\n            docvec![\"use <-\", call]\n        } else {\n            let assignments = use_.assignments.iter().map(|use_assignment| {\n                let pattern = self.pattern(&use_assignment.pattern);\n                let annotation = use_assignment\n                    .annotation\n                    .as_ref()\n                    .map(|a| \": \".to_doc().append(self.type_ast(a)));\n\n                pattern.append(annotation).group()\n            });\n            let assignments = Itertools::intersperse(assignments, break_(\",\", \", \"));\n            let left = [\"use\".to_doc(), break_(\"\", \" \")]\n                .into_iter()\n                .chain(assignments);\n            let left = concat(left).nest(INDENT).append(break_(\"\", \" \")).group();\n            docvec![left, \"<-\", call].group()\n        };\n\n        commented(doc, comments)\n    }\n\n    fn assert<'a>(&mut self, assert: &'a UntypedAssert) -> Document<'a> {\n        let comments = self.pop_comments(assert.location.start);\n\n        let expression = if assert.value.is_binop() || assert.value.is_pipeline() {\n            self.expr(&assert.value).nest(INDENT)\n        } else {\n            self.expr(&assert.value)\n        };\n\n        let doc =\n            self.append_as_message(expression, PrecedingAs::Expression, assert.message.as_ref());\n        commented(docvec![\"assert \", doc], comments)\n    }\n\n    fn bit_array<'a>(\n        &mut self,\n        segments: Vec<Document<'a>>,\n        packing: ItemsPacking,\n        location: &SrcSpan,\n    ) -> Document<'a> {\n        let comments = self.pop_comments(location.end);\n        let comments_doc = printed_comments(comments, false);\n\n        // Avoid adding illegal comma in empty bit array by explicitly handling it\n        if segments.is_empty() {\n            // We take all comments that come _before_ the end of the bit array,\n            // that is all comments that are inside \"<<\" and \">>\", if there's\n            // any comment we want to put it inside the empty bit array!\n            // Refer to the `list` function for a similar procedure.\n            return match comments_doc {\n                None => \"<<>>\".to_doc(),\n                Some(comments) => \"<<\"\n                    .to_doc()\n                    .append(break_(\"\", \"\").nest(INDENT))\n                    .append(comments)\n                    .append(break_(\"\", \"\"))\n                    .append(\">>\")\n                    // vvv We want to make sure the comments are on a separate\n                    //     line from the opening and closing angle brackets so\n                    //     we force the breaks to be split on newlines.\n                    .force_break(),\n            };\n        }\n\n        let comma = match packing {\n            ItemsPacking::FitMultiplePerLine => flex_break(\",\", \", \"),\n            ItemsPacking::FitOnePerLine | ItemsPacking::BreakOnePerLine => break_(\",\", \", \"),\n        };\n\n        let last_break = break_(\",\", \"\");\n        let doc = break_(\"<<\", \"<<\")\n            .append(join(segments, comma))\n            .nest(INDENT);\n\n        let doc = match comments_doc {\n            None => doc.append(last_break).append(\">>\"),\n            Some(comments) => doc\n                .append(last_break.nest(INDENT))\n                // ^ Notice how in this case we nest the final break before\n                //   adding it: this way the comments are going to be as\n                //   indented as the bit array items.\n                .append(comments.nest(INDENT))\n                .append(line())\n                .append(\">>\")\n                .force_break(),\n        };\n\n        match packing {\n            ItemsPacking::FitOnePerLine | ItemsPacking::FitMultiplePerLine => doc.group(),\n            ItemsPacking::BreakOnePerLine => doc.force_break(),\n        }\n    }\n\n    fn bit_array_segment_expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {\n        match expr {\n            UntypedExpr::BinOp { .. } => wrap_block(self.expr(expr)),\n\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::FieldAccess { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. }\n            | UntypedExpr::Block { .. } => self.expr(expr),\n        }\n    }\n\n    fn statement<'a>(&mut self, statement: &'a UntypedStatement) -> Document<'a> {\n        match statement {\n            Statement::Expression(expression) => self.expr(expression),\n            Statement::Assignment(assignment) => self.assignment(assignment),\n            Statement::Use(use_) => self.use_(use_),\n            Statement::Assert(assert) => self.assert(assert),\n        }\n    }\n\n    fn block<'a>(\n        &mut self,\n        location: &SrcSpan,\n        statements: &'a Vec1<UntypedStatement>,\n        force_breaks: bool,\n    ) -> Document<'a> {\n        let statements_doc =\n            docvec![break_(\"\", \" \"), self.statements(statements.as_vec())].nest(INDENT);\n        let trailing_comments = self.pop_comments(location.end);\n        let trailing_comments = printed_comments(trailing_comments, false);\n        let block_doc = match trailing_comments {\n            Some(trailing_comments_doc) => docvec![\n                \"{\",\n                statements_doc,\n                line().nest(INDENT),\n                trailing_comments_doc.nest(INDENT),\n                line(),\n                \"}\"\n            ]\n            .force_break(),\n            None => docvec![\"{\", statements_doc, break_(\"\", \" \"), \"}\"],\n        };\n\n        if force_breaks {\n            block_doc.force_break().group()\n        } else {\n            block_doc.group()\n        }\n    }\n\n    pub fn wrap_function_call_arguments<'a, I>(\n        &mut self,\n        arguments: I,\n        location: &SrcSpan,\n    ) -> Document<'a>\n    where\n        I: IntoIterator<Item = Document<'a>>,\n    {\n        let mut arguments = arguments.into_iter().peekable();\n        if arguments.peek().is_none() {\n            return \"()\".to_doc();\n        }\n\n        let arguments_doc = break_(\"\", \"\")\n            .append(join(arguments, break_(\",\", \", \")))\n            .nest_if_broken(INDENT);\n\n        // We get all remaining comments that come before the call's closing\n        // parenthesis.\n        // If there's any we add those before the closing parenthesis instead\n        // of moving those out of the call.\n        // Otherwise those would be moved out of the call.\n        let comments = self.pop_comments(location.end);\n        let closing_parens = match printed_comments(comments, false) {\n            None => docvec![break_(\",\", \"\"), \")\"],\n            Some(comment) => {\n                docvec![break_(\",\", \"\").nest(INDENT), comment, line(), \")\"].force_break()\n            }\n        };\n\n        \"(\".to_doc()\n            .append(arguments_doc)\n            .append(closing_parens)\n            .group()\n    }\n\n    pub fn wrap_arguments<'a, I>(&mut self, arguments: I, comments_limit: u32) -> Document<'a>\n    where\n        I: IntoIterator<Item = Document<'a>>,\n    {\n        let mut arguments = arguments.into_iter().peekable();\n        if arguments.peek().is_none() {\n            let comments = self.pop_comments(comments_limit);\n            return match printed_comments(comments, false) {\n                Some(comments) => \"(\"\n                    .to_doc()\n                    .append(break_(\"\", \"\"))\n                    .append(comments)\n                    .nest_if_broken(INDENT)\n                    .force_break()\n                    .append(break_(\"\", \"\"))\n                    .append(\")\"),\n                None => \"()\".to_doc(),\n            };\n        }\n        let doc = break_(\"(\", \"(\").append(join(arguments, break_(\",\", \", \")));\n\n        // Include trailing comments if there are any\n        let comments = self.pop_comments(comments_limit);\n        match printed_comments(comments, false) {\n            Some(comments) => doc\n                .append(break_(\",\", \"\"))\n                .append(comments)\n                .nest_if_broken(INDENT)\n                .force_break()\n                .append(break_(\"\", \"\"))\n                .append(\")\"),\n            None => doc\n                .nest_if_broken(INDENT)\n                .append(break_(\",\", \"\"))\n                .append(\")\"),\n        }\n    }\n\n    pub fn wrap_arguments_with_spread<'a, I>(\n        &mut self,\n        arguments: I,\n        comments_limit: u32,\n    ) -> Document<'a>\n    where\n        I: IntoIterator<Item = Document<'a>>,\n    {\n        let mut arguments = arguments.into_iter().peekable();\n        if arguments.peek().is_none() {\n            return self.wrap_arguments(arguments, comments_limit);\n        }\n        let doc = break_(\"(\", \"(\")\n            .append(join(arguments, break_(\",\", \", \")))\n            .append(break_(\",\", \", \"))\n            .append(\"..\");\n\n        // Include trailing comments if there are any\n        let comments = self.pop_comments(comments_limit);\n        match printed_comments(comments, false) {\n            Some(comments) => doc\n                .append(break_(\",\", \"\"))\n                .append(comments)\n                .nest_if_broken(INDENT)\n                .force_break()\n                .append(break_(\"\", \"\"))\n                .append(\")\"),\n            None => doc\n                .nest_if_broken(INDENT)\n                .append(break_(\",\", \"\"))\n                .append(\")\"),\n        }\n    }\n\n    /// Given some regular comments it pretty prints those with any respective\n    /// doc comment that might be preceding those.\n    /// For example:\n    ///\n    /// ```gleam\n    /// /// Doc\n    /// // comment\n    ///\n    /// /// Doc\n    /// pub fn wibble() {}\n    /// ```\n    ///\n    /// We don't want the first doc comment to be merged together with\n    /// `wibble`'s doc comment, so when we run into comments like `// comment`\n    /// we need to first print all documentation comments that come before it.\n    ///\n    fn printed_documented_comments<'a, 'b>(\n        &mut self,\n        comments: impl IntoIterator<Item = (u32, Option<&'b str>)>,\n    ) -> Option<Document<'a>> {\n        let mut comments = comments.into_iter().peekable();\n        let _ = comments.peek()?;\n\n        let mut doc = Vec::new();\n        while let Some(c) = comments.next() {\n            let (is_doc_commented, c) = match c {\n                (comment_start, Some(c)) => {\n                    let doc_comment = self.doc_comments(comment_start);\n                    let is_doc_commented = !doc_comment.is_empty();\n                    doc.push(doc_comment);\n                    (is_doc_commented, c)\n                }\n                (_, None) => continue,\n            };\n            doc.push(\"//\".to_doc().append(EcoString::from(c)));\n            match comments.peek() {\n                // Next line is a comment\n                Some((_, Some(_))) => doc.push(line()),\n                // Next line is empty\n                Some((_, None)) => {\n                    let _ = comments.next();\n                    doc.push(lines(2));\n                }\n                // We've reached the end, there are no more lines\n                None => {\n                    if is_doc_commented {\n                        doc.push(lines(2));\n                    } else {\n                        doc.push(line());\n                    }\n                }\n            }\n        }\n        let doc = concat(doc);\n        Some(doc.force_break())\n    }\n\n    fn append_as_message<'a>(\n        &mut self,\n        doc: Document<'a>,\n        preceding_as: PrecedingAs,\n        message: Option<&'a UntypedExpr>,\n    ) -> Document<'a> {\n        let Some(message) = message else { return doc };\n\n        let comments = self.pop_comments(message.location().start);\n        let comments = printed_comments(comments, false);\n\n        let as_ = match preceding_as {\n            PrecedingAs::Keyword => \" as\".to_doc(),\n            PrecedingAs::Expression => docvec![break_(\"\", \" \"), \"as\"].nest(INDENT),\n        };\n\n        let doc = match comments {\n            // If there's comments between the document and the message we want\n            // the `as` bit to be on the same line as the original document and\n            // go on a new indented line with the message and comments:\n            // ```gleam\n            // todo as\n            //   // comment!\n            //   \"wibble\"\n            // ```\n            Some(comments) => docvec![\n                doc.group(),\n                as_,\n                docvec![line(), comments, line(), self.expr(message).group()].nest(INDENT)\n            ],\n\n            None => {\n                let message = match (preceding_as, message) {\n                    // If we have `as` preceded by a keyword (like with `panic` and `todo`)\n                    // and the message is a block, we don't want to nest it any further. That is,\n                    // we want it to look like this:\n                    // ```gleam\n                    // panic as {\n                    //   wibble wobble\n                    // }\n                    // ```\n                    // instead of this:\n                    // ```gleam\n                    // panic as {\n                    //     wibble wobble\n                    //   }\n                    // ```\n                    (PrecedingAs::Keyword, UntypedExpr::Block { .. }) => self.expr(message).group(),\n                    _ => self.expr(message).group().nest(INDENT),\n                };\n                docvec![doc.group(), as_, \" \", message]\n            }\n        };\n\n        doc.group()\n    }\n\n    fn echo<'a>(\n        &mut self,\n        expression: &'a Option<Box<UntypedExpr>>,\n        message: &'a Option<Box<UntypedExpr>>,\n    ) -> Document<'a> {\n        let Some(expression) = expression else {\n            return self.append_as_message(\n                \"echo\".to_doc(),\n                PrecedingAs::Keyword,\n                message.as_deref(),\n            );\n        };\n\n        // When a binary expression gets broken on multiple lines we don't want\n        // it to be on the same line as echo, or it would look confusing;\n        // instead it's nested onto a new line:\n        //\n        // ```gleam\n        // echo first\n        //   |> wobble\n        //   |> wibble\n        // ```\n        //\n        // So it's easier to see echo is printing the whole thing. Otherwise,\n        // it would look like echo is printing just the first item:\n        //\n        // ```gleam\n        // echo first\n        // |> wobble\n        // |> wibble\n        // ```\n        //\n        let doc = self.expr(expression);\n        if expression.is_binop() || expression.is_pipeline() {\n            let doc = self.append_as_message(\n                doc.nest(INDENT),\n                PrecedingAs::Expression,\n                message.as_deref(),\n            );\n            docvec![\"echo \", doc]\n        } else {\n            docvec![\n                \"echo \",\n                self.append_as_message(doc, PrecedingAs::Expression, message.as_deref())\n            ]\n        }\n    }\n}\n\n/// This is used to describe the kind of things that might preceding an `as`\n/// message that can be added to various places: `panic`, `echo`, `let assert`,\n/// `assert`, `todo`.\n///\n/// It might be preceded by a keyword, like with `echo` and `panic`, or by\n/// an expression, like in `assert` or `let assert`.\n///\nenum PrecedingAs {\n    /// An expression is preceding the `as` message:\n    /// ```gleam\n    /// echo 1 as \"message\"\n    /// assert 1 == 2 as \"message\"\n    /// let assert Ok(_) = result as \"message\"\n    /// ```\n    ///\n    Expression,\n\n    /// A keyword is preceding the `as` message:\n    /// ```gleam\n    /// 1 |> echo as \"message\"\n    /// panic as \"message\"\n    /// todo as \"message\"\n    /// ```\n    ///\n    Keyword,\n}\n\nfn init_and_last<T>(vec: &[T]) -> Option<(&[T], &T)> {\n    match vec {\n        [] => None,\n        _ => match vec.split_at(vec.len() - 1) {\n            (init, [last]) => Some((init, last)),\n            _ => panic!(\"unreachable\"),\n        },\n    }\n}\n\nimpl<'a> Documentable<'a> for &'a ArgNames {\n    fn to_doc(self) -> Document<'a> {\n        match self {\n            ArgNames::Named { name, .. } | ArgNames::Discard { name, .. } => name.to_doc(),\n            ArgNames::LabelledDiscard { label, name, .. }\n            | ArgNames::NamedLabelled { label, name, .. } => {\n                docvec![label, \" \", name]\n            }\n        }\n    }\n}\n\nfn pub_(publicity: Publicity) -> Document<'static> {\n    match publicity {\n        Publicity::Public | Publicity::Internal { .. } => \"pub \".to_doc(),\n        Publicity::Private => nil(),\n    }\n}\n\nimpl<'a> Documentable<'a> for &'a UnqualifiedImport {\n    fn to_doc(self) -> Document<'a> {\n        self.name.as_str().to_doc().append(match &self.as_name {\n            None => nil(),\n            Some(s) => \" as \".to_doc().append(s.as_str()),\n        })\n    }\n}\n\nimpl<'a> Documentable<'a> for &'a BinOp {\n    fn to_doc(self) -> Document<'a> {\n        match self {\n            BinOp::And => \"&&\",\n            BinOp::Or => \"||\",\n            BinOp::LtInt => \"<\",\n            BinOp::LtEqInt => \"<=\",\n            BinOp::LtFloat => \"<.\",\n            BinOp::LtEqFloat => \"<=.\",\n            BinOp::Eq => \"==\",\n            BinOp::NotEq => \"!=\",\n            BinOp::GtEqInt => \">=\",\n            BinOp::GtInt => \">\",\n            BinOp::GtEqFloat => \">=.\",\n            BinOp::GtFloat => \">.\",\n            BinOp::AddInt => \"+\",\n            BinOp::AddFloat => \"+.\",\n            BinOp::SubInt => \"-\",\n            BinOp::SubFloat => \"-.\",\n            BinOp::MultInt => \"*\",\n            BinOp::MultFloat => \"*.\",\n            BinOp::DivInt => \"/\",\n            BinOp::DivFloat => \"/.\",\n            BinOp::RemainderInt => \"%\",\n            BinOp::Concatenate => \"<>\",\n        }\n        .to_doc()\n    }\n}\n\n#[allow(clippy::enum_variant_names)]\n#[derive(Debug)]\n/// This is used to determine how to fit the items of a list, or the segments of\n/// a bit array in a line.\n///\nenum ItemsPacking {\n    /// Try and fit everything on a single line; if the items don't fit, break\n    /// the list putting each item into its own line.\n    ///\n    /// ```gleam\n    /// // unbroken\n    /// [1, 2, 3]\n    ///\n    /// // broken\n    /// [\n    ///   1,\n    ///   2,\n    ///   3,\n    /// ]\n    /// ```\n    ///\n    FitOnePerLine,\n\n    /// Try and fit everything on a single line; if the items don't fit, break\n    /// the list putting as many items as possible in a single line.\n    ///\n    /// ```gleam\n    /// // unbroken\n    /// [1, 2, 3]\n    ///\n    /// // broken\n    /// [\n    ///   1, 2, 3, ...\n    ///   4, 100,\n    /// ]\n    /// ```\n    ///\n    FitMultiplePerLine,\n\n    /// Always break the list, putting each item into its own line:\n    ///\n    /// ```gleam\n    /// [\n    ///   1,\n    ///   2,\n    ///   3,\n    /// ]\n    /// ```\n    ///\n    BreakOnePerLine,\n}\n\npub fn break_block(doc: Document<'_>) -> Document<'_> {\n    \"{\".to_doc()\n        .append(line().append(doc).nest(INDENT))\n        .append(line())\n        .append(\"}\")\n        .force_break()\n}\n\npub fn wrap_block(doc: Document<'_>) -> Document<'_> {\n    break_(\"{\", \"{ \")\n        .append(doc)\n        .nest(INDENT)\n        .append(break_(\"\", \" \"))\n        .append(\"}\")\n}\n\nfn printed_comments<'a, 'comments>(\n    comments: impl IntoIterator<Item = Option<&'comments str>>,\n    trailing_newline: bool,\n) -> Option<Document<'a>> {\n    let mut comments = comments.into_iter().peekable();\n    let _ = comments.peek()?;\n\n    let mut doc = Vec::new();\n    while let Some(c) = comments.next() {\n        let c = match c {\n            Some(c) => c,\n            None => continue,\n        };\n        doc.push(\"//\".to_doc().append(EcoString::from(c)));\n        match comments.peek() {\n            // Next line is a comment\n            Some(Some(_)) => doc.push(line()),\n            // Next line is empty\n            Some(None) => {\n                let _ = comments.next();\n                match comments.peek() {\n                    Some(_) => doc.push(lines(2)),\n                    None => {\n                        if trailing_newline {\n                            doc.push(lines(2));\n                        }\n                    }\n                }\n            }\n            // We've reached the end, there are no more lines\n            None => {\n                if trailing_newline {\n                    doc.push(line());\n                }\n            }\n        }\n    }\n    let doc = concat(doc);\n    if trailing_newline {\n        Some(doc.force_break())\n    } else {\n        Some(doc)\n    }\n}\n\nfn commented<'a, 'comments>(\n    doc: Document<'a>,\n    comments: impl IntoIterator<Item = Option<&'comments str>>,\n) -> Document<'a> {\n    match printed_comments(comments, true) {\n        Some(comments) => comments.append(doc.group()),\n        None => doc,\n    }\n}\n\nfn bit_array_segment<Value, Type, ToDoc>(\n    segment: &BitArraySegment<Value, Type>,\n    mut to_doc: ToDoc,\n) -> Document<'_>\nwhere\n    ToDoc: FnMut(&Value) -> Document<'_>,\n{\n    match segment {\n        BitArraySegment { value, options, .. } if options.is_empty() => to_doc(value),\n\n        BitArraySegment { value, options, .. } => to_doc(value).append(\":\").append(join(\n            options\n                .iter()\n                .map(|option| segment_option(option, |value| to_doc(value))),\n            \"-\".to_doc(),\n        )),\n    }\n}\n\nfn segment_option<ToDoc, Value>(option: &BitArrayOption<Value>, mut to_doc: ToDoc) -> Document<'_>\nwhere\n    ToDoc: FnMut(&Value) -> Document<'_>,\n{\n    match option {\n        BitArrayOption::Bytes { .. } => \"bytes\".to_doc(),\n        BitArrayOption::Bits { .. } => \"bits\".to_doc(),\n        BitArrayOption::Int { .. } => \"int\".to_doc(),\n        BitArrayOption::Float { .. } => \"float\".to_doc(),\n        BitArrayOption::Utf8 { .. } => \"utf8\".to_doc(),\n        BitArrayOption::Utf16 { .. } => \"utf16\".to_doc(),\n        BitArrayOption::Utf32 { .. } => \"utf32\".to_doc(),\n        BitArrayOption::Utf8Codepoint { .. } => \"utf8_codepoint\".to_doc(),\n        BitArrayOption::Utf16Codepoint { .. } => \"utf16_codepoint\".to_doc(),\n        BitArrayOption::Utf32Codepoint { .. } => \"utf32_codepoint\".to_doc(),\n        BitArrayOption::Signed { .. } => \"signed\".to_doc(),\n        BitArrayOption::Unsigned { .. } => \"unsigned\".to_doc(),\n        BitArrayOption::Big { .. } => \"big\".to_doc(),\n        BitArrayOption::Little { .. } => \"little\".to_doc(),\n        BitArrayOption::Native { .. } => \"native\".to_doc(),\n\n        BitArrayOption::Size {\n            value,\n            short_form: false,\n            ..\n        } => \"size\"\n            .to_doc()\n            .append(\"(\")\n            .append(to_doc(value))\n            .append(\")\"),\n\n        BitArrayOption::Size {\n            value,\n            short_form: true,\n            ..\n        } => to_doc(value),\n\n        BitArrayOption::Unit { value, .. } => \"unit\"\n            .to_doc()\n            .append(\"(\")\n            .append(eco_format!(\"{value}\"))\n            .append(\")\"),\n    }\n}\n\npub fn comments_before<'a>(\n    comments: &'a [Comment<'a>],\n    empty_lines: &'a [u32],\n    limit: u32,\n    retain_empty_lines: bool,\n) -> (\n    impl Iterator<Item = (u32, Option<&'a str>)>,\n    &'a [Comment<'a>],\n    &'a [u32],\n) {\n    let end_comments = comments\n        .iter()\n        .position(|c| c.start > limit)\n        .unwrap_or(comments.len());\n    let end_empty_lines = empty_lines\n        .iter()\n        .position(|l| *l > limit)\n        .unwrap_or(empty_lines.len());\n    let popped_comments = comments\n        .get(0..end_comments)\n        .expect(\"0..end_comments is guaranteed to be in bounds\")\n        .iter()\n        .map(|c| (c.start, Some(c.content)));\n    let popped_empty_lines = if retain_empty_lines { empty_lines } else { &[] }\n        .get(0..end_empty_lines)\n        .unwrap_or(&[])\n        .iter()\n        .map(|i| (i, i))\n        // compact consecutive empty lines into a single line\n        .coalesce(|(a_start, a_end), (b_start, b_end)| {\n            if *a_end + 1 == *b_start {\n                Ok((a_start, b_end))\n            } else {\n                Err(((a_start, a_end), (b_start, b_end)))\n            }\n        })\n        .map(|l| (*l.0, None));\n    let popped = popped_comments\n        .merge_by(popped_empty_lines, |(a, _), (b, _)| a < b)\n        .skip_while(|(_, comment_or_line)| comment_or_line.is_none());\n    (\n        popped,\n        comments.get(end_comments..).expect(\"in bounds\"),\n        empty_lines.get(end_empty_lines..).expect(\"in bounds\"),\n    )\n}\n\nfn is_breakable_argument(expr: &UntypedExpr, arity: usize) -> bool {\n    match expr {\n        // A call is only breakable if it is the only argument\n        UntypedExpr::Call { .. } => arity == 1,\n\n        UntypedExpr::Fn { .. }\n        | UntypedExpr::Block { .. }\n        | UntypedExpr::Case { .. }\n        | UntypedExpr::List { .. }\n        | UntypedExpr::Tuple { .. }\n        | UntypedExpr::BitArray { .. } => true,\n\n        UntypedExpr::Int { .. }\n        | UntypedExpr::Float { .. }\n        | UntypedExpr::String { .. }\n        | UntypedExpr::Var { .. }\n        | UntypedExpr::BinOp { .. }\n        | UntypedExpr::PipeLine { .. }\n        | UntypedExpr::FieldAccess { .. }\n        | UntypedExpr::TupleIndex { .. }\n        | UntypedExpr::Todo { .. }\n        | UntypedExpr::Panic { .. }\n        | UntypedExpr::Echo { .. }\n        | UntypedExpr::RecordUpdate { .. }\n        | UntypedExpr::NegateBool { .. }\n        | UntypedExpr::NegateInt { .. } => false,\n    }\n}\n\nenum CallArgFormatting<'a, A> {\n    ShorthandLabelled(&'a EcoString),\n    Unlabelled(&'a A),\n    Labelled(&'a EcoString, &'a A),\n}\n\nfn expr_call_arg_formatting(arg: &CallArg<UntypedExpr>) -> CallArgFormatting<'_, UntypedExpr> {\n    match arg {\n        // An argument supplied using label shorthand syntax.\n        _ if arg.uses_label_shorthand() => CallArgFormatting::ShorthandLabelled(\n            arg.label.as_ref().expect(\"label shorthand with no label\"),\n        ),\n        // A labelled argument.\n        CallArg {\n            label: Some(label),\n            value,\n            ..\n        } => CallArgFormatting::Labelled(label, value),\n        // An unlabelled argument.\n        CallArg { value, .. } => CallArgFormatting::Unlabelled(value),\n    }\n}\n\nfn pattern_call_arg_formatting(\n    arg: &CallArg<UntypedPattern>,\n) -> CallArgFormatting<'_, UntypedPattern> {\n    match arg {\n        // An argument supplied using label shorthand syntax.\n        _ if arg.uses_label_shorthand() => CallArgFormatting::ShorthandLabelled(\n            arg.label.as_ref().expect(\"label shorthand with no label\"),\n        ),\n        // A labelled argument.\n        CallArg {\n            label: Some(label),\n            value,\n            ..\n        } => CallArgFormatting::Labelled(label, value),\n        // An unlabelled argument.\n        CallArg { value, .. } => CallArgFormatting::Unlabelled(value),\n    }\n}\n\nfn constant_call_arg_formatting<A, B>(\n    arg: &CallArg<Constant<A, B>>,\n) -> CallArgFormatting<'_, Constant<A, B>> {\n    match arg {\n        // An argument supplied using label shorthand syntax.\n        _ if arg.uses_label_shorthand() => CallArgFormatting::ShorthandLabelled(\n            arg.label.as_ref().expect(\"label shorthand with no label\"),\n        ),\n        // A labelled argument.\n        CallArg {\n            label: Some(label),\n            value,\n            ..\n        } => CallArgFormatting::Labelled(label, value),\n        // An unlabelled argument.\n        CallArg { value, .. } => CallArgFormatting::Unlabelled(value),\n    }\n}\n\nstruct AttributesPrinter<'a> {\n    external_erlang: &'a Option<(EcoString, EcoString, SrcSpan)>,\n    external_javascript: &'a Option<(EcoString, EcoString, SrcSpan)>,\n    deprecation: &'a Deprecation,\n    internal: bool,\n}\n\nimpl<'a> AttributesPrinter<'a> {\n    pub fn new() -> Self {\n        Self {\n            external_erlang: &None,\n            external_javascript: &None,\n            deprecation: &Deprecation::NotDeprecated,\n            internal: false,\n        }\n    }\n\n    pub fn set_external_erlang(\n        mut self,\n        external: &'a Option<(EcoString, EcoString, SrcSpan)>,\n    ) -> Self {\n        self.external_erlang = external;\n        self\n    }\n\n    pub fn set_external_javascript(\n        mut self,\n        external: &'a Option<(EcoString, EcoString, SrcSpan)>,\n    ) -> Self {\n        self.external_javascript = external;\n        self\n    }\n\n    pub fn set_internal(mut self, publicity: Publicity) -> Self {\n        self.internal = publicity.is_internal();\n        self\n    }\n\n    pub fn set_deprecation(mut self, deprecation: &'a Deprecation) -> Self {\n        self.deprecation = deprecation;\n        self\n    }\n}\n\nimpl<'a> Documentable<'a> for AttributesPrinter<'a> {\n    fn to_doc(self) -> Document<'a> {\n        let mut attributes = vec![];\n\n        // @deprecated attribute\n        if let Deprecation::Deprecated { message } = self.deprecation {\n            attributes.push(docvec![\"@deprecated(\\\"\", message, \"\\\")\"])\n        };\n\n        // @external attributes\n        if let Some((m, f, _)) = self.external_erlang {\n            attributes.push(docvec![\"@external(erlang, \\\"\", m, \"\\\", \\\"\", f, \"\\\")\"])\n        };\n\n        if let Some((m, f, _)) = self.external_javascript {\n            attributes.push(docvec![\"@external(javascript, \\\"\", m, \"\\\", \\\"\", f, \"\\\")\"])\n        };\n\n        // @internal attribute\n        if self.internal {\n            attributes.push(\"@internal\".to_doc());\n        };\n\n        if attributes.is_empty() {\n            nil()\n        } else {\n            join(attributes, line()).append(line())\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/graph.rs",
    "content": "//! General functions for working with graphs.\n\nuse petgraph::{Direction, prelude::NodeIndex, stable_graph::StableGraph};\n\n/// Sort a graph into a sequence from the leaves to the roots.\n///\n/// Nodes are returned in their smallest possible groups, which is either a leaf\n/// or a cycle.\n///\n/// This function is implemented using `pop_leaf_or_cycle`.\n///\npub fn into_dependency_order<N, E>(mut graph: StableGraph<N, E>) -> Vec<Vec<NodeIndex>> {\n    let mut items = vec![];\n\n    // Remove all self-edges from the graph.\n    graph.retain_edges(|graph, edge| match graph.edge_endpoints(edge) {\n        Some((a, b)) => a != b,\n        None => false,\n    });\n\n    loop {\n        let current = pop_leaf_or_cycle(&mut graph);\n        if current.is_empty() {\n            return items;\n        } else {\n            items.push(current);\n        }\n    }\n}\n\n/// The same as `leaf_or_cycle` but removes the nodes from the graph.\n/// See the docs there for more details.\n///\n/// # Panics\n///\n/// Panics if the graph contains a self-edge.\n///\nfn pop_leaf_or_cycle<N, E>(graph: &mut StableGraph<N, E>) -> Vec<NodeIndex> {\n    let nodes = leaf_or_cycle(graph);\n    for node in &nodes {\n        _ = graph.remove_node(*node);\n    }\n    nodes\n}\n\n/// Return a leaf from the graph. If there are no leaves then the largest cycle\n/// is returned instead.\n///\n/// If there are no leaves or cycles then an empty vector is returned.\n///\n/// The nodes returned are not removed from the graph.\n///\n/// # Panics\n///\n/// Panics if the graph contains a self-edge.\n///\nfn leaf_or_cycle<N, E>(graph: &StableGraph<N, E>) -> Vec<NodeIndex> {\n    if graph.node_count() == 0 {\n        return vec![];\n    }\n\n    // Find a leaf, returning one if found.\n    for node in graph.node_indices() {\n        let mut outgoing = graph.neighbors_directed(node, Direction::Outgoing);\n        let referenced = outgoing.next();\n\n        if referenced == Some(node) {\n            panic!(\"Self edge found in graph\");\n        }\n\n        // This is a leaf.\n        if referenced.is_none() {\n            return vec![node];\n        }\n    }\n\n    // No leaves were found, so find a cycle.\n    // We use a toposort to find the start of the cycle.\n    let start = petgraph::algo::toposort(&graph, None)\n        .expect_err(\"Non-empty graph has no leaves or cycles\")\n        .node_id();\n\n    // Then traverse the graph to find nodes in the cycle.\n    // This traverses all possible paths to find a cycle, this can likely be\n    // optimised. There's not a large number of functions in a module however so\n    // this is tolerable in this specific instance.\n    #[derive(Debug)]\n    enum Step {\n        Backtrack,\n        Next(NodeIndex),\n    }\n    let mut path = vec![];\n    let mut stack = vec![Step::Next(start)];\n    let mut cycles = vec![];\n\n    while let Some(step) = stack.pop() {\n        let node = match step {\n            // We have processed all the nodes in the branch so backtrack,\n            // popping the node off the path.\n            Step::Backtrack => {\n                _ = path.pop();\n                continue;\n            }\n            Step::Next(node) => node,\n        };\n\n        if path.contains(&node) {\n            continue;\n        }\n\n        // Add this node to the path and record the point at which we need to\n        // backtrack in order to go back up the tree.\n        stack.push(Step::Backtrack);\n        path.push(node);\n\n        // Check each child & add them to the stack if they are not the target.\n        for node in graph.neighbors_directed(node, Direction::Outgoing) {\n            if node == start {\n                cycles.push(path.clone());\n            } else {\n                stack.push(Step::Next(node));\n            }\n        }\n    }\n\n    cycles\n        .into_iter()\n        .max_by_key(|x| x.len())\n        .expect(\"Could not find cycle for toposort returned start node\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn leaf_or_cycle_empty() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        assert!(pop_leaf_or_cycle(&mut graph).is_empty());\n    }\n\n    #[test]\n    fn leaf_or_cycle_1() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        assert_eq!(into_dependency_order(graph), vec![vec![a]]);\n    }\n\n    #[test]\n    fn leaf_or_cycle_2() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n\n        assert_eq!(into_dependency_order(graph), vec![vec![a], vec![b]]);\n    }\n\n    #[test]\n    fn leaf_or_cycle_3() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        // Here a depends on b so b must come before a\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        let c = graph.add_node(());\n        _ = graph.add_edge(a, b, ());\n\n        assert_eq!(\n            into_dependency_order(graph),\n            vec![vec![b], vec![a], vec![c]]\n        );\n    }\n\n    #[test]\n    fn leaf_or_cycle_4() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        let c = graph.add_node(());\n        _ = graph.add_edge(a, b, ());\n        _ = graph.add_edge(a, c, ());\n\n        assert_eq!(\n            into_dependency_order(graph),\n            vec![vec![b], vec![c], vec![a]]\n        );\n    }\n\n    #[test]\n    fn leaf_or_cycle_5() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        let c = graph.add_node(());\n        _ = graph.add_edge(a, b, ());\n        _ = graph.add_edge(b, a, ());\n\n        assert_eq!(into_dependency_order(graph), vec![vec![c], vec![b, a]]);\n    }\n\n    #[test]\n    fn leaf_or_cycle_6() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        let c = graph.add_node(());\n        let d = graph.add_node(());\n        _ = graph.add_edge(a, b, ());\n        _ = graph.add_edge(b, c, ());\n        _ = graph.add_edge(c, a, ());\n        _ = graph.add_edge(d, a, ());\n\n        assert_eq!(into_dependency_order(graph), vec![vec![c, a, b], vec![d]]);\n    }\n\n    #[test]\n    fn leaf_or_cycle_7() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        _ = graph.add_edge(a, a, ());\n        _ = graph.add_edge(a, b, ());\n        _ = graph.add_edge(b, b, ());\n\n        // Here there are no true leafs, only cycles. However, b is in a loop\n        // with itself so counts as a leaf as far as we are concerned.\n\n        assert_eq!(into_dependency_order(graph), vec![vec![b], vec![a]]);\n    }\n\n    #[test]\n    fn leaf_or_cycle_8() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        _ = graph.add_edge(a, a, ());\n        _ = graph.add_edge(a, b, ());\n        _ = graph.add_edge(b, b, ());\n        _ = graph.add_edge(b, b, ());\n        _ = graph.add_edge(b, b, ());\n\n        // Here there are no true leafs, only cycles. However, b is in a loop\n        // with itself so counts as a leaf as far as we are concerned.\n        // This is different from the previous test as there are multiple self\n        // references for node b.\n\n        assert_eq!(into_dependency_order(graph), vec![vec![b], vec![a]]);\n    }\n\n    #[test]\n    fn leaf_or_cycle_9() {\n        let mut graph: StableGraph<(), ()> = StableGraph::new();\n        let a = graph.add_node(());\n        let b = graph.add_node(());\n        let c = graph.add_node(());\n\n        _ = graph.add_edge(a, a, ());\n        _ = graph.add_edge(a, b, ());\n\n        _ = graph.add_edge(b, b, ());\n        _ = graph.add_edge(b, c, ());\n\n        _ = graph.add_edge(c, b, ());\n        _ = graph.add_edge(c, c, ());\n\n        // Here there are no true leafs, only cycles. However, b is in a loop\n        // with itself so counts as a leaf as far as we are concerned.\n        // This is different from the previous test as there are multiple self\n        // references for node b.\n\n        assert_eq!(into_dependency_order(graph), vec![vec![c, b], vec![a]]);\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/hex.rs",
    "content": "use camino::Utf8Path;\nuse debug_ignore::DebugIgnore;\nuse flate2::read::GzDecoder;\nuse futures::future;\nuse hexpm::{ApiError, WriteActionCredentials, version::Version};\nuse tar::Archive;\n\nuse crate::{\n    Error, Result,\n    io::{FileSystemReader, FileSystemWriter, HttpClient, TarUnpacker},\n    manifest::{ManifestPackage, ManifestPackageSource},\n    paths::{self, ProjectPaths},\n};\n\npub const HEXPM_PUBLIC_KEY: &[u8] = b\"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB\nEdvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+\nIqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM\n3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW\nXgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ\nJ1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4\n0wIDAQAB\n-----END PUBLIC KEY-----\n\";\n\nfn key_name(hostname: &str) -> String {\n    format!(\"gleam-{hostname}\")\n}\n\npub async fn publish_package<Http: HttpClient>(\n    release_tarball: Vec<u8>,\n    version: String,\n    name: &str,\n    api_key: &WriteActionCredentials,\n    config: &hexpm::Config,\n    replace: bool,\n    http: &Http,\n) -> Result<()> {\n    tracing::info!(\"Publishing package, replace: {}\", replace);\n    let request = hexpm::api_publish_package_request(release_tarball, api_key, config, replace);\n    let response = http.send(request).await?;\n    hexpm::api_publish_package_response(response).map_err(|e| match e {\n        ApiError::NotReplacing => Error::HexPublishReplaceRequired { version },\n        ApiError::Forbidden => Error::HexPublishAccessDenied {\n            name: name.into(),\n            version,\n        },\n        ApiError::Json(_)\n        | ApiError::Io(_)\n        | ApiError::RateLimited\n        | ApiError::InvalidCredentials\n        | ApiError::UnexpectedResponse(..)\n        | ApiError::InvalidPackageNameFormat(_)\n        | ApiError::IncorrectPayloadSignature\n        | ApiError::InvalidProtobuf(_)\n        | ApiError::InvalidVersionFormat(_)\n        | ApiError::NotFound\n        | ApiError::InvalidVersionRequirementFormat(_)\n        | ApiError::IncorrectChecksum\n        | ApiError::OAuthTimeout\n        | ApiError::OAuthAccessDenied\n        | ApiError::ExpiredToken\n        | ApiError::OAuthRefreshTokenRejected\n        | ApiError::IncorrectOneTimePassword\n        | ApiError::LateModification => Error::hex(e),\n    })\n}\n\npub async fn transfer_owner<Http: HttpClient>(\n    api_key: &WriteActionCredentials,\n    package_name: String,\n    new_owner_username_or_email: String,\n    config: &hexpm::Config,\n    http: &Http,\n) -> Result<()> {\n    tracing::info!(\n        \"Transferring ownership of `{}` to {}\",\n        package_name,\n        new_owner_username_or_email\n    );\n    let request = hexpm::api_transfer_owner_request(\n        &package_name,\n        &new_owner_username_or_email,\n        api_key,\n        config,\n    );\n    let response = http.send(request).await?;\n    hexpm::api_transfer_owner_response(response).map_err(Error::hex)\n}\n\n#[derive(Debug, strum::EnumString, strum::VariantNames, Clone, Copy, PartialEq, Eq)]\n#[strum(serialize_all = \"lowercase\")]\npub enum RetirementReason {\n    Other,\n    Invalid,\n    Security,\n    Deprecated,\n    Renamed,\n}\n\nimpl RetirementReason {\n    pub fn to_library_enum(&self) -> hexpm::RetirementReason {\n        match self {\n            RetirementReason::Other => hexpm::RetirementReason::Other,\n            RetirementReason::Invalid => hexpm::RetirementReason::Invalid,\n            RetirementReason::Security => hexpm::RetirementReason::Security,\n            RetirementReason::Deprecated => hexpm::RetirementReason::Deprecated,\n            RetirementReason::Renamed => hexpm::RetirementReason::Renamed,\n        }\n    }\n}\n\npub async fn retire_release<Http: HttpClient>(\n    package: &str,\n    version: &str,\n    reason: RetirementReason,\n    message: Option<&str>,\n    api_key: &WriteActionCredentials,\n    config: &hexpm::Config,\n    http: &Http,\n) -> Result<()> {\n    tracing::info!(package=%package, version=%version, \"retiring_hex_release\");\n    let request = hexpm::api_retire_release_request(\n        package,\n        version,\n        reason.to_library_enum(),\n        message,\n        api_key,\n        config,\n    );\n    let response = http.send(request).await?;\n    hexpm::api_retire_release_response(response).map_err(Error::hex)\n}\n\npub async fn unretire_release<Http: HttpClient>(\n    package: &str,\n    version: &str,\n    api_key: &WriteActionCredentials,\n    config: &hexpm::Config,\n    http: &Http,\n) -> Result<()> {\n    tracing::info!(package=%package, version=%version, \"retiring_hex_release\");\n    let request = hexpm::api_unretire_release_request(package, version, api_key, config);\n    let response = http.send(request).await?;\n    hexpm::api_unretire_release_response(response).map_err(Error::hex)\n}\n\npub async fn remove_api_key<Http: HttpClient>(\n    hostname: &str,\n    config: &hexpm::Config,\n    auth_key: &WriteActionCredentials,\n    http: &Http,\n) -> Result<()> {\n    tracing::info!(\"Deleting API key from Hex\");\n    let request = hexpm::api_remove_api_key_request(&key_name(hostname), auth_key, config);\n    let response = http.send(request).await?;\n    hexpm::api_remove_api_key_response(response).map_err(Error::hex)\n}\n\n#[derive(Debug)]\npub struct Downloader {\n    fs_reader: DebugIgnore<Box<dyn FileSystemReader>>,\n    fs_writer: DebugIgnore<Box<dyn FileSystemWriter>>,\n    http: DebugIgnore<Box<dyn HttpClient>>,\n    untar: DebugIgnore<Box<dyn TarUnpacker>>,\n    hex_config: hexpm::Config,\n    paths: ProjectPaths,\n}\n\nimpl Downloader {\n    pub fn new(\n        fs_reader: Box<dyn FileSystemReader>,\n        fs_writer: Box<dyn FileSystemWriter>,\n        http: Box<dyn HttpClient>,\n        untar: Box<dyn TarUnpacker>,\n        paths: ProjectPaths,\n    ) -> Self {\n        Self {\n            fs_reader: DebugIgnore(fs_reader),\n            fs_writer: DebugIgnore(fs_writer),\n            http: DebugIgnore(http),\n            untar: DebugIgnore(untar),\n            hex_config: hexpm::Config::new(),\n            paths,\n        }\n    }\n\n    pub async fn ensure_package_downloaded(\n        &self,\n        package: &ManifestPackage,\n    ) -> Result<bool, Error> {\n        let outer_checksum = match &package.source {\n            ManifestPackageSource::Hex { outer_checksum } => outer_checksum,\n            ManifestPackageSource::Git { .. } | ManifestPackageSource::Local { .. } => {\n                panic!(\"Attempt to download non-hex package from hex\")\n            }\n        };\n\n        let tarball_path = paths::global_package_cache_package_tarball(outer_checksum);\n        if self.fs_reader.is_file(&tarball_path) {\n            tracing::info!(\n                package = package.name.as_str(),\n                version = %package.version,\n                \"package_in_cache\"\n            );\n            return Ok(false);\n        }\n        tracing::info!(\n            package = &package.name.as_str(),\n            version = %package.version,\n            \"downloading_package_to_cache\"\n        );\n\n        let request = hexpm::repository_get_package_tarball_request(\n            &package.name,\n            &package.version.to_string(),\n            None,\n            &self.hex_config,\n        );\n        let response = self.http.send(request).await?;\n\n        let tarball = hexpm::repository_get_package_tarball_response(response, &outer_checksum.0)\n            .map_err(|error| Error::DownloadPackageError {\n            package_name: package.name.to_string(),\n            package_version: package.version.to_string(),\n            error: error.to_string(),\n        })?;\n        self.fs_writer.write_bytes(&tarball_path, &tarball)?;\n        Ok(true)\n    }\n\n    pub async fn ensure_package_in_build_directory(\n        &self,\n        package: &ManifestPackage,\n    ) -> Result<bool> {\n        let _ = self.ensure_package_downloaded(package).await?;\n        self.extract_package_from_cache(package)\n    }\n\n    // It would be really nice if this was async but the library is sync\n    pub fn extract_package_from_cache(&self, package: &ManifestPackage) -> Result<bool> {\n        let contents_path = Utf8Path::new(\"contents.tar.gz\");\n        let destination = self.paths.build_packages_package(&package.name);\n\n        let outer_checksum = match &package.source {\n            ManifestPackageSource::Hex { outer_checksum } => outer_checksum,\n            ManifestPackageSource::Git { .. } | ManifestPackageSource::Local { .. } => {\n                panic!(\"Attempt to download non-hex package from hex\")\n            }\n        };\n\n        // If the directory already exists then there's nothing for us to do\n        if self.fs_reader.is_directory(&destination) {\n            tracing::info!(\n                package = package.name.as_str(),\n                \"Package already in build directory\"\n            );\n            return Ok(false);\n        }\n\n        tracing::info!(package = package.name.as_str(), \"writing_package_to_target\");\n        let tarball = paths::global_package_cache_package_tarball(outer_checksum);\n        let reader = self.fs_reader.reader(&tarball)?;\n        let mut archive = Archive::new(reader);\n\n        // Find the source code from within the outer tarball\n        for entry in self.untar.entries(&mut archive)? {\n            let file = entry.map_err(Error::expand_tar)?;\n\n            let path = file.header().path().map_err(Error::expand_tar)?;\n            if path.as_ref() == contents_path {\n                // Expand this inner source code and write to the file system\n                let archive = Archive::new(GzDecoder::new(file));\n                let result = self.untar.unpack(&destination, archive);\n\n                // If we failed to expand the tarball remove any source code\n                // that was partially written so that we don't mistakenly think\n                // the operation succeeded next time we run.\n                return match result {\n                    Ok(()) => Ok(true),\n                    Err(err) => {\n                        self.fs_writer.delete_directory(&destination)?;\n                        Err(err)\n                    }\n                };\n            }\n        }\n\n        Err(Error::ExpandTar {\n            error: \"Unable to locate Hex package contents.tar.gz\".into(),\n        })\n    }\n\n    pub async fn download_hex_packages<'a, Packages: Iterator<Item = &'a ManifestPackage>>(\n        &self,\n        packages: Packages,\n        project_name: &str,\n    ) -> Result<()> {\n        let futures = packages\n            .filter(|package| project_name != package.name)\n            .map(|package| self.ensure_package_in_build_directory(package));\n\n        // Run the futures to download the packages concurrently\n        let results = future::join_all(futures).await;\n\n        // Count the number of packages downloaded while checking for errors\n        for result in results {\n            let _ = result?;\n        }\n        Ok(())\n    }\n}\n\npub async fn publish_documentation<Http: HttpClient>(\n    name: &str,\n    version: &Version,\n    archive: Vec<u8>,\n    api_key: &WriteActionCredentials,\n    config: &hexpm::Config,\n    http: &Http,\n) -> Result<()> {\n    tracing::info!(\"publishing_documentation\");\n    let request =\n        hexpm::api_publish_docs_request(name, &version.to_string(), archive, api_key, config)\n            .map_err(Error::hex)?;\n    let response = http.send(request).await?;\n    hexpm::api_publish_docs_response(response).map_err(Error::hex)\n}\n\npub async fn get_package_release<Http: HttpClient>(\n    name: &str,\n    version: &Version,\n    config: &hexpm::Config,\n    http: &Http,\n) -> Result<hexpm::Release<hexpm::ReleaseMeta>> {\n    let version = version.to_string();\n    tracing::info!(\n        name = name,\n        version = version.as_str(),\n        \"looking_up_package_release\"\n    );\n    let request = hexpm::api_get_package_release_request(name, &version, None, config);\n    let response = http.send(request).await?;\n    hexpm::api_get_package_release_response(response).map_err(Error::hex)\n}\n"
  },
  {
    "path": "compiler-core/src/inline.rs",
    "content": "//! This module implements the function inlining optimisation. This allows\n//! function calls to be inlined at the callsite, and replaced with the contents\n//! of the function which is being called.\n//!\n//! Function inlining is useful for two main reasons:\n//! - It removes the overhead of calling other functions and jumping around\n//!   execution too much\n//! - It removes the barrier of the function call between the code around the\n//!   call, and the code inside the called function.\n//!\n//! For example, the following Gleam code make heavy use of `use` sugar and higher\n//! order functions:\n//!\n//! ```gleam\n//! pub fn try_sum(list: List(Result(String, Nil)), sum: Int) -> Result(Int, Nil) {\n//!   use <- bool.guard(when: sum >= 1000, return: Ok(sum))\n//!   case list {\n//!     [] -> Ok(sum)\n//!     [first, ..rest] -> {\n//!       use number <- result.try(int.parse(first))\n//!       try_sum(rest, sum + number)\n//!     }\n//!   }\n//! }\n//! ```\n//!\n//! This can make the code easier to read, but it normally would have a performance\n//! cost. There are two called functions, and two implicit anonymous functions.\n//! This function is also not tail recursive, as it uses higher order functions\n//! inside its body.\n//!\n//! However, with function inlining, the above code can be optimised to:\n//!\n//! ```gleam\n//! pub fn try_sum(list: List(Result(String, Nil)), sum: Int) -> Result(Int, Nil) {\n//!   case sum >= 1000 {\n//!     True -> Ok(sum)\n//!     False -> case list {\n//!       [] -> Ok(sum)\n//!       [first, ..rest] -> {\n//!         case int.parse(first) {\n//!           Ok(number) -> try_sum(rest, sum + number)\n//!           Error(error) -> Error(error)\n//!         }\n//!       }\n//!     }\n//!   }\n//! }\n//! ```\n//!\n//! Which now has no extra function calls, and is tail recursive!\n//!\n//! The process of function inlining is quite simple really. It is implemented\n//! using an AST folder, which traverses each node of the AST, and potentially\n//! alters it as it goes.\n//!\n//! Every time we encounter a function call, we decide whether or not we can\n//! inline it. For now, the criteria for inlining is very simple, although a\n//! more complex heuristic-based approach will likely be implemented in the\n//! future. For now though, a function can be inlined if:\n//! It is a standard library function within the hardcoded list - which can be\n//! found in the `inline_function` function - or, it is an anonymous function.\n//!\n//! Inlining anonymous functions allows us to:\n//! - Remove calls to parameters of higher-order functions once those higher-\n//!   order functions have been inlined. For example, the following example using\n//!   `result.map`:\n//!   ```gleam\n//!   result.map(Ok(10), fn(x) { x + 1 })\n//!   ```\n//!\n//!   Without inlining of anonymous function would be turned into:\n//!   ```gleam\n//!   case Ok(10) {\n//!     Ok(value) -> Ok(fn(x) { x + 1 }(value))\n//!     Error(error) -> Error(error)\n//!   }\n//!   ```\n//!\n//!   However if we inline anonymous functions also, we remove every call, and\n//!   so it becomes:\n//!\n//!   ```gleam\n//!   case Ok(10) {\n//!     Ok(value) -> Ok(value + 1)\n//!     Error(error) -> Error(error)\n//!   }\n//!   ```\n//!\n//! - Remove calls to anonymous functions in pipelines. Sometimes, an anonymous\n//!   function is used in a pipeline, which can sometimes be the result of an\n//!   expanded function capture. For example:\n//!\n//!   ```gleam\n//!   \"10\" |> int.parse |> result.unwrap(0) |> fn(x) { x * x } |> something_else\n//!   ```\n//!\n//!   This can now be desugared to:\n//!   ```gleam\n//!   let _pipe1 = \"10\"\n//!   let _pipe2 = int.parse(_pipe1)\n//!   let _pipe3 = result.unwrap(_pipe2, 0)\n//!   let _pipe4 = _pipe3 * _pipe3\n//!   something_else(_pipe4)\n//!   ```\n//!\n//! See documentation of individual functions to explain better how the process\n//! works.\n//!\n\n#![allow(dead_code)]\n\nuse std::{\n    collections::{HashMap, HashSet},\n    sync::Arc,\n};\n\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse vec1::Vec1;\n\nuse crate::{\n    STDLIB_PACKAGE_NAME,\n    analyse::Inferred,\n    ast::{\n        self, ArgNames, Assert, AssignName, Assignment, AssignmentKind, BitArrayOption,\n        BitArraySegment, BitArraySize, CallArg, Clause, FunctionLiteralKind, Pattern,\n        PipelineAssignmentKind, Publicity, SrcSpan, Statement, TailPattern, TypedArg, TypedAssert,\n        TypedAssignment, TypedBitArraySize, TypedClause, TypedDefinitions, TypedExpr,\n        TypedExprBitArraySegment, TypedFunction, TypedModule, TypedPattern,\n        TypedPipelineAssignment, TypedStatement, TypedUse, visit::Visit,\n    },\n    exhaustiveness::{Body, CompiledCase, Decision},\n    type_::{\n        self, Deprecation, ModuleInterface, ModuleValueConstructor, PRELUDE_MODULE_NAME,\n        PatternConstructor, Type, TypedCallArg, ValueConstructor, ValueConstructorVariant,\n        collapse_links,\n        error::VariableOrigin,\n        expression::{Implementations, Purity},\n    },\n};\n\n/// Perform function inlining across an entire module, applying it to each\n/// individual function.\npub fn module(\n    mut module: TypedModule,\n    modules: &im::HashMap<EcoString, ModuleInterface>,\n) -> TypedModule {\n    let mut inliner = Inliner::new(modules);\n\n    module.definitions = TypedDefinitions {\n        functions: module\n            .definitions\n            .functions\n            .into_iter()\n            .map(|function| inliner.function(function))\n            .collect(),\n        ..module.definitions\n    };\n\n    module\n}\n\nstruct Inliner<'a> {\n    /// Importable modules, containing information about functions which can be\n    /// inlined\n    modules: &'a im::HashMap<EcoString, ModuleInterface>,\n    /// Any variables which can be inlined. This is used when inlining the body\n    /// of function calls. Let's look at an example inlinable function:\n    /// ```gleam\n    /// pub fn add(a, b) {\n    ///   a + b\n    /// }\n    /// ```\n    /// If it is called - `add(1, 2)` - it can be inlined to the following:\n    /// ```gleam\n    /// {\n    ///   let a = 1\n    ///   let b = 2\n    ///   a + b\n    /// }\n    /// ```\n    ///\n    /// However, this can be inlined further. Since `a` and `b` are only used\n    /// once each in the body, the whole expression can be reduced to `1 + 2`.\n    ///\n    /// In the above example, this variable would contain `{a: 1, b: 2}`,\n    /// indicating the names of the variables to be inlined, as well as the\n    /// values to replace them with.\n    inline_variables: HashMap<EcoString, TypedExpr>,\n\n    /// The number we append to variable names in order to ensure uniqueness.\n    variable_number: usize,\n    /// Set of in-scope variables, used to determine when a conflict between\n    /// variable names occurs during inlining.\n    in_scope: HashSet<EcoString>,\n    /// If two variables conflict in names during inlining, we need to rename\n    /// one to avoid the conflict. Any variables renamed this way are stored\n    /// here.\n    renamed_variables: im::HashMap<EcoString, EcoString>,\n    /// The current position, whether we are inside the body of an inlined\n    /// function or not.\n    position: Position,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\nenum Position {\n    RegularFunction,\n    InlinedFunction,\n}\n\nimpl Inliner<'_> {\n    fn new(modules: &im::HashMap<EcoString, ModuleInterface>) -> Inliner<'_> {\n        Inliner {\n            modules,\n            inline_variables: HashMap::new(),\n            variable_number: 0,\n            renamed_variables: im::HashMap::new(),\n            in_scope: HashSet::new(),\n            position: Position::RegularFunction,\n        }\n    }\n\n    /// Defines a variable in the current scope, renaming it if necessary.\n    /// Currently, this duplicates work performed in the code generators, where\n    /// variables are renamed in a similar way. But since inlining can change\n    /// scope boundaries, it needs to be performed here too. Ideally, we would\n    /// move all the deduplicating logic from the code generators to here where\n    /// we perform inlining, but that is a fairly large item of work.\n    fn define_variable(&mut self, name: EcoString) -> EcoString {\n        let unique_in_scope = self.in_scope.insert(name.clone());\n        // If the variable name is already defined, and we are inlining a function,\n        // that means there is a potential conflict in names and we need to rename\n        // the variable.\n        if !unique_in_scope && self.position == Position::InlinedFunction {\n            // Prefixing the variable name with `_inline_` ensures it does\n            // not conflict with other defined variables.\n            let new_name = eco_format!(\"_inline_{name}_{}\", self.variable_number);\n            self.variable_number += 1;\n            _ = self.renamed_variables.insert(name, new_name.clone());\n            new_name\n        } else {\n            name\n        }\n    }\n\n    /// Get the name we are using for a variable, in case it is renamed.\n    fn variable_name(&self, name: EcoString) -> EcoString {\n        self.renamed_variables.get(&name).cloned().unwrap_or(name)\n    }\n\n    fn function(&mut self, mut function: TypedFunction) -> TypedFunction {\n        for argument in function.arguments.iter() {\n            match &argument.names {\n                ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => {}\n                ArgNames::Named { name, .. } | ArgNames::NamedLabelled { name, .. } => {\n                    _ = self.in_scope.insert(name.clone());\n                }\n            }\n        }\n\n        function.body = function\n            .body\n            .into_iter()\n            .map(|statement| self.statement(statement))\n            .collect_vec();\n        function\n    }\n\n    fn statement(&mut self, statement: TypedStatement) -> TypedStatement {\n        match statement {\n            Statement::Expression(expression_ast) => {\n                Statement::Expression(self.expression(expression_ast))\n            }\n            Statement::Assignment(assignment_ast) => {\n                Statement::Assignment(Box::new(self.assignment(*assignment_ast)))\n            }\n            Statement::Use(use_ast) => Statement::Use(self.use_(use_ast)),\n            Statement::Assert(assert_ast) => Statement::Assert(self.assert(assert_ast)),\n        }\n    }\n\n    fn assert(&mut self, assert: TypedAssert) -> TypedAssert {\n        let Assert {\n            location,\n            value,\n            message,\n        } = assert;\n\n        Assert {\n            location,\n            value: self.expression(value),\n            message: message.map(|expression| self.expression(expression)),\n        }\n    }\n\n    fn use_(&mut self, mut use_: TypedUse) -> TypedUse {\n        use_.call = self.boxed_expression(use_.call);\n        use_\n    }\n\n    fn assignment(&mut self, assignment: TypedAssignment) -> TypedAssignment {\n        let Assignment {\n            location,\n            value,\n            pattern,\n            kind,\n            annotation,\n            compiled_case,\n        } = assignment;\n\n        Assignment {\n            location,\n            value: self.expression(value),\n            pattern: self.register_pattern_variables(pattern),\n            kind: self.assignment_kind(kind),\n            annotation,\n            compiled_case,\n        }\n    }\n\n    /// Register variables defined in a pattern so we correctly keep track of\n    /// the scope, and rename any which conflict with existing variables.\n    fn register_pattern_variables(&mut self, pattern: TypedPattern) -> TypedPattern {\n        match pattern {\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Discard { .. }\n            | Pattern::Invalid { .. } => pattern,\n\n            Pattern::Variable {\n                location,\n                name,\n                type_,\n                origin,\n            } => Pattern::Variable {\n                location,\n                name: self.define_variable(name),\n                type_,\n                origin,\n            },\n            Pattern::BitArraySize(size) => Pattern::BitArraySize(self.bit_array_size(size)),\n            Pattern::Assign {\n                name,\n                location,\n                pattern,\n            } => Pattern::Assign {\n                name: self.define_variable(name),\n                location,\n                pattern: Box::new(self.register_pattern_variables(*pattern)),\n            },\n            Pattern::List {\n                location,\n                elements,\n                tail,\n                type_,\n            } => Pattern::List {\n                location,\n                elements: elements\n                    .into_iter()\n                    .map(|element| self.register_pattern_variables(element))\n                    .collect(),\n                tail: tail.map(|tail| {\n                    Box::new(TailPattern {\n                        location: tail.location,\n                        pattern: self.register_pattern_variables(tail.pattern),\n                    })\n                }),\n                type_,\n            },\n            Pattern::Constructor {\n                location,\n                name_location,\n                name,\n                arguments,\n                module,\n                constructor,\n                spread,\n                type_,\n            } => Pattern::Constructor {\n                location,\n                name_location,\n                name,\n                arguments: arguments\n                    .into_iter()\n                    .map(\n                        |CallArg {\n                             label,\n                             location,\n                             value,\n                             implicit,\n                         }| CallArg {\n                            label,\n                            location,\n                            value: self.register_pattern_variables(value),\n                            implicit,\n                        },\n                    )\n                    .collect(),\n                module,\n                constructor,\n                spread,\n                type_,\n            },\n            Pattern::Tuple { location, elements } => Pattern::Tuple {\n                location,\n                elements: elements\n                    .into_iter()\n                    .map(|element| self.register_pattern_variables(element))\n                    .collect(),\n            },\n            Pattern::BitArray { location, segments } => Pattern::BitArray {\n                location,\n                segments: segments\n                    .into_iter()\n                    .map(|segment| {\n                        self.bit_array_segment(segment, Self::register_pattern_variables)\n                    })\n                    .collect(),\n            },\n            Pattern::StringPrefix {\n                location,\n                left_location,\n                left_side_assignment,\n                right_location,\n                left_side_string,\n                right_side_assignment,\n            } => Pattern::StringPrefix {\n                location,\n                left_location,\n                left_side_assignment: left_side_assignment\n                    .map(|(name, location)| (self.define_variable(name), location)),\n                right_location,\n                left_side_string,\n                right_side_assignment: match right_side_assignment {\n                    AssignName::Variable(name) => AssignName::Variable(self.define_variable(name)),\n                    AssignName::Discard(name) => AssignName::Discard(name),\n                },\n            },\n        }\n    }\n\n    fn bit_array_size(&mut self, size: TypedBitArraySize) -> TypedBitArraySize {\n        match size {\n            BitArraySize::Int { .. } => size,\n            BitArraySize::Variable {\n                location,\n                name,\n                constructor,\n                type_,\n            } => BitArraySize::Variable {\n                location,\n                name: self.variable_name(name),\n                constructor,\n                type_,\n            },\n            BitArraySize::BinaryOperator {\n                location,\n                operator,\n                left,\n                right,\n            } => BitArraySize::BinaryOperator {\n                location,\n                operator,\n                left: Box::new(self.bit_array_size(*left)),\n                right: Box::new(self.bit_array_size(*right)),\n            },\n            BitArraySize::Block { location, inner } => BitArraySize::Block {\n                location,\n                inner: Box::new(self.bit_array_size(*inner)),\n            },\n        }\n    }\n\n    fn assignment_kind(&mut self, kind: AssignmentKind<TypedExpr>) -> AssignmentKind<TypedExpr> {\n        match kind {\n            AssignmentKind::Let | AssignmentKind::Generated => kind,\n            AssignmentKind::Assert {\n                location,\n                assert_keyword_start,\n                message,\n            } => AssignmentKind::Assert {\n                location,\n                assert_keyword_start,\n                message: message.map(|expression| self.expression(expression)),\n            },\n        }\n    }\n\n    fn boxed_expression(&mut self, boxed: Box<TypedExpr>) -> Box<TypedExpr> {\n        Box::new(self.expression(*boxed))\n    }\n\n    fn expressions(&mut self, expressions: Vec<TypedExpr>) -> Vec<TypedExpr> {\n        expressions\n            .into_iter()\n            .map(|expression| self.expression(expression))\n            .collect()\n    }\n\n    /// Perform inlining over an expression. This function is recursive, as\n    /// expressions can be deeply nested. Most expressions just recursively\n    /// call this function on each of their component parts, but some have\n    /// special handling.\n    fn expression(&mut self, mut expression: TypedExpr) -> TypedExpr {\n        match expression {\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Invalid { .. } => expression,\n\n            TypedExpr::Var {\n                ref constructor,\n                ref mut name,\n                ..\n            } => match &constructor.variant {\n                // If this variable can be inlined, replace it with its value.\n                // See the `inline_variables` documentation for an explanation.\n                ValueConstructorVariant::LocalVariable { .. } => {\n                    // We remove the variable as inlined variables can only be\n                    // inlined once. `inline_variables` only contains variables\n                    // which we have already checked are possible to inline, as\n                    // we check for variables which are only used once when converting\n                    // to an `InlinableFunction`.\n                    match self.inline_variables.remove(name) {\n                        Some(inlined_expression) => inlined_expression,\n                        None => match self.renamed_variables.get(name) {\n                            Some(new_name) => {\n                                *name = new_name.clone();\n                                expression\n                            }\n                            None => expression,\n                        },\n                    }\n                }\n                ValueConstructorVariant::ModuleConstant { .. }\n                | ValueConstructorVariant::ModuleFn { .. }\n                | ValueConstructorVariant::Record { .. } => expression,\n            },\n\n            TypedExpr::Block {\n                location,\n                statements,\n            } => TypedExpr::Block {\n                location,\n                statements: statements.mapped(|statement| self.statement(statement)),\n            },\n\n            TypedExpr::NegateBool { location, value } => TypedExpr::NegateBool {\n                location,\n                value: self.boxed_expression(value),\n            },\n\n            TypedExpr::NegateInt { location, value } => TypedExpr::NegateInt {\n                location,\n                value: self.boxed_expression(value),\n            },\n\n            TypedExpr::Pipeline {\n                location,\n                first_value,\n                assignments,\n                finally,\n                finally_kind,\n            } => self.pipeline(location, first_value, assignments, finally, finally_kind),\n\n            TypedExpr::List {\n                location,\n                type_,\n                elements,\n                tail,\n            } => TypedExpr::List {\n                location,\n                type_,\n                elements: self.expressions(elements),\n                tail: tail.map(|boxed_expression| self.boxed_expression(boxed_expression)),\n            },\n\n            TypedExpr::Call {\n                location,\n                type_,\n                fun,\n                arguments,\n            } => self.call(location, type_, fun, arguments),\n\n            TypedExpr::BinOp {\n                location,\n                type_,\n                name,\n                name_location,\n                left,\n                right,\n            } => TypedExpr::BinOp {\n                location,\n                type_,\n                name,\n                name_location,\n                left: self.boxed_expression(left),\n                right: self.boxed_expression(right),\n            },\n\n            TypedExpr::Case {\n                location,\n                type_,\n                subjects,\n                clauses,\n                compiled_case,\n            } => self.case(location, type_, subjects, clauses, compiled_case),\n\n            TypedExpr::RecordAccess {\n                location,\n                field_start,\n                type_,\n                label,\n                index,\n                record,\n                documentation,\n            } => TypedExpr::RecordAccess {\n                location,\n                field_start,\n                type_,\n                label,\n                index,\n                record: self.boxed_expression(record),\n                documentation,\n            },\n\n            TypedExpr::PositionalAccess {\n                location,\n                type_,\n                index,\n                record,\n            } => TypedExpr::PositionalAccess {\n                location,\n                type_,\n                index,\n                record: self.boxed_expression(record),\n            },\n\n            TypedExpr::Tuple {\n                location,\n                type_,\n                elements,\n            } => TypedExpr::Tuple {\n                location,\n                type_,\n                elements: self.expressions(elements),\n            },\n\n            TypedExpr::TupleIndex {\n                location,\n                type_,\n                index,\n                tuple,\n            } => TypedExpr::TupleIndex {\n                location,\n                type_,\n                index,\n                tuple: self.boxed_expression(tuple),\n            },\n\n            TypedExpr::Todo {\n                location,\n                message,\n                kind,\n                type_,\n            } => TypedExpr::Todo {\n                location,\n                message: message.map(|boxed_expression| self.boxed_expression(boxed_expression)),\n                kind,\n                type_,\n            },\n\n            TypedExpr::Panic {\n                location,\n                message,\n                type_,\n            } => TypedExpr::Panic {\n                location,\n                message: message.map(|boxed_expression| self.boxed_expression(boxed_expression)),\n                type_,\n            },\n\n            TypedExpr::Echo {\n                location,\n                type_,\n                expression,\n                message,\n            } => TypedExpr::Echo {\n                location,\n                expression: expression.map(|expression| self.boxed_expression(expression)),\n                message: message.map(|message| self.boxed_expression(message)),\n                type_,\n            },\n\n            TypedExpr::BitArray {\n                location,\n                type_,\n                segments,\n            } => self.bit_array(location, type_, segments),\n\n            TypedExpr::RecordUpdate {\n                location,\n                type_,\n                record_assignment,\n                constructor,\n                arguments,\n            } => TypedExpr::RecordUpdate {\n                location,\n                type_,\n                record_assignment: record_assignment\n                    .map(|assignment| Box::new(self.assignment(*assignment))),\n                constructor: self.boxed_expression(constructor),\n                arguments: self.arguments(arguments),\n            },\n        }\n    }\n\n    fn arguments(&mut self, arguments: Vec<TypedCallArg>) -> Vec<TypedCallArg> {\n        arguments\n            .into_iter()\n            .map(\n                |TypedCallArg {\n                     label,\n                     location,\n                     value,\n                     implicit,\n                 }| TypedCallArg {\n                    label,\n                    location,\n                    value: self.expression(value),\n                    implicit,\n                },\n            )\n            .collect()\n    }\n\n    /// Where the magic happens. First, we check the left-hand side of the call\n    /// to see if it's something we can inline. If not, we continue to walk the\n    /// tree like all the other expressions do. If it can be inlined, we follow\n    /// a three-step process:\n    ///\n    /// - Inlining: Here, we replace the reference to the function with an\n    ///   anonymous function with the same contents. If the left-hand side is\n    ///   already an anonymous function, we skip this step.\n    ///\n    /// - Beta reduction: The call to the anonymous function it transformed into\n    ///   a block with assignments for each argument at the beginning\n    ///\n    /// - Optimisation: We then recursively optimise the block. This allows us\n    ///   to, for example, inline anonymous functions passed to higher-order\n    ///   functions.\n    ///\n    /// Here is an example of inlining `result.map`:\n    ///\n    /// Initial code:\n    /// ```gleam\n    /// let x = Ok(10)\n    /// result.map(x, fn(x) {\n    ///   let y = x + 4\n    ///   int.to_string(y)\n    /// })\n    /// ```\n    ///\n    /// After inlining:\n    /// ```gleam\n    /// let x = Ok(10)\n    /// fn(result, function) {\n    ///   case result {\n    ///     Ok(value) -> Ok(function(value))\n    ///     Error(error) -> Error(error)\n    ///   }\n    /// }(x, fn(x) {\n    ///   let y = x + 4\n    ///   int.to_string(y)\n    /// })\n    /// ```\n    ///\n    /// After beta reduction:\n    /// ```gleam\n    /// let x = Ok(10)\n    /// {\n    ///   let result = x\n    ///   let function = fn(x) {\n    ///     let y = x + 4\n    ///     int.to_string(y)\n    ///   }\n    ///   case result {\n    ///     Ok(value) -> Ok(function(value))\n    ///     Error(error) -> Error(error)\n    ///   }\n    /// }\n    /// ```\n    ///\n    /// And finally, after the final optimising pass, where this inlining process\n    /// is repeated:\n    /// ```gleam\n    /// let x = Ok(10)\n    /// case x {\n    ///   Ok(value) -> Ok({\n    ///     let y = x + 4\n    ///     int.to_string(y)\n    ///   })\n    ///   Error(error) -> Error(error)\n    /// }\n    /// ```\n    ///\n    fn call(\n        &mut self,\n        location: SrcSpan,\n        type_: Arc<Type>,\n        function: Box<TypedExpr>,\n        arguments: Vec<TypedCallArg>,\n    ) -> TypedExpr {\n        let arguments = self.arguments(arguments);\n\n        // First, we traverse the left-hand side of this call. If this is called\n        // inside another inlined function, this could potentially inline an\n        // argument, allowing further inlining.\n        let function = self.expression(*function);\n\n        // If the left-hand side is in a block for some reason, for example\n        // `{ fn(x) { x + 1 } }(10)`, we still want to be able to inline it.\n        let function = expand_block(function);\n\n        let function = match function {\n            TypedExpr::Var {\n                ref constructor,\n                ref name,\n                ..\n            } => match &constructor.variant {\n                ValueConstructorVariant::ModuleFn { module, .. } => {\n                    // If the function is in the list of inlinable functions in\n                    // the module it belongs to, we can inline it!\n                    if let Some(function) = self\n                        .modules\n                        .get(module)\n                        .and_then(|module| module.inline_functions.get(name))\n                    {\n                        // First, we do the actual inlining, by converting it to\n                        // an anonymous function.\n                        let (parameters, body) = function.to_anonymous_function();\n                        // Then, we perform beta reduction, inlining the call to\n                        // the anonymous function.\n                        return self.inline_anonymous_function_call(\n                            &parameters,\n                            arguments,\n                            body,\n                            &function.inlinable_parameters,\n                        );\n                    } else {\n                        function\n                    }\n                }\n                // We cannot inline local variables or constants, as we do not\n                // have enough information to inline them. Records are not actually\n                // function calls, so they also cannot be inlined.\n                ValueConstructorVariant::LocalVariable { .. }\n                | ValueConstructorVariant::ModuleConstant { .. }\n                | ValueConstructorVariant::Record { .. } => function,\n            },\n            TypedExpr::ModuleSelect {\n                ref constructor,\n                label: ref name,\n                ref module_name,\n                ..\n            } => match constructor {\n                // We use the same logic here as for `TypedExpr::Var` above.\n                ModuleValueConstructor::Fn { .. } => {\n                    if let Some(function) = self\n                        .modules\n                        .get(module_name)\n                        .and_then(|module| module.inline_functions.get(name))\n                    {\n                        let (parameters, body) = function.to_anonymous_function();\n                        return self.inline_anonymous_function_call(\n                            &parameters,\n                            arguments,\n                            body,\n                            &function.inlinable_parameters,\n                        );\n                    } else {\n                        function\n                    }\n                }\n                ModuleValueConstructor::Record { .. } | ModuleValueConstructor::Constant { .. } => {\n                    function\n                }\n            },\n            // Direct calls to anonymous functions can always be inlined\n            TypedExpr::Fn {\n                arguments: parameters,\n                body,\n                ..\n            } => {\n                let inlinable_parameters = find_inlinable_parameters(&parameters, &body);\n                return self.inline_anonymous_function_call(\n                    &parameters,\n                    arguments,\n                    body,\n                    &inlinable_parameters,\n                );\n            }\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => function,\n        };\n\n        TypedExpr::Call {\n            location,\n            type_,\n            fun: Box::new(function),\n            arguments,\n        }\n    }\n\n    /// Turn a call to an anonymous function into a block with assignments.\n    fn inline_anonymous_function_call(\n        &mut self,\n        parameters: &[TypedArg],\n        arguments: Vec<TypedCallArg>,\n        body: Vec1<TypedStatement>,\n        inlinable_parameters: &[EcoString],\n    ) -> TypedExpr {\n        // Arguments to this call that can be inlined, and do not need an assignment.\n        let mut inline = HashMap::new();\n\n        // We start by collecting all the assignments for parameters which cannot\n        // be inlined.\n        let mut statements = parameters\n            .iter()\n            .zip(arguments)\n            .filter_map(|(parameter, argument)| {\n                let name = parameter.get_variable_name().cloned().unwrap_or(\"_\".into());\n\n                // An argument can be inlined if it is only used once (stored in\n                // the `InlineFunction` structure), and it is pure. Sometime impure\n                // arguments can be inlined, but for simplicity we avoid inlining\n                // all impure arguments for now. This heuristic can be improved\n                // later.\n                if inlinable_parameters.contains(&name)\n                    && argument.value.is_pure_value_constructor()\n                {\n                    _ = inline.insert(name, argument.value);\n                    return None;\n                }\n\n                let type_ = argument.value.type_();\n\n                // Register the variable in scope, so that it is renamed if\n                // necessary.\n                let name = self.define_variable(name);\n\n                // Otherwise, we make an assignment which assigns the value of\n                // the argument to the correct parameter name.\n                Some(Statement::Assignment(Box::new(Assignment {\n                    location: BLANK_LOCATION,\n                    value: argument.value,\n                    pattern: TypedPattern::Variable {\n                        location: BLANK_LOCATION,\n                        name: name.clone(),\n                        type_: type_.clone(),\n                        origin: VariableOrigin::generated(),\n                    },\n                    kind: AssignmentKind::Generated,\n                    compiled_case: CompiledCase::simple_variable_assignment(name, type_),\n                    annotation: None,\n                })))\n            })\n            .collect_vec();\n\n        // If we are performing inlining within an already inlined function, there\n        // might be inlinable variables in the outer scope. However, these cannot be\n        // inlined inside a nested function, so they are saved and restored afterwards.\n        let inline_variables = std::mem::replace(&mut self.inline_variables, inline);\n        let position = self.position;\n        self.position = Position::InlinedFunction;\n        let variables = self.renamed_variables.clone();\n\n        // Perform inlining on each of the statements in this function's body,\n        // potentially inlining parameters and function calls inside this function.\n        statements.extend(body.into_iter().map(|statement| self.statement(statement)));\n\n        // Restore scope\n        self.inline_variables = inline_variables;\n        self.position = position;\n        self.renamed_variables = variables;\n\n        // We try to expand this block, so a function which is inlined as a\n        // single expression does not get wrapped unnecessarily\n        expand_block(TypedExpr::Block {\n            location: BLANK_LOCATION,\n            statements: statements\n                .try_into()\n                .expect(\"Type checking ensures there is at least one statement\"),\n        })\n    }\n\n    fn pipeline(\n        &mut self,\n        location: SrcSpan,\n        first_value: TypedPipelineAssignment,\n        assignments: Vec<(TypedPipelineAssignment, PipelineAssignmentKind)>,\n        finally: Box<TypedExpr>,\n        finally_kind: PipelineAssignmentKind,\n    ) -> TypedExpr {\n        let first_value = self.pipeline_assignment(first_value);\n        let assignments = assignments\n            .into_iter()\n            .map(|(assignment, kind)| (self.pipeline_assignment(assignment), kind))\n            .collect();\n        let finally = self.boxed_expression(finally);\n\n        TypedExpr::Pipeline {\n            location,\n            first_value,\n            assignments,\n            finally,\n            finally_kind,\n        }\n    }\n\n    fn pipeline_assignment(\n        &mut self,\n        assignment: TypedPipelineAssignment,\n    ) -> TypedPipelineAssignment {\n        let TypedPipelineAssignment {\n            location,\n            name,\n            value,\n        } = assignment;\n\n        TypedPipelineAssignment {\n            location,\n            name,\n            value: self.boxed_expression(value),\n        }\n    }\n\n    fn bit_array(\n        &mut self,\n        location: SrcSpan,\n        type_: Arc<Type>,\n        segments: Vec<TypedExprBitArraySegment>,\n    ) -> TypedExpr {\n        let segments = segments\n            .into_iter()\n            .map(|segment| self.bit_array_segment(segment, Self::expression))\n            .collect();\n\n        TypedExpr::BitArray {\n            location,\n            type_,\n            segments,\n        }\n    }\n\n    fn bit_array_segment<Value>(\n        &mut self,\n        segment: BitArraySegment<Value, Arc<Type>>,\n        function: fn(&mut Self, Value) -> Value,\n    ) -> BitArraySegment<Value, Arc<Type>> {\n        let BitArraySegment {\n            location,\n            value,\n            options,\n            type_,\n        } = segment;\n\n        BitArraySegment {\n            location,\n            value: Box::new(function(self, *value)),\n            options: options\n                .into_iter()\n                .map(|option| self.bit_array_option(option, function))\n                .collect(),\n            type_,\n        }\n    }\n\n    fn bit_array_option<Value>(\n        &mut self,\n        option: BitArrayOption<Value>,\n        function: fn(&mut Self, Value) -> Value,\n    ) -> BitArrayOption<Value> {\n        match option {\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => option,\n            BitArrayOption::Size {\n                location,\n                value,\n                short_form,\n            } => BitArrayOption::Size {\n                location,\n                value: Box::new(function(self, *value)),\n                short_form,\n            },\n        }\n    }\n\n    fn case(\n        &mut self,\n        location: SrcSpan,\n        type_: Arc<Type>,\n        subjects: Vec<TypedExpr>,\n        clauses: Vec<TypedClause>,\n        compiled_case: CompiledCase,\n    ) -> TypedExpr {\n        let subjects = self.expressions(subjects);\n        let clauses = clauses\n            .into_iter()\n            .map(|clause| self.case_clause(clause))\n            .collect();\n\n        // Since JavaScript code generation uses the decision tree to generate\n        // code for `case` expressions, we need to rename the variables bound\n        // in the decision tree too. Because we have already renamed the variables\n        // in the pattern, we can simply look up the rebound names.\n        let compiled_case = CompiledCase {\n            tree: self.decision(compiled_case.tree),\n            subject_variables: compiled_case.subject_variables,\n        };\n\n        TypedExpr::Case {\n            location,\n            type_,\n            subjects,\n            clauses,\n            compiled_case,\n        }\n    }\n\n    fn case_clause(&mut self, clause: TypedClause) -> TypedClause {\n        let Clause {\n            location,\n            pattern,\n            alternative_patterns,\n            guard,\n            then,\n        } = clause;\n\n        let pattern = pattern\n            .into_iter()\n            .map(|pattern| self.register_pattern_variables(pattern))\n            .collect();\n\n        let alternative_patterns = alternative_patterns\n            .into_iter()\n            .map(|patterns| {\n                patterns\n                    .into_iter()\n                    .map(|pattern| self.register_pattern_variables(pattern))\n                    .collect()\n            })\n            .collect();\n\n        let then = self.expression(then);\n\n        Clause {\n            location,\n            pattern,\n            alternative_patterns,\n            guard,\n            then,\n        }\n    }\n\n    fn decision(&self, decision: Decision) -> Decision {\n        match decision {\n            Decision::Run { body } => Decision::Run {\n                body: self.case_body(body),\n            },\n            Decision::Guard {\n                guard,\n                if_true,\n                if_false,\n            } => Decision::Guard {\n                guard,\n                if_true: self.case_body(if_true),\n                if_false: Box::new(self.decision(*if_false)),\n            },\n            Decision::Switch {\n                var,\n                choices,\n                fallback,\n                fallback_check,\n            } => Decision::Switch {\n                var,\n                choices: choices\n                    .into_iter()\n                    .map(|(check, decision)| (check, self.decision(decision)))\n                    .collect(),\n                fallback: Box::new(self.decision(*fallback)),\n                fallback_check,\n            },\n            Decision::Fail => Decision::Fail,\n        }\n    }\n\n    fn case_body(&self, body: Body) -> Body {\n        let Body {\n            bindings,\n            clause_index,\n        } = body;\n\n        let bindings = bindings\n            .into_iter()\n            // We do this after renaming the variables in the pattern, so we can\n            // just lookup the new name, rather than renaming again.\n            .map(|(name, value)| (self.variable_name(name), value))\n            .collect();\n\n        Body {\n            bindings,\n            clause_index,\n        }\n    }\n}\n\nfn find_inlinable_parameters(parameters: &[TypedArg], body: &[TypedStatement]) -> Vec<EcoString> {\n    let mut parameter_map = HashMap::new();\n    for parameter in parameters {\n        let (name, location) = match &parameter.names {\n            ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => continue,\n            ArgNames::Named { name, location }\n            | ArgNames::NamedLabelled {\n                name,\n                name_location: location,\n                ..\n            } => (name, location),\n        };\n        _ = parameter_map.insert((name.clone(), *location), false);\n    }\n\n    let mut finder = FindInlinableParameters {\n        parameters: parameter_map,\n        position: FunctionPosition::Body,\n    };\n    for statement in body {\n        finder.visit_typed_statement(statement);\n    }\n\n    // Inlinable parameters are those that are used exactly once. Any parameters\n    // used more than once will be removed from this map and so will not be\n    // considered inlinable.\n    finder\n        .parameters\n        .into_iter()\n        .filter_map(|((name, _), used)| used.then_some(name))\n        .collect()\n}\n\n/// A struct for finding the inlinable parameters of an anonymous function. Since\n/// we want to inline all anonymous functions, not just a subset of them like we\n/// do with regular functions, this must be implemented slightly differently, but\n/// it means we can take advantage of the AST visitor, since we don't need to\n/// transform the anonymous function into an intermediate representation.\nstruct FindInlinableParameters {\n    parameters: HashMap<(EcoString, SrcSpan), bool>,\n    position: FunctionPosition,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum FunctionPosition {\n    Body,\n    NestedFunction,\n}\n\nimpl FindInlinableParameters {\n    fn register_reference(&mut self, name: &EcoString, location: SrcSpan) {\n        let key = (name.clone(), location);\n\n        match self.position {\n            FunctionPosition::Body => {}\n            // We don't inline any parameters which are referenced in nested\n            // anonymous function, as our system for inlining parameters cannot\n            // properly handle that case; it requires more complex rewriting of\n            // the code in some cases.\n            FunctionPosition::NestedFunction => {\n                _ = self.parameters.remove(&key);\n                return;\n            }\n        }\n\n        match self.parameters.get_mut(&key) {\n            Some(true) => _ = self.parameters.remove(&key),\n            Some(used @ false) => {\n                *used = true;\n            }\n            None => {}\n        }\n    }\n}\n\nimpl<'ast> Visit<'ast> for FindInlinableParameters {\n    fn visit_typed_expr_var(\n        &mut self,\n        _location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        if let ValueConstructorVariant::LocalVariable { location, .. } = constructor.variant {\n            self.register_reference(name, location);\n        }\n    }\n\n    fn visit_typed_clause_guard_var(\n        &mut self,\n        _location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        _type_: &'ast Arc<Type>,\n        location: &'ast SrcSpan,\n        _origin: &'ast VariableOrigin,\n    ) {\n        self.register_reference(name, *location);\n    }\n\n    fn visit_typed_bit_array_size_variable(\n        &mut self,\n        _location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        _type_: &'ast Arc<Type>,\n    ) {\n        let variant = match constructor {\n            Some(constructor) => &constructor.variant,\n            None => return,\n        };\n        if let ValueConstructorVariant::LocalVariable { location, .. } = variant {\n            self.register_reference(name, *location);\n        }\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        args: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        let previous_position = self.position;\n        self.position = FunctionPosition::NestedFunction;\n\n        ast::visit::visit_typed_expr_fn(self, location, type_, kind, args, body, return_annotation);\n\n        self.position = previous_position;\n    }\n}\n\n/// Removes any blocks which are acting as brackets (they hold a single expression)\nfn expand_block(expression: TypedExpr) -> TypedExpr {\n    match expression {\n        TypedExpr::Block {\n            location,\n            statements,\n        } if statements.len() == 1 => {\n            let (first, _rest) = statements.split_off_first();\n\n            match first {\n                // If this is several blocks inside each other, we want to\n                // expand them all.\n                Statement::Expression(inner) => expand_block(inner),\n                Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => {\n                    TypedExpr::Block {\n                        location,\n                        statements: Vec1::new(first),\n                    }\n                }\n            }\n        }\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => expression,\n    }\n}\n\n/// Converts a function from the Gleam AST into a special \"inlinable function\",\n/// which is a simplified version, containing just enough information for us to\n/// perform inlining, while keeping the cache files to a minimum size.\n///\n/// This function also determines whether a function is inlinable. Currently this\n/// just checks it against a list of stdlib functions we want to prioritise\n/// inlining, but later it will be changed to a more complicated heuristic.\n///\npub fn function_to_inlinable(\n    package: &str,\n    module: &str,\n    function: &TypedFunction,\n) -> Option<InlinableFunction> {\n    let (_, name) = function.name.as_ref()?;\n\n    if !is_inlinable(package, module, name) {\n        return None;\n    }\n\n    let parameters = function\n        .arguments\n        .iter()\n        .map(|argument| match &argument.names {\n            ArgNames::Discard { name, .. } | ArgNames::Named { name, .. } => InlinableParameter {\n                label: None,\n                name: name.clone(),\n            },\n            ArgNames::LabelledDiscard { label, name, .. }\n            | ArgNames::NamedLabelled { label, name, .. } => InlinableParameter {\n                label: Some(label.clone()),\n                name: name.clone(),\n            },\n        })\n        .collect();\n\n    let mut converter = FunctionToInlinable::new(&function.arguments);\n\n    let body = function\n        .body\n        .iter()\n        .map(|statement| converter.statement(statement))\n        .collect::<Option<_>>()?;\n\n    // Figure out which parameters can be inlined within the body of this function.\n    // When we inline a function, we convert it to a block with assignments for\n    // the parameters. Then, if those parameters contain no side effects and are\n    // only referenced once within the body, they can be inlined into the place\n    // they are referenced.\n    //\n    // This code checks for the parameters which are used exactly once, which\n    // can then be inlined. We can't inline parameters which are never used, as\n    // there is nowhere to inline them to, so it doesn't make sense. We still\n    // need to evaluate them though, as there could be side effects caused by\n    // the values passed to them.\n    let inlinable_parameters = converter\n        .parameter_references\n        .into_iter()\n        .filter_map(|((name, _), used)| used.then_some(name))\n        .collect();\n\n    Some(InlinableFunction {\n        parameters,\n        body,\n        inlinable_parameters,\n    })\n}\n\n/// The heuristic to determine whether a function is inlinable. For now, this\n/// just checks against a list of standard library functions.\nfn is_inlinable(package: &str, module: &str, name: &str) -> bool {\n    // For now we only offer inlining of standard library functions\n    if package != STDLIB_PACKAGE_NAME {\n        return false;\n    }\n\n    match (module, name) {\n        // These are the functions which we currently inline\n        (\"gleam/bool\", \"guard\") => true,\n        (\"gleam/bool\", \"lazy_guard\") => true,\n        (\"gleam/result\", \"try\") => true,\n        (\"gleam/result\", \"map\") => true,\n        (\"gleam/result\", \"map_error\") => true,\n        // For testing purposes it's useful to have a function which will always\n        // be inlined, which we can define however we want. We only inline this\n        // when we are in test mode though, because we wouldn't want this detail\n        // leaking out into real-world code and causing unexpected behaviour.\n        (\"testing\", \"always_inline\") => cfg!(test),\n        _ => false,\n    }\n}\n\n/// Holds state for converting a `TypedFunction` into an `InlinableFunction`.\nstruct FunctionToInlinable {\n    /// A map of parameters to a boolean of whether they have been used. Since\n    /// Gleam has variable shadowing, we must also store the definition location\n    /// of each parameter to ensure that it is not a variable shadowing the parameter\n    /// name.\n    /// If a parameter is used more than once, it is removed from the map, so it\n    /// is no longer tracked as an inlinable parameter.\n    parameter_references: HashMap<(EcoString, SrcSpan), bool>,\n}\n\nimpl FunctionToInlinable {\n    fn new(arguments: &[TypedArg]) -> Self {\n        let parameter_references = arguments\n            .iter()\n            .filter_map(|argument| {\n                let (name, location) = match &argument.names {\n                    ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => return None,\n                    ArgNames::Named { name, location } => (name.clone(), *location),\n                    ArgNames::NamedLabelled {\n                        name,\n                        name_location,\n                        ..\n                    } => (name.clone(), *name_location),\n                };\n\n                Some(((name, location), false))\n            })\n            .collect();\n\n        Self {\n            parameter_references,\n        }\n    }\n\n    fn statement(&mut self, statement: &TypedStatement) -> Option<InlinableExpression> {\n        match statement {\n            Statement::Expression(expression) => self.expression(expression),\n            Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => None,\n        }\n    }\n\n    /// Converts an expression to an `InlinableExpression`. We only convert a\n    /// small subset of the AST for now, enough to compile our desired inlinable\n    /// stdlib functions. Anything else returns `None`, indicating a function\n    /// cannot be inlined.\n    fn expression(&mut self, expression: &TypedExpr) -> Option<InlinableExpression> {\n        match expression {\n            TypedExpr::Case {\n                subjects,\n                clauses,\n                compiled_case,\n                type_,\n                ..\n            } => {\n                let subjects = subjects\n                    .iter()\n                    .map(|expression| self.expression(expression))\n                    .collect::<Option<_>>()?;\n                let clauses = clauses\n                    .iter()\n                    .map(|clause| self.clause(clause))\n                    .collect::<Option<_>>()?;\n\n                Some(InlinableExpression::Case {\n                    subjects,\n                    clauses,\n                    compiled_case: Box::new(compiled_case.clone()),\n                    type_: self.type_(type_),\n                })\n            }\n            TypedExpr::Var {\n                constructor, name, ..\n            } => {\n                match &constructor.variant {\n                    ValueConstructorVariant::LocalVariable { location, .. } => {\n                        let key = (name.clone(), *location);\n                        match self.parameter_references.get_mut(&key) {\n                            Some(true) => {\n                                _ = self.parameter_references.remove(&key);\n                            }\n                            Some(usage) => *usage = true,\n                            None => {}\n                        }\n                    }\n                    ValueConstructorVariant::ModuleConstant { .. }\n                    | ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::Record { .. } => {}\n                }\n\n                Some(InlinableExpression::Variable {\n                    name: name.clone(),\n                    constructor: self.value_constructor(constructor)?,\n                    type_: self.type_(&constructor.type_),\n                })\n            }\n            TypedExpr::Call {\n                fun,\n                arguments,\n                type_,\n                ..\n            } => {\n                let function = self.expression(fun)?;\n                let arguments = arguments\n                    .iter()\n                    .map(|argument| {\n                        Some(InlinableArgument {\n                            label: argument.label.clone(),\n                            value: self.expression(&argument.value)?,\n                        })\n                    })\n                    .collect::<Option<_>>()?;\n\n                Some(InlinableExpression::Call {\n                    function: Box::new(function),\n                    arguments,\n                    type_: self.type_(type_),\n                })\n            }\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    fn type_(&self, type_: &Arc<Type>) -> InlinableType {\n        match collapse_links(type_.clone()).as_ref() {\n            Type::Fn { arguments, return_ } => InlinableType::Function {\n                arguments: arguments\n                    .iter()\n                    .map(|argument| self.type_(argument))\n                    .collect(),\n                return_: Box::new(self.type_(return_)),\n            },\n            Type::Named {\n                module,\n                name,\n                arguments,\n                ..\n            } if module == PRELUDE_MODULE_NAME => self.prelude_type(name, arguments),\n            Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => InlinableType::Other,\n        }\n    }\n\n    fn prelude_type(&self, name: &str, arguments: &[Arc<Type>]) -> InlinableType {\n        match (name, arguments) {\n            (\"BitArray\", _) => InlinableType::BitArray,\n            (\"Bool\", _) => InlinableType::Bool,\n            (\"Float\", _) => InlinableType::Float,\n            (\"Int\", _) => InlinableType::Int,\n            (\"List\", [element]) => InlinableType::List(Box::new(self.type_(element))),\n            (\"Nil\", _) => InlinableType::Nil,\n            (\"Result\", [ok, error]) => InlinableType::Result {\n                ok: Box::new(self.type_(ok)),\n                error: Box::new(self.type_(error)),\n            },\n            (\"String\", _) => InlinableType::String,\n            (\"UtfCodepoint\", _) => InlinableType::UtfCodepoint,\n            _ => InlinableType::Other,\n        }\n    }\n\n    fn value_constructor(\n        &mut self,\n        constructor: &ValueConstructor,\n    ) -> Option<InlinableValueConstructor> {\n        match &constructor.variant {\n            ValueConstructorVariant::LocalVariable { .. } => {\n                Some(InlinableValueConstructor::LocalVariable)\n            }\n            ValueConstructorVariant::ModuleConstant { .. } => None,\n            ValueConstructorVariant::ModuleFn { name, module, .. } => {\n                Some(InlinableValueConstructor::Function {\n                    name: name.clone(),\n                    module: module.clone(),\n                })\n            }\n            ValueConstructorVariant::Record { name, module, .. } => {\n                Some(InlinableValueConstructor::Record {\n                    name: name.clone(),\n                    module: module.clone(),\n                })\n            }\n        }\n    }\n\n    fn clause(&mut self, clause: &TypedClause) -> Option<InlinableClause> {\n        let pattern = clause\n            .pattern\n            .iter()\n            .map(Self::pattern)\n            .collect::<Option<_>>()?;\n        let body = self.expression(&clause.then)?;\n        Some(InlinableClause { pattern, body })\n    }\n\n    fn pattern(pattern: &TypedPattern) -> Option<InlinablePattern> {\n        match pattern {\n            TypedPattern::Variable { name, .. } => {\n                Some(InlinablePattern::Variable { name: name.clone() })\n            }\n            TypedPattern::Constructor {\n                name,\n                arguments,\n                constructor: Inferred::Known(inferred),\n                ..\n            } => {\n                let arguments = arguments\n                    .iter()\n                    .map(|argument| {\n                        Some(InlinableArgument {\n                            label: argument.label.clone(),\n                            value: Self::pattern(&argument.value)?,\n                        })\n                    })\n                    .collect::<Option<_>>()?;\n\n                Some(InlinablePattern::Constructor {\n                    name: name.clone(),\n                    module: inferred.module.clone(),\n                    arguments,\n                })\n            }\n\n            TypedPattern::Constructor {\n                constructor: Inferred::Unknown,\n                ..\n            } => None,\n\n            TypedPattern::Int { .. }\n            | TypedPattern::Float { .. }\n            | TypedPattern::String { .. }\n            | TypedPattern::BitArraySize { .. }\n            | TypedPattern::Assign { .. }\n            | TypedPattern::Discard { .. }\n            | TypedPattern::List { .. }\n            | TypedPattern::Tuple { .. }\n            | TypedPattern::BitArray { .. }\n            | TypedPattern::StringPrefix { .. }\n            | TypedPattern::Invalid { .. } => None,\n        }\n    }\n}\n\n/// A simplified version of a `TypedFunction`.\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct InlinableFunction {\n    pub parameters: Vec<InlinableParameter>,\n    pub body: Vec<InlinableExpression>,\n    /// A list of parameters which are only referenced once and can therefore\n    /// be inlined within the body of this function.\n    pub inlinable_parameters: Vec<EcoString>,\n}\n\n/// Location information is not stored for inlinable functions, to reduce cache\n/// size. The only reason we should need location information is for generating\n/// code for panicking keywords, like `panic` or `todo`.\n///\n/// Those are not supported yet, and when they are they will likely require some\n/// more thought as to how they are implemented, as inlining a function completely\n/// changes its location in the codebase.\nconst BLANK_LOCATION: SrcSpan = SrcSpan { start: 0, end: 0 };\n\nimpl InlinableFunction {\n    /// Converts an `InlinableFunction` to an anonymous function, which can then\n    /// be inlined within another function.\n    fn to_anonymous_function(&self) -> (Vec<TypedArg>, Vec1<TypedStatement>) {\n        let parameters = self\n            .parameters\n            .iter()\n            .map(|parameter| parameter.to_typed_arg())\n            .collect();\n\n        let body = self\n            .body\n            .iter()\n            .map(|ast| Statement::Expression(ast.to_expression()))\n            .collect_vec();\n\n        (\n            parameters,\n            body.try_into()\n                .expect(\"Type-checking ensured that the body has at least 1 statement\"),\n        )\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum InlinableExpression {\n    Case {\n        subjects: Vec<InlinableExpression>,\n        clauses: Vec<InlinableClause>,\n        compiled_case: Box<CompiledCase>,\n        type_: InlinableType,\n    },\n\n    Variable {\n        name: EcoString,\n        constructor: InlinableValueConstructor,\n        type_: InlinableType,\n    },\n\n    Call {\n        function: Box<InlinableExpression>,\n        arguments: Vec<InlinableArgument<InlinableExpression>>,\n        type_: InlinableType,\n    },\n}\n\nimpl InlinableExpression {\n    fn to_expression(&self) -> TypedExpr {\n        match self {\n            InlinableExpression::Case {\n                subjects,\n                clauses,\n                compiled_case,\n                type_,\n            } => TypedExpr::Case {\n                location: BLANK_LOCATION,\n                type_: type_.to_type(),\n                subjects: subjects\n                    .iter()\n                    .map(|subject| subject.to_expression())\n                    .collect(),\n                clauses: clauses\n                    .iter()\n                    .map(|clause| clause.to_typed_clause())\n                    .collect(),\n                compiled_case: compiled_case.as_ref().clone(),\n            },\n            InlinableExpression::Variable {\n                name,\n                constructor,\n                type_,\n            } => TypedExpr::Var {\n                location: BLANK_LOCATION,\n                constructor: constructor.to_value_constructor(type_.to_type()),\n                name: name.clone(),\n            },\n            InlinableExpression::Call {\n                function,\n                arguments,\n                type_,\n            } => TypedExpr::Call {\n                location: BLANK_LOCATION,\n                type_: type_.to_type(),\n                fun: Box::new(function.to_expression()),\n                arguments: arguments\n                    .iter()\n                    .map(|argument| argument.to_call_arg(Self::to_expression))\n                    .collect(),\n            },\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct InlinableClause {\n    pub pattern: Vec<InlinablePattern>,\n    pub body: InlinableExpression,\n}\n\nimpl InlinableClause {\n    fn to_typed_clause(&self) -> TypedClause {\n        TypedClause {\n            location: BLANK_LOCATION,\n            pattern: self\n                .pattern\n                .iter()\n                .map(|pattern| pattern.to_typed_pattern())\n                .collect(),\n            alternative_patterns: Vec::new(),\n            guard: None,\n            then: self.body.to_expression(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum InlinablePattern {\n    Constructor {\n        name: EcoString,\n        module: EcoString,\n        arguments: Vec<InlinableArgument<InlinablePattern>>,\n    },\n\n    Variable {\n        name: EcoString,\n    },\n}\n\nimpl InlinablePattern {\n    fn to_typed_pattern(&self) -> TypedPattern {\n        match self {\n            InlinablePattern::Constructor {\n                name,\n                module,\n                arguments,\n            } => TypedPattern::Constructor {\n                location: BLANK_LOCATION,\n                name_location: BLANK_LOCATION,\n                name: name.clone(),\n                arguments: arguments\n                    .iter()\n                    .map(|argument| argument.to_call_arg(Self::to_typed_pattern))\n                    .collect(),\n                module: None,\n                constructor: Inferred::Known(PatternConstructor {\n                    name: name.clone(),\n                    field_map: None,\n                    documentation: None,\n                    module: module.clone(),\n                    location: BLANK_LOCATION,\n                    constructor_index: 0,\n                }),\n                spread: None,\n                type_: unknown_type(),\n            },\n            InlinablePattern::Variable { name } => TypedPattern::Variable {\n                location: BLANK_LOCATION,\n                name: name.clone(),\n                type_: unknown_type(),\n                origin: VariableOrigin::generated(),\n            },\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum InlinableValueConstructor {\n    LocalVariable,\n    Function { name: EcoString, module: EcoString },\n    Record { name: EcoString, module: EcoString },\n}\n\nimpl InlinableValueConstructor {\n    fn to_value_constructor(&self, type_: Arc<Type>) -> ValueConstructor {\n        let variant = match self {\n            InlinableValueConstructor::LocalVariable => ValueConstructorVariant::LocalVariable {\n                location: BLANK_LOCATION,\n                origin: VariableOrigin::generated(),\n            },\n            InlinableValueConstructor::Function { name, module } => {\n                ValueConstructorVariant::ModuleFn {\n                    name: name.clone(),\n                    field_map: None,\n                    module: module.clone(),\n                    arity: 0,\n                    location: BLANK_LOCATION,\n                    documentation: None,\n                    implementations: Implementations::supporting_all(),\n                    external_erlang: None,\n                    external_javascript: None,\n                    purity: Purity::Unknown,\n                }\n            }\n            InlinableValueConstructor::Record { name, module } => ValueConstructorVariant::Record {\n                name: name.clone(),\n                arity: 0,\n                field_map: None,\n                location: BLANK_LOCATION,\n                module: module.clone(),\n                variants_count: 0,\n                variant_index: 0,\n                documentation: None,\n            },\n        };\n        ValueConstructor {\n            publicity: Publicity::Private,\n            deprecation: Deprecation::NotDeprecated,\n            variant,\n            type_,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct InlinableArgument<T> {\n    pub label: Option<EcoString>,\n    pub value: T,\n}\n\nimpl<T> InlinableArgument<T> {\n    fn to_call_arg<U, F>(&self, convert_value: F) -> CallArg<U>\n    where\n        F: FnOnce(&T) -> U,\n    {\n        CallArg {\n            label: self.label.clone(),\n            location: BLANK_LOCATION,\n            value: convert_value(&self.value),\n            implicit: None,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct InlinableParameter {\n    pub label: Option<EcoString>,\n    pub name: EcoString,\n}\n\nimpl InlinableParameter {\n    fn to_typed_arg(&self) -> TypedArg {\n        let is_discard = self.name.starts_with('_');\n\n        let names = match &self.label {\n            Some(label) if is_discard => ArgNames::LabelledDiscard {\n                label: label.clone(),\n                label_location: BLANK_LOCATION,\n                name: self.name.clone(),\n                name_location: BLANK_LOCATION,\n            },\n            Some(label) => ArgNames::NamedLabelled {\n                label: label.clone(),\n                label_location: BLANK_LOCATION,\n                name: self.name.clone(),\n                name_location: BLANK_LOCATION,\n            },\n            None if is_discard => ArgNames::Discard {\n                name: self.name.clone(),\n                location: BLANK_LOCATION,\n            },\n            None => ArgNames::Named {\n                name: self.name.clone(),\n                location: BLANK_LOCATION,\n            },\n        };\n\n        TypedArg {\n            names,\n            location: BLANK_LOCATION,\n            annotation: None,\n            type_: unknown_type(),\n        }\n    }\n}\n\n/// A simplified version of `Type`, which only cares about prelude types. Code\n/// generation needs this type information, as some prelude types are handled\n/// specially in certain cases. Custom type don't matter though, so they all get\n/// reduced into a single value, which decreases cache size.\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum InlinableType {\n    BitArray,\n    Bool,\n    Float,\n    Int,\n    List(Box<InlinableType>),\n    Nil,\n    Result {\n        ok: Box<InlinableType>,\n        error: Box<InlinableType>,\n    },\n    String,\n    UtfCodepoint,\n\n    Function {\n        arguments: Vec<InlinableType>,\n        return_: Box<InlinableType>,\n    },\n\n    Other,\n}\n\nfn unknown_type() -> Arc<Type> {\n    type_::generic_var(0)\n}\n\nimpl InlinableType {\n    fn to_type(&self) -> Arc<Type> {\n        match self {\n            InlinableType::BitArray => type_::bit_array(),\n            InlinableType::Bool => type_::bool(),\n            InlinableType::Float => type_::float(),\n            InlinableType::Int => type_::int(),\n            InlinableType::List(element) => type_::list(element.to_type()),\n            InlinableType::Nil => type_::nil(),\n            InlinableType::Result { ok, error } => type_::result(ok.to_type(), error.to_type()),\n            InlinableType::String => type_::string(),\n            InlinableType::UtfCodepoint => type_::utf_codepoint(),\n\n            InlinableType::Function { arguments, return_ } => type_::fn_(\n                arguments.iter().map(Self::to_type).collect(),\n                return_.to_type(),\n            ),\n\n            // Code generation doesn't care about custom types at all, only\n            // prelude types are handled specially, so we treat custom types as\n            // opaque generic type variables.\n            InlinableType::Other => unknown_type(),\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/io/memory.rs",
    "content": "use super::*;\nuse std::ops::Deref;\nuse std::{\n    cell::RefCell,\n    collections::{HashMap, HashSet},\n    rc::Rc,\n    time::Duration,\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\n/// An in memory sharable collection of pretend files that can be used in place\n/// of a real file system. It is a shared reference to a set of buffer than can\n/// be cheaply cloned, all resulting copies pointing to the same internal\n/// buffers.\n///\n/// Useful in tests and in environments like the browser where there is no file\n/// system.\n///\n/// Not thread safe. The compiler is single threaded, so that's OK.\n///\n/// Only supports absolute paths. The root directory (\"/\") is always guaranteed\n/// to exist.\n///\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct InMemoryFileSystem {\n    files: Rc<RefCell<HashMap<Utf8PathBuf, InMemoryFile>>>,\n}\n\nimpl Default for InMemoryFileSystem {\n    fn default() -> Self {\n        let mut files = HashMap::new();\n\n        // Ensure root directory always exists.\n        let _ = files.insert(Utf8PathBuf::from(\"/\"), InMemoryFile::directory());\n\n        Self {\n            files: Rc::new(RefCell::new(files)),\n        }\n    }\n}\n\nimpl InMemoryFileSystem {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn reset(&self) {\n        self.files.deref().borrow_mut().clear();\n    }\n\n    /// Returns the contents of each file, excluding directories.\n    ///\n    /// # Panics\n    ///\n    /// Panics if this is not the only reference to the underlying files.\n    ///\n    pub fn into_contents(self) -> HashMap<Utf8PathBuf, Content> {\n        Rc::try_unwrap(self.files)\n            .expect(\"InMemoryFileSystem::into_files called on a clone\")\n            .into_inner()\n            .into_iter()\n            .filter_map(|(path, file)| file.into_content().map(|content| (path, content)))\n            .collect()\n    }\n\n    /// All files currently in the filesystem (directories are not included).\n    pub fn files(&self) -> Vec<Utf8PathBuf> {\n        self.files\n            .borrow()\n            .iter()\n            .filter(|(_, f)| !f.is_directory())\n            .map(|(path, _)| path)\n            .cloned()\n            .collect()\n    }\n\n    #[cfg(test)]\n    /// Set the modification time of a file.\n    ///\n    /// Panics if the file does not exist.\n    ///\n    pub fn set_modification_time(&self, path: &Utf8Path, time: SystemTime) {\n        self.files\n            .deref()\n            .borrow_mut()\n            .get_mut(path)\n            .unwrap()\n            .modification_time = time;\n    }\n\n    pub fn try_set_modification_time(\n        &self,\n        path: &Utf8Path,\n        time: SystemTime,\n    ) -> Result<(), Error> {\n        self.files\n            .deref()\n            .borrow_mut()\n            .get_mut(path)\n            .ok_or_else(|| Error::FileIo {\n                kind: FileKind::File,\n                action: FileIoAction::Open,\n                path: path.to_path_buf(),\n                err: None,\n            })?\n            .modification_time = time;\n        Ok(())\n    }\n}\n\nimpl FileSystemWriter for InMemoryFileSystem {\n    fn delete_directory(&self, path: &Utf8Path) -> Result<(), Error> {\n        let mut files = self.files.deref().borrow_mut();\n\n        if files.get(path).is_some_and(|f| !f.is_directory()) {\n            return Err(Error::FileIo {\n                kind: FileKind::Directory,\n                action: FileIoAction::Delete,\n                path: path.to_path_buf(),\n                err: None,\n            });\n        }\n\n        let root = Utf8Path::new(\"/\");\n        if path != root {\n            // Ensure the root path always exists.\n            // Deleting other files is fine.\n            let _ = files.remove(path);\n        }\n\n        // Remove any files in the directory\n        while let Some(file) = files\n            .keys()\n            .find(|file| file.as_path() != root && file.starts_with(path))\n        {\n            let file = file.clone();\n            let _ = files.remove(&file);\n        }\n\n        Ok(())\n    }\n\n    fn copy(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error> {\n        self.write_bytes(to, &self.read_bytes(from)?)\n    }\n\n    fn copy_dir(&self, _: &Utf8Path, _: &Utf8Path) -> Result<(), Error> {\n        panic!(\"unimplemented\") // TODO\n    }\n\n    fn mkdir(&self, path: &Utf8Path) -> Result<(), Error> {\n        // Traverse ancestors from parent to root.\n        // Create each missing ancestor.\n        for ancestor in path.ancestors() {\n            if ancestor == \"\" {\n                // Ignore the final ancestor of a relative path.\n                continue;\n            }\n            // Ensure we don't overwrite an existing file.\n            // We can ignore existing directories though.\n            let mut files = self.files.deref().borrow_mut();\n            if files.get(ancestor).is_some_and(|f| !f.is_directory()) {\n                return Err(Error::FileIo {\n                    kind: FileKind::Directory,\n                    action: FileIoAction::Create,\n                    path: ancestor.to_path_buf(),\n                    err: None,\n                });\n            }\n            let dir = InMemoryFile::directory();\n            _ = files.insert(ancestor.to_path_buf(), dir);\n        }\n\n        Ok(())\n    }\n\n    fn hardlink(&self, _: &Utf8Path, _: &Utf8Path) -> Result<(), Error> {\n        panic!(\"unimplemented\") // TODO\n    }\n\n    fn symlink_dir(&self, _: &Utf8Path, _: &Utf8Path) -> Result<(), Error> {\n        panic!(\"unimplemented\") // TODO\n    }\n\n    fn delete_file(&self, path: &Utf8Path) -> Result<(), Error> {\n        let mut files = self.files.deref().borrow_mut();\n        if files.get(path).is_some_and(|f| f.is_directory()) {\n            return Err(Error::FileIo {\n                kind: FileKind::File,\n                action: FileIoAction::Delete,\n                path: path.to_path_buf(),\n                err: None,\n            });\n        }\n        let _ = files.remove(path);\n        Ok(())\n    }\n\n    fn write(&self, path: &Utf8Path, content: &str) -> Result<(), Error> {\n        self.write_bytes(path, content.as_bytes())\n    }\n\n    fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<(), Error> {\n        // Ensure directories exist\n        if let Some(parent) = path.parent() {\n            self.mkdir(parent)?;\n        }\n\n        let mut file = InMemoryFile::default();\n        _ = io::Write::write(&mut file, content).expect(\"channel buffer write\");\n        _ = self\n            .files\n            .deref()\n            .borrow_mut()\n            .insert(path.to_path_buf(), file);\n        Ok(())\n    }\n\n    fn exists(&self, path: &Utf8Path) -> bool {\n        self.files.deref().borrow().contains_key(path)\n    }\n}\n\nimpl FileSystemReader for InMemoryFileSystem {\n    fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, Error> {\n        Ok(path.to_path_buf())\n    }\n\n    fn read(&self, path: &Utf8Path) -> Result<String, Error> {\n        let path = path.to_path_buf();\n        let files = self.files.deref().borrow();\n        let buffer = files\n            .get(&path)\n            .and_then(|file| file.node.as_file_buffer())\n            .ok_or_else(|| Error::FileIo {\n                kind: FileKind::File,\n                action: FileIoAction::Open,\n                path: path.clone(),\n                err: None,\n            })?;\n        let bytes = buffer.borrow();\n        let unicode = String::from_utf8(bytes.clone()).map_err(|err| Error::FileIo {\n            kind: FileKind::File,\n            action: FileIoAction::Read,\n            path: path.clone(),\n            err: Some(err.to_string()),\n        })?;\n        Ok(unicode)\n    }\n\n    fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>, Error> {\n        let path = path.to_path_buf();\n        let files = self.files.deref().borrow();\n        let buffer = files\n            .get(&path)\n            .and_then(|file| file.node.as_file_buffer())\n            .ok_or_else(|| Error::FileIo {\n                kind: FileKind::File,\n                action: FileIoAction::Open,\n                path: path.clone(),\n                err: None,\n            })?;\n        let bytes = buffer.borrow().clone();\n        Ok(bytes)\n    }\n\n    fn is_file(&self, path: &Utf8Path) -> bool {\n        self.files\n            .deref()\n            .borrow()\n            .get(path)\n            .is_some_and(|file| !file.is_directory())\n    }\n\n    fn is_directory(&self, path: &Utf8Path) -> bool {\n        self.files\n            .deref()\n            .borrow()\n            .get(path)\n            .is_some_and(|file| file.is_directory())\n    }\n\n    fn reader(&self, _path: &Utf8Path) -> Result<WrappedReader, Error> {\n        // TODO\n        unreachable!(\"Memory reader unimplemented\")\n    }\n\n    fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir> {\n        let read_dir = ReadDir::from_iter(\n            self.files\n                .deref()\n                .borrow()\n                .keys()\n                .map(|file_path| file_path.to_path_buf())\n                .filter(|file_path| file_path.parent().is_some_and(|parent| path == parent))\n                .map(DirEntry::from_pathbuf)\n                .map(Ok),\n        );\n\n        Ok(read_dir)\n    }\n\n    fn modification_time(&self, path: &Utf8Path) -> Result<SystemTime, Error> {\n        let files = self.files.deref().borrow();\n        let file = files.get(path).ok_or_else(|| Error::FileIo {\n            kind: FileKind::File,\n            action: FileIoAction::ReadMetadata,\n            path: path.to_path_buf(),\n            err: None,\n        })?;\n        Ok(file.modification_time)\n    }\n}\n\n/// The representation of a file or directory in the in-memory filesystem.\n///\n/// Stores a file's buffer of contents.\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum InMemoryFileNode {\n    File(Rc<RefCell<Vec<u8>>>),\n    Directory,\n}\n\nimpl InMemoryFileNode {\n    /// Returns this file's file buffer if this isn't a directory.\n    fn as_file_buffer(&self) -> Option<&Rc<RefCell<Vec<u8>>>> {\n        match self {\n            Self::File(buffer) => Some(buffer),\n            Self::Directory => None,\n        }\n    }\n\n    /// Returns this file's file buffer if this isn't a directory.\n    fn into_file_buffer(self) -> Option<Rc<RefCell<Vec<u8>>>> {\n        match self {\n            Self::File(buffer) => Some(buffer),\n            Self::Directory => None,\n        }\n    }\n}\n\n/// An in memory sharable that can be used in place of a real file. It is a\n/// shared reference to a buffer than can be cheaply cloned, all resulting copies\n/// pointing to the same internal buffer.\n///\n/// Useful in tests and in environments like the browser where there is no file\n/// system.\n///\n/// This struct holds common properties of different types of filesystem nodes\n/// (files and directories). The `node` field contains the file's content\n/// buffer, if this is not a directory.\n///\n/// Not thread safe. The compiler is single threaded, so that's OK.\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct InMemoryFile {\n    node: InMemoryFileNode,\n    modification_time: SystemTime,\n}\n\nimpl InMemoryFile {\n    /// Creates a directory.\n    pub fn directory() -> Self {\n        Self {\n            node: InMemoryFileNode::Directory,\n            ..Default::default()\n        }\n    }\n\n    /// Checks whether this is a directory's entry.\n    pub fn is_directory(&self) -> bool {\n        matches!(self.node, InMemoryFileNode::Directory)\n    }\n\n    /// Returns this file's contents if this is not a directory.\n    ///\n    /// # Panics\n    ///\n    /// Panics if this is not the only reference to the underlying files.\n    ///\n    pub fn into_content(self) -> Option<Content> {\n        let buffer = self.node.into_file_buffer()?;\n        let contents = Rc::try_unwrap(buffer)\n            .expect(\"InMemoryFile::into_content called with multiple references\")\n            .into_inner();\n\n        // All null bytes are usually from when a binary file is empty, and\n        // aren't particularly useful as text, so we treat them as binary.\n        if contents.iter().all(|byte| *byte == 0) {\n            return Some(Content::Binary(contents));\n        }\n\n        match String::from_utf8(contents) {\n            Ok(s) => Some(Content::Text(s)),\n            Err(e) => Some(Content::Binary(e.into_bytes())),\n        }\n    }\n}\n\nimpl Default for InMemoryFile {\n    fn default() -> Self {\n        Self {\n            node: InMemoryFileNode::File(Default::default()),\n            // We use a fixed time here so that the tests are deterministic. In\n            // future we may want to inject this in some fashion.\n            modification_time: SystemTime::UNIX_EPOCH + Duration::from_secs(663112800),\n        }\n    }\n}\n\nimpl io::Write for InMemoryFile {\n    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        let Some(buffer) = self.node.as_file_buffer() else {\n            // Not a file\n            return Err(io::Error::from(io::ErrorKind::NotFound));\n        };\n        let mut reference = (*buffer).borrow_mut();\n        reference.write(buf)\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        let Some(buffer) = self.node.as_file_buffer() else {\n            // Not a file\n            return Err(io::Error::from(io::ErrorKind::NotFound));\n        };\n        let mut reference = (*buffer).borrow_mut();\n        reference.flush()\n    }\n}\n\nimpl CommandExecutor for InMemoryFileSystem {\n    fn exec(&self, _command: Command) -> Result<i32, Error> {\n        Ok(0) // Always succeed.\n    }\n}\n\nimpl BeamCompiler for InMemoryFileSystem {\n    fn compile_beam(\n        &self,\n        _out: &Utf8Path,\n        _lib: &Utf8Path,\n        _modules: &HashSet<Utf8PathBuf>,\n        _stdio: Stdio,\n    ) -> Result<Vec<String>, Error> {\n        Ok(Vec::new()) // Always succeed.\n    }\n}\n\n#[test]\nfn test_empty_in_memory_fs_has_root() {\n    let imfs = InMemoryFileSystem::new();\n\n    assert!(imfs.exists(Utf8Path::new(\"/\")));\n}\n\n#[test]\nfn test_cannot_remove_root_from_in_memory_fs() -> Result<(), Error> {\n    let imfs = InMemoryFileSystem::new();\n    imfs.write(&Utf8PathBuf::from(\"/a/b/c.txt\"), \"a\")?;\n    imfs.delete_directory(Utf8Path::new(\"/\"))?;\n\n    assert!(!imfs.exists(Utf8Path::new(\"/a/b/c.txt\")));\n    assert!(imfs.exists(Utf8Path::new(\"/\")));\n\n    Ok(())\n}\n\n#[test]\nfn test_files() -> Result<(), Error> {\n    let imfs = InMemoryFileSystem::new();\n    imfs.write(&Utf8PathBuf::from(\"/a/b/c.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/d/e.txt\"), \"a\")?;\n\n    let mut files = imfs.files();\n\n    // Sort for test determinism due to hash map usage.\n    files.sort_unstable();\n\n    assert_eq!(\n        vec![\n            Utf8PathBuf::from(\"/a/b/c.txt\"),\n            Utf8PathBuf::from(\"/d/e.txt\"),\n        ],\n        files\n    );\n\n    Ok(())\n}\n\n#[test]\nfn test_in_memory_dir_walking() -> Result<(), Error> {\n    use itertools::Itertools;\n    let imfs = InMemoryFileSystem::new();\n    imfs.write(&Utf8PathBuf::from(\"/a/b/a.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/a/b/b.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/a/b/c.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/b/d.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/a/c/e.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/a/c/d/f.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/a/g.txt\"), \"a\")?;\n    imfs.write(&Utf8PathBuf::from(\"/h.txt\"), \"a\")?;\n    imfs.mkdir(&Utf8PathBuf::from(\"/a/e\"))?;\n\n    let mut walked_entries: Vec<String> = DirWalker::new(Utf8PathBuf::from(\"/a/\"))\n        .into_file_iter(&imfs)\n        .map_ok(Utf8PathBuf::into_string)\n        .try_collect()?;\n\n    // Keep test deterministic due to hash map usage\n    walked_entries.sort_unstable();\n\n    assert_eq!(\n        vec![\n            \"/a/b/a.txt\".to_owned(),\n            \"/a/b/b.txt\".to_owned(),\n            \"/a/b/c.txt\".to_owned(),\n            \"/a/c/d/f.txt\".to_owned(),\n            \"/a/c/e.txt\".to_owned(),\n            \"/a/g.txt\".to_owned(),\n        ],\n        walked_entries,\n    );\n\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-core/src/io.rs",
    "content": "pub mod memory;\n\nuse crate::error::{Error, FileIoAction, FileKind, Result};\nuse async_trait::async_trait;\nuse debug_ignore::DebugIgnore;\nuse flate2::read::GzDecoder;\nuse std::{\n    collections::{HashMap, HashSet, VecDeque},\n    fmt::Debug,\n    io,\n    iter::Extend,\n    time::SystemTime,\n    vec::IntoIter,\n};\nuse tar::{Archive, Entry};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\n/// Takes in a source path and a target path and determines a relative path\n/// from source -> target.\n/// If given a relative target path, no calculation occurs.\n/// # Panics\n/// The provided source path should be absolute, otherwise will panic.\npub fn make_relative(source_path: &Utf8Path, target_path: &Utf8Path) -> Utf8PathBuf {\n    assert!(source_path.is_absolute());\n    // Input target will always be canonicalised whereas source will not\n    // This causes problems with diffing on windows since canonicalised paths have a special root\n    // As such we are attempting to strip the target path\n    // Based on https://github.com/rust-lang/rust/issues/42869#issuecomment-1712317081\n    #[cfg(target_family = \"windows\")]\n    let binding = target_path.to_string();\n    #[cfg(target_family = \"windows\")]\n    let target_path = Utf8Path::new(binding.trim_start_matches(r\"\\\\?\\\"));\n\n    match target_path.is_absolute() {\n        true => pathdiff::diff_utf8_paths(target_path, source_path)\n            .expect(\"Should not fail on two absolute paths\"),\n\n        false => target_path.into(),\n    }\n}\n\npub trait Reader: io::Read {\n    /// A wrapper around `std::io::Read` that has Gleam's error handling.\n    fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<usize> {\n        self.read(buffer).map_err(|e| self.convert_err(e))\n    }\n\n    fn convert_err<E: std::error::Error>(&self, error: E) -> Error;\n}\n\npub trait Utf8Writer: std::fmt::Write {\n    /// A wrapper around `fmt::Write` that has Gleam's error handling.\n    fn str_write(&mut self, str: &str) -> Result<()> {\n        self.write_str(str).map_err(|e| self.convert_err(e))\n    }\n\n    fn convert_err<E: std::error::Error>(&self, err: E) -> Error;\n}\n\nimpl Utf8Writer for String {\n    fn convert_err<E: std::error::Error>(&self, error: E) -> Error {\n        Error::FileIo {\n            action: FileIoAction::WriteTo,\n            kind: FileKind::File,\n            path: Utf8PathBuf::from(\"<in memory>\"),\n            err: Some(error.to_string()),\n        }\n    }\n}\n\npub trait Writer: io::Write + Utf8Writer {\n    /// A wrapper around `io::Write` that has Gleam's error handling.\n    fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {\n        io::Write::write(self, bytes)\n            .map(|_| ())\n            .map_err(|e| self.convert_err(e))\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Content {\n    Binary(Vec<u8>),\n    Text(String),\n}\n\nimpl Content {\n    pub fn as_bytes(&self) -> &[u8] {\n        match self {\n            Content::Binary(data) => data,\n            Content::Text(data) => data.as_bytes(),\n        }\n    }\n\n    pub fn text(&self) -> Option<&str> {\n        match self {\n            Content::Binary(_) => None,\n            Content::Text(s) => Some(s),\n        }\n    }\n}\n\nimpl From<Vec<u8>> for Content {\n    fn from(bytes: Vec<u8>) -> Self {\n        Content::Binary(bytes)\n    }\n}\n\nimpl From<&[u8]> for Content {\n    fn from(bytes: &[u8]) -> Self {\n        Content::Binary(bytes.to_vec())\n    }\n}\n\nimpl From<String> for Content {\n    fn from(text: String) -> Self {\n        Content::Text(text)\n    }\n}\n\nimpl From<&str> for Content {\n    fn from(text: &str) -> Self {\n        Content::Text(text.to_string())\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct OutputFile {\n    pub content: Content,\n    pub path: Utf8PathBuf,\n}\n\n#[derive(Debug)]\npub struct ReadDir {\n    entries: Vec<io::Result<DirEntry>>,\n}\n\nimpl FromIterator<io::Result<DirEntry>> for ReadDir {\n    fn from_iter<I: IntoIterator<Item = io::Result<DirEntry>>>(iter: I) -> Self {\n        ReadDir {\n            entries: iter.into_iter().collect(),\n        }\n    }\n}\n\nimpl ReadDir {\n    pub fn extend(mut self, other: ReadDir) -> Self {\n        self.entries.extend(other);\n\n        ReadDir {\n            entries: self.entries,\n        }\n    }\n}\n\nimpl IntoIterator for ReadDir {\n    type Item = io::Result<DirEntry>;\n    type IntoIter = IntoIter<Self::Item>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.entries.into_iter()\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct DirEntry {\n    pub pathbuf: Utf8PathBuf,\n}\n\nimpl DirEntry {\n    pub fn from_path<P: AsRef<Utf8Path>>(path: P) -> DirEntry {\n        DirEntry {\n            pathbuf: path.as_ref().to_path_buf(),\n        }\n    }\n\n    pub fn from_pathbuf(pathbuf: Utf8PathBuf) -> DirEntry {\n        DirEntry { pathbuf }\n    }\n\n    pub fn as_path(&self) -> &Utf8Path {\n        self.pathbuf.as_path()\n    }\n\n    pub fn into_path(self) -> Utf8PathBuf {\n        self.pathbuf\n    }\n}\n\n/// Structure holding state to walk across a directory's descendant files at\n/// any level. Note that each descendant directory is only visited once\n/// regardless of symlinks, avoiding infinite symlink loops.\n#[derive(Debug, Clone)]\npub struct DirWalker {\n    walk_queue: VecDeque<Utf8PathBuf>,\n    dirs_walked: im::HashSet<Utf8PathBuf>,\n}\n\nimpl DirWalker {\n    /// Create a directory walker starting at the given path.\n    pub fn new(dir: Utf8PathBuf) -> Self {\n        Self {\n            walk_queue: VecDeque::from([dir]),\n            dirs_walked: im::HashSet::new(),\n        }\n    }\n\n    /// Convert this walker to an iterator over file paths.\n    ///\n    /// This iterator calls [`Self::next_file`]. Errors are returned if certain\n    /// directories cannot be read.\n    pub fn into_file_iter(\n        mut self,\n        io: &impl FileSystemReader,\n    ) -> impl Iterator<Item = Result<Utf8PathBuf>> + '_ {\n        std::iter::from_fn(move || self.next_file(io).transpose())\n    }\n\n    /// Advance the directory walker to the next file. The returned path will\n    /// be relative to the starting directory's path, even with symlinks\n    /// (it is not canonicalised).\n    pub fn next_file(&mut self, io: &impl FileSystemReader) -> Result<Option<Utf8PathBuf>> {\n        while let Some(next_path) = self.walk_queue.pop_front() {\n            let real_path = io.canonicalise(&next_path)?;\n\n            if io.is_file(&real_path) {\n                // Return the path relative to the starting directory, not the\n                // canonicalised path (which we only use to check for already\n                // visited directories).\n                return Ok(Some(next_path));\n            }\n\n            // If it's not a directory then it contains no other files, so there's nothing to do.\n            if !io.is_directory(&real_path) {\n                continue;\n            }\n\n            // If we have already processed this directory then we don't need to do it again.\n            // This could be due to symlinks.\n            let already_seen = self.dirs_walked.insert(real_path.clone()).is_some();\n            if already_seen {\n                continue;\n            }\n\n            for entry in io.read_dir(&next_path)? {\n                let Ok(entry) = entry else {\n                    return Err(Error::FileIo {\n                        kind: FileKind::Directory,\n                        action: FileIoAction::Read,\n                        path: next_path,\n                        err: None,\n                    });\n                };\n\n                self.walk_queue.push_back(entry.into_path())\n            }\n        }\n\n        Ok(None)\n    }\n}\n\n/// A trait used to read files.\n/// Typically we use an implementation that reads from the file system,\n/// but in tests and in other places other implementations may be used.\npub trait FileSystemReader {\n    fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir>;\n    fn read(&self, path: &Utf8Path) -> Result<String, Error>;\n    fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>, Error>;\n    fn reader(&self, path: &Utf8Path) -> Result<WrappedReader, Error>;\n    fn is_file(&self, path: &Utf8Path) -> bool;\n    fn is_directory(&self, path: &Utf8Path) -> bool;\n    fn modification_time(&self, path: &Utf8Path) -> Result<SystemTime, Error>;\n    fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, Error>;\n}\n\n/// Iterates over files with the given extension in a certain directory.\n/// Symlinks are followed.\npub fn files_with_extension<'a>(\n    io: &'a impl FileSystemReader,\n    dir: &'a Utf8Path,\n    extension: &'a str,\n) -> impl Iterator<Item = Utf8PathBuf> + 'a {\n    DirWalker::new(dir.to_path_buf())\n        .into_file_iter(io)\n        .filter_map(Result::ok)\n        .filter(|path| path.extension() == Some(extension))\n}\n\n/// A trait used to run other programs.\npub trait CommandExecutor {\n    fn exec(&self, command: Command) -> Result<i32, Error>;\n}\n\n/// A command one can run with a `CommandExecutor`\n#[derive(Debug, Eq, PartialEq)]\npub struct Command {\n    pub program: String,\n    pub args: Vec<String>,\n    pub env: Vec<(String, String)>,\n    pub cwd: Option<Utf8PathBuf>,\n    pub stdio: Stdio,\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum Stdio {\n    Inherit,\n    Null,\n}\n\nimpl Stdio {\n    pub fn get_process_stdio(&self) -> std::process::Stdio {\n        match self {\n            Stdio::Inherit => std::process::Stdio::inherit(),\n            Stdio::Null => std::process::Stdio::null(),\n        }\n    }\n}\n\n/// A trait used to compile Erlang and Elixir modules to BEAM bytecode.\npub trait BeamCompiler {\n    fn compile_beam(\n        &self,\n        out: &Utf8Path,\n        lib: &Utf8Path,\n        modules: &HashSet<Utf8PathBuf>,\n        stdio: Stdio,\n    ) -> Result<Vec<String>, Error>;\n}\n\n/// A trait used to write files.\n/// Typically we use an implementation that writes to the file system,\n/// but in tests and in other places other implementations may be used.\npub trait FileSystemWriter {\n    fn mkdir(&self, path: &Utf8Path) -> Result<(), Error>;\n    fn write(&self, path: &Utf8Path, content: &str) -> Result<(), Error>;\n    fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<(), Error>;\n    fn delete_directory(&self, path: &Utf8Path) -> Result<(), Error>;\n    fn copy(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error>;\n    fn copy_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error>;\n    fn hardlink(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error>;\n    fn symlink_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<(), Error>;\n    fn delete_file(&self, path: &Utf8Path) -> Result<(), Error>;\n    fn exists(&self, path: &Utf8Path) -> bool;\n}\n\n#[derive(Debug)]\n/// A wrapper around a Read implementing object that has Gleam's error handling.\npub struct WrappedReader {\n    path: Utf8PathBuf,\n    inner: DebugIgnore<Box<dyn io::Read>>,\n}\n\nimpl WrappedReader {\n    pub fn new(path: &Utf8Path, inner: Box<dyn io::Read>) -> Self {\n        Self {\n            path: path.to_path_buf(),\n            inner: DebugIgnore(inner),\n        }\n    }\n\n    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {\n        self.inner.read(buffer)\n    }\n}\n\nimpl io::Read for WrappedReader {\n    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {\n        self.read(buffer)\n    }\n}\n\nimpl Reader for WrappedReader {\n    fn convert_err<E: std::error::Error>(&self, err: E) -> Error {\n        Error::FileIo {\n            kind: FileKind::File,\n            action: FileIoAction::Read,\n            path: self.path.clone(),\n            err: Some(err.to_string()),\n        }\n    }\n}\n\n#[async_trait]\npub trait HttpClient {\n    async fn send(&self, request: http::Request<Vec<u8>>)\n    -> Result<http::Response<Vec<u8>>, Error>;\n}\n\npub trait TarUnpacker {\n    // FIXME: The reader types are restrictive here. We should be more generic\n    // than this.\n    fn io_result_entries<'a>(\n        &self,\n        archive: &'a mut Archive<WrappedReader>,\n    ) -> io::Result<tar::Entries<'a, WrappedReader>>;\n\n    fn entries<'a>(\n        &self,\n        archive: &'a mut Archive<WrappedReader>,\n    ) -> Result<tar::Entries<'a, WrappedReader>> {\n        tracing::debug!(\"iterating through tar archive\");\n        self.io_result_entries(archive)\n            .map_err(|e| Error::ExpandTar {\n                error: e.to_string(),\n            })\n    }\n\n    fn io_result_unpack(\n        &self,\n        path: &Utf8Path,\n        archive: Archive<GzDecoder<Entry<'_, WrappedReader>>>,\n    ) -> io::Result<()>;\n\n    fn unpack(\n        &self,\n        path: &Utf8Path,\n        archive: Archive<GzDecoder<Entry<'_, WrappedReader>>>,\n    ) -> Result<()> {\n        tracing::debug!(path = ?path, \"unpacking tar archive\");\n        self.io_result_unpack(path, archive)\n            .map_err(|e| Error::FileIo {\n                action: FileIoAction::WriteTo,\n                kind: FileKind::Directory,\n                path: path.to_path_buf(),\n                err: Some(e.to_string()),\n            })\n    }\n}\n\n#[inline]\npub fn is_native_file_extension(extension: &str) -> bool {\n    matches!(\n        extension,\n        \"erl\" | \"hrl\" | \"ex\" | \"js\" | \"mjs\" | \"cjs\" | \"ts\"\n    )\n}\n\npub fn ordered_map<S, K, V>(value: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>\nwhere\n    S: serde::Serializer,\n    K: serde::Serialize + Ord,\n    V: serde::Serialize,\n{\n    use serde::Serialize;\n    let ordered: std::collections::BTreeMap<_, _> = value.iter().collect();\n    ordered.serialize(serializer)\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/decision.rs",
    "content": "use super::{\n    INDENT, bit_array_segment_int_value_to_bytes,\n    expression::{self, Generator, Ordering, float, float_from_value},\n};\nuse crate::{\n    ast::{AssignmentKind, Endianness, SrcSpan, TypedClause, TypedExpr, TypedPattern},\n    docvec,\n    exhaustiveness::{\n        BitArrayMatchedValue, BitArrayTest, Body, BoundValue, CompiledCase, Decision,\n        FallbackCheck, MatchTest, Offset, ReadAction, ReadSize, ReadType, RuntimeCheck,\n        SizeOperator, SizeTest, Variable, VariableUsage,\n    },\n    format::break_block,\n    javascript::{\n        expression::{eco_string_int, string},\n        maybe_escape_property,\n    },\n    pretty::{Document, Documentable, break_, concat, join, line, nil},\n    strings::{convert_string_escape_chars, length_utf16},\n};\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse num_bigint::BigInt;\nuse std::{collections::HashMap, sync::OnceLock};\n\npub static ASSIGNMENT_VAR: &str = \"$\";\n\npub fn case<'a>(\n    compiled_case: &'a CompiledCase,\n    clauses: &'a [TypedClause],\n    subjects: &'a [TypedExpr],\n    expression_generator: &mut Generator<'_, 'a>,\n) -> Document<'a> {\n    let scope_position = expression_generator.scope_position.clone();\n    let mut variables = Variables::new(expression_generator, VariableAssignment::Declare);\n    let assignments = variables.assign_case_subjects(compiled_case, subjects);\n    let mut printer = CasePrinter {\n        variables,\n        assignments: &assignments,\n        kind: DecisionKind::Case { clauses },\n    };\n\n    let decision = match &compiled_case.tree {\n        // Printing needs extra care if we're dealing with a sort of \"degenerate\"\n        // tree that immediately starts with a guard node.\n        // Code generation for guard nodes require defining variables outside of\n        // the safe scope of the generated `if` statement. So if we were to just\n        // generate code like usual we run the risk of leaking variables in the\n        // outer scope:\n        //\n        // ```case\n        // case 11 {\n        //   n if n == 10 -> todo\n        //   _ -> todo\n        // }\n        //\n        // let n = 12\n        // ```\n        //\n        // That case would have us generate something like this:\n        //\n        // ```js\n        // let n = 11\n        // if (n === 10) { todo } else { todo }\n        //\n        // // If we don't wrap it in a block that `n = 11` definition that was\n        // // introduced would end up clashing with the `let n = 12` that comes\n        // // later!\n        // ```\n        //\n        // So in this special case we have to wrap everything in a block.\n        tree @ Decision::Guard { .. } if !scope_position.is_tail() => break_block(\n            printer\n                .inside_new_scope(|this| this.decision(tree))\n                .into_doc(),\n        ),\n\n        tree @ (Decision::Run { .. }\n        | Decision::Guard { .. }\n        | Decision::Switch { .. }\n        | Decision::Fail) => printer.decision(tree).into_doc(),\n    };\n    docvec![assignments_to_doc(assignments), decision].force_break()\n}\n\n/// The generated code for a decision tree.\nenum CaseBody<'a> {\n    /// A JavaScript `if`` statement by itself. This can be merged with any\n    /// preceding `else` statements to form an `else if` construct.\n    If {\n        check: Document<'a>,\n        body: Document<'a>,\n    },\n    /// A sequence of statements. This must be wrapped as the body of an `if` or\n    /// `else` statement.\n    Statements(Document<'a>),\n\n    /// A JavaScript `if` statement followed by a single `else` clause. In some\n    /// cases this can be flattened to reduce the size of the generated decision\n    /// tree.\n    IfElse {\n        check: Document<'a>,\n        if_body: Document<'a>,\n        else_body: Document<'a>,\n        /// The decision in the tree that is used to generate the code for the\n        /// `else` clause of this statement. If this is the same as another `if`-\n        /// `else` statement, the two can be merged into one.\n        fallback_decision: &'a Decision,\n    },\n\n    /// A JavaScript `if` statement followed by more than one `else` clause. This\n    /// can sometimes be merged with preceding `else` statements in the same way\n    /// that `if` can.\n    IfElseChain(Document<'a>),\n}\n\nimpl<'a> CaseBody<'a> {\n    fn into_doc(self) -> Document<'a> {\n        match self {\n            CaseBody::If { check, body } => docvec![\n                \"if (\",\n                break_(\"\", \"\")\n                    .append(check)\n                    .nest(INDENT)\n                    .append(break_(\"\", \"\"))\n                    .group(),\n                \") \",\n                break_block(body)\n            ],\n            // If we have some code like the following:\n            // ```javascript\n            // if (some_condition) {\n            //\n            // } else {\n            //   fallback()\n            // }\n            // ```\n            //\n            // Here, the body of the `if` statement is empty. This can happen\n            // sometimes when generating decision trees for `let assert`.\n            //\n            // Instead, we can write this more concisely:\n            // ```javascript\n            // if (!some_condition) {\n            //   fallback()\n            // }\n            // ```\n            CaseBody::IfElse {\n                check,\n                if_body,\n                else_body,\n                ..\n            } if if_body.is_empty() => docvec![\n                \"if (!(\",\n                break_(\"\", \"\")\n                    .append(check)\n                    .nest(INDENT)\n                    .append(break_(\"\", \"\"))\n                    .group(),\n                \")) \",\n                else_body,\n            ],\n            CaseBody::IfElse {\n                check,\n                if_body,\n                else_body,\n                ..\n            } => docvec![\n                \"if (\",\n                break_(\"\", \"\")\n                    .append(check)\n                    .nest(INDENT)\n                    .append(break_(\"\", \"\"))\n                    .group(),\n                \") \",\n                break_block(if_body),\n                \" else \",\n                else_body,\n            ],\n            CaseBody::Statements(document) | CaseBody::IfElseChain(document) => document,\n        }\n    }\n\n    /// Convert this value into the required document to put directly after an\n    /// `else` keyword.\n    fn document_after_else(self) -> Document<'a> {\n        match self {\n            // `if` and `if-else` statements can come directly after an `else` keyword\n            CaseBody::If { .. } | CaseBody::IfElse { .. } => self.into_doc(),\n            CaseBody::IfElseChain(document) => document,\n            // Lists of statements must be wrapped in a block\n            CaseBody::Statements(document) => break_block(document),\n        }\n    }\n\n    fn is_empty(&self) -> bool {\n        match self {\n            CaseBody::If { .. } | CaseBody::IfElse { .. } => false,\n            CaseBody::Statements(document) | CaseBody::IfElseChain(document) => document.is_empty(),\n        }\n    }\n}\n\nstruct CasePrinter<'module, 'generator, 'a, 'assignments> {\n    variables: Variables<'generator, 'module, 'a>,\n    assignments: &'assignments Vec<SubjectAssignment<'a>>,\n    kind: DecisionKind<'a>,\n}\n\n/// Information specific to the different kinds of decision trees: `case`\n/// expressions and `let assert` statements.\nenum DecisionKind<'a> {\n    Case {\n        clauses: &'a [TypedClause],\n    },\n    LetAssert {\n        kind: &'a AssignmentKind<TypedExpr>,\n        subject_location: SrcSpan,\n        pattern_location: SrcSpan,\n        subject: EcoString,\n    },\n}\n\nenum BodyExpression<'a> {\n    /// This happens when a case expression branch returns the same value that\n    /// is being matched on. So instead of rebuilding it from scratch we can\n    /// return the case subject directly. For example:\n    /// `Ok(1) -> Ok(1)`\n    /// `a -> a`\n    /// `[1, ..rest] -> [1, ..rest]`\n    ///\n    Variable(Document<'a>),\n\n    /// This happens when a case expression has a complex body that is not just\n    /// returning the matched subject. For example:\n    /// `Ok(1) -> Ok(2)`\n    /// `_ -> [1, 2, 3]`\n    /// `1 -> \"wibble\"`\n    ///\n    Expressions(Document<'a>),\n}\n\n/// Code generation for decision trees can look a bit daunting at a first glance\n/// so let's go over the big idea to hopefully make it easier to understand why\n/// the code is organised the way it is :)\n///\n/// > It might be helpful to go over the `exhaustiveness` module first and get\n/// > familiar with the structure of the decision tree!\n///\n/// A decision tree has nodes that perform checks on pattern variables until\n/// it reaches a body with an expression to run. This will be turned into a\n/// series of if-else checks.\n///\n/// While on the surface it might sound pretty straightforward, the code generation\n/// needs to take care of a couple of tricky aspects: when a check succeeds it's\n/// not just allowing us to move to the next check, but it also introduces new\n/// variables in the scope that we can reference. Let's look at an example:\n///\n/// ```gleam\n/// case value {\n///   [1, ..rest] -> rest\n///   _ -> []\n/// }\n/// ```\n///\n/// Here we will first need to check that the list is not empty:\n///\n/// ```js\n/// if (value instanceOf $NonEmptyList) {\n///   // ...\n/// } else {\n///   return [];\n/// }\n/// ```\n///\n/// Once that check succeeds we know that now we can access two new values: the\n/// first element of the list and the rest of the list! So we need to keep track\n/// of that in case further checks need to use those values; and in the example\n/// above they actually do! The second check we need to perform will be on the\n/// first item of the list, so we need to actually create a variable for it:\n///\n/// ```js\n/// if (value instanceOf $NonEmptyList) {\n///   let $ = value.head;\n///   if ($ === 1) {\n///     // ...\n///   } else {\n///     // ...\n///   }\n/// } else {\n///   return [];\n/// }\n/// ```\n///\n/// So, as we're generating code for each check and move further down the decision\n/// tree, we will have to keep track of all the variables that we've discovered\n/// after each successful check.\n///\n/// In order to do that we'll be using a `Variables` data structure to hold all\n/// this information about the current scope.\n///\nimpl<'a> CasePrinter<'_, '_, 'a, '_> {\n    fn decision(&mut self, decision: &'a Decision) -> CaseBody<'a> {\n        match decision {\n            Decision::Fail => {\n                if let DecisionKind::LetAssert {\n                    kind,\n                    subject_location,\n                    pattern_location,\n                    subject,\n                } = &self.kind\n                {\n                    CaseBody::Statements(self.assignment_no_match(\n                        subject.to_doc(),\n                        kind,\n                        *subject_location,\n                        *pattern_location,\n                    ))\n                } else {\n                    unreachable!(\"Invalid decision tree reached code generation\")\n                }\n            }\n            Decision::Run { body } => {\n                let bindings = self.variables.bindings_doc(&body.bindings);\n                let body = self.body_expression(body.clause_index);\n                let body = match body {\n                    BodyExpression::Variable(variable) => variable,\n                    BodyExpression::Expressions(body) => join_with_line(bindings, body),\n                };\n                CaseBody::Statements(body)\n            }\n            Decision::Switch {\n                var,\n                choices,\n                fallback,\n                fallback_check,\n            } => self.switch(var, choices, fallback, fallback_check),\n            Decision::Guard {\n                guard,\n                if_true,\n                if_false,\n            } => self.decision_guard(*guard, if_true, if_false),\n        }\n    }\n\n    fn body_expression(&mut self, clause_index: usize) -> BodyExpression<'a> {\n        // If we are not in a `case` expression, there is no additional code to\n        // execute when a branch matches; we only assign variables bound in the\n        // pattern.\n        let DecisionKind::Case { clauses } = &self.kind else {\n            return BodyExpression::Expressions(nil());\n        };\n\n        let clause = &clauses.get(clause_index).expect(\"invalid clause index\");\n        let body = &clause.then;\n\n        if let Some(subject_index) = clause.returned_subject() {\n            let variable = self\n                .assignments\n                .get(subject_index)\n                .expect(\"case with no subjects\")\n                .name();\n\n            BodyExpression::Variable(\n                self.variables\n                    .expression_generator\n                    .wrap_return(variable.to_doc()),\n            )\n        } else {\n            BodyExpression::Expressions(\n                self.variables\n                    .expression_generator\n                    .expression_flattening_blocks(body),\n            )\n        }\n    }\n\n    fn switch(\n        &mut self,\n        var: &'a Variable,\n        choices: &'a [(RuntimeCheck, Decision)],\n        fallback: &'a Decision,\n        fallback_check: &'a FallbackCheck,\n    ) -> CaseBody<'a> {\n        // If there's just a single choice we can just generate the code for\n        // it: no need to do any checking, we know it must match!\n        if choices.is_empty() {\n            // However, if the choice had an associated check (that is, it was\n            // not just a simple catch all) we need to keep track of all the\n            // variables brought into scope by the (always) successfull check.\n            if let FallbackCheck::RuntimeCheck { check } = fallback_check {\n                self.variables.record_check_assignments(var, check);\n            }\n            return self.inside_new_scope(|this| this.decision(fallback));\n        }\n\n        // Otherwise we'll have to generate a series of if-else to check which\n        // pattern is going to match!\n        let mut assignments = vec![];\n        if !self.variables.is_bound_in_scope(var) {\n            // If the variable we need to perform a check on is not already bound\n            // in scope we will be binding it to a new made up name. This way we\n            // can also reference this exact name in further checks instead of\n            // recomputing the value each time.\n            let name = self.variables.next_local_var(&ASSIGNMENT_VAR.into());\n            let value = self.variables.get_value(var);\n            self.variables.bind(name.clone(), var);\n            assignments.push(let_doc(name, value.to_doc()))\n        };\n\n        let mut if_ = CaseBody::Statements(nil());\n        for (i, (check, decision)) in choices.iter().enumerate() {\n            self.variables.record_check_assignments(var, check);\n\n            // For each check we generate:\n            // - the document to perform such check\n            // - the body to run if the check is successful\n            // - the assignments we need to bring all the bit array segments\n            //   referenced by this check\n            let (check_doc, body, mut segment_assignments) = self.inside_new_scope(|this| {\n                let segment_assignments = this.variables.bit_array_segment_assignments(check);\n                let check_doc = this.variables.runtime_check(var, check);\n                let body = this.decision(decision);\n                (check_doc, body, segment_assignments)\n            });\n            assignments.append(&mut segment_assignments);\n\n            let (check_doc, body) = match body {\n                // If we have a statement like this:\n                // ```javascript\n                // if (x) {\n                //   if (y) {\n                //     ...\n                //   }\n                // }\n                // ```\n                //\n                // We can transform it into:\n                // ```javascript\n                // if (x && y) {\n                //   ...\n                // }\n                // ```\n                CaseBody::If { check, body } => {\n                    (docvec![check_doc, break_(\" &&\", \" && \"), check], body)\n                }\n\n                // The following code is a pretty common pattern in the code\n                // generated by decision trees:\n                //\n                // ```javascript\n                // if (something) {\n                //   if (something_else) {\n                //     do_thing()\n                //   } else {\n                //     do_fallback()\n                //   }\n                // } else {\n                //   do_fallback()\n                // }\n                // ```\n                //\n                // Here, the `do_fallback()` branch is repeated, which we want\n                // to avoid if possible. In this case, we can transform the above\n                // code into the following:\n                //\n                // ```javascript\n                // if (something && something_else) {\n                //   do_thing()\n                // } else {\n                //   do_fallback()\n                // }\n                // ```\n                //\n                // This only works if both `else` branches run the same code,\n                // otherwise we would be losing information.\n                // It also only works if the inner statement has only a single\n                // `else` clause, and not multiple `else if`s.\n                CaseBody::IfElse {\n                    check,\n                    if_body,\n                    fallback_decision: decision,\n                    ..\n                } if decision == fallback => {\n                    (docvec![check_doc, break_(\" &&\", \" && \"), check], if_body)\n                }\n\n                if_else @ CaseBody::IfElse { .. } => (check_doc, if_else.into_doc()),\n\n                CaseBody::Statements(document) | CaseBody::IfElseChain(document) => {\n                    (check_doc, document)\n                }\n            };\n\n            if_ = match if_ {\n                // The first statement will always be an `if`\n                _ if i == 0 => CaseBody::If {\n                    check: check_doc,\n                    body,\n                },\n                // If this is the second check, the `if` becomes `else if`\n                CaseBody::If { .. } | CaseBody::IfElse { .. } => CaseBody::IfElseChain(docvec![\n                    if_.into_doc(),\n                    \" else if (\",\n                    break_(\"\", \"\")\n                        .append(check_doc)\n                        .nest(INDENT)\n                        .append(break_(\"\", \"\"))\n                        .group(),\n                    \") \",\n                    break_block(body)\n                ]),\n                CaseBody::IfElseChain(document) | CaseBody::Statements(document) => {\n                    CaseBody::IfElseChain(docvec![\n                        document,\n                        \" else if (\",\n                        break_(\"\", \"\")\n                            .append(check_doc)\n                            .nest(INDENT)\n                            .append(break_(\"\", \"\"))\n                            .group(),\n                        \") \",\n                        break_block(body)\n                    ])\n                }\n            };\n        }\n\n        // In case there's some new variables we can extract after the\n        // successful final check we store those. But we don't need to perform\n        // the check itself: the type system ensures that, if we ever get here,\n        // the check is going to match no matter what!\n        if let FallbackCheck::RuntimeCheck { check } = fallback_check {\n            self.variables.record_check_assignments(var, check);\n        }\n\n        let else_body = self.inside_new_scope(|this| this.decision(fallback));\n        let document = if else_body.is_empty() {\n            if_\n        } else if let CaseBody::If {\n            check,\n            body: if_body,\n        } = if_\n        {\n            CaseBody::IfElse {\n                check,\n                if_body,\n                else_body: else_body.document_after_else(),\n                fallback_decision: fallback,\n            }\n        } else {\n            CaseBody::IfElseChain(docvec![\n                if_.into_doc(),\n                \" else \",\n                else_body.document_after_else()\n            ])\n        };\n\n        if assignments.is_empty() {\n            document\n        } else {\n            CaseBody::Statements(join_with_line(\n                join(assignments, line()),\n                document.into_doc(),\n            ))\n        }\n    }\n\n    fn inside_new_scope<A, F>(&mut self, run: F) -> A\n    where\n        F: Fn(&mut Self) -> A,\n    {\n        // Since we use reassignment for `let assert`, we can't reset the scope\n        // as it loses data about the assigned variables.\n        let old_scope = match &self.kind {\n            DecisionKind::Case { .. } => self\n                .variables\n                .expression_generator\n                .current_scope_vars\n                .clone(),\n            DecisionKind::LetAssert { .. } => Default::default(),\n        };\n\n        let old_names = self.variables.scoped_variable_names.clone();\n        let old_segments = self.variables.segment_values.clone();\n        let old_segment_names = self.variables.scoped_segment_names.clone();\n        let output = run(self);\n\n        match &self.kind {\n            DecisionKind::Case { .. } => {\n                self.variables.expression_generator.current_scope_vars = old_scope\n            }\n            DecisionKind::LetAssert { .. } => {}\n        }\n\n        self.variables.scoped_variable_names = old_names;\n        self.variables.segment_values = old_segments;\n        self.variables.scoped_segment_names = old_segment_names;\n        output\n    }\n\n    fn decision_guard(\n        &mut self,\n        guard: usize,\n        if_true: &'a Body,\n        if_false: &'a Decision,\n    ) -> CaseBody<'a> {\n        let DecisionKind::Case { clauses } = &self.kind else {\n            unreachable!(\"Guards cannot appear in let assert decision trees\")\n        };\n\n        let guard = clauses\n            .get(guard)\n            .expect(\"invalid clause index\")\n            .guard\n            .as_ref()\n            .expect(\"missing guard\");\n\n        // Before generating the if-else condition we want to generate all the\n        // assignments that will be needed by the guard condition so we can rest\n        // assured they are in scope and the guard check can use those.\n        let guard_variables = guard.referenced_variables();\n        let (check_bindings, if_true_bindings): (Vec<_>, Vec<_>) = if_true\n            .bindings\n            .iter()\n            .partition(|(variable, _)| guard_variables.contains(variable));\n\n        let (check_bindings, check, if_true) = self.inside_new_scope(|this| {\n            // check_bindings and if_true generation have to be in this scope so that pattern-bound\n            // variables used in guards don't leak into other case branches (if_false).\n            let check_bindings = this.variables.bindings_ref_doc(&check_bindings);\n            let check = this.variables.expression_generator.guard(guard);\n            // All the other bindings that are not needed by the guard check will\n            // end up directly in the body of the if clause.\n            let if_true_bindings = this.variables.bindings_ref_doc(&if_true_bindings);\n            let if_true_body = this.body_expression(if_true.clause_index);\n            let if_true = match if_true_body {\n                BodyExpression::Variable(variable) => variable,\n                BodyExpression::Expressions(if_true_body) => {\n                    join_with_line(if_true_bindings, if_true_body)\n                }\n            };\n            (check_bindings, check, if_true)\n        });\n\n        let if_false_body = self.inside_new_scope(|this| this.decision(if_false));\n\n        // We can now piece everything together into a case body!\n        let if_ = if if_false_body.is_empty() {\n            CaseBody::If {\n                check,\n                body: if_true,\n            }\n        } else {\n            CaseBody::IfElse {\n                check,\n                if_body: if_true,\n                else_body: if_false_body.document_after_else(),\n                fallback_decision: if_false,\n            }\n        };\n\n        if check_bindings.is_empty() {\n            if_\n        } else {\n            CaseBody::Statements(join_with_line(check_bindings, if_.into_doc()))\n        }\n    }\n\n    fn assignment_no_match(\n        &mut self,\n        subject: Document<'a>,\n        kind: &'a AssignmentKind<TypedExpr>,\n        subject_location: SrcSpan,\n        pattern_location: SrcSpan,\n    ) -> Document<'a> {\n        let AssignmentKind::Assert {\n            location, message, ..\n        } = kind\n        else {\n            unreachable!(\"inexhaustive let made it to code generation\");\n        };\n\n        let generator = &mut self.variables.expression_generator;\n        let message = match message {\n            None => string(\"Pattern match failed, no pattern matched the value.\"),\n            Some(message) => generator\n                .not_in_tail_position(Some(Ordering::Strict), |this| this.wrap_expression(message)),\n        };\n        generator.throw_error(\n            \"let_assert\",\n            &message,\n            *location,\n            [\n                (\"value\", subject),\n                (\"start\", location.start.to_doc()),\n                (\"end\", subject_location.end.to_doc()),\n                (\"pattern_start\", pattern_location.start.to_doc()),\n                (\"pattern_end\", pattern_location.end.to_doc()),\n            ],\n        )\n    }\n}\n\npub fn let_<'a>(\n    compiled_case: &'a CompiledCase,\n    subject: &'a TypedExpr,\n    kind: &'a AssignmentKind<TypedExpr>,\n    expression_generator: &mut Generator<'_, 'a>,\n    pattern: &'a TypedPattern,\n) -> Document<'a> {\n    let scope_position = expression_generator.scope_position.clone();\n    let mut variables = Variables::new(expression_generator, VariableAssignment::Reassign);\n\n    let assignment = variables.assign_let_subject(compiled_case, subject);\n    let assignment_name = assignment.name();\n    let assignments = vec![assignment];\n\n    let decision = CasePrinter {\n        variables,\n        assignments: &assignments,\n        kind: DecisionKind::LetAssert {\n            kind,\n            subject_location: subject.location(),\n            pattern_location: pattern.location(),\n            subject: assignment_name.clone(),\n        },\n    }\n    .decision(&compiled_case.tree);\n\n    // When we generate `let assert` statements, we want to produce code like\n    // this:\n    // ```javascript\n    // let some_var;\n    // let other_var;\n    // if (condition_to_check_pattern) {\n    //   some_var = x;\n    //   other_var = y;\n    // }\n    // ```\n    // This generates the code for binding the initial variables before the\n    // check so the scoping of them is correct.\n    //\n    // We must generate this after we generate the code for the decision tree\n    // itself as we might be re-binding variables which are used in the checks\n    // to determine whether the pattern matches or not.\n    let beginning_assignments = pattern.bound_variables().into_iter().map(|bound_variable| {\n        docvec![\n            \"let \",\n            expression_generator.local_var(&bound_variable.name()),\n            \";\",\n            line()\n        ]\n    });\n\n    let doc = docvec![\n        assignments_to_doc(assignments),\n        concat(beginning_assignments),\n        decision.into_doc()\n    ];\n\n    match scope_position {\n        expression::Position::Expression(_) | expression::Position::Statement => doc,\n        expression::Position::Tail => docvec![doc, line(), \"return \", assignment_name, \";\"],\n        expression::Position::Assign(variable) => {\n            docvec![doc, line(), variable, \" = \", assignment_name, \";\"]\n        }\n    }\n}\n\nenum VariableAssignment {\n    Declare,\n    Reassign,\n}\n\n/// This is a useful piece of state that is kept separate from the generator\n/// itself so we can reuse it both with `case`s and `let`s without rewriting\n/// everything from scratch.\n///\nstruct Variables<'generator, 'module, 'a> {\n    expression_generator: &'generator mut Generator<'module, 'a>,\n\n    /// Whether to bind variables using `let` as we do in `case` expressions,\n    /// or to reassign them as we do in `let assert` statements.\n    variable_assignment: VariableAssignment,\n\n    /// All the pattern variables will be assigned a specific value: being bound\n    /// to a constructor field, tuple element and so on. Pattern variables never\n    /// end up in the generated code but we replace them with their actual value.\n    /// We store those values as `EcoString`s in this map; the key is the pattern\n    /// variable's unique id.\n    ///\n    variable_values: HashMap<usize, EcoString>,\n\n    /// The same happens for bit array segments. Unlike pattern variables, we\n    /// identify those using their names and store their value as a `Document`.\n    segment_values: HashMap<EcoString, Document<'a>>,\n\n    /// When we discover new variables after a runtime check we don't immediately\n    /// generate assignments for each of them, because that could lead to wasted\n    /// work. Let's consider the following check:\n    ///\n    /// ```txt\n    /// a is Wibble(3, c, 1) -> c\n    /// a is _ -> 1\n    /// ```\n    ///\n    /// If we generated variables for it as soon as we enter its corresponding\n    /// branch we would find ourselves with this piece of code:\n    ///\n    /// ```js\n    /// if (a instanceof Wibble) {\n    ///   let a$0 = wibble.0;\n    ///   let a$1 = wibble.1;\n    ///   let a$2 = wibble.2;\n    ///\n    ///   // and now we go on checking these new variables\n    /// }\n    /// ```\n    ///\n    /// However, by extracting all the fields immediately we might end up doing\n    /// wasted work: as soon as we find out that `a$0 != 3` we don't even need\n    /// to check the other fields, we know the pattern can't match! So we\n    /// extracted two fields we're not even checking.\n    ///\n    /// To avoid this situation, we only bind a variable to a name right before\n    /// we're checking it so we're sure we're never generating useless bindings.\n    /// The previous example would become something like this:\n    ///\n    /// ```js\n    /// if (a instanceof Wibble) {\n    ///   let a$0 = wibble.0;\n    ///   if (a$0 === 3) {\n    ///     let a$2 = wibble.2\n    ///     // further checks\n    ///   } else {\n    ///     return 1;\n    ///   }\n    /// }\n    /// ```\n    ///\n    /// In this map we store the name a variable is bound to in the current\n    /// scope. For example here we know that `wibble.0` is bound to the name\n    /// `a$0`.\n    ///\n    scoped_variable_names: HashMap<usize, EcoString>,\n\n    /// Once again, this is the same as `scoped_variable_names` with the\n    /// difference that a segment is identified by its name.\n    ///\n    scoped_segment_names: HashMap<EcoString, EcoString>,\n}\n\nimpl<'generator, 'module, 'a> Variables<'generator, 'module, 'a> {\n    fn new(\n        expression_generator: &'generator mut Generator<'module, 'a>,\n        variable_assignment: VariableAssignment,\n    ) -> Self {\n        Variables {\n            expression_generator,\n            variable_assignment,\n            variable_values: HashMap::new(),\n            scoped_variable_names: HashMap::new(),\n            segment_values: HashMap::new(),\n            scoped_segment_names: HashMap::new(),\n        }\n    }\n\n    /// Give a unique name to each of the subjects of a case expression and keep\n    /// track of each of those names in case it needs to be referenced later.\n    ///\n    fn assign_case_subjects(\n        &mut self,\n        compiled_case: &'a CompiledCase,\n        subjects: &'a [TypedExpr],\n    ) -> Vec<SubjectAssignment<'a>> {\n        let assignments = subjects\n            .iter()\n            .map(|subject| assign_subject(self.expression_generator, subject, Ordering::Strict))\n            .collect_vec();\n\n        for (variable, assignment) in compiled_case\n            .subject_variables\n            .iter()\n            .zip(assignments.iter())\n        {\n            // We need to record the fact that each subject corresponds to a\n            // pattern variable.\n            self.set_value(variable, assignment.name());\n            self.bind(assignment.name(), variable);\n        }\n\n        assignments\n    }\n\n    /// Give a unique name to the subject of a let expression (if it needs one\n    /// and it's not already a variable) and keep track of that name in case it\n    /// needs to be referenced later.\n    ///\n    fn assign_let_subject(\n        &mut self,\n        compiled_case: &'a CompiledCase,\n        subject: &'a TypedExpr,\n    ) -> SubjectAssignment<'a> {\n        let variable = compiled_case\n            .subject_variables\n            .first()\n            .expect(\"decision tree with no subjects\");\n        let assignment = assign_subject(self.expression_generator, subject, Ordering::Loose);\n        self.set_value(variable, assignment.name());\n        self.bind(assignment.name(), variable);\n        assignment\n    }\n\n    fn local_var(&mut self, name: &EcoString) -> EcoString {\n        self.expression_generator.local_var(name)\n    }\n\n    fn next_local_var(&mut self, name: &EcoString) -> EcoString {\n        self.expression_generator.next_local_var(name)\n    }\n\n    /// Records that a given pattern `variable` has been assigned a runtime\n    /// `value`. For example if we had something like this:\n    ///\n    /// ```txt\n    /// a is Wibble(1, b) -> todo\n    /// ```\n    ///\n    /// After a successful `is Wibble` check, we know we'd end up with two\n    /// additional checks that look like this:\n    ///\n    /// ```txt\n    /// a0 is 1, a1 is b -> todo\n    /// ```\n    ///\n    /// But what's the runtime value of `a0` and `a1`? To get those we'd have to\n    /// extract the two fields from `a`, so they would have a value that looks\n    /// like this: `a[0]` and `a[1]`; these values are set with this `set_value`\n    /// function as we discover them.\n    ///\n    fn set_value(&mut self, variable: &Variable, value: EcoString) {\n        let _ = self.variable_values.insert(variable.id, value);\n    }\n\n    /// This is conceptually the same as set value, but it's for bit array\n    /// segments instead of pattern variables.\n    fn set_segment_value(\n        &mut self,\n        bit_array: &Variable,\n        segment_name: EcoString,\n        read_action: &ReadAction,\n    ) {\n        let value = self.read_action_to_doc(bit_array, read_action);\n        let _ = self.segment_values.insert(segment_name, value);\n    }\n\n    /// During the code generation process we might end up having to generate\n    /// code to materialises one of the pattern variables and gives it a name to\n    /// be used to avoid repeating it every single time.\n    ///\n    /// For example if a pattern variable is referencing the fifth element in a\n    /// list it's runtime value would look something like this:\n    /// `list.tail.tail.tail.tail.head`; if we where to perform additional\n    /// checks on this value, it would be quite wasteful to recompute it every\n    /// single time. Imagine this piece of code:\n    ///\n    /// ```gleam\n    /// case list {\n    ///   [_, _, _, _, 1] -> todo\n    ///   [_, _, _, _, 2] -> todo\n    ///   // ...\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    /// The corresponding check would end up looking something like this:\n    ///\n    /// ```js\n    /// if (list.tail.tail.tail.tail.head === 1) {}\n    /// else if (list.tail.tail.tail.tail.head === 2) {}\n    /// // ...\n    /// else {}\n    /// ```\n    ///\n    /// So before a check we might want to bind a pattern variable to a name so\n    /// we can use that to reference it in the check:\n    ///\n    /// ```js\n    /// let $ = list.tail.tail.tail.tail.head;\n    /// if ($ === 1) {}\n    /// else if ($ === 2) {}\n    /// // ...\n    /// else {}\n    /// ```\n    ///\n    /// This makes for neater code! These bindings are kept track of with this\n    /// function.\n    ///\n    fn bind(&mut self, name: EcoString, variable: &Variable) {\n        let _ = self.scoped_variable_names.insert(variable.id, name);\n    }\n\n    /// This has the exact same purpose as `bind` but works with bit array\n    /// segments instead of pattern variables introduced during the decision\n    /// tree compilation.\n    ///\n    fn bind_segment(&mut self, bound_to_variable: EcoString, segment: EcoString) {\n        let _ = self.scoped_segment_names.insert(segment, bound_to_variable);\n    }\n\n    fn bindings_doc(&mut self, bindings: &'a [(EcoString, BoundValue)]) -> Document<'a> {\n        let bindings =\n            (bindings.iter()).map(|(variable, value)| self.body_binding_doc(variable, value));\n        join(bindings, line())\n    }\n\n    fn bindings_ref_doc(&mut self, bindings: &[&'a (EcoString, BoundValue)]) -> Document<'a> {\n        let bindings =\n            (bindings.iter()).map(|(variable, value)| self.body_binding_doc(variable, value));\n        join(bindings, line())\n    }\n\n    fn body_binding_doc(\n        &mut self,\n        variable_name: &'a EcoString,\n        value: &'a BoundValue,\n    ) -> Document<'a> {\n        let local_variable_name = self.next_local_var(variable_name);\n        let assigned_value = match value {\n            BoundValue::Variable(variable) => self.get_value(variable).to_doc(),\n            BoundValue::LiteralString(value) => string(value),\n            BoundValue::LiteralFloat(value) => float(value),\n            BoundValue::LiteralInt(value) => eco_string_int(eco_format!(\"{value}\")),\n            BoundValue::BitArraySlice {\n                bit_array,\n                read_action,\n            } => self\n                .get_segment_value(variable_name)\n                .unwrap_or_else(|| self.read_action_to_doc(bit_array, read_action)),\n        };\n\n        match self.variable_assignment {\n            VariableAssignment::Declare => let_doc(local_variable_name.clone(), assigned_value),\n            VariableAssignment::Reassign => {\n                reassignment_doc(local_variable_name.clone(), assigned_value)\n            }\n        }\n    }\n\n    /// Generates the document to perform a (possibly negated) runtime check on\n    /// the given variable.\n    ///\n    fn runtime_check(\n        &mut self,\n        variable: &Variable,\n        runtime_check: &'a RuntimeCheck,\n    ) -> Document<'a> {\n        let value = self.get_value(variable);\n\n        let equality = \" === \";\n\n        match runtime_check {\n            RuntimeCheck::String { value: expected } => docvec![value, equality, string(expected)],\n            RuntimeCheck::Float {\n                float_value: expected,\n            } => docvec![value, equality, float_from_value(expected.value())],\n            RuntimeCheck::Int {\n                int_value: expected,\n            } => docvec![value, equality, expected.clone()],\n            RuntimeCheck::StringPrefix { prefix, .. } => {\n                docvec![value, \".startsWith(\", string(prefix), \")\"]\n            }\n\n            RuntimeCheck::BitArray { test } => match test {\n                // In this case we need to check that the remaining part of the\n                // bit array has a whole number of bytes.\n                BitArrayTest::CatchAllIsBytes { size_so_far } => {\n                    if size_so_far.is_zero() {\n                        docvec![value, \".bitSize % 8\", equality, \"0\"]\n                    } else {\n                        let size_so_far = self.offset_to_doc(size_so_far, true);\n                        let remaining_bits = docvec![value, \".bitSize - \", size_so_far];\n                        docvec![\"(\", remaining_bits, \") % 8\", equality, \"0\"]\n                    }\n                }\n\n                BitArrayTest::ReadSizeIsNotNegative { size } => {\n                    docvec![self.read_size_to_doc(size), \" >= 0\"]\n                }\n\n                BitArrayTest::SegmentIsFiniteFloat {\n                    read_action:\n                        ReadAction {\n                            from: start,\n                            size,\n                            endianness,\n                            ..\n                        },\n                } => {\n                    let start_doc = self.offset_to_doc(start, false);\n                    let end = match (start.constant_bits(), size.constant_bits()) {\n                        (Some(start), _) if start == BigInt::ZERO => self\n                            .read_size_to_doc(size)\n                            .expect(\"unexpected catch all size\"),\n                        (Some(start), Some(end)) => (start + end).to_doc(),\n                        (_, _) => docvec![start_doc.clone(), \" + \", self.read_size_to_doc(size)],\n                    };\n                    let check = self.bit_array_slice_to_float(value, start_doc, end, endianness);\n\n                    docvec![\"Number.isFinite(\", check, \")\"]\n                }\n\n                // Here we need to make sure that the bit array has a specific\n                // size.\n                BitArrayTest::Size(SizeTest { operator, size }) => {\n                    let operator = match operator {\n                        SizeOperator::GreaterEqual => \" >= \",\n                        SizeOperator::Equal => equality,\n                    };\n                    let size = self.offset_to_doc(size, false);\n                    docvec![value, \".bitSize\", operator, size]\n                }\n\n                // Finally, here we need to check that a given portion of the\n                // bit array matches a given value.\n                BitArrayTest::Match(MatchTest {\n                    value: expected,\n                    read_action,\n                }) => match expected {\n                    BitArrayMatchedValue::LiteralString {\n                        value: _,\n                        encoding: _,\n                        bytes: expected,\n                    } => self.literal_string_segment_bytes_check(value, expected, read_action),\n                    BitArrayMatchedValue::LiteralFloat(expected) => {\n                        self.literal_float_segment_bytes_check(value, expected, read_action)\n                    }\n                    BitArrayMatchedValue::LiteralInt {\n                        value: expected, ..\n                    } => self.literal_int_segment_bytes_check(value, expected.clone(), read_action),\n                    BitArrayMatchedValue::Variable(..)\n                    | BitArrayMatchedValue::Discard(..)\n                    | BitArrayMatchedValue::Assign { .. } => {\n                        panic!(\"unreachable\")\n                    }\n                },\n            },\n\n            // When checking on a tuple there's always going to be a single choice\n            // and the code generation will always skip generating the check for it\n            // as the type system ensures it must match.\n            RuntimeCheck::Tuple { .. } => unreachable!(\"tried generating runtime check for tuple\"),\n\n            // Some variants like `Bool` and `Result` are special cased and checked\n            // in a different way from all other variants.\n            RuntimeCheck::Variant { match_, .. } if variable.type_.is_bool() => {\n                match match_.name().as_str() {\n                    \"True\" => value.to_doc(),\n                    _ => docvec![\"!\", value],\n                }\n            }\n\n            RuntimeCheck::Variant { match_, index, .. } => {\n                if variable.type_.is_result() && match_.module().is_none() {\n                    if *index == 0 {\n                        self.expression_generator.tracker.ok_used = true;\n                    } else {\n                        self.expression_generator.tracker.error_used = true;\n                    }\n                }\n\n                let qualification = match_\n                    .module()\n                    .map(|module| eco_format!(\"${module}.\"))\n                    .unwrap_or_default();\n\n                docvec![value, \" instanceof \", qualification, match_.name()]\n            }\n\n            RuntimeCheck::NonEmptyList { .. } => {\n                self.expression_generator.tracker.list_non_empty_class_used = true;\n                docvec![value, \" instanceof $NonEmpty\"]\n            }\n\n            RuntimeCheck::EmptyList => {\n                self.expression_generator.tracker.list_empty_class_used = true;\n                docvec![value, \" instanceof $Empty\"]\n            }\n        }\n    }\n\n    /// Turns a read action into a document that can be used to extract the\n    /// corresponding value from the given bit array and assign it to a\n    /// variable.\n    ///\n    fn read_action_to_doc(\n        &mut self,\n        bit_array: &Variable,\n        read_action: &ReadAction,\n    ) -> Document<'a> {\n        let ReadAction {\n            from,\n            size,\n            type_,\n            endianness,\n            signed,\n        } = read_action;\n        let bit_array = self.get_value(bit_array);\n        let from_bits = from.constant_bits();\n\n        // There's two special cases we need to take care of:\n        match (size, &from_bits) {\n            // If we're reading a single byte as un unsigned int from a byte aligned\n            // offset then we can optimise this call as a `.byteAt` call!\n            (ReadSize::ConstantBits(size), Some(from_bits))\n                if type_.is_int()\n                    && *size == BigInt::from(8)\n                    && !signed\n                    && from_bits.clone() % 8 == BigInt::ZERO =>\n            {\n                let from_byte: BigInt = from_bits / 8;\n                return docvec![bit_array, \".byteAt(\", from_byte, \")\"];\n            }\n\n            // If we're reading all the remaining bits/bytes of an array we'll\n            // take the remaining slice.\n            (ReadSize::RemainingBits | ReadSize::RemainingBytes, _) => {\n                return self.bit_array_slice(bit_array, from);\n            }\n\n            _ => (),\n        }\n\n        // Otherwise we'll take a regular slice out of the bit array, depending\n        // on the type of the segment.\n        let (start, end) =\n            if let (ReadSize::ConstantBits(size), Some(from_bits)) = (size, from_bits) {\n                // If both the start and and are known at compile time we can use\n                // those directly in the slice call and perform no addition at\n                // runtime.\n                let start = from_bits.clone().to_doc();\n                let end = (from_bits + size).to_doc();\n                (start, end)\n            } else {\n                // Otherwise we'll have to sum the variable part and the constant\n                // one to tell how long the slice should be.\n                let size = self.read_size_to_doc(size).expect(\"no variable size\");\n                let start = self.offset_to_doc(from, false);\n                let end = if from.is_zero() {\n                    size\n                } else {\n                    docvec![start.clone(), \" + \", size]\n                };\n                (start, end)\n            };\n\n        match type_ {\n            ReadType::Int => {\n                self.bit_array_slice_to_int(bit_array, start, end, endianness, *signed)\n            }\n            ReadType::Float => self.bit_array_slice_to_float(bit_array, start, end, endianness),\n            ReadType::BitArray => self.bit_array_slice_with_end(bit_array, from, end),\n            ReadType::String | ReadType::UtfCodepoint => {\n                panic!(\"invalid slice type made it to code generation: {type_:#?}\")\n            }\n        }\n    }\n\n    fn offset_to_doc(&mut self, offset: &Offset, parenthesise: bool) -> Document<'a> {\n        if offset.is_zero() {\n            return \"0\".to_doc();\n        }\n\n        let mut pieces = vec![];\n        if offset.constant != BigInt::ZERO {\n            pieces.push(eco_string_int(offset.constant.to_string().into()));\n        }\n\n        for (variable, times) in offset\n            .variables\n            .iter()\n            .sorted_by(|(one, _), (other, _)| one.name().cmp(other.name()))\n        {\n            let mut variable = match variable {\n                VariableUsage::PatternSegment(segment_name, _) => self\n                    .get_segment_value(segment_name)\n                    .expect(\"segment referenced in a check before being created\"),\n                VariableUsage::OutsideVariable(name) => self.local_var(name).to_doc(),\n            };\n            if *times != 1 {\n                variable = variable.append(\" * \").append(*times)\n            }\n            pieces.push(variable.to_doc())\n        }\n\n        for calculation in offset.calculations.iter() {\n            let left = self.offset_to_doc(&calculation.left, true);\n            let right = self.offset_to_doc(&calculation.right, true);\n\n            let calculation = self.expression_generator.bin_op_with_doc_operands(\n                calculation.operator.to_bin_op(),\n                left,\n                right,\n                &crate::type_::int(),\n            );\n\n            if parenthesise {\n                pieces.push(calculation.surround(\"(\", \")\"))\n            } else {\n                pieces.push(calculation)\n            }\n        }\n\n        if pieces.len() > 1 && parenthesise {\n            docvec![\"(\", join(pieces, \" + \".to_doc()), \")\"]\n        } else {\n            join(pieces, \" + \".to_doc())\n        }\n    }\n\n    /// If the read size has a constant value (that is, it's not a \"read all the\n    /// remaining bits/bytes\") this returns a document representing that size.\n    ///\n    fn read_size_to_doc(&mut self, size: &ReadSize) -> Option<Document<'a>> {\n        match size {\n            ReadSize::ConstantBits(value) => Some(value.clone().to_doc()),\n            ReadSize::VariableBits { variable, unit } => {\n                let variable = self.local_var(variable.name());\n                Some(if *unit == 1 {\n                    variable.to_doc()\n                } else {\n                    docvec![variable, \" * \", *unit as i64]\n                })\n            }\n            ReadSize::RemainingBits | ReadSize::RemainingBytes => None,\n\n            ReadSize::BinaryOperator {\n                left,\n                right,\n                operator,\n            } => {\n                let left = if self.read_size_must_be_wrapped(left) {\n                    self.read_size_to_doc(left)?.surround(\"(\", \")\")\n                } else {\n                    self.read_size_to_doc(left)?\n                };\n                let right = if self.read_size_must_be_wrapped(right) {\n                    self.read_size_to_doc(right)?.surround(\"(\", \")\")\n                } else {\n                    self.read_size_to_doc(right)?\n                };\n\n                Some(self.expression_generator.bin_op_with_doc_operands(\n                    operator.to_bin_op(),\n                    left,\n                    right,\n                    &crate::type_::int(),\n                ))\n            }\n        }\n    }\n\n    fn read_size_must_be_wrapped(&self, size: &ReadSize) -> bool {\n        match size {\n            ReadSize::ConstantBits(_) | ReadSize::RemainingBits | ReadSize::RemainingBytes => false,\n\n            ReadSize::VariableBits { unit, .. } => *unit != 1,\n            ReadSize::BinaryOperator { .. } => true,\n        }\n    }\n\n    /// Generates the document that calls the `bitArraySliceToInt` function, with\n    /// the given arguments.\n    ///\n    fn bit_array_slice_to_int(\n        &mut self,\n        bit_array: impl Documentable<'a>,\n        start: impl Documentable<'a>,\n        end: impl Documentable<'a>,\n        endianness: &Endianness,\n        signed: bool,\n    ) -> Document<'a> {\n        self.expression_generator\n            .tracker\n            .bit_array_slice_to_int_used = true;\n\n        let endianness = match endianness {\n            Endianness::Big => \"true\",\n            Endianness::Little => \"false\",\n        };\n        let signed = if signed { \"true\" } else { \"false\" };\n        let arguments = join(\n            [\n                bit_array.to_doc(),\n                start.to_doc(),\n                end.to_doc(),\n                endianness.to_doc(),\n                signed.to_doc(),\n            ],\n            \", \".to_doc(),\n        );\n        docvec![\"bitArraySliceToInt(\", arguments, \")\"]\n    }\n\n    /// Generates the document that calls the `bitArraySliceToFloat` function,\n    /// with the given arguments.\n    ///\n    fn bit_array_slice_to_float(\n        &mut self,\n        bit_array: impl Documentable<'a>,\n        start: impl Documentable<'a>,\n        end: impl Documentable<'a>,\n        endianness: &Endianness,\n    ) -> Document<'a> {\n        self.expression_generator\n            .tracker\n            .bit_array_slice_to_float_used = true;\n\n        let endianness = match endianness {\n            Endianness::Big => \"true\",\n            Endianness::Little => \"false\",\n        };\n        let arguments = join(\n            [\n                bit_array.to_doc(),\n                start.to_doc(),\n                end.to_doc(),\n                endianness.to_doc(),\n            ],\n            \", \".to_doc(),\n        );\n        docvec![\"bitArraySliceToFloat(\", arguments, \")\"]\n    }\n\n    /// Generates the document that calls the `bitArraySlice` function, with\n    /// an end argument as well. If you need to take a slice that starts at a\n    /// given offset and read the entire array you can use `bit_array_slice`.\n    ///\n    fn bit_array_slice_with_end(\n        &mut self,\n        bit_array: impl Documentable<'a>,\n        from: &Offset,\n        end: impl Documentable<'a>,\n    ) -> Document<'a> {\n        self.expression_generator.tracker.bit_array_slice_used = true;\n        let from = self.offset_to_doc(from, false);\n        docvec![\"bitArraySlice(\", bit_array, \", \", from, \", \", end, \")\"]\n    }\n\n    /// Generates the document that calls the `bitArraySlice` function, starting\n    /// at a given offset. This will read the entire remaining bit of the array,\n    /// if you know that the slice should end at a given offset you can use\n    /// `bit_array_slice_with_end` instead.\n    ///\n    fn bit_array_slice(&mut self, bit_array: impl Documentable<'a>, from: &Offset) -> Document<'a> {\n        self.expression_generator.tracker.bit_array_slice_used = true;\n        let from = self.offset_to_doc(from, false);\n        docvec![\"bitArraySlice(\", bit_array, \", \", from, \")\"]\n    }\n\n    /// This generates all the checks that need to be performed to make sure a\n    /// bit array segment (obtained with the read action passed as argument)\n    /// matches with a literal string.\n    ///\n    fn literal_string_segment_bytes_check(\n        &mut self,\n        // A string representing the bit array value we read bits from.\n        bit_array: EcoString,\n        // The bytes of the literal string we should be matching on.\n        string_bytes: &Vec<u8>,\n        read_action: &ReadAction,\n    ) -> Document<'a> {\n        let ReadAction {\n            from: start,\n            endianness,\n            signed,\n            ..\n        } = read_action;\n        let mut checks = vec![];\n\n        let equality = \" === \";\n\n        let bytes = string_bytes.as_slice();\n\n        if let Some(mut from_byte) = start.constant_bytes() {\n            // If the string starts at a compile-time known byte, then we can\n            // optimise this by reading all the subsequent bytes and checking\n            // they have a specific value.\n            for byte in bytes {\n                let byte_access = docvec![bit_array.clone(), \".byteAt(\", from_byte.clone(), \")\"];\n                checks.push(docvec![byte_access, equality, byte]);\n                from_byte += 1;\n            }\n        } else {\n            let mut start = start.clone();\n\n            // If the string doesn't start at a byte aligned offset then we'll\n            // have to take slices out of it to check that each byte matches.\n            for byte in bytes {\n                let start_doc = self.offset_to_doc(&start, false);\n                let end = start.add_constant(8);\n                let end_doc = self.offset_to_doc(&end, false);\n                let byte_access = self\n                    .bit_array_slice_to_int(&bit_array, start_doc, end_doc, endianness, *signed);\n                checks.push(docvec![byte_access, equality, byte]);\n                start = end;\n            }\n        }\n\n        // Otherwise the check succeeds if all the byte checks succeed.\n        join(checks, break_(\" &&\", \" && \")).nest(INDENT).group()\n    }\n\n    /// This generates all the checks that need to be performed to make sure a\n    /// bit array segment (obtained with the read action passed as argument)\n    /// matches with a literal int.\n    ///\n    fn literal_int_segment_bytes_check(\n        &mut self,\n        // A string representing the bit array value we read bits from.\n        bit_array: EcoString,\n        literal_int: BigInt,\n        read_action: &ReadAction,\n    ) -> Document<'a> {\n        let ReadAction {\n            from: start,\n            size,\n            endianness,\n            signed,\n            ..\n        } = read_action;\n\n        let equality = \" === \";\n\n        if let (Some(mut from_byte), Some(size)) = (start.constant_bytes(), size.constant_bytes()) {\n            // If the number starts at a byte-aligned offset and is made of a\n            // whole number of bytes then we can optimise this by checking that\n            // all the bytes starting at the given offset match the int bytes.\n            let mut checks = vec![];\n            for byte in bit_array_segment_int_value_to_bytes(literal_int, size * 8, *endianness) {\n                let byte_access = docvec![bit_array.clone(), \".byteAt(\", from_byte.clone(), \")\"];\n                checks.push(docvec![byte_access, equality, byte]);\n                from_byte += 1;\n            }\n\n            join(checks, break_(\" &&\", \" && \")).nest(INDENT).group()\n        } else {\n            // Otherwise we have to take an int slice out of the bit array and\n            // check it matches the expected value.\n            let start_doc = self.offset_to_doc(start, false);\n            let end = match (start.constant_bits(), size.constant_bits()) {\n                (Some(start), _) if start == BigInt::ZERO => self\n                    .read_size_to_doc(size)\n                    .expect(\"unexpected catch all size\"),\n                (Some(start), Some(end)) => (start + end).to_doc(),\n                (_, _) => docvec![start_doc.clone(), \" + \", self.read_size_to_doc(size)],\n            };\n            let check = self.bit_array_slice_to_int(bit_array, start_doc, end, endianness, *signed);\n            docvec![check, equality, literal_int]\n        }\n    }\n\n    /// This generates all the checks that need to be performed to make sure a\n    /// bit array segment (obtained with the read action passed as argument)\n    /// matches with a literal float.\n    ///\n    fn literal_float_segment_bytes_check(\n        &mut self,\n        // A string representing the bit array value we read bits from.\n        bit_array: EcoString,\n        expected: &EcoString,\n        read_action: &ReadAction,\n    ) -> Document<'a> {\n        let ReadAction {\n            from: start,\n            size,\n            endianness,\n            ..\n        } = read_action;\n\n        let equality = \" === \";\n\n        // Unlike literal integers and strings, for now we don't try and apply any\n        // optimisation in the way we match on those: we take an entire slice,\n        // convert it to a float and check if it matches the expected value.\n        let start_doc = self.offset_to_doc(start, false);\n        let end = match (start.constant_bits(), size.constant_bits()) {\n            (Some(start), _) if start == BigInt::ZERO => self\n                .read_size_to_doc(size)\n                .expect(\"unexpected catch all size\"),\n            (Some(start), Some(end)) => (start + end).to_doc(),\n            (_, _) => docvec![start_doc.clone(), \" + \", self.read_size_to_doc(size)],\n        };\n        let check = self.bit_array_slice_to_float(bit_array, start_doc, end, endianness);\n        docvec![check, equality, expected]\n    }\n\n    #[must_use]\n    fn is_bound_in_scope(&self, variable: &Variable) -> bool {\n        self.scoped_variable_names.contains_key(&variable.id)\n    }\n\n    #[must_use]\n    fn segment_is_bound_in_scope(&self, segment_name: &EcoString) -> bool {\n        self.scoped_segment_names.contains_key(segment_name)\n    }\n\n    /// In case the check introduces new variables, this will record their\n    /// actual value to be used by later checks and assignments.\n    ///\n    fn record_check_assignments(&mut self, variable: &Variable, check: &RuntimeCheck) {\n        let value = self.get_value(variable);\n        match check {\n            RuntimeCheck::Int { .. }\n            | RuntimeCheck::Float { .. }\n            | RuntimeCheck::String { .. }\n            | RuntimeCheck::EmptyList => (),\n\n            RuntimeCheck::BitArray { test } => {\n                for (segment_name, read_action) in test.referenced_segment_patterns() {\n                    self.set_segment_value(variable, segment_name.clone(), read_action)\n                }\n            }\n\n            RuntimeCheck::StringPrefix { rest, prefix } => {\n                let prefix_size = utf16_no_escape_len(prefix);\n                self.set_value(rest, eco_format!(\"{value}.slice({prefix_size})\"));\n            }\n\n            RuntimeCheck::Tuple { elements, .. } => {\n                for (i, element) in elements.iter().enumerate() {\n                    self.set_value(element, eco_format!(\"{value}[{i}]\"));\n                }\n            }\n\n            RuntimeCheck::Variant { fields, labels, .. } => {\n                for (i, field) in fields.iter().enumerate() {\n                    let access = match labels.get(&i) {\n                        Some(label) => eco_format!(\"{value}.{}\", maybe_escape_property(label)),\n                        None => eco_format!(\"{value}[{i}]\"),\n                    };\n                    self.set_value(field, access);\n                }\n            }\n\n            RuntimeCheck::NonEmptyList { first, rest } => {\n                self.set_value(first, eco_format!(\"{value}.head\"));\n                self.set_value(rest, eco_format!(\"{value}.tail\"));\n            }\n        }\n    }\n\n    /// A runtime check might need to reference some bit array segments in its\n    /// check (for example if a bit array length depends on a previous segment).\n    /// This function returns a vector with all the assignments needed to bring\n    /// the referenced segments into scope, so they're available to use for the\n    /// runtime check.\n    ///\n    fn bit_array_segment_assignments(&mut self, check: &RuntimeCheck) -> Vec<Document<'a>> {\n        let mut check_assignments = vec![];\n        for (segment, _) in check.referenced_segment_patterns() {\n            // If the segment was already bound to a variable in this scope we\n            // don't need to generate any further assignment for it. We will just\n            // reuse that existing variable when we need to access this segment\n            if self.segment_is_bound_in_scope(segment) {\n                continue;\n            }\n\n            let variable_name = self.next_local_var(segment);\n            let segment_value = self\n                .get_segment_value(segment)\n                .expect(\"segment referenced in a check before being created\");\n            self.bind_segment(variable_name.clone(), segment.clone());\n            check_assignments.push(let_doc(variable_name, segment_value))\n        }\n        check_assignments\n    }\n\n    /// Returns a string representing the value of a pattern variable: it might\n    /// be the code needed to obtain such variable (for example accessing a\n    /// list item `wibble.head`), or it could be a name this variable was bound\n    /// to in the current scope to avoid doing any repeated work!\n    ///\n    fn get_value(&self, variable: &Variable) -> EcoString {\n        // If the pattern variable was already assigned to a variable that is\n        // in scope we use that variable name!\n        if let Some(name) = self.scoped_variable_names.get(&variable.id) {\n            return name.clone();\n        }\n\n        // Otherwise we fallback to using its value directly.\n        self.variable_values\n            .get(&variable.id)\n            .expect(\"pattern variable used before assignment\")\n            .clone()\n    }\n\n    fn get_segment_value(&self, segment_name: &EcoString) -> Option<Document<'a>> {\n        // If the segment was already assigned to a variable that is in scope\n        // we use that variable name!\n        if let Some(name) = self.scoped_segment_names.get(segment_name) {\n            return Some(name.clone().to_doc());\n        }\n\n        // Otherwise we fallback to using its value directly.\n        self.segment_values.get(segment_name).cloned()\n    }\n}\n\n/// When going over the subjects of a case expression/let we might end up in two\n/// situation: the subject might be a variable or it could be a more complex\n/// expression (like a function call, a complex expression, ...).\n///\n/// ```gleam\n/// case a_variable { ... }\n/// case a_function_call(wobble) { ... }\n/// ```\n///\n/// When checking on a case we might end up repeating the subjects multiple times\n/// (as they need to appear in various checks), this means that if we ended up\n/// doing the simple thing of just repeating the subject as it is, we might end\n/// up dramatically changing the meaning of the program when the subject is a\n/// complex expression! Imagine this example:\n///\n/// ```gleam\n/// case wibble(\"a\") {\n///   1 -> todo\n///   2 -> todo\n///   _ -> todo\n/// }\n/// ```\n///\n/// If we just repeated the subject every time we need to check it, the decision\n/// tree would end up looking something like this:\n///\n/// ```js\n/// if (wibble(\"a\") === 1) {}\n/// else if (wibble(\"a\") === 2) {}\n/// else {}\n/// ```\n///\n/// It would be quite bad as we would end up running the same function multiple\n/// times instead of just once!\n///\n/// So we need to split each subject in two categories: if it is a simple\n/// variable already, it's no big deal and we can repeat that name as many times\n/// as we want; however, if it's anything else we first need to bind that subject\n/// to a variable we can then reference multiple times.\n///\nenum SubjectAssignment<'a> {\n    /// The subject is a complex expression with a `value` that has to be\n    /// assigned to a variable with the given `name` as repeating the `value`\n    /// multiple times could possibly change the meaning of the program.\n    BindToVariable {\n        name: EcoString,\n        value: Document<'a>,\n    },\n    /// The subject is already a simple variable with the given name, we will\n    /// keep using that name to reference it.\n    AlreadyAVariable { name: EcoString },\n}\n\nimpl SubjectAssignment<'_> {\n    fn name(&self) -> EcoString {\n        match self {\n            SubjectAssignment::BindToVariable { name, value: _ }\n            | SubjectAssignment::AlreadyAVariable { name } => name.clone(),\n        }\n    }\n}\n\nfn assign_subject<'a>(\n    expression_generator: &mut Generator<'_, 'a>,\n    subject: &'a TypedExpr,\n    ordering: Ordering,\n) -> SubjectAssignment<'a> {\n    static ASSIGNMENT_VAR_ECO_STR: OnceLock<EcoString> = OnceLock::new();\n\n    // If the value is a variable we don't need to assign it to a new\n    // variable, we can use the value expression safely without worrying about\n    // performing computation or side effects multiple times.\n    if let TypedExpr::Var {\n        name, constructor, ..\n    } = subject\n        && constructor.is_local_variable()\n    {\n        SubjectAssignment::AlreadyAVariable {\n            name: expression_generator.local_var(name),\n        }\n    } else {\n        // If it's not a variable we need to assign it to a variable\n        // to avoid rendering the subject expression multiple times\n        let name = expression_generator\n            .next_local_var(ASSIGNMENT_VAR_ECO_STR.get_or_init(|| ASSIGNMENT_VAR.into()));\n        let value = expression_generator\n            .not_in_tail_position(Some(ordering), |this| this.wrap_expression(subject));\n\n        SubjectAssignment::BindToVariable { value, name }\n    }\n}\n\nfn assignments_to_doc(assignments: Vec<SubjectAssignment<'_>>) -> Document<'_> {\n    let mut assignments_docs = vec![];\n    for assignment in assignments.into_iter() {\n        let SubjectAssignment::BindToVariable { name, value } = assignment else {\n            continue;\n        };\n        assignments_docs.push(docvec![let_doc(name, value), line()])\n    }\n    assignments_docs.to_doc()\n}\n\n/// Appends the second document to the first one separating the two with a newline.\n/// However, if the second document is empty the empty line is not added.\n///\nfn join_with_line<'a>(one: Document<'a>, other: Document<'a>) -> Document<'a> {\n    if one.is_empty() {\n        other\n    } else if other.is_empty() {\n        one\n    } else {\n        docvec![one, line(), other]\n    }\n}\n\nfn reassignment_doc(variable_name: EcoString, value: Document<'_>) -> Document<'_> {\n    docvec![variable_name, \" = \", value, \";\"]\n}\n\nfn let_doc(variable_name: EcoString, value: Document<'_>) -> Document<'_> {\n    docvec![\"let \", variable_name, \" = \", value, \";\"]\n}\n\n/// Calculates the length of str as utf16 without escape characters.\n///\nfn utf16_no_escape_len(str: &EcoString) -> usize {\n    length_utf16(&convert_string_escape_chars(str))\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/expression.rs",
    "content": "use num_bigint::BigInt;\nuse vec1::Vec1;\n\nuse super::{decision::ASSIGNMENT_VAR, *};\nuse crate::{\n    ast::*,\n    exhaustiveness::StringEncoding,\n    line_numbers::LineNumbers,\n    pretty::*,\n    type_::{\n        ModuleValueConstructor, Type, TypedCallArg, ValueConstructor, ValueConstructorVariant,\n    },\n};\nuse std::sync::Arc;\n\n#[derive(Debug, Clone)]\npub enum Position {\n    /// We are compiling the last expression in a function, meaning that it should\n    /// use `return` to return the value it produces from the function.\n    Tail,\n    /// We are inside a function, but the value of this expression isn't being\n    /// used, so we don't need to do anything with the returned value.\n    Statement,\n    /// The value of this expression needs to be used inside another expression,\n    /// so we need to use the value that is returned by this expression.\n    Expression(Ordering),\n    /// We are compiling an expression inside a block, meaning we must assign\n    /// to the `_block` variable at the end of the scope, because blocks are not\n    /// expressions in JS.\n    /// Since JS doesn't have variable shadowing, we must store the name of the\n    /// variable being used, which will include the incrementing counter.\n    /// For example, `block$2`\n    Assign(EcoString),\n}\n\nimpl Position {\n    /// Returns `true` if the position is [`Tail`].\n    ///\n    /// [`Tail`]: Position::Tail\n    #[must_use]\n    pub fn is_tail(&self) -> bool {\n        matches!(self, Self::Tail)\n    }\n\n    #[must_use]\n    pub fn ordering(&self) -> Ordering {\n        match self {\n            Self::Expression(ordering) => *ordering,\n            Self::Tail | Self::Assign(_) | Self::Statement => Ordering::Loose,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\n/// Determines whether we can lift blocks into statement level instead of using\n/// immediately invoked function expressions. Consider the following piece of code:\n///\n/// ```gleam\n/// some_function(function_with_side_effect(), {\n///   let a = 10\n///   other_function_with_side_effects(a)\n/// })\n/// ```\n/// Here, if we lift the block that is the second argument of the function, we\n/// would end up running `other_function_with_side_effects` before\n/// `function_with_side_effects`. This would be invalid, as code in Gleam should be\n/// evaluated left-to-right, top-to-bottom. In this case, the ordering would be\n/// `Strict`, indicating that we cannot lift the block.\n///\n/// However, in this example:\n///\n/// ```gleam\n/// let value = !{\n///   let value = False\n///   some_function_with_side_effect()\n///   value\n/// }\n/// ```\n/// The only expression is the block, meaning it can be safely lifted without\n/// changing the evaluation order of the program. So the ordering is `Loose`.\n///\npub enum Ordering {\n    Strict,\n    Loose,\n}\n\n/// Tracking where the current function is a module function or an anonymous function.\n#[derive(Debug)]\nenum CurrentFunction {\n    /// The current function is a module function\n    ///\n    /// ```gleam\n    /// pub fn main() -> Nil {\n    ///   // we are here\n    /// }\n    /// ```\n    Module,\n\n    /// The current function is a module function, but one of its arguments shadows\n    /// the reference to itself so it cannot recurse.\n    ///\n    /// ```gleam\n    /// pub fn main(main: fn() -> Nil) -> Nil {\n    ///   // we are here\n    /// }\n    /// ```\n    ModuleWithShadowingArgument,\n\n    /// The current function is an anonymous function\n    ///\n    /// ```gleam\n    /// pub fn main() -> Nil {\n    ///   fn() {\n    ///     // we are here\n    ///   }\n    /// }\n    /// ```\n    Anonymous,\n}\n\nimpl CurrentFunction {\n    #[inline]\n    fn can_recurse(&self) -> bool {\n        match self {\n            CurrentFunction::Module => true,\n            CurrentFunction::ModuleWithShadowingArgument => false,\n            CurrentFunction::Anonymous => false,\n        }\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct Generator<'module, 'ast> {\n    module_name: EcoString,\n    src_path: EcoString,\n    line_numbers: &'module LineNumbers,\n    function_name: EcoString,\n    function_arguments: Vec<Option<&'module EcoString>>,\n    current_function: CurrentFunction,\n    pub current_scope_vars: im::HashMap<EcoString, usize>,\n    pub function_position: Position,\n    pub scope_position: Position,\n    // We register whether these features are used within an expression so that\n    // the module generator can output a suitable function if it is needed.\n    pub tracker: &'module mut UsageTracker,\n    // We track whether tail call recursion is used so that we can render a loop\n    // at the top level of the function to use in place of pushing new stack\n    // frames.\n    pub tail_recursion_used: bool,\n    /// Statements to be compiled when lifting blocks into statement scope.\n    /// For example, when compiling the following code:\n    /// ```gleam\n    /// let a = {\n    ///   let b = 1\n    ///   b + 1\n    /// }\n    /// ```\n    /// There will be 2 items in `statement_level`: The first will be `let _block;`\n    /// The second will be the generated code for the block being assigned to `a`.\n    /// This lets use return `_block` as the value that the block evaluated to,\n    /// while still including the necessary code in the output at the right place.\n    ///\n    /// Once the `let` statement has compiled its value, it will add anything accumulated\n    /// in `statement_level` to the generated code, so it will result in:\n    ///\n    /// ```javascript\n    /// let _block;\n    /// {...}\n    /// let a = _block;\n    /// ```\n    ///\n    statement_level: Vec<Document<'ast>>,\n\n    /// This will be true if we've generated a `let assert` statement that we know\n    /// is guaranteed to throw.\n    /// This means we can stop code generation for all the following statements\n    /// in the same block!\n    pub let_assert_always_panics: bool,\n}\n\nimpl<'module, 'a> Generator<'module, 'a> {\n    #[allow(clippy::too_many_arguments)] // TODO: FIXME\n    pub fn new(\n        module_name: EcoString,\n        src_path: EcoString,\n        line_numbers: &'module LineNumbers,\n        function_name: EcoString,\n        function_arguments: Vec<Option<&'module EcoString>>,\n        tracker: &'module mut UsageTracker,\n        mut current_scope_vars: im::HashMap<EcoString, usize>,\n    ) -> Self {\n        let mut current_function = CurrentFunction::Module;\n        for &name in function_arguments.iter().flatten() {\n            // Initialise the function arguments\n            let _ = current_scope_vars.insert(name.clone(), 0);\n\n            // If any of the function arguments shadow the current function then\n            // recursion is no longer possible.\n            if function_name.as_ref() == name {\n                current_function = CurrentFunction::ModuleWithShadowingArgument;\n            }\n        }\n        Self {\n            tracker,\n            module_name,\n            src_path,\n            line_numbers,\n            function_name,\n            function_arguments,\n            tail_recursion_used: false,\n            current_scope_vars,\n            current_function,\n            function_position: Position::Tail,\n            scope_position: Position::Tail,\n            statement_level: Vec::new(),\n            let_assert_always_panics: false,\n        }\n    }\n\n    pub fn local_var(&mut self, name: &EcoString) -> EcoString {\n        match self.current_scope_vars.get(name) {\n            None => {\n                let _ = self.current_scope_vars.insert(name.clone(), 0);\n                maybe_escape_identifier(name)\n            }\n            Some(0) => maybe_escape_identifier(name),\n            Some(n) if name == \"$\" => eco_format!(\"${n}\"),\n            Some(n) => eco_format!(\"{name}${n}\"),\n        }\n    }\n\n    pub fn next_local_var(&mut self, name: &EcoString) -> EcoString {\n        let next = self.current_scope_vars.get(name).map_or(0, |i| i + 1);\n        let _ = self.current_scope_vars.insert(name.clone(), next);\n        self.local_var(name)\n    }\n\n    pub fn function_body(\n        &mut self,\n        body: &'a [TypedStatement],\n        arguments: &'a [TypedArg],\n    ) -> Document<'a> {\n        let body = self.statements(body);\n        if self.tail_recursion_used {\n            self.tail_call_loop(body, arguments)\n        } else {\n            body\n        }\n    }\n\n    fn tail_call_loop(&mut self, body: Document<'a>, arguments: &'a [TypedArg]) -> Document<'a> {\n        let loop_assignments = concat(arguments.iter().flat_map(Arg::get_variable_name).map(\n            |name| {\n                let var = maybe_escape_identifier(name);\n                docvec![\"let \", var, \" = loop$\", name, \";\", line()]\n            },\n        ));\n        docvec![\n            \"while (true) {\",\n            docvec![line(), loop_assignments, body].nest(INDENT),\n            line(),\n            \"}\"\n        ]\n    }\n\n    fn statement(&mut self, statement: &'a TypedStatement) -> Document<'a> {\n        let expression_doc = match statement {\n            Statement::Expression(expression) => self.expression(expression),\n            Statement::Assignment(assignment) => self.assignment(assignment),\n            Statement::Use(use_) => self.expression(&use_.call),\n            Statement::Assert(assert) => self.assert(assert),\n        };\n        self.add_statement_level(expression_doc)\n    }\n\n    fn add_statement_level(&mut self, expression: Document<'a>) -> Document<'a> {\n        if self.statement_level.is_empty() {\n            expression\n        } else {\n            let mut statements = std::mem::take(&mut self.statement_level);\n            statements.push(expression);\n            join(statements, line())\n        }\n    }\n\n    pub fn expression(&mut self, expression: &'a TypedExpr) -> Document<'a> {\n        let document = match expression {\n            TypedExpr::String { value, .. } => string(value),\n\n            TypedExpr::Int { value, .. } => int(value),\n            TypedExpr::Float { float_value, .. } => float_from_value(float_value.value()),\n\n            TypedExpr::List { elements, tail, .. } => {\n                self.not_in_tail_position(Some(Ordering::Strict), |this| match tail {\n                    Some(tail) => {\n                        this.tracker.prepend_used = true;\n                        let tail = this.wrap_expression(tail);\n                        prepend(\n                            elements.iter().map(|element| this.wrap_expression(element)),\n                            tail,\n                        )\n                    }\n                    None => {\n                        this.tracker.list_used = true;\n                        list(elements.iter().map(|element| this.wrap_expression(element)))\n                    }\n                })\n            }\n\n            TypedExpr::Tuple { elements, .. } => self.tuple(elements),\n            TypedExpr::TupleIndex { tuple, index, .. } => self.tuple_index(tuple, *index),\n\n            TypedExpr::Case {\n                subjects,\n                clauses,\n                compiled_case,\n                ..\n            } => decision::case(compiled_case, clauses, subjects, self),\n\n            TypedExpr::Call { fun, arguments, .. } => self.call(fun, arguments),\n            TypedExpr::Fn {\n                arguments, body, ..\n            } => self.fn_(arguments, body),\n\n            TypedExpr::RecordAccess { record, label, .. } => self.record_access(record, label),\n\n            TypedExpr::PositionalAccess { record, index, .. } => {\n                self.positional_access(record, *index)\n            }\n\n            TypedExpr::RecordUpdate {\n                record_assignment,\n                constructor,\n                arguments,\n                ..\n            } => self.record_update(record_assignment, constructor, arguments),\n\n            TypedExpr::Var {\n                name, constructor, ..\n            } => self.variable(name, constructor),\n\n            TypedExpr::Pipeline {\n                first_value,\n                assignments,\n                finally,\n                ..\n            } => self.pipeline(first_value, assignments.as_slice(), finally),\n\n            TypedExpr::Block { statements, .. } => self.block(statements),\n\n            TypedExpr::BinOp {\n                name, left, right, ..\n            } => self.bin_op(name, left, right),\n\n            TypedExpr::Todo {\n                message, location, ..\n            } => self.todo(message.as_ref().map(|m| &**m), location),\n\n            TypedExpr::Panic {\n                location, message, ..\n            } => self.panic(location, message.as_ref().map(|m| &**m)),\n\n            TypedExpr::BitArray { segments, .. } => self.bit_array(segments),\n\n            TypedExpr::ModuleSelect {\n                module_alias,\n                label,\n                constructor,\n                ..\n            } => self.module_select(module_alias, label, constructor),\n\n            TypedExpr::NegateBool { value, .. } => self.negate_with(\"!\", value),\n\n            TypedExpr::NegateInt { value, .. } => self.negate_with(\"- \", value),\n\n            TypedExpr::Echo {\n                expression,\n                message,\n                location,\n                ..\n            } => {\n                let expression = expression\n                    .as_ref()\n                    .expect(\"echo with no expression outside of pipe\");\n                let expresion_doc =\n                    self.not_in_tail_position(None, |this| this.wrap_expression(expression));\n                self.echo(expresion_doc, message.as_deref(), location)\n            }\n\n            TypedExpr::Invalid { .. } => {\n                panic!(\"invalid expressions should not reach code generation\")\n            }\n        };\n        if expression.handles_own_return() {\n            document\n        } else {\n            self.wrap_return(document)\n        }\n    }\n\n    fn negate_with(&mut self, with: &'static str, value: &'a TypedExpr) -> Document<'a> {\n        self.not_in_tail_position(None, |this| docvec![with, this.wrap_expression(value)])\n    }\n\n    fn bit_array(&mut self, segments: &'a [TypedExprBitArraySegment]) -> Document<'a> {\n        self.tracker.bit_array_literal_used = true;\n\n        // Collect all the values used in segments.\n        let segments_array = array(segments.iter().map(|segment| {\n            let value = self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                this.wrap_expression(&segment.value)\n            });\n\n            let details = self.bit_array_segment_details(segment);\n\n            match details.type_ {\n                BitArraySegmentType::BitArray => {\n                    if segment.size().is_some() {\n                        self.tracker.bit_array_slice_used = true;\n                        docvec![\"bitArraySlice(\", value, \", 0, \", details.size, \")\"]\n                    } else {\n                        value\n                    }\n                }\n                BitArraySegmentType::Int => match (details.size_value, segment.value.as_ref()) {\n                    (Some(size_value), TypedExpr::Int { int_value, .. })\n                        if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()\n                            && (&size_value % BigInt::from(8) == BigInt::ZERO) =>\n                    {\n                        let bytes = bit_array_segment_int_value_to_bytes(\n                            int_value.clone(),\n                            size_value,\n                            segment.endianness(),\n                        );\n\n                        u8_slice(&bytes)\n                    }\n\n                    (Some(size_value), _) if size_value == 8.into() => value,\n\n                    (Some(size_value), _) if size_value <= 0.into() => nil(),\n\n                    _ => {\n                        self.tracker.sized_integer_segment_used = true;\n                        let size = details.size;\n                        let is_big = bool(segment.endianness().is_big());\n                        docvec![\"sizedInt(\", value, \", \", size, \", \", is_big, \")\"]\n                    }\n                },\n                BitArraySegmentType::Float => {\n                    self.tracker.float_bit_array_segment_used = true;\n                    let size = details.size;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"sizedFloat(\", value, \", \", size, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::String(StringEncoding::Utf8) => {\n                    self.tracker.string_bit_array_segment_used = true;\n                    docvec![\"stringBits(\", value, \")\"]\n                }\n                BitArraySegmentType::String(StringEncoding::Utf16) => {\n                    self.tracker.string_utf16_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"stringToUtf16(\", value, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::String(StringEncoding::Utf32) => {\n                    self.tracker.string_utf32_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"stringToUtf32(\", value, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::UtfCodepoint(StringEncoding::Utf8) => {\n                    self.tracker.codepoint_bit_array_segment_used = true;\n                    docvec![\"codepointBits(\", value, \")\"]\n                }\n                BitArraySegmentType::UtfCodepoint(StringEncoding::Utf16) => {\n                    self.tracker.codepoint_utf16_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"codepointToUtf16(\", value, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::UtfCodepoint(StringEncoding::Utf32) => {\n                    self.tracker.codepoint_utf32_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"codepointToUtf32(\", value, \", \", is_big, \")\"]\n                }\n            }\n        }));\n\n        docvec![\"toBitArray(\", segments_array, \")\"]\n    }\n\n    fn bit_array_segment_details(\n        &mut self,\n        segment: &'a TypedExprBitArraySegment,\n    ) -> BitArraySegmentDetails<'a> {\n        let size = segment.size();\n        let unit = segment.unit();\n        let (size_value, size) = match size {\n            Some(TypedExpr::Int { int_value, .. }) => {\n                let size_value = int_value * unit;\n                let size = eco_format!(\"{}\", size_value).to_doc();\n                (Some(size_value), size)\n            }\n            Some(size) => {\n                let mut size = self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                    this.wrap_expression(size)\n                });\n\n                if unit != 1 {\n                    size = size.group().append(\" * \".to_doc().append(unit.to_doc()));\n                }\n\n                (None, size)\n            }\n\n            None => {\n                let size_value: usize = if segment.type_.is_int() { 8 } else { 64 };\n                (Some(BigInt::from(size_value)), docvec![size_value])\n            }\n        };\n\n        let type_ = BitArraySegmentType::from_segment(segment);\n\n        BitArraySegmentDetails {\n            type_,\n            size,\n            size_value,\n            endianness: segment.endianness(),\n        }\n    }\n\n    pub fn wrap_return(&mut self, document: Document<'a>) -> Document<'a> {\n        match &self.scope_position {\n            Position::Tail => docvec![\"return \", document, \";\"],\n            Position::Expression(_) | Position::Statement => document,\n            Position::Assign(name) => docvec![name.clone(), \" = \", document, \";\"],\n        }\n    }\n\n    pub fn not_in_tail_position<CompileFn, Output>(\n        &mut self,\n        // If ordering is None, it is inherited from the parent scope.\n        // It will be None in cases like `!x`, where `x` can be lifted\n        // only if the ordering is already loose.\n        ordering: Option<Ordering>,\n        compile: CompileFn,\n    ) -> Output\n    where\n        CompileFn: Fn(&mut Self) -> Output,\n    {\n        let new_ordering = ordering.unwrap_or(self.scope_position.ordering());\n\n        let function_position = std::mem::replace(\n            &mut self.function_position,\n            Position::Expression(new_ordering),\n        );\n        let scope_position =\n            std::mem::replace(&mut self.scope_position, Position::Expression(new_ordering));\n\n        let result = compile(self);\n\n        self.function_position = function_position;\n        self.scope_position = scope_position;\n        result\n    }\n\n    /// Use the `_block` variable if the expression is JS statement.\n    pub fn wrap_expression(&mut self, expression: &'a TypedExpr) -> Document<'a> {\n        match (expression, &self.scope_position) {\n            (_, Position::Tail | Position::Assign(_)) => self.expression(expression),\n            (\n                TypedExpr::Panic { .. }\n                | TypedExpr::Todo { .. }\n                | TypedExpr::Case { .. }\n                | TypedExpr::Pipeline { .. }\n                | TypedExpr::RecordUpdate {\n                    // Record updates that assign a variable generate multiple statements\n                    record_assignment: Some(_),\n                    ..\n                },\n                Position::Expression(Ordering::Loose),\n            ) => self.wrap_block(|this| this.expression(expression)),\n            (\n                TypedExpr::Panic { .. }\n                | TypedExpr::Todo { .. }\n                | TypedExpr::Case { .. }\n                | TypedExpr::Pipeline { .. }\n                | TypedExpr::RecordUpdate {\n                    // Record updates that assign a variable generate multiple statements\n                    record_assignment: Some(_),\n                    ..\n                },\n                Position::Expression(Ordering::Strict),\n            ) => self.immediately_invoked_function_expression(expression, |this, expr| {\n                this.expression(expr)\n            }),\n            _ => self.expression(expression),\n        }\n    }\n\n    /// Wrap an expression using the `_block` variable if required due to being\n    /// a JS statement, or in parens if required due to being an operator or\n    /// a function literal.\n    pub fn child_expression(&mut self, expression: &'a TypedExpr) -> Document<'a> {\n        match expression {\n            TypedExpr::BinOp { name, .. } if name.is_operator_to_wrap() => {}\n            TypedExpr::Fn { .. } => {}\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => return self.wrap_expression(expression),\n        }\n\n        let document = self.expression(expression);\n        match &self.scope_position {\n            // Here the document is a return statement: `return <expr>;`\n            // or an assignment: `_block = <expr>;`\n            Position::Tail | Position::Assign(_) | Position::Statement => document,\n            Position::Expression(_) => docvec![\"(\", document, \")\"],\n        }\n    }\n\n    /// Wrap an expression in an immediately invoked function expression\n    fn immediately_invoked_function_expression<T, ToDoc>(\n        &mut self,\n        statements: &'a T,\n        to_doc: ToDoc,\n    ) -> Document<'a>\n    where\n        ToDoc: FnOnce(&mut Self, &'a T) -> Document<'a>,\n    {\n        // Save initial state\n        let scope_position = std::mem::replace(&mut self.scope_position, Position::Tail);\n        let statement_level = std::mem::take(&mut self.statement_level);\n\n        // Set state for in this iife\n        let current_scope_vars = self.current_scope_vars.clone();\n\n        // Generate the expression\n        let result = to_doc(self, statements);\n        let doc = self.add_statement_level(result);\n        let doc = immediately_invoked_function_expression_document(doc);\n\n        // Reset\n        self.current_scope_vars = current_scope_vars;\n        self.scope_position = scope_position;\n        self.statement_level = statement_level;\n\n        self.wrap_return(doc)\n    }\n\n    fn wrap_block<CompileFn>(&mut self, compile: CompileFn) -> Document<'a>\n    where\n        CompileFn: Fn(&mut Self) -> Document<'a>,\n    {\n        let block_variable = self.next_local_var(&BLOCK_VARIABLE.into());\n\n        // Save initial state\n        let scope_position = std::mem::replace(\n            &mut self.scope_position,\n            Position::Assign(block_variable.clone()),\n        );\n        let function_position = std::mem::replace(\n            &mut self.function_position,\n            Position::Expression(Ordering::Strict),\n        );\n\n        // Generate the expression\n        let statement_doc = compile(self);\n\n        // Reset\n        self.scope_position = scope_position;\n        self.function_position = function_position;\n\n        self.statement_level\n            .push(docvec![\"let \", block_variable.clone(), \";\"]);\n        self.statement_level.push(statement_doc);\n\n        self.wrap_return(block_variable.to_doc())\n    }\n\n    fn variable(&mut self, name: &'a EcoString, constructor: &'a ValueConstructor) -> Document<'a> {\n        match &constructor.variant {\n            ValueConstructorVariant::Record { arity, .. } => {\n                let type_ = constructor.type_.clone();\n                let tracker = &mut self.tracker;\n                record_constructor(type_, None, name, *arity, tracker)\n            }\n            ValueConstructorVariant::ModuleFn { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::LocalVariable { .. } => self.local_var(name).to_doc(),\n        }\n    }\n\n    fn pipeline(\n        &mut self,\n        first_value: &'a TypedPipelineAssignment,\n        assignments: &'a [(TypedPipelineAssignment, PipelineAssignmentKind)],\n        finally: &'a TypedExpr,\n    ) -> Document<'a> {\n        let count = assignments.len();\n        let mut documents = Vec::with_capacity((count + 2) * 2);\n\n        let all_assignments = std::iter::once(first_value)\n            .chain(assignments.iter().map(|(assignment, _kind)| assignment));\n\n        let mut latest_local_var: Option<EcoString> = None;\n        for assignment in all_assignments {\n            // An echo in a pipeline won't result in an assignment, instead it\n            // just prints the previous variable assigned in the pipeline.\n            if let TypedExpr::Echo {\n                expression: None,\n                message,\n                location,\n                ..\n            } = assignment.value.as_ref()\n            {\n                documents.push(self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                    let var = latest_local_var\n                        .as_ref()\n                        .expect(\"echo with no previous step in a pipe\");\n                    this.echo(var.to_doc(), message.as_deref(), location)\n                }))\n            } else {\n                // Otherwise we assign the intermediate pipe value to a variable.\n                let assignment_document = self\n                    .not_in_tail_position(Some(Ordering::Strict), |this| {\n                        this.simple_variable_assignment(&assignment.name, &assignment.value)\n                    });\n                documents.push(self.add_statement_level(assignment_document));\n                latest_local_var = Some(self.local_var(&assignment.name));\n            }\n\n            documents.push(line());\n        }\n\n        if let TypedExpr::Echo {\n            expression: None,\n            message,\n            location,\n            ..\n        } = finally\n        {\n            let var = latest_local_var.expect(\"echo with no previous step in a pipe\");\n            documents.push(self.echo(var.to_doc(), message.as_deref(), location));\n        } else {\n            let finally = self.expression(finally);\n            documents.push(self.add_statement_level(finally))\n        }\n\n        documents.to_doc().force_break()\n    }\n\n    pub(crate) fn expression_flattening_blocks(\n        &mut self,\n        expression: &'a TypedExpr,\n    ) -> Document<'a> {\n        if let TypedExpr::Block { statements, .. } = expression {\n            self.statements(statements)\n        } else {\n            self.expression(expression)\n        }\n    }\n\n    fn block(&mut self, statements: &'a Vec1<TypedStatement>) -> Document<'a> {\n        if statements.len() == 1 {\n            match statements.first() {\n                Statement::Expression(expression) => return self.child_expression(expression),\n\n                Statement::Assignment(assignment) => match &assignment.kind {\n                    AssignmentKind::Let | AssignmentKind::Generated => {\n                        return self.child_expression(&assignment.value);\n                    }\n                    // We can't just return the right-hand side of a `let assert`\n                    // assignment; we still need to check that the pattern matches.\n                    AssignmentKind::Assert { .. } => {}\n                },\n\n                Statement::Use(use_) => return self.child_expression(&use_.call),\n\n                // Similar to `let assert`, we can't immediately return the value\n                // that is asserted; we have to actually perform the assertion.\n                Statement::Assert(_) => {}\n            }\n        }\n        match &self.scope_position {\n            Position::Tail | Position::Assign(_) | Position::Statement => {\n                self.block_document(statements)\n            }\n            Position::Expression(Ordering::Strict) => self\n                .immediately_invoked_function_expression(statements, |this, statements| {\n                    this.statements(statements)\n                }),\n            Position::Expression(Ordering::Loose) => self.wrap_block(|this| {\n                // Save previous scope\n                let current_scope_vars = this.current_scope_vars.clone();\n\n                let document = this.block_document(statements);\n\n                // Restore previous state\n                this.current_scope_vars = current_scope_vars;\n\n                document\n            }),\n        }\n    }\n\n    fn block_document(&mut self, statements: &'a Vec1<TypedStatement>) -> Document<'a> {\n        let statements = self.statements(statements);\n        docvec![\"{\", docvec![line(), statements].nest(INDENT), line(), \"}\"]\n    }\n\n    fn statements(&mut self, statements: &'a [TypedStatement]) -> Document<'a> {\n        // If there are any statements that need to be printed at statement level, that's\n        // for an outer scope so we don't want to print them inside this one.\n        let statement_level = std::mem::take(&mut self.statement_level);\n        let count = statements.len();\n        let mut documents = Vec::with_capacity(count * 3);\n        for (i, statement) in statements.iter().enumerate() {\n            if i + 1 < count {\n                let function_position =\n                    std::mem::replace(&mut self.function_position, Position::Statement);\n                let scope_position =\n                    std::mem::replace(&mut self.scope_position, Position::Statement);\n\n                documents.push(self.statement(statement));\n\n                self.function_position = function_position;\n                self.scope_position = scope_position;\n\n                if requires_semicolon(statement) {\n                    documents.push(\";\".to_doc());\n                }\n                documents.push(line());\n            } else {\n                documents.push(self.statement(statement));\n            }\n\n            // If we've generated code for a statement that always throws, we\n            // can skip code generation for all the following ones.\n            if self.let_assert_always_panics {\n                self.let_assert_always_panics = false;\n                break;\n            }\n        }\n        self.statement_level = statement_level;\n        if count == 1 {\n            documents.to_doc()\n        } else {\n            documents.to_doc().force_break()\n        }\n    }\n\n    fn simple_variable_assignment(\n        &mut self,\n        name: &'a EcoString,\n        value: &'a TypedExpr,\n    ) -> Document<'a> {\n        // Subject must be rendered before the variable for variable numbering\n        let subject =\n            self.not_in_tail_position(Some(Ordering::Loose), |this| this.wrap_expression(value));\n        let js_name = self.next_local_var(name);\n        let assignment = docvec![\"let \", js_name.clone(), \" = \", subject, \";\"];\n        let assignment = match &self.scope_position {\n            Position::Expression(_) | Position::Statement => assignment,\n            Position::Tail => docvec![assignment, line(), \"return \", js_name, \";\"],\n            Position::Assign(block_variable) => docvec![\n                assignment,\n                line(),\n                block_variable.clone(),\n                \" = \",\n                js_name,\n                \";\"\n            ],\n        };\n\n        assignment.force_break()\n    }\n\n    fn assignment(&mut self, assignment: &'a TypedAssignment) -> Document<'a> {\n        let TypedAssignment {\n            pattern,\n            kind,\n            value,\n            compiled_case,\n            annotation: _,\n            location: _,\n        } = assignment;\n\n        // In case the pattern is just a variable, we special case it to\n        // generate just a simple assignment instead of using the decision tree\n        // for the code generation step.\n        if let TypedPattern::Variable { name, .. } = pattern {\n            return self.simple_variable_assignment(name, value);\n        }\n\n        decision::let_(compiled_case, value, kind, self, pattern)\n    }\n\n    fn assert(&mut self, assert: &'a TypedAssert) -> Document<'a> {\n        let TypedAssert {\n            location,\n            value,\n            message,\n        } = assert;\n\n        let message = match message {\n            Some(message) => {\n                self.not_in_tail_position(Some(Ordering::Strict), |this| this.expression(message))\n            }\n            None => string(\"Assertion failed.\"),\n        };\n\n        let check = self.not_in_tail_position(Some(Ordering::Loose), |this| {\n            this.assert_check(value, &message, *location)\n        });\n\n        match &self.scope_position {\n            Position::Expression(_) | Position::Statement => check,\n            Position::Tail | Position::Assign(_) => {\n                docvec![check, line(), self.wrap_return(\"undefined\".to_doc())]\n            }\n        }\n    }\n\n    fn assert_check(\n        &mut self,\n        subject: &'a TypedExpr,\n        message: &Document<'a>,\n        location: SrcSpan,\n    ) -> Document<'a> {\n        let (subject_document, mut fields) = match subject {\n            TypedExpr::Call { fun, arguments, .. } => {\n                let argument_variables = arguments\n                    .iter()\n                    .map(|element| {\n                        self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                            this.assign_to_variable(&element.value)\n                        })\n                    })\n                    .collect_vec();\n                (\n                    self.call_with_doc_arguments(fun, argument_variables.clone()),\n                    vec![\n                        (\"kind\", string(\"function_call\")),\n                        (\n                            \"arguments\",\n                            array(argument_variables.into_iter().zip(arguments).map(\n                                |(variable, argument)| {\n                                    self.asserted_expression(\n                                        AssertExpression::from_expression(&argument.value),\n                                        Some(variable),\n                                        argument.location(),\n                                    )\n                                },\n                            )),\n                        ),\n                    ],\n                )\n            }\n\n            TypedExpr::BinOp {\n                name, left, right, ..\n            } => {\n                match name {\n                    BinOp::And => return self.assert_and(left, right, message, location),\n                    BinOp::Or => return self.assert_or(left, right, message, location),\n                    BinOp::Eq\n                    | BinOp::NotEq\n                    | BinOp::LtInt\n                    | BinOp::LtEqInt\n                    | BinOp::LtFloat\n                    | BinOp::LtEqFloat\n                    | BinOp::GtEqInt\n                    | BinOp::GtInt\n                    | BinOp::GtEqFloat\n                    | BinOp::GtFloat\n                    | BinOp::AddInt\n                    | BinOp::AddFloat\n                    | BinOp::SubInt\n                    | BinOp::SubFloat\n                    | BinOp::MultInt\n                    | BinOp::MultFloat\n                    | BinOp::DivInt\n                    | BinOp::DivFloat\n                    | BinOp::RemainderInt\n                    | BinOp::Concatenate => {}\n                }\n\n                let left_document = self.not_in_tail_position(Some(Ordering::Loose), |this| {\n                    this.assign_to_variable(left)\n                });\n                let right_document = self.not_in_tail_position(Some(Ordering::Loose), |this| {\n                    this.assign_to_variable(right)\n                });\n\n                (\n                    self.bin_op_with_doc_operands(\n                        *name,\n                        left_document.clone(),\n                        right_document.clone(),\n                        &left.type_(),\n                    )\n                    .surround(\"(\", \")\"),\n                    vec![\n                        (\"kind\", string(\"binary_operator\")),\n                        (\"operator\", string(name.name())),\n                        (\n                            \"left\",\n                            self.asserted_expression(\n                                AssertExpression::from_expression(left),\n                                Some(left_document),\n                                left.location(),\n                            ),\n                        ),\n                        (\n                            \"right\",\n                            self.asserted_expression(\n                                AssertExpression::from_expression(right),\n                                Some(right_document),\n                                right.location(),\n                            ),\n                        ),\n                    ],\n                )\n            }\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => (\n                self.wrap_expression(subject),\n                vec![\n                    (\"kind\", string(\"expression\")),\n                    (\n                        \"expression\",\n                        self.asserted_expression(\n                            AssertExpression::from_expression(subject),\n                            Some(\"false\".to_doc()),\n                            subject.location(),\n                        ),\n                    ),\n                ],\n            ),\n        };\n\n        fields.push((\"start\", location.start.to_doc()));\n        fields.push((\"end\", subject.location().end.to_doc()));\n        fields.push((\"expression_start\", subject.location().start.to_doc()));\n\n        docvec![\n            \"if (\",\n            docvec![\"!\", subject_document].nest(INDENT),\n            break_(\"\", \"\"),\n            \") {\",\n            docvec![\n                line(),\n                self.throw_error(\"assert\", message, location, fields),\n            ]\n            .nest(INDENT),\n            line(),\n            \"}\",\n        ]\n        .group()\n    }\n\n    fn negate_bool_expression(&mut self, value: &'a TypedExpr) -> Document<'a> {\n        match value {\n            TypedExpr::BinOp {\n                name, left, right, ..\n            } => match name {\n                BinOp::And => self.print_bin_op(left, right, \"||\"),\n                BinOp::Or => self.print_bin_op(left, right, \"&&\"),\n                BinOp::Eq => self.equal(left, right, false),\n                BinOp::NotEq => self.equal(left, right, true),\n                BinOp::LtInt | BinOp::LtFloat => self.print_bin_op(left, right, \">=\"),\n                BinOp::LtEqInt | BinOp::LtEqFloat => self.print_bin_op(left, right, \">\"),\n                BinOp::GtInt | BinOp::GtFloat => self.print_bin_op(left, right, \"<=\"),\n                BinOp::GtEqInt | BinOp::GtEqFloat => self.print_bin_op(left, right, \"<\"),\n                BinOp::AddInt\n                | BinOp::AddFloat\n                | BinOp::SubInt\n                | BinOp::SubFloat\n                | BinOp::MultInt\n                | BinOp::MultFloat\n                | BinOp::DivInt\n                | BinOp::DivFloat\n                | BinOp::RemainderInt\n                | BinOp::Concatenate => unreachable!(\"type checking should make this impossible\"),\n            },\n            TypedExpr::NegateBool { value, .. } => self.wrap_expression(value),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => docvec![\"!\", self.wrap_expression(value)],\n        }\n    }\n\n    /// In Gleam, the `&&` operator is short-circuiting, meaning that we can't\n    /// pre-evaluate both sides of it, and use them in the exception that is\n    /// thrown.\n    /// Instead, we need to implement this short-circuiting logic ourself.\n    ///\n    /// If we short-circuit, we must leave the second expression unevaluated,\n    /// and signal that using the `unevaluated` variant, as detailed in the\n    /// exception format. For the first expression, we know it must be `false`,\n    /// otherwise we would have continued by evaluating the second expression.\n    ///\n    /// Similarly, if we do evaluate the second expression and fail, we know\n    /// that the first expression must have evaluated to `true`, and the second\n    /// to `false`. This way, we avoid needing to evaluate either expression\n    /// twice.\n    ///\n    /// The generated code then looks something like this:\n    /// ```javascript\n    /// if (expr1) {\n    ///   if (!expr2) {\n    ///     <throw exception>\n    ///   }\n    /// } else {\n    ///   <throw exception>\n    /// }\n    /// ```\n    ///\n    fn assert_and(\n        &mut self,\n        left: &'a TypedExpr,\n        right: &'a TypedExpr,\n        message: &Document<'a>,\n        location: SrcSpan,\n    ) -> Document<'a> {\n        let left_kind = AssertExpression::from_expression(left);\n        let right_kind = AssertExpression::from_expression(right);\n\n        let fields_if_short_circuiting = vec![\n            (\"kind\", string(\"binary_operator\")),\n            (\"operator\", string(\"&&\")),\n            (\n                \"left\",\n                self.asserted_expression(left_kind, Some(\"false\".to_doc()), left.location()),\n            ),\n            (\n                \"right\",\n                self.asserted_expression(AssertExpression::Unevaluated, None, right.location()),\n            ),\n            (\"start\", location.start.to_doc()),\n            (\"end\", right.location().end.to_doc()),\n            (\"expression_start\", left.location().start.to_doc()),\n        ];\n\n        let fields = vec![\n            (\"kind\", string(\"binary_operator\")),\n            (\"operator\", string(\"&&\")),\n            (\n                \"left\",\n                self.asserted_expression(left_kind, Some(\"true\".to_doc()), left.location()),\n            ),\n            (\n                \"right\",\n                self.asserted_expression(right_kind, Some(\"false\".to_doc()), right.location()),\n            ),\n            (\"start\", location.start.to_doc()),\n            (\"end\", right.location().end.to_doc()),\n            (\"expression_start\", left.location().start.to_doc()),\n        ];\n\n        let left_value =\n            self.not_in_tail_position(Some(Ordering::Loose), |this| this.wrap_expression(left));\n\n        let right_value = self.not_in_tail_position(Some(Ordering::Strict), |this| {\n            this.negate_bool_expression(right)\n        });\n\n        let right_check = docvec![\n            line(),\n            \"if (\",\n            right_value.nest(INDENT),\n            \") {\",\n            docvec![\n                line(),\n                self.throw_error(\"assert\", message, location, fields)\n            ]\n            .nest(INDENT),\n            line(),\n            \"}\",\n        ];\n\n        docvec![\n            \"if (\",\n            left_value.nest(INDENT),\n            \") {\",\n            right_check.nest(INDENT),\n            line(),\n            \"} else {\",\n            docvec![\n                line(),\n                self.throw_error(\"assert\", message, location, fields_if_short_circuiting)\n            ]\n            .nest(INDENT),\n            line(),\n            \"}\"\n        ]\n    }\n\n    /// Similar to `&&`, `||` is also short-circuiting in Gleam. However, if `||`\n    /// short-circuits, that's because the first expression evaluated to `true`,\n    /// meaning the whole assertion succeeds. This allows us to directly use the\n    /// `||` operator in JavaScript.\n    ///\n    /// The only difference is that due to the nature of `||`, if the assertion fails,\n    /// we know that both sides must have evaluated to `false`, so we don't\n    /// need to store the values of them in variables beforehand.\n    fn assert_or(\n        &mut self,\n        left: &'a TypedExpr,\n        right: &'a TypedExpr,\n        message: &Document<'a>,\n        location: SrcSpan,\n    ) -> Document<'a> {\n        let fields = vec![\n            (\"kind\", string(\"binary_operator\")),\n            (\"operator\", string(\"||\")),\n            (\n                \"left\",\n                self.asserted_expression(\n                    AssertExpression::from_expression(left),\n                    Some(\"false\".to_doc()),\n                    left.location(),\n                ),\n            ),\n            (\n                \"right\",\n                self.asserted_expression(\n                    AssertExpression::from_expression(right),\n                    Some(\"false\".to_doc()),\n                    right.location(),\n                ),\n            ),\n            (\"start\", location.start.to_doc()),\n            (\"end\", right.location().end.to_doc()),\n            (\"expression_start\", left.location().start.to_doc()),\n        ];\n\n        let left_value =\n            self.not_in_tail_position(Some(Ordering::Loose), |this| this.child_expression(left));\n\n        let right_value =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(right));\n\n        docvec![\n            line(),\n            \"if (\",\n            docvec![\"!(\", left_value, \" || \", right_value, \")\"].nest(INDENT),\n            \") {\",\n            docvec![\n                line(),\n                self.throw_error(\"assert\", message, location, fields)\n            ]\n            .nest(INDENT),\n            line(),\n            \"}\",\n        ]\n    }\n\n    fn assign_to_variable(&mut self, value: &'a TypedExpr) -> Document<'a> {\n        if let TypedExpr::Var { .. } = value {\n            self.expression(value)\n        } else {\n            let value = self.wrap_expression(value);\n            let variable = self.next_local_var(&ASSIGNMENT_VAR.into());\n            let assignment = docvec![\"let \", variable.clone(), \" = \", value, \";\"];\n            self.statement_level.push(assignment);\n            variable.to_doc()\n        }\n    }\n\n    fn asserted_expression(\n        &mut self,\n        kind: AssertExpression,\n        value: Option<Document<'a>>,\n        location: SrcSpan,\n    ) -> Document<'a> {\n        let kind = match kind {\n            AssertExpression::Literal => string(\"literal\"),\n            AssertExpression::Expression => string(\"expression\"),\n            AssertExpression::Unevaluated => string(\"unevaluated\"),\n        };\n\n        let start = location.start.to_doc();\n        let end = location.end.to_doc();\n        let items = if let Some(value) = value {\n            vec![\n                (\"kind\", kind),\n                (\"value\", value),\n                (\"start\", start),\n                (\"end\", end),\n            ]\n        } else {\n            vec![(\"kind\", kind), (\"start\", start), (\"end\", end)]\n        };\n\n        wrap_object(\n            items\n                .into_iter()\n                .map(|(key, value)| (key.to_doc(), Some(value))),\n        )\n    }\n\n    fn tuple(&mut self, elements: &'a [TypedExpr]) -> Document<'a> {\n        self.not_in_tail_position(Some(Ordering::Strict), |this| {\n            array(elements.iter().map(|element| this.wrap_expression(element)))\n        })\n    }\n\n    fn call(&mut self, fun: &'a TypedExpr, arguments: &'a [TypedCallArg]) -> Document<'a> {\n        let arguments = arguments\n            .iter()\n            .map(|element| {\n                self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                    this.wrap_expression(&element.value)\n                })\n            })\n            .collect_vec();\n\n        self.call_with_doc_arguments(fun, arguments)\n    }\n\n    fn call_with_doc_arguments(\n        &mut self,\n        fun: &'a TypedExpr,\n        arguments: Vec<Document<'a>>,\n    ) -> Document<'a> {\n        match fun {\n            // Qualified record construction\n            TypedExpr::ModuleSelect {\n                constructor: ModuleValueConstructor::Record { name, .. },\n                module_alias,\n                ..\n            } => self.wrap_return(construct_record(Some(module_alias), name, arguments)),\n\n            // Record construction\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { .. },\n                        type_,\n                        ..\n                    },\n                name,\n                ..\n            } => {\n                if type_.is_result_constructor() {\n                    if name == \"Ok\" {\n                        self.tracker.ok_used = true;\n                    } else if name == \"Error\" {\n                        self.tracker.error_used = true;\n                    }\n                }\n                self.wrap_return(construct_record(None, name, arguments))\n            }\n\n            // Tail call optimisation. If we are calling the current function\n            // and we are in tail position we can avoid creating a new stack\n            // frame, enabling recursion with constant memory usage.\n            TypedExpr::Var { name, .. }\n                if self.function_name == *name\n                    && self.current_function.can_recurse()\n                    && self.function_position.is_tail()\n                    && self.current_scope_vars.get(name) == Some(&0) =>\n            {\n                let mut docs = Vec::with_capacity(arguments.len() * 4);\n                // Record that tail recursion is happening so that we know to\n                // render the loop at the top level of the function.\n                self.tail_recursion_used = true;\n\n                for (i, (element, argument)) in arguments\n                    .into_iter()\n                    .zip(&self.function_arguments)\n                    .enumerate()\n                {\n                    if i != 0 {\n                        docs.push(line());\n                    }\n                    // Create an assignment for each variable created by the function arguments\n                    if let Some(name) = argument {\n                        docs.push(\"loop$\".to_doc());\n                        docs.push(name.to_doc());\n                        docs.push(\" = \".to_doc());\n                    }\n                    // Render the value given to the function. Even if it is not\n                    // assigned we still render it because the expression may\n                    // have some side effects.\n                    docs.push(element);\n                    docs.push(\";\".to_doc());\n                }\n                docs.to_doc()\n            }\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => {\n                let fun = self.not_in_tail_position(None, |this| -> Document<'_> {\n                    let is_fn_literal = matches!(fun, TypedExpr::Fn { .. });\n                    let fun = this.wrap_expression(fun);\n                    if is_fn_literal {\n                        docvec![\"(\", fun, \")\"]\n                    } else {\n                        fun\n                    }\n                });\n                let arguments = call_arguments(arguments);\n                self.wrap_return(docvec![fun, arguments])\n            }\n        }\n    }\n\n    fn fn_(&mut self, arguments: &'a [TypedArg], body: &'a [TypedStatement]) -> Document<'a> {\n        // New function, this is now the tail position\n        let function_position = std::mem::replace(&mut self.function_position, Position::Tail);\n        let scope_position = std::mem::replace(&mut self.scope_position, Position::Tail);\n\n        // And there's a new scope\n        let scope = self.current_scope_vars.clone();\n        for name in arguments.iter().flat_map(Arg::get_variable_name) {\n            let _ = self.current_scope_vars.insert(name.clone(), 0);\n        }\n\n        // This is a new function so track that so that we don't\n        // mistakenly trigger tail call optimisation\n        let mut current_function = CurrentFunction::Anonymous;\n        std::mem::swap(&mut self.current_function, &mut current_function);\n\n        // Generate the function body\n        let result = self.statements(body);\n\n        // Reset function name, scope, and tail position tracking\n        self.function_position = function_position;\n        self.scope_position = scope_position;\n        self.current_scope_vars = scope;\n        std::mem::swap(&mut self.current_function, &mut current_function);\n\n        docvec![\n            docvec![\n                fun_arguments(arguments, false),\n                \" => {\",\n                break_(\"\", \" \"),\n                result\n            ]\n            .nest(INDENT)\n            .append(break_(\"\", \" \"))\n            .group(),\n            \"}\",\n        ]\n    }\n\n    fn record_access(&mut self, record: &'a TypedExpr, label: &'a str) -> Document<'a> {\n        self.not_in_tail_position(None, |this| {\n            let record = this.wrap_expression(record);\n            docvec![record, \".\", maybe_escape_property(label)]\n        })\n    }\n\n    fn positional_access(&mut self, record: &'a TypedExpr, index: u64) -> Document<'a> {\n        self.not_in_tail_position(None, |this| {\n            let record = this.wrap_expression(record);\n            docvec![record, \"[\", index, \"]\"]\n        })\n    }\n\n    fn record_update(\n        &mut self,\n        record: &'a Option<Box<TypedAssignment>>,\n        constructor: &'a TypedExpr,\n        arguments: &'a [TypedCallArg],\n    ) -> Document<'a> {\n        match record.as_ref() {\n            Some(record) => docvec![\n                self.not_in_tail_position(None, |this| this.assignment(record)),\n                line(),\n                self.call(constructor, arguments),\n            ],\n            None => self.call(constructor, arguments),\n        }\n    }\n\n    fn tuple_index(&mut self, tuple: &'a TypedExpr, index: u64) -> Document<'a> {\n        self.not_in_tail_position(None, |this| {\n            let tuple = this.wrap_expression(tuple);\n            docvec![tuple, eco_format!(\"[{index}]\")]\n        })\n    }\n\n    fn bin_op(\n        &mut self,\n        name: &'a BinOp,\n        left: &'a TypedExpr,\n        right: &'a TypedExpr,\n    ) -> Document<'a> {\n        match name {\n            BinOp::And => self.print_bin_op(left, right, \"&&\"),\n            BinOp::Or => self.print_bin_op(left, right, \"||\"),\n            BinOp::LtInt | BinOp::LtFloat => self.print_bin_op(left, right, \"<\"),\n            BinOp::LtEqInt | BinOp::LtEqFloat => self.print_bin_op(left, right, \"<=\"),\n            BinOp::Eq => self.equal(left, right, true),\n            BinOp::NotEq => self.equal(left, right, false),\n            BinOp::GtInt | BinOp::GtFloat => self.print_bin_op(left, right, \">\"),\n            BinOp::GtEqInt | BinOp::GtEqFloat => self.print_bin_op(left, right, \">=\"),\n            BinOp::Concatenate | BinOp::AddInt | BinOp::AddFloat => {\n                self.print_bin_op(left, right, \"+\")\n            }\n            BinOp::SubInt | BinOp::SubFloat => self.print_bin_op(left, right, \"-\"),\n            BinOp::MultInt | BinOp::MultFloat => self.print_bin_op(left, right, \"*\"),\n            BinOp::RemainderInt => self.remainder_int(left, right),\n            BinOp::DivInt => self.div_int(left, right),\n            BinOp::DivFloat => self.div_float(left, right),\n        }\n    }\n\n    fn div_int(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Document<'a> {\n        let left_doc =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(left));\n        let right_doc =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(right));\n\n        // If we have a constant value divided by zero then it's safe to replace\n        // it directly with 0.\n        if left.is_literal() && right.is_zero_compile_time_number() {\n            \"0\".to_doc()\n        } else if right.is_non_zero_compile_time_number() {\n            let division = if let TypedExpr::BinOp { .. } = left {\n                docvec![left_doc.surround(\"(\", \")\"), \" / \", right_doc]\n            } else {\n                docvec![left_doc, \" / \", right_doc]\n            };\n            docvec![\"globalThis.Math.trunc\", wrap_arguments([division])]\n        } else {\n            self.tracker.int_division_used = true;\n            docvec![\"divideInt\", wrap_arguments([left_doc, right_doc])]\n        }\n    }\n\n    fn remainder_int(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Document<'a> {\n        let left_doc =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(left));\n        let right_doc =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(right));\n\n        // If we have a constant value divided by zero then it's safe to replace\n        // it directly with 0.\n        if left.is_literal() && right.is_zero_compile_time_number() {\n            \"0\".to_doc()\n        } else if right.is_non_zero_compile_time_number() {\n            if let TypedExpr::BinOp { .. } = left {\n                docvec![left_doc.surround(\"(\", \")\"), \" % \", right_doc]\n            } else {\n                docvec![left_doc, \" % \", right_doc]\n            }\n        } else {\n            self.tracker.int_remainder_used = true;\n            docvec![\"remainderInt\", wrap_arguments([left_doc, right_doc])]\n        }\n    }\n\n    fn div_float(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Document<'a> {\n        let left_doc =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(left));\n        let right_doc =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(right));\n\n        // If we have a constant value divided by zero then it's safe to replace\n        // it directly with 0.\n        if left.is_literal() && right.is_zero_compile_time_number() {\n            \"0.0\".to_doc()\n        } else if right.is_non_zero_compile_time_number() {\n            if let TypedExpr::BinOp { .. } = left {\n                docvec![left_doc.surround(\"(\", \")\"), \" / \", right_doc]\n            } else {\n                docvec![left_doc, \" / \", right_doc]\n            }\n        } else {\n            self.tracker.float_division_used = true;\n            docvec![\"divideFloat\", wrap_arguments([left_doc, right_doc])]\n        }\n    }\n\n    fn equal(\n        &mut self,\n        left: &'a TypedExpr,\n        right: &'a TypedExpr,\n        should_be_equal: bool,\n    ) -> Document<'a> {\n        // If it is a simple scalar type then we can use JS' reference identity\n        if is_js_scalar(left.type_()) {\n            let left_doc = self\n                .not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(left));\n            let right_doc = self\n                .not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(right));\n            let operator = if should_be_equal { \" === \" } else { \" !== \" };\n            return docvec![left_doc, operator, right_doc];\n        }\n\n        // For comparison with singleton custom types, ie, one with no fields.\n        // If you have some code like this\n        // ```gleam\n        //  pub type Wibble {\n        //    Wibble\n        //    Wobble\n        //  }\n\n        //  pub fn is_wibble(w: Wibble) -> Bool {\n        //    w == Wibble\n        //  }\n        // ```\n        // Instead of `isEqual(w, new Wibble())`, generate `w instanceof Wibble`\n        // because the first approach needs to construct a new Wibble, and then call the isEqual function,\n        // which supports any shape of data, and so does a lot of extra logic which isn't necessary.\n\n        if let Some(doc) = self.singleton_variant_equality(left, right, should_be_equal) {\n            return doc;\n        }\n\n        if let Some(doc) = self.singleton_variant_equality(right, left, should_be_equal) {\n            return doc;\n        }\n\n        // Other types must be compared using structural equality\n        let left =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.wrap_expression(left));\n        let right =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.wrap_expression(right));\n\n        self.prelude_equal_call(should_be_equal, left, right)\n    }\n\n    fn singleton_variant_equality(\n        &mut self,\n        left: &'a TypedExpr,\n        right: &'a TypedExpr,\n        should_be_equal: bool,\n    ) -> Option<Document<'a>> {\n        match right {\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        variant: ValueConstructorVariant::Record { arity: 0, name, .. },\n                        ..\n                    },\n                ..\n            } => {\n                let left_doc = self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                    this.wrap_expression(left)\n                });\n                Some(self.singleton_equal(left_doc, None, name, should_be_equal))\n            }\n            TypedExpr::ModuleSelect {\n                module_alias,\n                constructor: ModuleValueConstructor::Record { arity: 0, name, .. },\n                ..\n            } => {\n                let left_doc = self.not_in_tail_position(Some(Ordering::Strict), |this| {\n                    this.wrap_expression(left)\n                });\n                Some(self.singleton_equal(left_doc, Some(module_alias), name, should_be_equal))\n            }\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    fn singleton_equal(\n        &self,\n        value: Document<'a>,\n        module: Option<&'a str>,\n        name: &'a str,\n        should_be_equal: bool,\n    ) -> Document<'a> {\n        let record = if let Some(module) = module {\n            docvec![\"$\", module, \".\", name]\n        } else {\n            name.to_doc()\n        };\n\n        if should_be_equal {\n            docvec![value, \" instanceof \", record]\n        } else {\n            docvec![\"!(\", value, \" instanceof \", record, \")\"]\n        }\n    }\n\n    fn equal_with_doc_operands(\n        &mut self,\n        left: Document<'a>,\n        right: Document<'a>,\n        type_: Arc<Type>,\n        should_be_equal: bool,\n    ) -> Document<'a> {\n        // If it is a simple scalar type then we can use JS' reference identity\n        if is_js_scalar(type_) {\n            let operator = if should_be_equal { \" === \" } else { \" !== \" };\n            return docvec![left, operator, right];\n        }\n\n        // Other types must be compared using structural equality\n        self.prelude_equal_call(should_be_equal, left, right)\n    }\n\n    pub(super) fn prelude_equal_call(\n        &mut self,\n        should_be_equal: bool,\n        left: Document<'a>,\n        right: Document<'a>,\n    ) -> Document<'a> {\n        // Record that we need to import the prelude's isEqual function into the module\n        self.tracker.object_equality_used = true;\n        // Construct the call\n        let arguments = wrap_arguments([left, right]);\n        let operator = if should_be_equal {\n            \"isEqual\"\n        } else {\n            \"!isEqual\"\n        };\n        docvec![operator, arguments]\n    }\n\n    fn print_bin_op(\n        &mut self,\n        left: &'a TypedExpr,\n        right: &'a TypedExpr,\n        op: &'a str,\n    ) -> Document<'a> {\n        let left =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(left));\n        let right =\n            self.not_in_tail_position(Some(Ordering::Strict), |this| this.child_expression(right));\n        docvec![left, \" \", op, \" \", right]\n    }\n\n    pub(super) fn bin_op_with_doc_operands(\n        &mut self,\n        name: BinOp,\n        left: Document<'a>,\n        right: Document<'a>,\n        type_: &Arc<Type>,\n    ) -> Document<'a> {\n        match name {\n            BinOp::And => docvec![left, \" && \", right],\n            BinOp::Or => docvec![left, \" || \", right],\n            BinOp::LtInt | BinOp::LtFloat => docvec![left, \" < \", right],\n            BinOp::LtEqInt | BinOp::LtEqFloat => docvec![left, \" <= \", right],\n            BinOp::Eq => self.equal_with_doc_operands(left, right, type_.clone(), true),\n            BinOp::NotEq => self.equal_with_doc_operands(left, right, type_.clone(), false),\n            BinOp::GtInt | BinOp::GtFloat => docvec![left, \" > \", right],\n            BinOp::GtEqInt | BinOp::GtEqFloat => docvec![left, \" >= \", right],\n            BinOp::Concatenate | BinOp::AddInt | BinOp::AddFloat => {\n                docvec![left, \" + \", right]\n            }\n            BinOp::SubInt | BinOp::SubFloat => docvec![left, \" - \", right],\n            BinOp::MultInt | BinOp::MultFloat => docvec![left, \" * \", right],\n            BinOp::RemainderInt => {\n                self.tracker.int_remainder_used = true;\n                docvec![\"remainderInt\", wrap_arguments([left, right])]\n            }\n            BinOp::DivInt => {\n                self.tracker.int_division_used = true;\n                docvec![\"divideInt\", wrap_arguments([left, right])]\n            }\n            BinOp::DivFloat => {\n                self.tracker.float_division_used = true;\n                docvec![\"divideFloat\", wrap_arguments([left, right])]\n            }\n        }\n    }\n\n    fn todo(&mut self, message: Option<&'a TypedExpr>, location: &'a SrcSpan) -> Document<'a> {\n        let message = match message {\n            Some(m) => self.not_in_tail_position(None, |this| this.wrap_expression(m)),\n            None => string(\"`todo` expression evaluated. This code has not yet been implemented.\"),\n        };\n        self.throw_error(\"todo\", &message, *location, vec![])\n    }\n\n    fn panic(&mut self, location: &'a SrcSpan, message: Option<&'a TypedExpr>) -> Document<'a> {\n        let message = match message {\n            Some(m) => self.not_in_tail_position(None, |this| this.wrap_expression(m)),\n            None => string(\"`panic` expression evaluated.\"),\n        };\n        self.throw_error(\"panic\", &message, *location, vec![])\n    }\n\n    pub(crate) fn throw_error<Fields>(\n        &mut self,\n        error_name: &'a str,\n        message: &Document<'a>,\n        location: SrcSpan,\n        fields: Fields,\n    ) -> Document<'a>\n    where\n        Fields: IntoIterator<Item = (&'a str, Document<'a>)>,\n    {\n        self.tracker.make_error_used = true;\n        let module = self.module_name.clone().to_doc().surround('\"', '\"');\n        let function = self.function_name.clone().to_doc().surround(\"\\\"\", \"\\\"\");\n        let line = self.line_numbers.line_number(location.start).to_doc();\n        let fields = wrap_object(fields.into_iter().map(|(k, v)| (k.to_doc(), Some(v))));\n\n        docvec![\n            \"throw makeError\",\n            wrap_arguments([\n                string(error_name),\n                \"FILEPATH\".to_doc(),\n                module,\n                line,\n                function,\n                message.clone(),\n                fields\n            ]),\n        ]\n    }\n\n    fn module_select(\n        &mut self,\n        module: &'a str,\n        label: &'a EcoString,\n        constructor: &'a ModuleValueConstructor,\n    ) -> Document<'a> {\n        match constructor {\n            ModuleValueConstructor::Fn { .. } | ModuleValueConstructor::Constant { .. } => {\n                docvec![\"$\", module, \".\", maybe_escape_identifier(label)]\n            }\n\n            ModuleValueConstructor::Record {\n                name, arity, type_, ..\n            } => record_constructor(type_.clone(), Some(module), name, *arity, self.tracker),\n        }\n    }\n\n    fn echo(\n        &mut self,\n        expression: Document<'a>,\n        message: Option<&'a TypedExpr>,\n        location: &'a SrcSpan,\n    ) -> Document<'a> {\n        self.tracker.echo_used = true;\n\n        let message = match message {\n            Some(message) => self\n                .not_in_tail_position(Some(Ordering::Strict), |this| this.wrap_expression(message)),\n            None => \"undefined\".to_doc(),\n        };\n\n        let echo_arguments = call_arguments(vec![\n            expression,\n            message,\n            self.src_path.clone().to_doc(),\n            self.line_numbers.line_number(location.start).to_doc(),\n        ]);\n        self.wrap_return(docvec![\"echo\", echo_arguments])\n    }\n\n    pub(crate) fn constant_expression(\n        &mut self,\n        context: Context,\n        expression: &'a TypedConstant,\n    ) -> Document<'a> {\n        match expression {\n            Constant::Int { value, .. } => int(value),\n            Constant::Float { value, .. } => float(value),\n            Constant::String { value, .. } => string(value),\n            Constant::Tuple { elements, .. } => array(\n                elements\n                    .iter()\n                    .map(|element| self.constant_expression(context, element)),\n            ),\n\n            Constant::List { elements, tail, .. } => {\n                self.tracker.list_used = true;\n\n                let tail_elements = tail\n                    .as_deref()\n                    .and_then(|tail| tail.list_elements())\n                    .unwrap_or_default();\n\n                let list = list(\n                    elements\n                        .iter()\n                        .chain(tail_elements)\n                        .map(|element| self.constant_expression(context, element)),\n                );\n\n                match context {\n                    Context::Constant => docvec![\"/* @__PURE__ */ \", list],\n                    Context::Guard => list,\n                }\n            }\n\n            Constant::Record { type_, name, .. } if type_.is_bool() && name == \"True\" => {\n                \"true\".to_doc()\n            }\n            Constant::Record { type_, name, .. } if type_.is_bool() && name == \"False\" => {\n                \"false\".to_doc()\n            }\n            Constant::Record { type_, .. } if type_.is_nil() => \"undefined\".to_doc(),\n\n            Constant::Record {\n                arguments,\n                module,\n                name,\n                tag,\n                type_,\n                ..\n            } => {\n                if module.is_none() && type_.is_result() {\n                    if tag == \"Ok\" {\n                        self.tracker.ok_used = true;\n                    } else {\n                        self.tracker.error_used = true;\n                    }\n                }\n\n                // If there's no arguments and the type is a function that takes\n                // arguments then this is the constructor being referenced, not the\n                // function being called.\n                if let Some(arity) = type_.fn_arity()\n                    && arguments.is_empty()\n                    && arity != 0\n                {\n                    let arity = arity as u16;\n                    return record_constructor(type_.clone(), None, name, arity, self.tracker);\n                }\n\n                // Record updates are fully expanded during type checking, so we just handle arguments\n                let field_values = arguments\n                    .iter()\n                    .map(|argument| self.constant_expression(context, &argument.value))\n                    .collect_vec();\n\n                let constructor = construct_record(\n                    module.as_ref().map(|(module, _)| module.as_str()),\n                    name,\n                    field_values,\n                );\n                match context {\n                    Context::Constant => docvec![\"/* @__PURE__ */ \", constructor],\n                    Context::Guard => constructor,\n                }\n            }\n            Constant::BitArray { segments, .. } => {\n                let bit_array = self.constant_bit_array(segments, context);\n                match context {\n                    Context::Constant => docvec![\"/* @__PURE__ */ \", bit_array],\n                    Context::Guard => bit_array,\n                }\n            }\n\n            Constant::Var { name, module, .. } => {\n                match (module, context) {\n                    (None, Context::Guard) => self.local_var(name).to_doc(),\n                    (None, Context::Constant) => maybe_escape_identifier(name).to_doc(),\n                    (Some((module, _)), _) => {\n                        // JS keywords can be accessed here, but we must escape anyway\n                        // as we escape when exporting such names in the first place,\n                        // and the imported name has to match the exported name.\n                        docvec![\"$\", module, \".\", maybe_escape_identifier(name)]\n                    }\n                }\n            }\n\n            Constant::StringConcatenation { left, right, .. } => {\n                let left = self.constant_expression(context, left);\n                let right = self.constant_expression(context, right);\n                docvec![left, \" + \", right]\n            }\n\n            Constant::RecordUpdate { .. } => {\n                panic!(\"record updates should not reach code generation\")\n            }\n\n            Constant::Invalid { .. } => {\n                panic!(\"invalid constants should not reach code generation\")\n            }\n        }\n    }\n\n    fn constant_bit_array(\n        &mut self,\n        segments: &'a [TypedConstantBitArraySegment],\n        context: Context,\n    ) -> Document<'a> {\n        self.tracker.bit_array_literal_used = true;\n        let segments_array = array(segments.iter().map(|segment| {\n            let value = match context {\n                Context::Constant => self.constant_expression(context, &segment.value),\n                Context::Guard => self.guard_constant_expression(&segment.value),\n            };\n\n            let details = self.constant_bit_array_segment_details(segment, context);\n\n            match details.type_ {\n                BitArraySegmentType::BitArray => {\n                    if segment.size().is_some() {\n                        self.tracker.bit_array_slice_used = true;\n                        docvec![\"bitArraySlice(\", value, \", 0, \", details.size, \")\"]\n                    } else {\n                        value\n                    }\n                }\n                BitArraySegmentType::Int => match (details.size_value, segment.value.as_ref()) {\n                    (Some(size_value), Constant::Int { int_value, .. })\n                        if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()\n                            && (&size_value % BigInt::from(8) == BigInt::ZERO) =>\n                    {\n                        let bytes = bit_array_segment_int_value_to_bytes(\n                            int_value.clone(),\n                            size_value,\n                            segment.endianness(),\n                        );\n\n                        u8_slice(&bytes)\n                    }\n\n                    (Some(size_value), _) if size_value == 8.into() => value,\n\n                    (Some(size_value), _) if size_value <= 0.into() => nil(),\n\n                    _ => {\n                        self.tracker.sized_integer_segment_used = true;\n                        let size = details.size;\n                        let is_big = bool(segment.endianness().is_big());\n                        docvec![\"sizedInt(\", value, \", \", size, \", \", is_big, \")\"]\n                    }\n                },\n                BitArraySegmentType::Float => {\n                    self.tracker.float_bit_array_segment_used = true;\n                    let size = details.size;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"sizedFloat(\", value, \", \", size, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::String(StringEncoding::Utf8) => {\n                    self.tracker.string_bit_array_segment_used = true;\n                    docvec![\"stringBits(\", value, \")\"]\n                }\n                BitArraySegmentType::String(StringEncoding::Utf16) => {\n                    self.tracker.string_utf16_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"stringToUtf16(\", value, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::String(StringEncoding::Utf32) => {\n                    self.tracker.string_utf32_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"stringToUtf32(\", value, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::UtfCodepoint(StringEncoding::Utf8) => {\n                    self.tracker.codepoint_bit_array_segment_used = true;\n                    docvec![\"codepointBits(\", value, \")\"]\n                }\n                BitArraySegmentType::UtfCodepoint(StringEncoding::Utf16) => {\n                    self.tracker.codepoint_utf16_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"codepointToUtf16(\", value, \", \", is_big, \")\"]\n                }\n                BitArraySegmentType::UtfCodepoint(StringEncoding::Utf32) => {\n                    self.tracker.codepoint_utf32_bit_array_segment_used = true;\n                    let is_big = bool(details.endianness.is_big());\n                    docvec![\"codepointToUtf32(\", value, \", \", is_big, \")\"]\n                }\n            }\n        }));\n\n        docvec![\"toBitArray(\", segments_array, \")\"]\n    }\n\n    fn constant_bit_array_segment_details(\n        &mut self,\n        segment: &'a TypedConstantBitArraySegment,\n        context: Context,\n    ) -> BitArraySegmentDetails<'a> {\n        let size = segment.size();\n        let unit = segment.unit();\n        let (size_value, size) = match size {\n            Some(Constant::Int { int_value, .. }) => {\n                let size_value = int_value * unit;\n                let size = eco_format!(\"{}\", size_value).to_doc();\n                (Some(size_value), size)\n            }\n\n            Some(size) => {\n                let mut size = match context {\n                    Context::Constant => self.constant_expression(context, size),\n                    Context::Guard => self.guard_constant_expression(size),\n                };\n                if unit != 1 {\n                    size = size.group().append(\" * \".to_doc().append(unit.to_doc()));\n                }\n\n                (None, size)\n            }\n\n            None => {\n                let size_value: usize = if segment.type_.is_int() { 8 } else { 64 };\n                (Some(BigInt::from(size_value)), docvec![size_value])\n            }\n        };\n\n        let type_ = BitArraySegmentType::from_segment(segment);\n\n        BitArraySegmentDetails {\n            type_,\n            size,\n            size_value,\n            endianness: segment.endianness(),\n        }\n    }\n\n    pub(crate) fn guard(&mut self, guard: &'a TypedClauseGuard) -> Document<'a> {\n        match guard {\n            ClauseGuard::Block { value, .. } => self.guard(value).surround(\"(\", \")\"),\n\n            ClauseGuard::BinaryOperator {\n                left,\n                right,\n                operator,\n                ..\n            } => {\n                let left_document = self.wrapped_guard(left);\n                let right_document = self.wrapped_guard(right);\n\n                let operator = match operator {\n                    BinOp::Eq if is_js_scalar(left.type_()) => \"===\",\n                    BinOp::NotEq if is_js_scalar(left.type_()) => \"!==\",\n                    BinOp::Eq | BinOp::NotEq => {\n                        let should_be_equal = *operator == BinOp::Eq;\n\n                        // Handle singleton equality optimization for guards\n                        if let Some(doc) =\n                            self.singleton_variant_guard_equality(left, right, should_be_equal)\n                        {\n                            return doc;\n                        }\n\n                        if let Some(doc) =\n                            self.singleton_variant_guard_equality(right, left, should_be_equal)\n                        {\n                            return doc;\n                        }\n\n                        let left_doc = self.guard(left);\n                        let right_doc = self.guard(right);\n                        return self.prelude_equal_call(should_be_equal, left_doc, right_doc);\n                    }\n\n                    BinOp::GtFloat | BinOp::GtInt => \">\",\n                    BinOp::GtEqFloat | BinOp::GtEqInt => \">=\",\n                    BinOp::LtFloat | BinOp::LtInt => \"<\",\n                    BinOp::LtEqFloat | BinOp::LtEqInt => \"<=\",\n\n                    BinOp::AddFloat | BinOp::AddInt | BinOp::Concatenate => \"+\",\n                    BinOp::SubFloat | BinOp::SubInt => \"-\",\n                    BinOp::MultFloat | BinOp::MultInt => \"*\",\n\n                    BinOp::DivFloat => {\n                        self.tracker.float_division_used = true;\n                        return docvec![\n                            \"divideFloat\",\n                            wrap_arguments([left_document, right_document])\n                        ];\n                    }\n\n                    BinOp::DivInt => {\n                        self.tracker.int_division_used = true;\n                        return docvec![\n                            \"divideInt\",\n                            wrap_arguments([left_document, right_document])\n                        ];\n                    }\n\n                    BinOp::RemainderInt => {\n                        self.tracker.int_remainder_used = true;\n                        return docvec![\n                            \"remainderInt\",\n                            wrap_arguments([left_document, right_document])\n                        ];\n                    }\n\n                    BinOp::And => \"&&\",\n                    BinOp::Or => \"||\",\n                };\n\n                docvec![left_document, \" \", operator, \" \", right_document]\n            }\n\n            ClauseGuard::Var { name, .. } => self.local_var(name).to_doc(),\n\n            ClauseGuard::TupleIndex { tuple, index, .. } => {\n                docvec![self.guard(tuple,), \"[\", index, \"]\"]\n            }\n\n            ClauseGuard::FieldAccess {\n                label, container, ..\n            } => docvec![self.guard(container), \".\", maybe_escape_property(label)],\n\n            ClauseGuard::ModuleSelect {\n                module_alias,\n                label,\n                ..\n            } => docvec![\"$\", module_alias, \".\", label],\n\n            ClauseGuard::Not { expression, .. } => docvec![\"!\", self.guard(expression,)],\n\n            ClauseGuard::Constant(constant) => self.guard_constant_expression(constant),\n        }\n    }\n\n    fn singleton_variant_guard_equality(\n        &mut self,\n        left: &'a TypedClauseGuard,\n        right: &'a TypedClauseGuard,\n        should_be_equal: bool,\n    ) -> Option<Document<'a>> {\n        if let ClauseGuard::Constant(Constant::Record {\n            record_constructor: Some(constructor),\n            module,\n            name,\n            ..\n        }) = right\n            && let ValueConstructorVariant::Record { arity: 0, .. } = constructor.variant\n        {\n            let left_doc = self.guard(left);\n            return Some(self.singleton_equal(\n                left_doc,\n                module.as_ref().map(|(module, _)| module.as_str()),\n                name,\n                should_be_equal,\n            ));\n        }\n        None\n    }\n\n    fn wrapped_guard(&mut self, guard: &'a TypedClauseGuard) -> Document<'a> {\n        match guard {\n            ClauseGuard::Var { .. }\n            | ClauseGuard::TupleIndex { .. }\n            | ClauseGuard::Constant(_)\n            | ClauseGuard::Not { .. }\n            | ClauseGuard::FieldAccess { .. }\n            | ClauseGuard::Block { .. } => self.guard(guard),\n\n            ClauseGuard::BinaryOperator { .. } | ClauseGuard::ModuleSelect { .. } => {\n                docvec![\"(\", self.guard(guard), \")\"]\n            }\n        }\n    }\n\n    fn guard_constant_expression(&mut self, expression: &'a TypedConstant) -> Document<'a> {\n        match expression {\n            Constant::Tuple { elements, .. } => array(\n                elements\n                    .iter()\n                    .map(|element| self.guard_constant_expression(element)),\n            ),\n\n            Constant::List { elements, .. } => {\n                self.tracker.list_used = true;\n                list(\n                    elements\n                        .iter()\n                        .map(|element| self.guard_constant_expression(element)),\n                )\n            }\n            Constant::Record { type_, name, .. } if type_.is_bool() && name == \"True\" => {\n                \"true\".to_doc()\n            }\n            Constant::Record { type_, name, .. } if type_.is_bool() && name == \"False\" => {\n                \"false\".to_doc()\n            }\n            Constant::Record { type_, .. } if type_.is_nil() => \"undefined\".to_doc(),\n\n            Constant::Record {\n                arguments,\n                module,\n                name,\n                tag,\n                type_,\n                ..\n            } => {\n                if module.is_none() && type_.is_result() {\n                    if tag == \"Ok\" {\n                        self.tracker.ok_used = true;\n                    } else {\n                        self.tracker.error_used = true;\n                    }\n                }\n\n                // If there's no arguments and the type is a function that takes\n                // arguments then this is the constructor being referenced, not the\n                // function being called.\n                if let Some(arity) = type_.fn_arity()\n                    && arguments.is_empty()\n                    && arity != 0\n                {\n                    let arity = arity as u16;\n                    return record_constructor(type_.clone(), None, name, arity, self.tracker);\n                }\n\n                // Record updates are fully expanded during type checking, so we just\n                // handle arguments\n                let field_values = arguments\n                    .iter()\n                    .map(|argument| self.guard_constant_expression(&argument.value))\n                    .collect_vec();\n                construct_record(\n                    module.as_ref().map(|(module, _)| module.as_str()),\n                    name,\n                    field_values,\n                )\n            }\n\n            Constant::BitArray { segments, .. } => {\n                self.constant_bit_array(segments, Context::Guard)\n            }\n\n            Constant::Var { name, .. } => self.local_var(name).to_doc(),\n\n            Constant::Int { .. }\n            | Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::RecordUpdate { .. }\n            | Constant::StringConcatenation { .. }\n            | Constant::Invalid { .. } => self.constant_expression(Context::Guard, expression),\n        }\n    }\n}\n\n#[derive(Clone, Copy)]\nenum AssertExpression {\n    Literal,\n    Expression,\n    Unevaluated,\n}\n\nimpl AssertExpression {\n    fn from_expression(expression: &TypedExpr) -> Self {\n        if expression.is_literal() {\n            Self::Literal\n        } else {\n            Self::Expression\n        }\n    }\n}\n\npub fn int(value: &str) -> Document<'_> {\n    eco_string_int(value.into())\n}\n\npub fn eco_string_int<'a>(value: EcoString) -> Document<'a> {\n    let mut out = EcoString::with_capacity(value.len());\n\n    if value.starts_with('-') {\n        out.push('-');\n    } else if value.starts_with('+') {\n        out.push('+');\n    };\n    let value = value.trim_start_matches(['+', '-'].as_ref());\n\n    let value = if value.starts_with(\"0x\") {\n        out.push_str(\"0x\");\n        value.trim_start_matches(\"0x\")\n    } else if value.starts_with(\"0o\") {\n        out.push_str(\"0o\");\n        value.trim_start_matches(\"0o\")\n    } else if value.starts_with(\"0b\") {\n        out.push_str(\"0b\");\n        value.trim_start_matches(\"0b\")\n    } else {\n        value\n    };\n\n    let value = value.trim_start_matches(['0', '_']);\n    if value.is_empty() {\n        out.push('0');\n    }\n\n    out.push_str(value);\n\n    out.to_doc()\n}\n\npub fn float(value: &str) -> Document<'_> {\n    let mut out = EcoString::with_capacity(value.len());\n\n    if value.starts_with('-') {\n        out.push('-');\n    } else if value.starts_with('+') {\n        out.push('+');\n    };\n    let value = value.trim_start_matches(['+', '-'].as_ref());\n\n    let value = value.trim_start_matches(['0', '_']);\n    if value.starts_with(['.', 'e', 'E']) {\n        out.push('0');\n    }\n    out.push_str(value);\n\n    out.to_doc()\n}\n\npub fn float_from_value(value: f64) -> Document<'static> {\n    if value.is_infinite() {\n        if value.is_sign_positive() {\n            \"Infinity\".to_doc()\n        } else {\n            \"-Infinity\".to_doc()\n        }\n    } else if value.is_nan() {\n        // NOTE: this case is probably unnecessary, as this function is only\n        // invoked with `LiteralFloatValue` values, which cannot be nan.\n        \"NaN\".to_doc()\n    } else {\n        value.to_doc()\n    }\n}\n\n/// The context where the constant expression is used, it might be inside a\n/// function call, or in the definition of another constant.\n///\n/// Based on the context we might want to annotate pure function calls as\n/// \"@__PURE__\".\n///\n#[derive(Debug, Clone, Copy)]\npub enum Context {\n    Constant,\n    Guard,\n}\n\n#[derive(Debug)]\nstruct BitArraySegmentDetails<'a> {\n    type_: BitArraySegmentType,\n    size: Document<'a>,\n    /// The size of the bit array segment stored as a BigInt.\n    /// This has a value when the segment's size is known at compile time.\n    size_value: Option<BigInt>,\n    endianness: Endianness,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum BitArraySegmentType {\n    BitArray,\n    Int,\n    Float,\n    String(StringEncoding),\n    UtfCodepoint(StringEncoding),\n}\n\nimpl BitArraySegmentType {\n    fn from_segment<Value>(segment: &BitArraySegment<Value, Arc<Type>>) -> Self {\n        if segment.type_.is_int() {\n            BitArraySegmentType::Int\n        } else if segment.type_.is_float() {\n            BitArraySegmentType::Float\n        } else if segment.type_.is_bit_array() {\n            BitArraySegmentType::BitArray\n        } else if segment.type_.is_string() {\n            let encoding = if segment.has_utf16_option() {\n                StringEncoding::Utf16\n            } else if segment.has_utf32_option() {\n                StringEncoding::Utf32\n            } else {\n                StringEncoding::Utf8\n            };\n            BitArraySegmentType::String(encoding)\n        } else if segment.type_.is_utf_codepoint() {\n            let encoding = if segment.has_utf16_codepoint_option() {\n                StringEncoding::Utf16\n            } else if segment.has_utf32_codepoint_option() {\n                StringEncoding::Utf32\n            } else {\n                StringEncoding::Utf8\n            };\n            BitArraySegmentType::UtfCodepoint(encoding)\n        } else {\n            panic!(\n                \"Invalid bit array segment type reached code generation: {:?}\",\n                segment.type_\n            );\n        }\n    }\n}\n\npub fn string(value: &str) -> Document<'_> {\n    if value.contains('\\n') {\n        EcoString::from(value.replace('\\n', r\"\\n\"))\n            .to_doc()\n            .surround(\"\\\"\", \"\\\"\")\n    } else {\n        value.to_doc().surround(\"\\\"\", \"\\\"\")\n    }\n}\n\npub(crate) fn array<'a, Elements: IntoIterator<Item = Document<'a>>>(\n    elements: Elements,\n) -> Document<'a> {\n    let elements = Itertools::intersperse(elements.into_iter(), break_(\",\", \", \")).collect_vec();\n    if elements.is_empty() {\n        // Do not add a trailing comma since that adds an 'undefined' element\n        \"[]\".to_doc()\n    } else {\n        docvec![\n            \"[\",\n            docvec![break_(\"\", \"\"), elements].nest(INDENT),\n            break_(\",\", \"\"),\n            \"]\"\n        ]\n        .group()\n    }\n}\n\npub(crate) fn list<'a, I: IntoIterator<Item = Document<'a>>>(elements: I) -> Document<'a>\nwhere\n    I::IntoIter: DoubleEndedIterator,\n{\n    let array = array(elements);\n    docvec![\"toList(\", array, \")\"]\n}\n\nfn prepend<'a, I: IntoIterator<Item = Document<'a>>>(\n    elements: I,\n    tail: Document<'a>,\n) -> Document<'a>\nwhere\n    I::IntoIter: DoubleEndedIterator + ExactSizeIterator,\n{\n    elements.into_iter().rev().fold(tail, |tail, element| {\n        let arguments = call_arguments([element, tail]);\n        docvec![\"listPrepend\", arguments]\n    })\n}\n\nfn call_arguments<'a, Elements: IntoIterator<Item = Document<'a>>>(\n    elements: Elements,\n) -> Document<'a> {\n    let elements = Itertools::intersperse(elements.into_iter(), break_(\",\", \", \"))\n        .collect_vec()\n        .to_doc();\n    if elements.is_empty() {\n        return \"()\".to_doc();\n    }\n    docvec![\n        \"(\",\n        docvec![break_(\"\", \"\"), elements].nest(INDENT),\n        break_(\",\", \"\"),\n        \")\"\n    ]\n    .group()\n}\n\npub(crate) fn construct_record<'a>(\n    module: Option<&'a str>,\n    name: &'a str,\n    arguments: impl IntoIterator<Item = Document<'a>>,\n) -> Document<'a> {\n    let mut any_arguments = false;\n    let arguments = join(\n        arguments.into_iter().inspect(|_| {\n            any_arguments = true;\n        }),\n        break_(\",\", \", \"),\n    );\n    let arguments = docvec![break_(\"\", \"\"), arguments].nest(INDENT);\n    let name = if let Some(module) = module {\n        docvec![\"$\", module, \".\", name]\n    } else {\n        name.to_doc()\n    };\n    if any_arguments {\n        docvec![\"new \", name, \"(\", arguments, break_(\",\", \"\"), \")\"].group()\n    } else {\n        docvec![\"new \", name, \"()\"]\n    }\n}\n\nimpl TypedExpr {\n    fn handles_own_return(&self) -> bool {\n        match self {\n            TypedExpr::Todo { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::RecordUpdate { .. } => true,\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => false,\n        }\n    }\n}\n\nimpl BinOp {\n    fn is_operator_to_wrap(&self) -> bool {\n        match self {\n            BinOp::And\n            | BinOp::Or\n            | BinOp::Eq\n            | BinOp::NotEq\n            | BinOp::LtInt\n            | BinOp::LtEqInt\n            | BinOp::LtFloat\n            | BinOp::LtEqFloat\n            | BinOp::GtEqInt\n            | BinOp::GtInt\n            | BinOp::GtEqFloat\n            | BinOp::GtFloat\n            | BinOp::AddInt\n            | BinOp::AddFloat\n            | BinOp::SubInt\n            | BinOp::SubFloat\n            | BinOp::MultFloat\n            | BinOp::DivInt\n            | BinOp::DivFloat\n            | BinOp::RemainderInt\n            | BinOp::Concatenate => true,\n            BinOp::MultInt => false,\n        }\n    }\n}\n\npub fn is_js_scalar(t: Arc<Type>) -> bool {\n    t.is_int() || t.is_float() || t.is_bool() || t.is_nil() || t.is_string()\n}\n\nfn requires_semicolon(statement: &TypedStatement) -> bool {\n    match statement {\n        Statement::Expression(\n            TypedExpr::Int { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Block { .. },\n        ) => true,\n\n        Statement::Expression(\n            TypedExpr::Todo { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::Invalid { .. },\n        ) => false,\n\n        Statement::Assignment(_) => false,\n        Statement::Use(_) => false,\n        Statement::Assert(_) => false,\n    }\n}\n\n/// Wrap a document in an immediately invoked function expression\nfn immediately_invoked_function_expression_document(document: Document<'_>) -> Document<'_> {\n    docvec![\n        docvec![\"(() => {\", break_(\"\", \" \"), document].nest(INDENT),\n        break_(\"\", \" \"),\n        \"})()\",\n    ]\n    .group()\n}\n\npub(crate) fn record_constructor<'a>(\n    type_: Arc<Type>,\n    qualifier: Option<&'a str>,\n    name: &'a str,\n    arity: u16,\n    tracker: &mut UsageTracker,\n) -> Document<'a> {\n    if qualifier.is_none() && type_.is_result_constructor() {\n        if name == \"Ok\" {\n            tracker.ok_used = true;\n        } else if name == \"Error\" {\n            tracker.error_used = true;\n        }\n    }\n    if type_.is_bool() && name == \"True\" {\n        \"true\".to_doc()\n    } else if type_.is_bool() {\n        \"false\".to_doc()\n    } else if type_.is_nil() {\n        \"undefined\".to_doc()\n    } else if arity == 0 {\n        match qualifier {\n            Some(module) => docvec![\"new $\", module, \".\", name, \"()\"],\n            None => docvec![\"new \", name, \"()\"],\n        }\n    } else {\n        let vars = (0..arity).map(|i| eco_format!(\"var{i}\").to_doc());\n        let body = docvec![\n            \"return \",\n            construct_record(qualifier, name, vars.clone()),\n            \";\"\n        ];\n        docvec![\n            docvec![wrap_arguments(vars), \" => {\", break_(\"\", \" \"), body]\n                .nest(INDENT)\n                .append(break_(\"\", \" \"))\n                .group(),\n            \"}\",\n        ]\n    }\n}\n\nfn u8_slice<'a>(bytes: &[u8]) -> Document<'a> {\n    let s: EcoString = bytes\n        .iter()\n        .map(u8::to_string)\n        .collect::<Vec<_>>()\n        .join(\", \")\n        .into();\n\n    docvec![s]\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/import.rs",
    "content": "use std::collections::{HashMap, HashSet};\n\nuse ecow::EcoString;\nuse itertools::Itertools;\n\nuse crate::{\n    docvec,\n    javascript::{INDENT, JavaScriptCodegenTarget},\n    pretty::{Document, Documentable, break_, concat, join, line},\n};\n\n/// A collection of JavaScript import statements from Gleam imports and from\n/// external functions, to be rendered into a JavaScript module.\n///\n#[derive(Debug, Default)]\npub(crate) struct Imports<'a> {\n    imports: HashMap<EcoString, Import<'a>>,\n    exports: HashSet<EcoString>,\n}\n\nimpl<'a> Imports<'a> {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn register_export(&mut self, export: EcoString) {\n        let _ = self.exports.insert(export);\n    }\n\n    pub fn register_module(\n        &mut self,\n        path: EcoString,\n        aliases: impl IntoIterator<Item = EcoString>,\n        unqualified_imports: impl IntoIterator<Item = Member<'a>>,\n    ) {\n        let import = self\n            .imports\n            .entry(path.clone())\n            .or_insert_with(|| Import::new(path.clone()));\n        import.aliases.extend(aliases);\n        import.unqualified.extend(unqualified_imports)\n    }\n\n    pub fn into_doc(self, codegen_target: JavaScriptCodegenTarget) -> Document<'a> {\n        let imports = concat(\n            self.imports\n                .into_values()\n                .sorted_by(|a, b| a.path.cmp(&b.path))\n                .map(|import| Import::into_doc(import, codegen_target)),\n        );\n\n        if self.exports.is_empty() {\n            imports\n        } else {\n            let names = join(\n                self.exports\n                    .into_iter()\n                    .sorted()\n                    .map(|string| string.to_doc()),\n                break_(\",\", \", \"),\n            );\n            let names = docvec![\n                docvec![break_(\"\", \" \"), names].nest(INDENT),\n                break_(\",\", \" \")\n            ]\n            .group();\n\n            let export_keyword = match codegen_target {\n                JavaScriptCodegenTarget::JavaScript => \"export {\",\n                JavaScriptCodegenTarget::TypeScriptDeclarations => \"export type {\",\n            };\n\n            imports\n                .append(line())\n                .append(export_keyword)\n                .append(names)\n                .append(\"};\")\n                .append(line())\n        }\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.imports.is_empty() && self.exports.is_empty()\n    }\n}\n\n#[derive(Debug)]\nstruct Import<'a> {\n    path: EcoString,\n    aliases: HashSet<EcoString>,\n    unqualified: Vec<Member<'a>>,\n}\n\nimpl<'a> Import<'a> {\n    fn new(path: EcoString) -> Self {\n        Self {\n            path,\n            aliases: Default::default(),\n            unqualified: Default::default(),\n        }\n    }\n\n    pub fn into_doc(self, codegen_target: JavaScriptCodegenTarget) -> Document<'a> {\n        let path = self.path.to_doc();\n        let import_modifier = if codegen_target == JavaScriptCodegenTarget::TypeScriptDeclarations {\n            \"type \"\n        } else {\n            \"\"\n        };\n        let alias_imports = concat(self.aliases.into_iter().sorted().map(|alias| {\n            docvec![\n                \"import \",\n                import_modifier,\n                \"* as \",\n                alias,\n                \" from \\\"\",\n                path.clone(),\n                r#\"\";\"#,\n                line()\n            ]\n        }));\n        if self.unqualified.is_empty() {\n            alias_imports\n        } else {\n            let members = self.unqualified.into_iter().map(Member::into_doc);\n            let members = join(members, break_(\",\", \", \"));\n            let members = docvec![\n                docvec![break_(\"\", \" \"), members].nest(INDENT),\n                break_(\",\", \" \")\n            ]\n            .group();\n            docvec![\n                alias_imports,\n                \"import \",\n                import_modifier,\n                \"{\",\n                members,\n                \"} from \\\"\",\n                path,\n                r#\"\";\"#,\n                line()\n            ]\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct Member<'a> {\n    pub name: Document<'a>,\n    pub alias: Option<Document<'a>>,\n}\n\nimpl<'a> Member<'a> {\n    fn into_doc(self) -> Document<'a> {\n        match self.alias {\n            None => self.name,\n            Some(alias) => docvec![self.name, \" as \", alias],\n        }\n    }\n}\n\n#[test]\nfn into_doc() {\n    let mut imports = Imports::new();\n    imports.register_module(\"./gleam/empty\".into(), [], []);\n    imports.register_module(\n        \"./multiple/times\".into(),\n        [\"wibble\".into(), \"wobble\".into()],\n        [],\n    );\n    imports.register_module(\"./multiple/times\".into(), [\"wubble\".into()], []);\n    imports.register_module(\n        \"./multiple/times\".into(),\n        [],\n        [Member {\n            name: \"one\".to_doc(),\n            alias: None,\n        }],\n    );\n\n    imports.register_module(\n        \"./other\".into(),\n        [],\n        [\n            Member {\n                name: \"one\".to_doc(),\n                alias: None,\n            },\n            Member {\n                name: \"one\".to_doc(),\n                alias: Some(\"onee\".to_doc()),\n            },\n            Member {\n                name: \"two\".to_doc(),\n                alias: Some(\"twoo\".to_doc()),\n            },\n        ],\n    );\n\n    imports.register_module(\n        \"./other\".into(),\n        [],\n        [\n            Member {\n                name: \"three\".to_doc(),\n                alias: None,\n            },\n            Member {\n                name: \"four\".to_doc(),\n                alias: None,\n            },\n        ],\n    );\n\n    imports.register_module(\n        \"./zzz\".into(),\n        [],\n        [\n            Member {\n                name: \"one\".to_doc(),\n                alias: None,\n            },\n            Member {\n                name: \"two\".to_doc(),\n                alias: None,\n            },\n        ],\n    );\n\n    assert_eq!(\n        line()\n            .append(imports.into_doc(JavaScriptCodegenTarget::JavaScript))\n            .to_pretty_string(40),\n        r#\"\nimport * as wibble from \"./multiple/times\";\nimport * as wobble from \"./multiple/times\";\nimport * as wubble from \"./multiple/times\";\nimport { one } from \"./multiple/times\";\nimport {\n  one,\n  one as onee,\n  two as twoo,\n  three,\n  four,\n} from \"./other\";\nimport { one, two } from \"./zzz\";\n\"#\n        .to_string()\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/assert.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn assert_variable() {\n    assert_js!(\n        \"\npub fn main() {\n  let x = True\n  assert x\n}\n\"\n    );\n}\n\n#[test]\nfn assert_literal() {\n    assert_js!(\n        \"\npub fn main() {\n  assert False\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operation() {\n    assert_js!(\n        \"\npub fn main() {\n  let x = True\n  assert x || False\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operation2() {\n    assert_js!(\n        \"\npub fn eq(a, b) {\n  assert a == b\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operation3() {\n    assert_js!(\n        \"\npub fn assert_answer(x) {\n  assert x == 42\n}\n\"\n    );\n}\n\n#[test]\nfn assert_function_call() {\n    assert_js!(\n        \"\nfn bool() {\n  True\n}\n\npub fn main() {\n  assert bool()\n}\n\"\n    );\n}\n\n#[test]\nfn assert_function_call2() {\n    assert_js!(\n        \"\nfn and(a, b) {\n  a && b\n}\n\npub fn go(x) {\n  assert and(True, x)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_nested_function_call() {\n    assert_js!(\n        \"\nfn and(x, y) {\n  x && y\n}\n\npub fn main() {\n  assert and(and(True, False), True)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operator_with_side_effects() {\n    assert_js!(\n        \"\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert True && wibble(1, 4)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_binary_operator_with_side_effects2() {\n    assert_js!(\n        \"\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert wibble(5, 5) && wibble(4, 6)\n}\n\"\n    );\n}\n\n#[test]\nfn assert_with_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  assert True as \"This shouldn't fail\"\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_with_block_message() {\n    assert_js!(\n        r#\"\nfn identity(a) {\n  a\n}\n\npub fn main() {\n  assert identity(True) as {\n    let message = identity(\"This shouldn't fail\")\n    message\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_nil_always_throws() {\n    assert_js!(\n        r#\"\npub fn go(x: Nil) {\n  let assert Nil = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4643\n#[test]\nfn assert_with_pipe_on_right() {\n    assert_js!(\n        \"\nfn add(a, b) { a + b }\n\npub fn main() {\n  assert 3 == 1 |> add(2)\n}\n\"\n    );\n}\n\n#[test]\nfn prova() {\n    assert_js!(\n        \"\npub fn main() {\n  assert Ok([]) == Ok([] |> id)\n}\n\nfn id(x) { x }\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/5251\n#[test]\nfn assert_with_logical_and_binary_rhs_1() {\n    assert_js!(\n        \"\npub fn main() {\n  assert True && 3 < 4\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5251\n#[test]\nfn assert_with_logical_and_binary_rhs_2() {\n    assert_js!(\n        \"\npub fn main() {\n  assert True && \\\"wibble\\\" == \\\"wibble\\\"\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5251\n#[test]\nfn assert_with_logical_and_binary_rhs_3() {\n    assert_js!(\n        \"\npub fn main() {\n  assert True && \\\"wobble\\\" != \\\"wobble\\\"\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5251\n#[test]\nfn assert_with_case_rhs() {\n    assert_js!(\n        \"\npub fn main() {\n  assert True && case 1 > 2 {\n    True -> True\n    False -> False\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5251\n#[test]\nfn assert_with_negated_case_rhs() {\n    assert_js!(\n        \"\npub fn main() {\n  assert True && !case 3 - 2 {\n    1 -> True\n    _ -> False\n  }\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/assignments.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn tuple_matching() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert #(1, 2) = x\n}\n\"#,\n    )\n}\n\n#[test]\nfn assert() {\n    assert_js!(r#\"pub fn go(x) { let assert 1 = x }\"#,);\n}\n\n#[test]\nfn assert1() {\n    assert_js!(r#\"pub fn go(x) { let assert #(1, 2) = x }\"#,);\n}\n\n#[test]\nfn nested_binding() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert #(a, #(b, c, 2) as t, _, 1) = x\n}\n\"#,\n    )\n}\n\n#[test]\nfn variable_renaming() {\n    assert_js!(\n        r#\"\n\npub fn go(x, wibble) {\n  let a = 1\n  wibble(a)\n  let a = 2\n  wibble(a)\n  let assert #(a, 3) = x\n  let b = a\n  wibble(b)\n  let c = {\n    let a = a\n    #(a, b)\n  }\n  wibble(a)\n  // make sure arguments are counted in initial state\n  let x = c\n  x\n}\n\"#,\n    )\n}\n\n#[test]\nfn constant_assignments() {\n    assert_js!(\n        r#\"\nconst a = True\n\npub fn go() {\n  a\n  let a = 10\n  a + 20\n}\n\nfn second() {\n  let a = 10\n  a + 20\n}\n\"#,\n    );\n}\n\n#[test]\nfn returning_literal_subject() {\n    assert_js!(r#\"pub fn go(x) { let assert 1 = x + 1 }\"#,);\n}\n\n#[test]\nfn rebound_argument() {\n    assert_js!(\n        r#\"pub fn main(x) {\n  let x = False\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn rebound_function() {\n    assert_js!(\n        r#\"pub fn x() {\n  Nil\n}\n\npub fn main() {\n  let x = False\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn rebound_function_and_arg() {\n    assert_js!(\n        r#\"pub fn x() {\n  Nil\n}\n\npub fn main(x) {\n  let x = False\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn variable_used_in_pattern_and_assignment() {\n    assert_js!(\n        r#\"pub fn main(x) {\n  let #(x) = #(x)\n  x\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1253\n#[test]\nfn correct_variable_renaming_in_assigned_functions() {\n    assert_js!(\n        r#\"\npub fn debug(x) {\n  let x = x\n  fn(x) { x + 1 }\n}\n\"#,\n    );\n}\n\n#[test]\nfn module_const_var() {\n    assert_js!(\n        r#\"\npub const int = 42\npub const int_alias = int\npub fn use_int_alias() { int_alias }\n\npub const compound: #(Int, Int) = #(int, int_alias)\npub fn use_compound() { compound.0 + compound.1 }\n\"#\n    );\n}\n\n#[test]\nfn module_const_var1() {\n    assert_ts_def!(\n        r#\"\npub const int = 42\npub const int_alias = int\npub const compound: #(Int, Int) = #(int, int_alias)\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2443\n#[test]\nfn let_assert_string_prefix() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let assert \"Game \" <> id = \"Game 1\"\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3894\n#[test]\nfn let_assert_nested_string_prefix() {\n    assert_js!(\n        r#\"\ntype Wibble {\n  Wibble(wibble: String)\n}\n\npub fn main() {\n  let assert Wibble(wibble: \"w\" as prefix <> rest) = Wibble(\"wibble\")\n  prefix <> rest\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2931\n#[test]\nfn keyword_assignment() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let class = 10\n  let debugger = 50\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3004\n#[test]\nfn escaped_variables_in_constants() {\n    assert_js!(\n        r#\"\npub const class = 5\npub const something = class\n\"#\n    );\n}\n\n#[test]\nfn message() {\n    assert_js!(\n        r#\"\npub fn unwrap_or_panic(value) {\n  let assert Ok(inner) = value as \"Oops, there was an error\"\n  inner\n}\n\"#\n    );\n}\n\n#[test]\nfn variable_message() {\n    assert_js!(\n        r#\"\npub fn expect(value, message) {\n  let assert Ok(inner) = value as message\n  inner\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4471\n#[test]\nfn case_message() {\n    assert_js!(\n        r#\"\npub fn expect(value, message) {\n  let assert Ok(inner) = value as case message {\n    Ok(message) -> message\n    Error(_) -> \"No message provided\"\n  }\n  inner\n}\n\"#\n    );\n}\n\n#[test]\nfn assert_that_always_succeeds() {\n    assert_js!(\n        r#\"\ntype Wibble {\n    Wibble(Int)\n}\n\npub fn go() {\n  let assert Wibble(n) = Wibble(1)\n  n\n}\n\"#,\n    );\n}\n\n#[test]\nfn assert_that_always_fails() {\n    assert_js!(\n        r#\"\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n}\n\npub fn go() {\n  let assert Wobble(n) = Wibble(1)\n  n\n}\n\"#,\n    );\n}\n\n#[test]\nfn catch_all_assert() {\n    assert_js!(\n        r#\"\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n}\n\npub fn go() {\n  let assert _ = Wibble(1)\n  1\n}\n\"#,\n    );\n}\n\n#[test]\nfn assert_with_multiple_variants() {\n    assert_js!(\n        r#\"\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n    Woo(Int)\n}\n\npub fn go() {\n  let assert Wobble(n) = todo\n  n\n}\n\"#,\n    );\n}\n\n#[test]\nfn use_discard_assignment() {\n    assert_js!(\n        r#\"\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n    Woo(Int)\n}\n\nfn fun(f) { f(Wibble(1)) }\n\npub fn go() {\n  use _ <- fun\n  1\n}\n\"#,\n    );\n}\n\n#[test]\nfn use_matching_assignment() {\n    assert_js!(\n        r#\"\nfn fun(f) { f(#(2, 4)) }\n\npub fn go() {\n  use #(_, n) <- fun\n  n\n}\n\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/bit_arrays.rs",
    "content": "use hexpm::version::Version;\nuse pubgrub::Range;\n\nuse crate::{\n    assert_js, assert_js_no_warnings_with_gleam_version, assert_js_warnings_with_gleam_version,\n    assert_ts_def,\n};\n\n#[test]\nfn empty() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn one() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn two() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256, 4>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn integer() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256:int>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn float() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<1.1:float>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_big_endian() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<1.1:float-big>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_little_endian() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<1.1:float-little>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_sized() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<1.1:float-32>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_sized_big_endian() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<1.1:float-32-big>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_sized_little_endian() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<1.1:float-32-little>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_constant_value() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256:64>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_dynamic_value() {\n    assert_js!(\n        r#\"\npub fn go(i: Int) {\n  <<i:64>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_constant_value_positive_overflow() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<80_000:16>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_constant_value_negative_overflow() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<-80_000:16>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_constant_value_max_size_for_compile_time_evaluation() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<-1:48>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_big_endian_constant_value() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256:16-big>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_big_endian_dynamic_value() {\n    assert_js!(\n        r#\"\npub fn go(i: Int) {\n  <<i:16-big>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_little_endian_constant_value() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256:16-little>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn sized_little_endian_dynamic_value() {\n    assert_js!(\n        r#\"\npub fn go(i: Int) {\n  <<i:16-little>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn explicit_sized_constant_value() {\n    assert_js!(\n        r#\"\npub fn go() {\n  <<256:size(32)>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn explicit_sized_dynamic_value() {\n    assert_js!(\n        r#\"\npub fn go(i: Int) {\n  <<i:size(32)>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn variable_sized() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  <<x:size(y)>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn variable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  <<256, 4, x>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn utf8() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  <<256, 4, x, \"Gleam\":utf8>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_utf8_with_escape_chars() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<\"\\\"\\\\\\r\\n\\t\\f\\u{1f600}\">> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_utf8() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<\"Gleam 👍\":utf8>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_case_utf8_with_escape_chars() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<\"\\\"\\\\\\r\\n\\t\\f\\u{1f600}\">> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_case_utf8() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<\"Gleam 👍\":utf8>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn utf8_codepoint() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  <<x:utf8_codepoint, \"Gleam\":utf8>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn utf8_codepoint_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn go(x) {\n  <<x:utf8_codepoint, \"Gleam\":utf8>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn bit_string() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  <<x:bits>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn bits() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  <<x:bits>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn bit_array_sliced() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  <<<<0xAB>>:bits-4>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn bit_array_dynamic_slice() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let i = 4\n  <<<<0xAB>>:bits-size(i)>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn bit_string_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn go(x) {\n  <<x:bits>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn bits_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn go(x) {\n  <<x:bits>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn empty_match() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_empty_match() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_bytes() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1, y>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_bytes() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1, y>> -> y\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16, b:8>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16, b:8>> -> a + b\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_unaligned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:17, b:7>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_unaligned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:17, b:7>> -> b * 2\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16, 123:8>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16, 123:8>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_unsigned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:unsigned>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_unsigned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:unsigned>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_unsigned_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<-2:unsigned>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_unsigned_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<-2:unsigned>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_signed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:signed>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_signed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:signed>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_signed_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<-1:signed>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_signed_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<-1:signed>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_big_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16-big>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_big_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16-big>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_big_endian_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16-big>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_big_endian_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16-big>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16-little>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16-little>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_little_endian_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16-little>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_little_endian_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16-little>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_big_endian_unsigned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16-big-unsigned>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_big_endian_unsigned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16-big-unsigned>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_big_endian_unsigned_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16-big-unsigned>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_big_endian_unsigned_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16-big-unsigned>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_big_endian_signed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16-big-signed>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_big_endian_signed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16-big-signed>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_big_endian_signed_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16-big-signed>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_big_endian_signed_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16-big-signed>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_little_endian_unsigned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16-little-unsigned>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_little_endian_unsigned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16-little-unsigned>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_little_endian_unsigned_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16-little-unsigned>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_little_endian_unsigned_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16-little-unsigned>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_little_endian_signed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:16-little-signed>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_little_endian_signed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:16-little-signed>> -> a\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_little_endian_signed_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1234:16-little-signed>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_little_endian_signed_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1234:16-little-signed>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_dynamic_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  let assert <<a:size(n)>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_dynamic_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  case x {\n    <<a:size(n)>> -> a\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn match_dynamic_size_with_other_segments() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  let m = 32\n  let assert <<first:size(8), a:size(n), b:size(m), rest:bits>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_dynamic_size_with_other_segments() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  let m = 32\n  case x {\n    <<first:size(8), a:size(n), b:size(m), rest:bits>> -> first + a + b\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn match_dynamic_size_shadowed_variable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  let n = 5\n  let assert <<a:size(n)>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_dynamic_size_shadowed_variable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  let n = 5\n  case x {\n    <<a:size(n)>> -> a\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn match_dynamic_size_literal_value() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 8\n  let assert <<a:size(n), 0b010101:size(8)>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_dynamic_size_literal_value() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 8\n  case x {\n    <<a:size(n), 0b010101:size(8)>> -> a\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn match_dynamic_bits_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  let assert <<a:bits-size(n)>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_dynamic_bits_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 16\n  case x {\n    <<a:bits-size(n)>> -> a\n    _ -> x\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn match_dynamic_bytes_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 3\n  let assert <<a:bytes-size(n)>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_dynamic_bytes_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 3\n  case x {\n    <<a:bytes-size(n)>> -> a\n    _ -> x\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_sized() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_:16, _:8>> = x\n  let assert <<_:16-little-signed, _:8>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_discard_sized() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:16, _:8>> -> 1\n    _ -> 2\n  }\n  case x {\n    <<_:16-little-signed, _:8>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_value() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<i:16>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_value() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<i:16>> -> i\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_sized_value_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<258:16>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_sized_value_constant_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<258:16>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float_big_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float-big, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_float_big_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float-big, b:int>> -> #(a, b)\n    _ -> #(1.1, 1)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float-little, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_float_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float-little, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float_sized() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float-32, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_float_sized() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float-32, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float_sized_big_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float-32-big, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_float_sized_big_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float-32-big, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float_sized_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float-32-little, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_float_sized_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float-32-little, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_literal_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1.4, b:int>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_literal_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1.4, b:int>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_literal_unaligned_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 1\n  let assert <<_:size(n), 1.1, _:bits>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_literal_unaligned_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 1\n  case x {\n    <<_:size(n), 1.1, _:int>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_literal_aligned_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_, 1.1, _:bits>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_literal_aligned_float() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_, 1.1, _:int>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_float_16_bit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<a:float-size(16)>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn case_match_float_16_bit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<a:float-size(16)>> -> a\n    _ -> 1.1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn match_rest() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_, b:bytes>> = <<1,2,3>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_rest() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case <<1, 2, 3>> {\n    <<_, b:bytes>> -> b\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_bytes_with_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<f:bytes-2>> = <<1, 2>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_bytes_with_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case <<1, 2>> {\n    <<f:bytes-2>> -> f\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_bits_with_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_:4, f:bits-2, _:1>> = <<0x77:7>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_bits_with_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case <<0x77:7>> {\n    <<_:4, f:bits-2, _:1>> -> f\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_rest_bytes() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_, b:bytes>> = <<1,2,3>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_rest_bytes() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_, b:bytes>> -> b\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_rest_bits() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_, b:bits>> = <<1,2,3>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_rest_bits() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_, b:bits>> -> b\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_rest_bits_unaligned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_:5, b:bits>> = <<1,2,3>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_rest_bits_unaligned() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:5, b:bits>> -> b\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn match_binary_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<_, a:2-bytes>> = x\n  let assert <<_, b:bytes-size(2)>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_match_binary_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_, a:2-bytes>> -> a\n    _ -> x\n  }\n\n  case x {\n    <<_, b:bytes-size(2)>> -> b\n    _ -> x\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn unaligned_int_expression_requires_v1_9() {\n    assert_js_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        \"\npub fn main() {\n  <<0:1>>\n}\n  \",\n    );\n}\n\n#[test]\nfn bits_expression_does_not_require_v1_9() {\n    assert_js_no_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        \"\npub fn main() {\n  <<<<0>>:bits>>\n}\n  \",\n    );\n}\n\n#[test]\nfn sized_bits_expression_requires_v1_9() {\n    assert_js_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        \"\npub fn main() {\n  <<<<0>>:bits-5>>\n}\n  \",\n    );\n}\n\n#[test]\nfn unaligned_int_pattern_requires_v1_9() {\n    assert_js_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        \"\npub fn main() {\n  let assert <<_:3>> = <<0>>\n}\n  \",\n    );\n}\n\n#[test]\nfn bits_pattern_requires_v1_9() {\n    assert_js_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        \"\npub fn main() {\n  let assert <<_:bits>> = <<0>>\n}\n  \",\n    );\n}\n\n#[test]\nfn bytes_pattern_with_odd_size_does_not_require_v1_9() {\n    assert_js_no_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        \"\npub fn main() {\n  let assert <<_:bytes-3>> = <<0, 1, 2>>\n}\n  \",\n    );\n}\n\n#[test]\nfn sized_bits_expression_with_javascript_external_does_not_require_v1_9() {\n    assert_js_no_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        r#\"\n@external(javascript, \"test.mjs\", \"go\")\npub fn go() -> BitArray {\n  <<0:size(5)>>\n}\n  \"#,\n    );\n}\n\n#[test]\nfn bits_pattern_with_javascript_external_does_not_require_v1_9() {\n    assert_js_no_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 8, 0)),\n        r#\"\n@external(javascript, \"test.mjs\", \"go\")\npub fn go() -> BitArray {\n  let <<a:bits>> = <<>>\n  a\n}\n  \"#,\n    );\n}\n\n#[test]\nfn as_module_const() {\n    assert_js!(\n        r#\"\n          pub const data = <<\n            0x1,\n            2,\n            2:size(16),\n            0x4:size(32),\n            -1:32,\n            \"Gleam\":utf8,\n            4.2:float,\n            4.2:32-float,\n            <<0xFA>>:bits-6,\n            -1:64,\n            <<\n              <<1, 2, 3>>:bits,\n              \"Gleam\":utf8,\n              1024\n            >>:bits\n          >>\n        \"#\n    )\n}\n\n#[test]\nfn bit_array_literal_string_constant_is_treated_as_utf8() {\n    assert_js!(r#\"pub const a = <<\"hello\", \" \", \"world\">>\"#);\n}\n\n#[test]\nfn bit_array_literal_string_is_treated_as_utf8() {\n    assert_js!(\n        r#\"\npub fn main() {\n  <<\"hello\", \" \", \"world\">>\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_literal_string_pattern_is_treated_as_utf8() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case <<>> {\n    <<\"a\", \"b\", _:bytes>> -> 1\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn with_unit() {\n    assert_js!(\n        r#\"\npub fn main() {\n  <<1:size(2)-unit(2), 2:size(3)-unit(4)>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn dynamic_size_with_unit() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let size = 3\n  <<1:size(size)-unit(2)>>\n}\n\"#,\n    );\n}\n\n#[test]\nfn pattern_with_unit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<1:size(2)-unit(2), 2:size(3)-unit(4)>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_pattern_with_unit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<1:size(2)-unit(2), 2:size(3)-unit(4)>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn dynamic_size_pattern_with_unit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let size = 3\n  let assert <<1:size(size)-unit(2)>> = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_dynamic_size_pattern_with_unit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let size = 3\n  case x {\n    <<1:size(size)-unit(2)>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_dynamic_size_float_pattern_with_unit() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let size = 3\n  case x {\n    <<1.3:size(size)-unit(2)>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_with_remaining_bytes_after_constant_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_, _, _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_with_remaining_bytes_after_variable_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 1\n  case x {\n    <<_:size(n), _, _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_with_remaining_bytes_after_variable_size_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 1\n  case x {\n    <<m:size(n), _:size(m), _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_is_byte_aligned() {\n    assert_js!(\n        r#\"\npub fn is_byte_aligned(x) {\n  case x {\n    <<_:bytes>> -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn alternative_patterns_with_variable_size() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_, n, rest:size(n)>> |\n    <<n, _, rest:size(n)>> -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn variable_sized_segment() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<n, rest:size(n)>> -> 1\n    _ -> 2\n  }\n}\n\"#\n    )\n}\n\n#[test]\nfn segments_shadowing_each_other() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = 1\n  case x {\n    <<n, rest:size(n)>> -> 1\n    _ -> 2\n  }\n}\n\"#\n    )\n}\n\n#[test]\nfn negative_size_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let n = -10\n  case x {\n    <<int:size(n)>> -> int\n    _ -> 2\n  }\n}\n\"#\n    )\n}\n\n#[test]\nfn negative_size_pattern_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<n:signed, int:size(n)>> -> int\n    _ -> 2\n  }\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_int() {\n    assert_js!(\n        \"\npub fn main() {\n let assert <<1 as a>> = <<1>>\n a\n}\n\"\n    );\n}\n\n#[test]\nfn case_bit_array_assignment_int() {\n    assert_js!(\n        \"\npub fn go(x) {\n case x {\n    <<1 as n>>\n    | <<2 as n, _:bytes>> -> n\n    _ -> 1\n }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_float() {\n    assert_js!(\n        \"\npub fn main() {\n let assert <<3.14 as pi:float>> = <<3.14>>\n pi\n}\n\"\n    );\n}\n\n#[test]\nfn case_bit_array_assignment_float() {\n    assert_js!(\n        \"\npub fn go(x) {\n case x {\n    <<3.14 as pi:float>>\n    | <<1.1 as pi:float, _:bytes>> -> pi\n    _ -> 1.1\n }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_string() {\n    assert_js!(\n        r#\"\npub fn main() {\n let assert <<\"Hello, world!\" as message:utf8>> = <<\"Hello, world!\">>\n message\n}\n\"#\n    );\n}\n\n#[test]\nfn case_bit_array_assignment_string() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n case x {\n    <<\"Hello\" as message>>\n    | <<\"Jak\" as message, _:bytes>> -> message\n    _ -> \"wibble\"\n }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\n#[test]\nfn bit_array_assignment_discard() {\n    assert_js!(\n        r#\"\npub fn main() {\n let assert <<_ as number>> = <<10>>\n number\n}\n\"#\n    );\n}\n\n#[test]\nfn case_bit_array_assignment_discard() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n case x {\n    <<_ as n>>\n    | <<_ as n, _:bytes>> -> n\n    _ -> 1\n }\n}\n\"#\n    );\n}\n\n#[test]\nfn utf16() {\n    assert_js!(\n        r#\"\npub fn main() {\n  <<\"Hello, world!\":utf16>>\n}\n\"#\n    );\n}\n\n#[test]\nfn utf16_codepoint() {\n    assert_js!(\n        r#\"\nfn codepoint() -> UtfCodepoint { todo }\n\npub fn main() {\n  let my_codepoint = codepoint()\n  <<my_codepoint:utf16_codepoint>>\n}\n\"#\n    );\n}\n\n#[test]\nfn utf32() {\n    assert_js!(\n        r#\"\npub fn main() {\n  <<\"Hello, world!\":utf32>>\n}\n\"#\n    );\n}\n\n#[test]\nfn utf32_codepoint() {\n    assert_js!(\n        r#\"\nfn codepoint() -> UtfCodepoint { todo }\n\npub fn main() {\n  let my_codepoint = codepoint()\n  <<my_codepoint:utf32_codepoint>>\n}\n\"#\n    );\n}\n\n#[test]\nfn const_utf16() {\n    assert_js!(\n        r#\"\npub const message = <<\"Hello, world!\":utf16>>\n\"#\n    );\n}\n\n#[test]\nfn const_utf32() {\n    assert_js!(\n        r#\"\npub const message = <<\"Hello, world!\":utf32>>\n\"#\n    );\n}\n\n#[test]\nfn pattern_match_utf16() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<\"Hello\":utf16, _rest:bytes>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_match_utf32() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<\"Hello\":utf32, _rest:bytes>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn utf16_little_endian() {\n    assert_js!(\n        r#\"\npub fn main() {\n  <<\"Hello, world!\":utf16-little>>\n}\n\"#\n    );\n}\n\n#[test]\nfn utf32_little_endian() {\n    assert_js!(\n        r#\"\npub fn main() {\n  <<\"Hello, world!\":utf32-little>>\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_match_utf16_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<\"Hello\":utf16-little, _rest:bytes>> = x\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_match_utf32_little_endian() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert <<\"Hello\":utf32-little, _rest:bytes>> = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4630\n#[test]\nfn tuple_bit_array() {\n    assert_js!(\n        \"\npub fn go(x) {\n  let assert #(<<>>) = x\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4630\n#[test]\nfn tuple_bit_array_case() {\n    assert_js!(\n        \"\npub fn go(x) {\n  case x {\n    #(<<>>) -> 1\n    _ -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn tuple_multiple_bit_arrays() {\n    assert_js!(\n        \"\npub fn go(x) {\n  let assert #(<<>>, <<1>>, <<2, 3>>) = x\n}\n\"\n    );\n}\n\n#[test]\nfn tuple_multiple_bit_arrays_case() {\n    assert_js!(\n        \"\npub fn go(x) {\n  case x {\n    #(<<>>, <<1>>, <<2, 3>>) -> True\n    _ -> False\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4637\n#[test]\nfn pattern_matching_on_32_float_plus_infinity_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7f800000:32>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_plus_infinity_still_reachable_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7f80:16, 0x0000:16>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_minus_infinity_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0xff800000:32>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_minus_infinity_still_reachable_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0xff80:16, 0x0000:16>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_nan_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7fc00000:32>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_nan_still_reachable_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7fc0:16, 0x0000:16>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_plus_infinity_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff0000000000000:64>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_plus_infinity_still_reachable_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff00000:32, 0x00000000:32>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_minus_infinity_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0xfff0000000000000:64>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_minus_infinity_still_reachable_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0xfff00000:32, 0x00000000:32>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_nan_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff8000000000000:64>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_nan_still_reachable_2() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff80000:32, 0x00000000:32>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_int_is_still_reachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-int>> -> \"Int\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_float_is_unreachable() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-float>> -> \"unreachable\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn unit_with_bits_option() {\n    assert_js!(\n        \"\npub fn go(x) {\n  <<x:bits-size(4)-unit(8)>>\n}\n\"\n    );\n}\n\n#[test]\nfn unit_with_bits_option_constant() {\n    assert_js!(\n        \"\npub const bits = <<1, 2, 3>>\npub const more_bits = <<bits:bits-size(3)-unit(8)>>\n\"\n    );\n}\n\n#[test]\nfn operator_in_size_for_bit_array_segment() {\n    assert_js!(\n        \"\npub fn go(x) {\n  <<x:bits-size(4 + 1)>>\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4712\n#[test]\nfn multiple_variable_size_segments() {\n    assert_js!(\n        \"\npub fn main() {\n  let assert <<a, b:size(a), c:size(b)>> = <<1, 2, 3, 4>>\n  a + b + c\n}\n\"\n    );\n}\n\n#[test]\nfn utf16_codepoint_little_endian() {\n    assert_js!(\n        \"\npub fn go(codepoint) {\n  <<codepoint:utf16_codepoint-little>>\n}\n\"\n    );\n}\n\n#[test]\nfn utf32_codepoint_little_endian() {\n    assert_js!(\n        \"\npub fn go(codepoint) {\n  <<codepoint:utf32_codepoint-little>>\n}\n\"\n    );\n}\n\n#[test]\nfn operator_in_pattern_size() {\n    assert_js!(\n        \"\npub fn main() {\n  let assert <<len, payload:size(len * 8)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn operator_in_pattern_size2() {\n    assert_js!(\n        \"\npub fn main() {\n  let assert <<len, payload:size(len / 8 - 1)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn operator_in_pattern_size3() {\n    assert_js!(\n        \"\npub fn main() {\n  let additional = 10\n  let assert <<len, payload:size(len + additional * 8)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn block_in_pattern_size() {\n    assert_js!(\n        \"\npub fn main() {\n  let assert <<len, payload:size({ len - 1 } * 8)>> = <<>>\n}\n\"\n    );\n}\n\n#[test]\nfn non_byte_aligned_size_calculation() {\n    assert_js!(\n        \"\npub fn main() {\n  case <<>> {\n    <<a:1, b:3, c:size(b - 2)>> -> c + b\n    _ -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn pattern_match_on_negative_size_calculation() {\n    assert_js!(\n        \"\npub fn main() {\n  let assert <<a, b:size(a - 100000), c:size(b)>> = <<1, 2, 3, 4, 5>>\n}\n\"\n    );\n}\n\n#[test]\nfn pattern_match_unknown_size_and_literal_string() {\n    assert_js!(\n        r#\"\npub fn go(x, n) {\n  case x {\n    <<_:size(n), \"\\r\\n\">> -> 1\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_match_size_arithmetic() {\n    assert_js!(\n        r#\"\npub fn wibble(bits, wobble) {\n  case bits {\n    <<_:size(1), _:size(wobble - 1), _:bits>> -> 0\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_pattern_match_all_reachable() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n    case x {\n    <<_, \"==\">> -> 1\n    <<_, _, \"=\">> -> 2\n    // ^^^ This should be reachable\n    _ -> 3\n    }\n}\n        \"#\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/blocks.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn block() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = {\n    1\n    2\n  }\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn nested_simple_blocks() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = {\n    {\n      3\n    }\n  }\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn nested_multiexpr_blocks() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      3\n    }\n  }\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn nested_multiexpr_blocks_with_pipe() {\n    assert_js!(\n        r#\"\npub fn add1(a) {\n  a + 1\n}\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      3 |> add1\n    } |> add1\n  }\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn nested_multiexpr_non_ending_blocks() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      3\n    }\n    4\n  }\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn nested_multiexpr_blocks_with_case() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      case True {\n        _ -> 3\n      }\n    }\n  }\n  x\n}\n\"#,\n    );\n}\n\n#[test]\nfn sequences() {\n    assert_js!(\n        r#\"\npub fn go() {\n  \"one\"\n  \"two\"\n  \"three\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn left_operator_sequence() {\n    assert_js!(\n        r#\"\npub fn go() {\n  1 == {\n    1\n    2\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn right_operator_sequence() {\n    assert_js!(\n        r#\"\npub fn go() {\n  {\n    1\n    2\n  } == 1\n}\n\"#,\n    );\n}\n\n#[test]\nfn concat_blocks() {\n    assert_js!(\n        r#\"\npub fn main(f, a, b) {\n  {\n    a\n    |> f\n  } <> {\n    b\n    |> f\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn blocks_returning_functions() {\n    assert_js!(\n        r#\"\npub fn b() {\n  {\n    fn(cb) { cb(1) }\n  }\n  {\n    fn(cb) { cb(2) }\n  }\n  3\n}\n\"#\n    );\n}\n\n#[test]\nfn blocks_returning_use() {\n    assert_js!(\n        r#\"\npub fn b() {\n  {\n    use a <- fn(cb) { cb(1) }\n    a\n  }\n  {\n    use b <- fn(cb) { cb(2) }\n    b\n  }\n  3\n}\n    \"#\n    );\n}\n\n#[test]\nfn block_with_parenthesised_expression_returning_from_function() {\n    assert_js!(\n        r#\"\npub fn b() {\n  {\n    1 + 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn block_in_tail_position_is_not_an_iife() {\n    assert_js!(\n        r#\"\npub fn b() {\n  let x = 1\n  {\n    Nil\n    x + 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn block_in_tail_position_shadowing_variables() {\n    assert_js!(\n        r#\"\npub fn b() {\n  let x = 1\n  {\n    let x = 2\n    x + 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn block_in_tail_position_with_just_an_assignment() {\n    assert_js!(\n        r#\"\npub fn b() {\n  let x = 1\n  {\n    let x = x\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn shadowed_variable_in_nested_scope() {\n    assert_js!(\n        \"\npub fn main() {\n  {\n    let x = 1\n    let _ = {\n      let x = 2\n      x\n    }\n    x\n  }\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/4393\n#[test]\nfn let_assert_only_statement_in_block() {\n    assert_js!(\n        \"\npub fn main() {\n  {\n    let assert Ok(1) = Error(Nil)\n  }\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/4394\n#[test]\nfn assignment_last_in_block() {\n    assert_js!(\n        \"\npub fn main() {\n  let a = {\n    let b = 1\n    let c = b + 1\n  }\n  a\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/4394\n#[test]\nfn pattern_assignment_last_in_block() {\n    assert_js!(\n        \"\npub fn main() {\n  let a = {\n    let b = #(1, 2)\n    let #(x, y) = b\n  }\n  a\n}\n\"\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/4395\n#[test]\nfn let_assert_message_no_lifted() {\n    assert_js!(\n        r#\"\nfn side_effects(x) {\n  // Some side effects\n  x\n}\n\npub fn main() {\n  let assert Error(Nil) = side_effects(Ok(10))\n    as {\n    let message = side_effects(\"some message\")\n    message\n  }\n}\n\"#\n    )\n}\n\n#[test]\nfn blocks_whose_values_are_unused_do_not_generate_assignments() {\n    // There's no point generating `_block` assignments here, as the values\n    // would be unused.\n    assert_js!(\n        \"\npub fn main() {\n  {\n    let x = 10\n    echo x\n  }\n\n  {\n    let a = 1\n    let b = 2\n    a + b\n  }\n\n  Nil\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/bools.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn expressions() {\n    assert_js!(\n        r#\"\npub fn go() {\n    True\n    False\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn constants() {\n    assert_js!(\n        r#\"\npub const a = True\npub const b = False\npub const c = Nil\n\"#,\n    );\n}\n\n#[test]\nfn constants_typescript() {\n    assert_ts_def!(\n        r#\"\npub const a = True\npub const b = False\npub const c = Nil\n\"#,\n    );\n}\n\n#[test]\nfn operators() {\n    assert_js!(\n        r#\"\npub fn go() {\n    True && True\n    False || False\n}\n\"#,\n    );\n}\n\n#[test]\nfn assigning() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  let assert True = x\n  let assert False = x\n  let assert Nil = y\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1112\n// differentiate between prelude constructors and custom type constructors\n#[test]\nfn shadowed_bools_and_nil() {\n    assert_js!(\n        r#\"\npub type True { True False Nil }\npub fn go(x, y) {\n  let assert True = x\n  let assert False = x\n  let assert Nil = y\n}\n\"#,\n    );\n}\n\n#[test]\nfn shadowed_bools_and_nil_typescript() {\n    assert_ts_def!(\n        r#\"\npub type True { True False Nil }\npub fn go(x, y) {\n  let assert True = x\n  let assert False = x\n  let assert Nil = y\n}\n\"#,\n    );\n}\n\n#[test]\nfn equality() {\n    assert_js!(\n        r#\"\npub fn go(a, b) {\n  a == True\n  a != True\n  a == False\n  a != False\n  a == a\n  a != a\n  b == Nil\n  b != Nil\n  b == b\n}\n\"#,\n    );\n}\n\n#[test]\nfn case() {\n    assert_js!(\n        r#\"\npub fn go(a) {\n  case a {\n    True -> 1\n    False -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn nil_case() {\n    assert_js!(\n        r#\"\npub fn go(a) {\n  case a {\n    Nil -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn negation() {\n    assert_js!(\n        \"pub fn negate(x) {\n    !x\n}\"\n    );\n}\n\n#[test]\nfn negation_block() {\n    assert_js!(\n        \"pub fn negate(x) {\n  !{\n    123\n    x\n  }\n}\"\n    );\n}\n\n#[test]\nfn binop_panic_right() {\n    assert_js!(\n        \"pub fn negate(x) {\n    x && panic\n}\"\n    );\n}\n\n#[test]\nfn binop_panic_left() {\n    assert_js!(\n        \"pub fn negate(x) {\n    panic && x\n}\"\n    );\n}\n\n#[test]\nfn binop_todo_right() {\n    assert_js!(\n        \"pub fn negate(x) {\n    x && todo\n}\"\n    );\n}\n\n#[test]\nfn binop_todo_left() {\n    assert_js!(\n        \"pub fn negate(x) {\n    todo && x\n}\"\n    );\n}\n\n#[test]\nfn negate_panic() {\n    assert_js!(\n        \"pub fn negate(x) {\n  !panic\n}\"\n    );\n}\n\n#[test]\nfn negate_todo() {\n    assert_js!(\n        \"pub fn negate(x) {\n  !todo\n}\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/case.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn case_on_error() {\n    assert_js!(\n        r#\"\nfn a_result() { Error(1) }\n\npub fn main() {\n  case a_result() {\n    Error(_) -> 1\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn tuple_and_guard() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case #(1, 2) {\n    #(1, a) if a == 2 -> 1\n    #(_, _) -> 2\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn guard_variable_only_brought_into_scope_when_needed() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    // We want `a` to be defined before the guard check, and\n    // `b` to be defined only if the predicate on a matches!\n    [a, b] if a == 1 -> a + b\n    _ -> 2\n  }\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/4221\n#[test]\nfn guard_variable_only_brought_into_scope_when_needed_1() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case 1 {\n    i if i == 1 -> True\n    i if i < 2 -> True\n    _ -> False\n  }\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1187\n#[test]\nfn pointless() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    _ -> x\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1188\n#[test]\nfn following_todo() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    True -> todo\n    _ -> 1\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn multi_subject_catch_all() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  case x, y {\n    True, True -> 1\n    _, _ -> 0\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn multi_subject_or() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  case x, y {\n    True, _ | _, True -> 1\n    _, _ -> 0\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn multi_subject_no_catch_all() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  case x, y {\n    True, _ -> 1\n    _, True -> 2\n    False, False -> 0\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn multi_subject_subject_assignments() {\n    assert_js!(\n        r#\"\npub fn go() {\n  case True, False {\n    True, True -> 1\n    _, _ -> 0\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn assignment() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let y = case x {\n    True -> 1\n    _ -> 0\n  }\n  y\n}\n\"#,\n    )\n}\n\n#[test]\nfn preassign_assignment() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let y = case x() {\n    True -> 1\n    _ -> 0\n  }\n  y\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1237\n#[test]\nfn pipe() {\n    assert_js!(\n        r#\"\npub fn go(x, f) {\n  case x |> f {\n    0 -> 1\n    _ -> 2\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn result() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    Ok(_) -> 1\n    Error(_) -> 0\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1506\n#[test]\nfn called_case() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  case x {\n    0 -> y\n    _ -> y\n  }()\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/1978\n#[test]\nfn case_local_var_in_tuple() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  let z = False\n  case True {\n    x if #(x, z) == #(True, False) -> x\n    _ -> False\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2665\n#[test]\nfn case_branches_guards_are_wrapped_in_parentheses() {\n    assert_js!(\n        r#\"\npub fn anything() -> a {\n  case [] {\n    [a] if False || True -> a\n    _ -> anything()\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2759\n#[test]\nfn nested_string_prefix_match() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case Ok([\"a\", \"b c\", \"d\"]) {\n    Ok([\"a\", \"b \" <> _, \"d\"]) -> 1\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2759\n#[test]\nfn nested_string_prefix_match_that_would_crash_on_js() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case Ok([\"b c\", \"d\"]) {\n    Ok([\"b \" <> _, \"d\"]) -> 1\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn slicing_is_handled_properly_with_multiple_branches() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case \"12345\" {\n    \"0\" <> rest -> rest\n    \"123\" <> rest -> rest\n    _ -> \"\"\n  }\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3379\n#[test]\nfn single_clause_variables() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let text = \"first defined\"\n  case \"defined again\" {\n    text -> Nil\n  }\n  let text = \"a third time\"\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3379\n#[test]\nfn single_clause_variables_assigned() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let text = \"first defined\"\n  let other = case \"defined again\" {\n    text -> Nil\n  }\n  let text = \"a third time\"\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3894\n#[test]\nfn nested_string_prefix_assignment() {\n    assert_js!(\n        r#\"\ntype Wibble {\n  Wibble(wobble: String)\n}\n\npub fn main() {\n  let tmp = Wibble(wobble: \"wibble\")\n  case tmp {\n    Wibble(wobble: \"w\" as wibble <> rest) -> wibble <> rest\n    _ -> panic\n  }\n}\n\"#\n    )\n}\n\n#[test]\nfn deeply_nested_string_prefix_assignment() {\n    assert_js!(\n        r#\"\ntype Wibble {\n  Wibble(Wobble)\n}\ntype Wobble {\n  Wobble(wabble: Wabble)\n}\ntype Wabble {\n  Wabble(tuple: #(Int, String))\n}\n\npub fn main() {\n  let tmp = Wibble(Wobble(Wabble(#(42, \"wibble\"))))\n  case tmp {\n    Wibble(Wobble(Wabble(#(_int, \"w\" as wibble <> rest)))) -> wibble <> rest\n    _ -> panic\n  }\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/4383\n#[test]\nfn record_update_in_pipeline_in_case_clause() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int)\n}\n\nfn identity(x) {\n  x\n}\n\npub fn go(x) {\n  case x {\n    Wibble(1, _) -> Wibble(..x, wibble: 4) |> identity\n    Wibble(_, 3) -> Wibble(..x, wobble: 10) |> identity\n    _ -> panic\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_aliased_result_constructor() {\n    assert_js!(\n        \"\nimport gleam.{Error as E, Ok as O}\n\npub fn go(x) {\n  case x {\n    E(_) -> 1\n    O(_) -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_with_guard() {\n    assert_js!(\n        \"\npub fn go(x) {\n  case x {\n    [] -> 0\n    [first, ..] if first < 10 -> first * 2\n    [first, ..] -> first\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_with_guard_no_binding() {\n    assert_js!(\n        \"\npub fn go(x) {\n  case x {\n    [] -> 0\n    [first, ..] if 1 < 10 -> first * 2\n    [first, ..] -> first\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn case_building_simple_value_matched_by_pattern() {\n    assert_js!(\n        \"pub fn go(x) {\n   case x {\n     1 -> 2\n     n -> n\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_list_matched_by_pattern() {\n    assert_js!(\n        \"pub fn go(x) {\n   case x {\n     [] -> []\n     [a, b] -> [a, b]\n     [1, ..rest] -> [1, ..rest]\n     _ -> x\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_matched_by_pattern() {\n    assert_js!(\n        \"pub fn go(x) {\n   case x {\n     Ok(1) -> Ok(1)\n     Ok(n) -> Ok(n)\n     Error(_) -> Error(Nil)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_select_matched_by_pattern() {\n    assert_js!(\n        \"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(1) -> gleam.Ok(1)\n     _ -> Error(Nil)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_select_matched_by_pattern_2() {\n    assert_js!(\n        \"\nimport gleam\n\npub fn go(x) {\n   case x {\n     gleam.Ok(1) -> gleam.Ok(1)\n     _ -> Error(Nil)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_select_matched_by_pattern_3() {\n    assert_js!(\n        \"\nimport gleam\n\npub fn go(x) {\n   case x {\n     gleam.Ok(1) -> Ok(1)\n     _ -> Error(Nil)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_matched_string_1() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     \"a\" <> rest -> \"a\" <> rest\n     _ -> \"\"\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_string_2() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     \"a\" as a <> rest -> a <> rest\n     _ -> \"\"\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_value_wrapped_in_block() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     1 -> { 1 }\n     _ -> 2\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_value_alias() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(_) as a -> a\n     Error(Nil) -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_value_alias_2() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(1) as a -> Ok(1)\n     Ok(_) -> Ok(2)\n     Error(Nil) -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_value_alias_3() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(1 as a) -> Ok(a)\n     Ok(_) -> Ok(2)\n     Error(Nil) -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_no_variant_record() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n   case x {\n     Ok(Nil) -> Ok(Nil)\n     _ -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_no_variant_record_2() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(gleam.Nil) -> Ok(Nil)\n     _ -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_no_variant_record_3() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(Nil) -> Ok(gleam.Nil)\n     _ -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_matched_no_variant_record_4() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(gleam.Nil) -> Ok(gleam.Nil)\n     _ -> Error(Nil)\n   }\n}\"#\n    )\n}\n\n#[test]\nfn case_building_record_with_labels_matched_by_pattern_1() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(1, s) -> Wibble(1, s)\n     _ -> Wobble(1)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_labels_matched_by_pattern_2() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(string:, int:) -> Wibble(string:, int:)\n     _ -> Wobble(1)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_labels_matched_by_pattern_3() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     // This should not be optimised away!\n     Wibble(string:, int:) -> Wibble(string:, int: 1)\n     _ -> Wobble(1)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_labels_matched_by_pattern_4() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(string:, int:) -> Wibble(int:, string:)\n     _ -> Wobble(1)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_labels_matched_by_pattern_5() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(string:, int: 1) -> Wibble(1, string:)\n     _ -> Wobble(1)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_building_record_with_labels_matched_by_pattern_6() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(1, string:) -> Wibble(string:, int: 1)\n     _ -> Wobble(1)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_with_multiple_subjects_building_simple_value_matched_by_pattern() {\n    assert_js!(\n        \"pub fn go(x) {\n   case x, x + 1 {\n     1, _ -> 2\n     _, n -> n\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_with_multiple_subjects_building_list_matched_by_pattern() {\n    assert_js!(\n        \"pub fn go(n, x) {\n   case n, x {\n     1, [] -> []\n     _, [a, b] -> [a, b]\n     3, [1, ..rest] -> [1, ..rest]\n     _, _ -> x\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_with_multiple_subjects_building_record_matched_by_pattern() {\n    assert_js!(\n        \"pub fn go(x, y) {\n   case x, y {\n     Ok(1), Error(_) -> Ok(1)\n     Error(_), Ok(n) -> Ok(n)\n     _, _ -> Error(Nil)\n   }\n}\"\n    )\n}\n\n#[test]\nfn case_with_multiple_subjects_building_same_value_as_two_subjects_one_is_picked() {\n    assert_js!(\n        \"\nimport gleam\n\npub fn go(x, y) {\n   case x, y {\n     gleam.Ok(1), Ok(1) -> Ok(1)\n     _, Error(Nil) -> Error(Nil)\n     _, _ -> Error(Nil)\n   }\n}\"\n    )\n}\n\n#[test]\nfn interfering_string_pattern_succeeds_if_succeeding() {\n    assert_js!(\n        r#\"\npub fn wibble(bits) {\n  case bits {\n    <<\"aaa\", 0, _:bits>> -> 1\n    // If the first one succeeds, so will the second check, so it won't be\n    // performed twice inside the first if branch!\n    <<\"aaa\", 1, _:bits>> -> 2\n    _ -> 3\n  }\n}\"#\n    );\n}\n\n#[test]\nfn string_concatenation_in_clause_guards() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let wibble = \"wob\"\n  case wibble {\n    x if x <> \"ble\" == \"wobble\" -> 1\n    _ -> 0\n  }\n}\"#\n    );\n}\n\n#[test]\nfn var_true() {\n    assert_js!(\n        r#\"\nfn true() { True }\npub fn main() {\n    let true_ = true()\n    assert 0 == case Nil {\n        _ if true_ -> 0\n        _ -> 1\n    }\n}\n\"#\n    )\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/5283\nfn duplicate_name_for_variables_used_in_guards() {\n    assert_js!(\n        r#\"\npub fn wibble() {\n  let a = case 1337 {\n    n if n == 1347 -> Nil\n    _ -> Nil\n  }\n  let b = case 1337 {\n    n -> Nil\n  }\n}\"#\n    )\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/5283\nfn duplicate_name_for_variables_used_in_guards_shadowing_outer_name() {\n    assert_js!(\n        r#\"\npub fn wibble() {\n  let n = 1\n  let a = case 1337 {\n    n if n == 1347 -> n\n    _ -> n\n  }\n  let b = case 1337 {\n    n -> Nil\n  }\n}\"#\n    )\n}\n\n#[test]\nfn directly_matching_case_subject() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = \"ABC\"\n  case True {\n    True -> {\n      let x = 79\n      0\n    }\n    False -> {\n      let x = True\n      0\n    }\n  }\n  x\n}\"#\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/case_clause_guards.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn referencing_pattern_var() {\n    assert_js!(\n        r#\"pub fn main(xs) {\n  case xs {\n    #(x) if x -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn rebound_var() {\n    assert_js!(\n        r#\"pub fn main() {\n  let x = False\n  let x = True\n  case x {\n    _ if x -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn bitarray_with_var() {\n    assert_js!(\n        r#\"pub fn main() {\n  case 5 {\n    z if <<z>> == <<z>> -> Nil\n    _ -> Nil\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/3004\n#[test]\nfn keyword_var() {\n    assert_js!(\n        r#\"\npub const function = 5\npub const do = 10\npub fn main() {\n  let class = 5\n  let while = 10\n  let var = 7\n  case var {\n    _ if class == while -> True\n    _ if [class] == [5] -> True\n    function if #(function) == #(5) -> False\n    _ if do == function -> True\n    while if while > 5 -> False\n    class -> False\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn operator_wrapping_right() {\n    assert_js!(\n        r#\"pub fn main(xs, y: Bool, z: Bool) {\n  case xs {\n    #(x) if x == { y == z } -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn operator_wrapping_left() {\n    assert_js!(\n        r#\"pub fn main(xs, y: Bool, z: Bool) {\n  case xs {\n    #(x) if { x == y } == z -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn eq_scalar() {\n    assert_js!(\n        r#\"pub fn main(xs, y: Int) {\n  case xs {\n    #(x) if x == y -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn not_eq_scalar() {\n    assert_js!(\n        r#\"pub fn main(xs, y: Int) {\n  case xs {\n    #(x) if x != y -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn tuple_index() {\n    assert_js!(\n        r#\"pub fn main(x, xs: #(Bool, Bool, Bool)) {\n  case x {\n    _ if xs.2 -> 1\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn not_eq_complex() {\n    assert_js!(\n        r#\"pub fn main(xs, y) {\n  case xs {\n    #(x) if xs != y -> x\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn eq_complex() {\n    assert_js!(\n        r#\"pub fn main(xs, y) {\n  case xs {\n    #(x) if xs == y -> x\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn constant() {\n    assert_js!(\n        r#\"pub fn main(xs) {\n  case xs {\n    #(x) if x == 1 -> x\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn alternative_patterns() {\n    assert_js!(\n        r#\"pub fn main(xs) {\n  case xs {\n    1 | 2 -> 0\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn alternative_patterns_list() {\n    assert_js!(\n        r#\"pub fn main(xs) -> Int {\n  case xs {\n    [1] | [1, 2] -> 0\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn alternative_patterns_assignment() {\n    assert_js!(\n        r#\"pub fn main(xs) -> Int {\n  case xs {\n    [x] | [_, x] -> x\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn alternative_patterns_guard() {\n    assert_js!(\n        r#\"pub fn main(xs) -> Int {\n  case xs {\n    [x] | [_, x] if x == 1 -> x\n    _ -> 0\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn field_access() {\n    assert_js!(\n        r#\"\n        pub type Person {\n          Person(username: String, name: String, age: Int)\n        }\n        pub fn main() {\n          let given_name = \"jack\"\n          let raiden = Person(\"raiden\", \"jack\", 31)\n          case given_name {\n            name if name == raiden.name -> \"It's jack\"\n            _ -> \"It's not jack\"\n          }\n        }\n        \"#\n    )\n}\n\n#[test]\nfn nested_record_access() {\n    assert_js!(\n        r#\"\npub type A {\n  A(b: B)\n}\n\npub type B {\n  B(c: C)\n}\n\npub type C {\n  C(d: Bool)\n}\n\npub fn a(a: A) {\n  case a {\n    _ if a.b.c.d -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn module_string_access() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub const ironman = \"Tony Stark\"\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_list_access() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub const heroes = [\"Tony Stark\", \"Bruce Wayne\"]\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let names = [\"Tony Stark\", \"Bruce Wayne\"]\n            case names {\n              n if n == hero.heroes -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_tuple_access() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub const hero = #(\"ironman\", \"Tony Stark\")\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.hero.1 -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_access() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub type Hero {\n                Hero(name: String)\n              }\n              pub const ironman = Hero(\"Tony Stark\")\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman.name -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_access_submodule() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero/submodule\",\n            r#\"\n              pub type Hero {\n                Hero(name: String)\n              }\n              pub const ironman = Hero(\"Tony Stark\")\n            \"#\n        ),\n        r#\"\n          import hero/submodule\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == submodule.ironman.name -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_access_aliased() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero/submodule\",\n            r#\"\n              pub type Hero {\n                Hero(name: String)\n              }\n              pub const ironman = Hero(\"Tony Stark\")\n            \"#\n        ),\n        r#\"\n          import hero/submodule as myhero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == myhero.ironman.name -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn module_nested_access() {\n    assert_js!(\n        (\n            \"package\",\n            \"hero\",\n            r#\"\n              pub type Person {\n                Person(name: String)\n              }\n              pub type Hero {\n                Hero(secret_identity: Person)\n              }\n              const bruce = Person(\"Bruce Wayne\")\n              pub const batman = Hero(bruce)\n            \"#\n        ),\n        r#\"\n          import hero\n          pub fn main() {\n            let name = \"Bruce Wayne\"\n            case name {\n              n if n == hero.batman.secret_identity.name -> True\n              _ -> False\n            }\n          }\n        \"#\n    );\n}\n\n#[test]\nfn not() {\n    assert_js!(\n        r#\"pub fn main(x, y) {\n  case x {\n    _ if !y -> 0\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn not_two() {\n    assert_js!(\n        r#\"pub fn main(x, y) {\n  case x {\n    _ if !y && !x -> 0\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn custom_type_constructor_imported_and_aliased() {\n    assert_js!(\n        (\"package\", \"other_module\", \"pub type T { A }\"),\n        r#\"import other_module.{A as B}\npub fn func() {\n  case B {\n    x if x == B -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn imported_aliased_ok() {\n    assert_js!(\n        r#\"import gleam.{Ok as Y}\npub type X {\n  Ok\n}\npub fn func() {\n  case Y {\n    y if y == Y -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn imported_ok() {\n    assert_js!(\n        r#\"import gleam\npub type X {\n  Ok\n}\npub fn func(x) {\n  case gleam.Ok {\n    _ if [] == [ gleam.Ok ] -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n// Variant of https://github.com/lpil/decode/pull/6\n#[test]\nfn constructor_function_in_guard() {\n    assert_js!(\n        r#\"pub fn func(x) {\n    case [] {\n        _ if [] == [ Ok ] -> True\n        _ -> False\n    }\n}\n    \"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4241\n#[test]\nfn int_division() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case 5 / 2 {\n    x if x == 5 / 2 -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4241\n#[test]\nfn float_division() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case 5.1 /. 0.0 {\n    x if x == 5.1 /. 0.0 -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4241\n#[test]\nfn int_remainder() {\n    assert_js!(\n        r#\"\npub fn main() {\n  case 4 % 0 {\n    x if x == 4 % 0 -> True\n    _ -> False\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5094\n#[test]\nfn guard_pattern_does_not_shadow_outer_scope() {\n    assert_js!(\n        r#\"\npub type Option(a) {\n  Some(a)\n  None\n}\n\npub type Container {\n  Container(x: Option(Int))\n}\n\npub fn main() {\n  let x: Option(Int) = Some(42)\n  case Some(1) {\n    Some(x) if x < 0 -> Container(None)\n    _ -> {\n      Container(x:)\n    }\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5214\n#[test]\nfn bit_array_referencing_shadowed_variable() {\n    assert_js!(\n        \"\npub fn main() {\n  let a = 1\n  let a = 2\n\n  case Nil {\n    _ if <<a>> == <<1>> -> False\n    _ if <<a>> == <<2>> -> True\n    _ -> False\n  }\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/consts.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn custom_type_constructor_imported_and_aliased() {\n    assert_js!(\n        (\"package\", \"other_module\", \"pub type T { A }\"),\n        r#\"import other_module.{A as B}\n\npub const local = B\n\"#,\n    );\n}\n\n#[test]\nfn imported_aliased_ok() {\n    assert_js!(\n        r#\"import gleam.{Ok as Y}\n\npub type X {\n  Ok\n}\n\npub const y = Y\n\"#,\n    );\n}\n\n#[test]\nfn imported_ok() {\n    assert_js!(\n        r#\"import gleam\n\npub type X {\n  Ok\n}\n\npub const y = gleam.Ok\n\"#,\n    );\n}\n\n#[test]\nfn constant_constructor_gets_pure_annotation() {\n    assert_js!(\n        r#\"\npub type X {\n  X(Int, List(String))\n}\n\npub const x = X(1, [\"1\"])\npub const y = X(1, [])\n        \"#\n    );\n}\n\n#[test]\nfn constant_list_with_constructors_gets_pure_annotation() {\n    assert_js!(\n        r#\"\npub type X {\n  X(Int, List(String))\n}\n\npub const x = [X(1, [\"1\"])]\npub const y = [X(1, [\"1\"])]\n        \"#\n    );\n}\n\n#[test]\nfn constant_tuple_with_constructors_gets_pure_annotation() {\n    assert_js!(\n        r#\"\npub type X {\n  X(Int, List(String))\n}\n\npub const x = #(X(1, [\"1\"]))\npub const y = #(X(1, [\"1\"]))\n        \"#\n    );\n}\n\n#[test]\nfn literal_int_does_not_get_constant_annotation() {\n    assert_js!(\"pub const a = 1\");\n}\n\n#[test]\nfn literal_float_does_not_get_constant_annotation() {\n    assert_js!(\"pub const a = 1.1\");\n}\n\n#[test]\nfn literal_string_does_not_get_constant_annotation() {\n    assert_js!(\"pub const a = \\\"1\\\"\");\n}\n\n#[test]\nfn literal_bool_does_not_get_constant_annotation() {\n    assert_js!(\n        \"\n        pub const a = True\n        pub const b = False\n    \"\n    );\n}\n\n#[test]\nfn literal_list_does_not_get_constant_annotation() {\n    assert_js!(\"pub const a = [1, 2, 3]\");\n}\n\n#[test]\nfn literal_tuple_does_not_get_constant_annotation() {\n    assert_js!(\"pub const a = #(1, 2, 3)\");\n}\n\n#[test]\nfn literal_nil_does_not_get_constant_annotation() {\n    assert_js!(\"pub const a = Nil\");\n}\n\n// https://github.com/lpil/decode/pull/6\n#[test]\nfn constructor_function_in_constant() {\n    assert_js!(\"pub const a = Ok\");\n}\n\n#[test]\nfn constants_get_their_own_jsdoc_comment() {\n    assert_js!(\n        \"\n/// 11 is clearly the best number!\npub const jaks_favourite_number = 11\n\"\n    );\n}\n\n#[test]\nfn list_prepend() {\n    assert_js!(\n        \"\nconst wibble = [2, 3, 4]\npub const wobble = [0, 1, ..wibble]\n\"\n    );\n}\n\n#[test]\nfn list_prepend_from_other_module() {\n    assert_js!(\n        (\"mod\", \"pub const wibble = [2, 3, 4]\"),\n        \"\nimport mod\n\npub const wobble = [0, 1, ..mod.wibble]\n\"\n    );\n}\n\n#[test]\nfn list_prepend_literal() {\n    assert_js!(\n        \"\npub const wibble = [0, 1, ..[2, 3, 4]]\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/custom_types.rs",
    "content": "use crate::javascript::tests::CURRENT_PACKAGE;\nuse crate::{assert_js, assert_ts_def};\n\n#[test]\nfn zero_arity_literal() {\n    assert_js!(\n        r#\"\npub type Mine {\n    This\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n}\n\npub fn go() {\n    This\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n}\n\"#,\n    );\n}\n\n#[test]\nfn zero_arity_const() {\n    assert_js!(\n        r#\"\npub type Mine {\n    This\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n}\n\npub const this = This\npub const that = ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n\"#,\n    );\n}\n\n#[test]\nfn zero_arity_imported() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two }\"#),\n        r#\"import other\npub fn main() {\n  other.Two\n}\"#,\n    );\n}\n\n#[test]\nfn zero_arity_imported_typscript() {\n    assert_ts_def!(\n        (CURRENT_PACKAGE, \"other\", r#\"pub type One { Two }\"#),\n        r#\"import other\npub fn main() {\n  other.Two\n}\"#,\n    );\n}\n\n#[test]\nfn zero_arity_imported_unqualified() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two\n}\"#,\n    );\n}\n\n#[test]\nfn zero_arity_imported_unqualified_typescript() {\n    assert_ts_def!(\n        (CURRENT_PACKAGE, \"other\", r#\"pub type One { Two }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two\n}\"#,\n    );\n}\n\n#[test]\nfn zero_arity_imported_unqualified_aliased() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two }\"#),\n        r#\"import other.{Two as Three}\npub fn main() {\n  Three\n}\"#\n    );\n}\n\n#[test]\nfn zero_arity_imported_unqualified_aliased_typescript() {\n    assert_ts_def!(\n        (CURRENT_PACKAGE, \"other\", r#\"pub type One { Two }\"#),\n        r#\"import other.{Two as Three}\npub fn main() {\n  Three\n}\"#\n    );\n}\n\n#[test]\nfn const_zero_arity_imported() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two }\"#),\n        r#\"import other\npub const x = other.Two\n\"#,\n    );\n}\n\n#[test]\nfn const_zero_arity_imported_unqualified() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two }\"#),\n        r#\"import other.{Two}\npub const a = Two\n\"#,\n    );\n}\n\n#[test]\nfn const_with_fields() {\n    assert_js!(\n        r#\"\npub type Mine {\n  Mine(a: Int, b: Int)\n}\n\npub const labels = Mine(b: 2, a: 1)\npub const no_labels = Mine(3, 4)\n\"#,\n    );\n}\n\n#[test]\nfn const_with_fields_typescript() {\n    assert_ts_def!(\n        r#\"\npub type Mine {\n  Mine(a: Int, b: Int)\n}\n\npub const labels = Mine(b: 2, a: 1)\npub const no_labels = Mine(3, 4)\n\"#,\n    );\n}\n\n#[test]\nfn unnamed_fields() {\n    assert_js!(\n        r#\"\npub type Ip {\n    Ip(String)\n}\n\npub const local = Ip(\"0.0.0.0\")\n\npub fn build(x) {\n    x(\"1.2.3.4\")\n}\n\npub fn go() {\n    build(Ip)\n    Ip(\"5.6.7.8\")\n}\n\npub fn destructure(x) {\n  let Ip(raw) = x\n  raw\n}\n\"#,\n    );\n}\n\n#[test]\nfn unnamed_fields_typescript() {\n    assert_ts_def!(\n        r#\"\npub type Ip{\n    Ip(String)\n}\n\npub const local = Ip(\"0.0.0.0\")\n\n\"#,\n    );\n}\n\n#[test]\nfn long_name_variant_without_labels() {\n    assert_js!(\n        r#\"\npub type TypeWithALongNameAndSeveralArguments{\n  TypeWithALongNameAndSeveralArguments(String, String, String, String, String)\n}\n\n\npub fn go() {\n  TypeWithALongNameAndSeveralArguments\n}\n\"#,\n    );\n}\n\n#[test]\nfn long_name_variant_mixed_labels_typescript() {\n    assert_ts_def!(\n        r#\"\npub type TypeWithALongNameAndSeveralArguments{\n  TypeWithALongNameAndSeveralArguments(String, String, String, a: String, b: String)\n}\n\npub const local = TypeWithALongNameAndSeveralArguments(\"one\", \"two\", \"three\", \"four\", \"five\")\n\"#,\n    );\n}\n\n#[test]\nfn custom_type_with_named_fields() {\n    assert_js!(\n        r#\"\npub type Cat {\n  Cat(name: String, cuteness: Int)\n}\n\npub type Box {\n  Box(occupant: Cat)\n}\n\npub const felix = Cat(\"Felix\", 12)\npub const tom = Cat(cuteness: 1, name: \"Tom\")\n\npub fn go() {\n  Cat(\"Nubi\", 1)\n  Cat(2, name: \"Nubi\")\n  Cat(cuteness: 3, name: \"Nubi\")\n}\n\npub fn update(cat) {\n  Cat(..cat, name: \"Sid\")\n  Cat(..cat, name: \"Bartholemew Wonder Puss the Fourth !!!!!!!!!!!!!!!!\")\n  Cat(..new_cat(), name: \"Molly\")\n  let box = Box(occupant: cat)\n  Cat(..box.occupant, cuteness: box.occupant.cuteness + 1)\n}\n\npub fn access(cat: Cat) {\n  cat.cuteness\n}\n\npub fn new_cat() {\n  Cat(name: \"Beau\", cuteness: 11)\n}\n\"#,\n    );\n}\n\n#[test]\nfn destructure_custom_type_with_named_fields() {\n    assert_js!(\n        r#\"\npub type Cat {\n  Cat(name: String, cuteness: Int)\n}\n\npub fn go(cat) {\n  let Cat(x, y) = cat\n  let Cat(name: x, ..) = cat\n  let assert Cat(cuteness: 4, name: x) = cat\n  x\n}\n\n\"#,\n    )\n}\n\n#[test]\nfn destructure_custom_type_with_mixed_fields_first_unlabelled() {\n    assert_js!(\n        r#\"\npub type Cat {\n  Cat(String, cuteness: Int)\n}\n\npub fn go(cat) {\n  let Cat(x, y) = cat\n  let Cat(cuteness: y, ..) = cat\n  let Cat(x, cuteness: y) = cat\n  x\n}\n\n\"#,\n    )\n}\n\n#[test]\nfn nested_pattern_with_labels() {\n    assert_js!(\n        r#\"pub type Box(x) { Box(a: Int, b: x) }\npub fn go(x) {\n  case x {\n    Box(a: _, b: Box(a: a, b: b)) -> a + b\n    _ -> 1\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn imported_no_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(Int) }\"#),\n        r#\"import other\npub fn main() {\n  other.Two(1)\n}\"#,\n    );\n}\n\n#[test]\nfn imported_ignoring_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other\npub fn main() {\n  other.Two(1)\n}\"#,\n    );\n}\n\n#[test]\nfn imported_using_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other\npub fn main() {\n  other.Two(field: 1)\n}\"#,\n    );\n}\n\n#[test]\nfn imported_multiple_fields() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other\npub fn main() {\n  other.Two(b: 2, c: 3, a: 1)\n}\"#,\n    );\n}\n\n#[test]\nfn unqualified_imported_no_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(Int) }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two(1)\n}\"#,\n    );\n}\n\n#[test]\nfn unqualified_imported_no_label_typescript() {\n    assert_ts_def!(\n        (CURRENT_PACKAGE, \"other\", r#\"pub type One { Two(Int) }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two(1)\n}\"#,\n    );\n}\n\n#[test]\nfn unqualified_imported_ignoring_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two(1)\n}\"#,\n    );\n}\n\n#[test]\nfn unqualified_imported_using_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two(field: 1)\n}\"#,\n    );\n}\n\n#[test]\nfn unqualified_imported_multiple_fields() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two(b: 2, c: 3, a: 1)\n}\"#,\n    );\n}\n\n#[test]\nfn constructor_as_value() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other\npub fn main() {\n  other.Two\n}\"#,\n    );\n}\n\n#[test]\nfn unqualified_constructor_as_value() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other.{Two}\npub fn main() {\n  Two\n}\"#,\n    );\n}\n\n#[test]\nfn const_imported_no_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(Int) }\"#),\n        r#\"import other\npub const main = other.Two(1)\n\"#,\n    );\n}\n\n#[test]\nfn const_imported_ignoring_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other\npub const main = other.Two(1)\n\"#,\n    );\n}\n\n#[test]\nfn const_imported_using_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other\npub const main = other.Two(field: 1)\n\"#,\n    );\n}\n\n#[test]\nfn const_imported_multiple_fields() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other\npub const main = other.Two(b: 2, c: 3, a: 1)\n\"#,\n    );\n}\n\n#[test]\nfn const_unqualified_imported_no_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(Int) }\"#),\n        r#\"import other.{Two}\npub const main = Two(1)\n\"#,\n    );\n}\n\n#[test]\nfn const_unqualified_imported_ignoring_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other.{Two}\npub const main = Two(1)\n\"#,\n    );\n}\n\n#[test]\nfn const_unqualified_imported_using_label() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(field: Int) }\"#),\n        r#\"import other.{Two}\npub const main = Two(field: 1)\n\"#,\n    );\n}\n\n#[test]\nfn const_unqualified_imported_multiple_fields() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other.{Two}\npub const main = Two(b: 2, c: 3, a: 1)\n\"#,\n    );\n}\n\n#[test]\nfn imported_pattern() {\n    assert_js!(\n        (\"other\", r#\"pub type One { Two(a: Int, b: Int, c: Int) }\"#),\n        r#\"import other.{Two}\n\npub fn main(x) {\n  case x {\n    Two(a: 1, ..) -> 1\n    other.Two(b: 2, c: c, ..) -> c\n    _ -> 3\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn keyword_label_name() {\n    assert_js!(\n        r#\"pub type Thing {\n  Thing(in: Int, class: Nil)\n}\n\"#,\n    );\n}\n\n#[test]\nfn qualified() {\n    assert_js!(\n        (\"other\", r#\"pub type One { One }\"#),\n        r#\"import other\n\npub fn main() {\n  other.One\n}\n\"#,\n    );\n}\n\n#[test]\nfn unapplied_record_constructors_typescript() {\n    assert_ts_def!(\n        r#\"pub type Cat { Cat(name: String) }\n\npub fn return_unapplied_cat() {\n  Cat\n}\n\"#\n    );\n}\n\n#[test]\nfn opaque_types_typescript() {\n    assert_ts_def!(\n        r#\"pub opaque type Animal {\n  Cat(goes_outside: Bool)\n  Dog(plays_fetch: Bool)\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1650\n#[test]\nfn types_must_be_rendered_before_functions() {\n    assert_js!(\n        r#\"\npub fn one() { One }\npub type One { One }\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2386\n#[test]\nfn new_type_import_syntax() {\n    assert_js!(\n        (\"package\", \"a\", r#\"pub type A { A }\"#),\n        r#\"\nimport a.{type A, A}\n\npub fn main() {\n  A\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3813\n#[test]\nfn record_with_field_named_constructor() {\n    assert_js!(\n        r#\"\npub type Thing {\n  Thing(constructor: Nil)\n}\n\npub fn main() {\n  let a = Thing(constructor: Nil)\n  let b = Thing(..a, constructor: Nil)\n  b.constructor\n}\n\"#\n    );\n}\n\n#[test]\nfn record_with_field_named_then() {\n    assert_js!(\n        r#\"\npub type Thing {\n  Thing(then: Nil)\n}\n\npub fn main() {\n  let a = Thing(then: Nil)\n  let b = Thing(..a, then: Nil)\n  b.then\n}\n\"#\n    );\n}\n#[test]\nfn record_access_in_guard_with_reserved_field_name() {\n    assert_js!(\n        r#\"\npub type Thing {\n  Thing(constructor: Nil)\n}\n\npub fn main() {\n  let a = Thing(constructor: Nil)\n  case Nil {\n      Nil if a.constructor == Nil -> a.constructor\n      _ -> Nil\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn record_access_in_pattern_with_reserved_field_name() {\n    assert_js!(\n        r#\"\npub type Thing {\n  Thing(constructor: Nil)\n}\n\npub fn main() {\n  let a = Thing(constructor: Nil)\n  let Thing(constructor: ctor) = a\n  case a {\n      a if a.constructor == ctor -> Nil\n      Thing(constructor:) if ctor == constructor -> Nil\n      _ -> Nil\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn constructors_get_their_own_jsdoc() {\n    assert_js!(\n        r#\"\npub type Wibble {\n  /// Wibbling!!\n  Wibble(field: Int)\n\n  /// Wobbling!!\n  Wobble(field: Int)\n}\n\"#\n    );\n}\n\n#[test]\nfn singleton_record_equality() {\n    assert_js!(\n        r#\"\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn is_wibble(w: Wibble) -> Bool {\n  w == Wibble\n}\n\"#,\n    );\n}\n\n#[test]\nfn singleton_record_inequality() {\n    assert_js!(\n        r#\"\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn is_not_wibble(w: Wibble) -> Bool {\n  w != Wibble\n}\n\"#,\n    );\n}\n\n#[test]\nfn singleton_record_reverse_order() {\n    assert_js!(\n        r#\"\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn is_wibble_reverse(w: Wibble) -> Bool {\n  Wibble == w\n}\n\"#,\n    );\n}\n\n#[test]\nfn non_singleton_record_equality() {\n    assert_js!(\n        r#\"\npub type Person {\n  Person(name: String, age: Int)\n}\n\npub fn same_person(p1: Person, p2: Person) -> Bool {\n  p1 == p2\n}\n\"#,\n    );\n}\n\n#[test]\nfn multiple_singleton_constructors() {\n    assert_js!(\n        r#\"\npub type Status {\n  Loading\n  Success\n  Error\n}\n\npub fn is_loading(s: Status) -> Bool {\n  s == Loading\n}\n\npub fn is_success(s: Status) -> Bool {\n  s == Success\n}\n\"#,\n    );\n}\n\n#[test]\nfn mixed_singleton_and_non_singleton() {\n    assert_js!(\n        r#\"\npub type Result {\n  Ok(value: Int)\n  Error\n}\n\npub fn is_error(r: Result) -> Bool {\n  r == Error\n}\n\"#,\n    );\n}\n\n#[test]\nfn singleton_in_case_guard() {\n    assert_js!(\n        r#\"\npub type State {\n  Active\n  Inactive\n}\n\npub fn process(s: State) -> String {\n  case s {\n    state if state == Active -> \"active\"\n    _ -> \"inactive\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn equality_with_non_singleton_variant() {\n    assert_js!(\n        r#\"\npub type Thing {\n  Variant\n  Other(String)\n}\n\npub fn check_other(x: Thing) -> Bool {\n  x == Other(\"hello\")\n}\n\"#,\n    );\n}\n\n#[test]\nfn guard_equality_with_non_singleton_variant() {\n    assert_js!(\n        r#\"\npub type Thing {\n  Variant\n  Other(String)\n}\n\npub fn process(e: Thing) -> String {\n  case e {\n    value if value == Other(\"hello\") -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn variant_defined_in_another_module_qualified_expression() {\n    assert_js!(\n        (\n            \"other_module\",\n            r#\"pub type Thingy { Variant OtherVariant }\"#\n        ),\n        r#\"\nimport other_module\n\npub fn check(x) -> Bool {\n  x == other_module.Variant\n}\n\"#,\n    );\n}\n\n#[test]\nfn variant_defined_in_another_module_unqualified_expression() {\n    assert_js!(\n        (\"other_module\", r#\"pub type Thingy { Variant Other(Int) }\"#),\n        r#\"\nimport other_module.{Variant}\n\npub fn check(x) -> Bool {\n  x == Variant\n}\n\"#,\n    );\n}\n\n#[test]\nfn variant_defined_in_another_module_aliased_expression() {\n    assert_js!(\n        (\"other_module\", r#\"pub type Thingy { Variant Other(Int) }\"#),\n        r#\"\nimport other_module.{Variant as Aliased}\n\npub fn check(x) -> Bool {\n  x == Aliased\n}\n\"#,\n    );\n}\n\n#[test]\nfn variant_defined_in_another_module_qualified_clause_guard() {\n    assert_js!(\n        (\"other_module\", r#\"pub type Thingy { Variant Other(Int) }\"#),\n        r#\"\nimport other_module\n\npub fn process(e) -> String {\n  case e {\n    value if value == other_module.Variant -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn variant_defined_in_another_module_unqualified_clause_guard() {\n    assert_js!(\n        (\"other_module\", r#\"pub type Thingy { Variant Other(Int) }\"#),\n        r#\"\nimport other_module.{Variant}\n\npub fn process(e) -> String {\n  case e {\n    value if value == Variant -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn variant_defined_in_another_module_aliased_clause_guard() {\n    assert_js!(\n        (\"other_module\", r#\"pub type Thingy { Variant Other(Int) }\"#),\n        r#\"\nimport other_module.{Variant as Aliased}\n\npub fn process(e) -> String {\n  case e {\n    value if value == Aliased -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn external_annotation() {\n    assert_ts_def!(\n        r#\"\n@external(javascript, \"./gleam_stdlib.d.ts\", \"Dict\")\npub type Dict(key, value)\n\"#\n    );\n}\n\n#[test]\nfn external_annotated_type_used_in_function() {\n    assert_ts_def!(\n        r#\"\n@external(javascript, \"./gleam_stdlib.d.ts\", \"Dict\")\npub type Dict(key, value)\n\n@external(javascript, \"./gleam_stdlib.mjs\", \"get\")\npub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5127\n#[test]\nfn unused_opaque_constructor_is_generated_correctly() {\n    assert_ts_def!(\n        \"\ntype Wibble {\n  Wibble\n}\n\npub opaque type Wobble {\n  Wobble(Wibble)\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5312\n#[test]\nfn generic_type_parameter_used_in_field() {\n    assert_ts_def!(\n        \"\npub type Wibble(value, error) {\n  Wibble(\n    wibble: value,\n    wobble: Result(value, error),\n    wubble: error,\n  )\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/echo.rs",
    "content": "use crate::assert_js;\n\n#[test]\npub fn echo_with_a_simple_expression() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo 1\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_simple_expression_and_a_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo 1 as \"hello!\"\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_complex_expression_as_a_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo 1 as case name() {\n    \"Giacomo\" -> \"hello Jak!\"\n    _ -> \"hello!\"\n  }\n}\n\nfn name() { \"Giacomo\" }\n\"#\n    );\n}\n\n#[test]\npub fn echo_evaluates_printed_value_before_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo name() as case name() {\n    \"Giacomo\" -> \"hello Jak!\"\n    _ -> \"hello!\"\n  }\n}\n\nfn name() { \"Giacomo\" }\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_block_as_a_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo 1 as {\n    let name = \"Giacomo\"\n    \"Hello, \" <> name\n  }\n}\n\"#\n    );\n}\n\n#[test]\npub fn multiple_echos_inside_expression() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo 1\n  echo 2\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_case_expression() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo case 1 {\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_panic() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo panic\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_function_call() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo wibble(1, 2)\n}\n\nfn wibble(n: Int, m: Int) { n + m }\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_function_call_and_a_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo wibble(1, 2) as message()\n}\n\nfn wibble(n: Int, m: Int) { n + m }\nfn message() { \"Hello!\" }\n\"#\n    );\n}\n\n#[test]\npub fn echo_with_a_block() {\n    assert_js!(\n        r#\"\npub fn main() {\n  echo {\n    Nil\n    1\n  }\n}\n\"#\n    );\n}\n\n#[test]\npub fn echo_in_a_pipeline() {\n    assert_js!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn echo_in_a_pipeline_with_message() {\n    assert_js!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo as \"message!!\"\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn multiple_echos_in_a_pipeline() {\n    assert_js!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n  |> echo\n  |> wibble\n  |> echo\n}\n\npub fn wibble(n) { n }\n\"#\n    )\n}\n\n#[test]\npub fn module_named_inspect() {\n    assert_js!(\n        (\"other\", \"other/inspect\", \"pub const x = Nil\"),\n        r#\"\nimport other/inspect\n\npub fn main() {\n  echo inspect.x\n}\n\"#\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/externals.rs",
    "content": "use crate::{assert_js, assert_module_error, assert_ts_def};\n\n#[test]\nfn type_() {\n    assert_js!(r#\"pub type Thing\"#,);\n}\n\n#[test]\nfn module_fn() {\n    assert_js!(\n        r#\"\n@external(javascript, \"utils\", \"inspect\")\nfn show(x: anything) -> Nil\"#,\n    );\n}\n\n#[test]\nfn at_namespace_module() {\n    assert_js!(\n        r#\"\n@external(javascript, \"@namespace/package\", \"inspect\")\nfn show(x: anything) -> Nil\"#,\n    );\n}\n\n#[test]\nfn pub_module_fn() {\n    assert_js!(\n        r#\"\n@external(javascript, \"utils\", \"inspect\")\npub fn show(x: anything) -> Nil\"#,\n    );\n}\n\n#[test]\nfn pub_module_fn_typescript() {\n    assert_ts_def!(\n        r#\"\n@external(javascript, \"utils\", \"inspect\")\npub fn show(x: anything) -> Nil\"#,\n    );\n}\n\n#[test]\nfn same_name_external() {\n    assert_js!(\n        r#\"\n@external(javascript, \"thingy\", \"fetch\")\npub fn fetch(request: Nil) -> Nil\"#,\n    );\n}\n\n#[test]\nfn same_module_multiple_imports() {\n    assert_js!(\n        r#\"\n@external(javascript, \"./the/module.mjs\", \"one\")\npub fn one() -> Nil\n\n@external(javascript, \"./the/module.mjs\", \"two\")\npub fn two() -> Nil\n\"#,\n    );\n}\n\n#[test]\nfn duplicate_import() {\n    assert_js!(\n        r#\"\n@external(javascript, \"./the/module.mjs\", \"dup\")\npub fn one() -> Nil\n\n@external(javascript, \"./the/module.mjs\", \"dup\")\npub fn two() -> Nil\n\"#,\n    );\n}\n\n#[test]\nfn name_to_escape() {\n    assert_js!(\n        r#\"\n@external(javascript, \"./the/module.mjs\", \"one\")\npub fn class() -> Nil\n\"#,\n    );\n}\n\n#[test]\nfn external_type_typescript() {\n    assert_ts_def!(\n        r#\"pub type Queue(a)\n\n@external(javascript, \"queue\", \"new\")\npub fn new() -> Queue(a)\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1636\n#[test]\nfn external_fn_escaping() {\n    assert_js!(\n        r#\"\n@external(javascript, \"./ffi.js\", \"then\")\npub fn then(a: a) -> b\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1954\n#[test]\nfn pipe_variable_shadow() {\n    assert_js!(\n        r#\"\n@external(javascript, \"module\", \"string\")\nfn name() -> String\n\npub fn main() {\n  let name = name()\n  name\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2090\n#[test]\nfn tf_type_name_usage() {\n    assert_ts_def!(\n        r#\"\npub type TESTitem\n\n@external(javascript, \"it\", \"one\")\npub fn one(a: TESTitem) -> TESTitem\n\"#\n    );\n}\n\n#[test]\nfn attribute_erlang() {\n    assert_js!(\n        r#\"\n@external(erlang, \"one\", \"one_erl\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn attribute_javascript() {\n    assert_js!(\n        r#\"\n@external(javascript, \"./one.mjs\", \"oneJs\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn erlang_and_javascript() {\n    assert_js!(\n        r#\"\n@external(erlang, \"one\", \"one\")\n@external(javascript, \"./one.mjs\", \"oneJs\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn private_attribute_erlang() {\n    assert_js!(\n        r#\"\n@external(erlang, \"one\", \"one_erl\")\nfn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn private_attribute_javascript() {\n    assert_js!(\n        r#\"\n@external(javascript, \"./one.mjs\", \"oneJs\")\nfn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn private_erlang_and_javascript() {\n    assert_js!(\n        r#\"\n@external(erlang, \"one\", \"one\")\n@external(javascript, \"./one.mjs\", \"oneJs\")\nfn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\"#\n    );\n}\n\n#[test]\nfn no_body() {\n    assert_js!(\n        r#\"\n@external(javascript, \"one\", \"one\")\npub fn one(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn no_module() {\n    assert_module_error!(\n        r#\"\n@external(javascript, \"\", \"one\")\npub fn one(x: Int) -> Int {\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn inline_function() {\n    assert_module_error!(\n        r#\"\n@external(javascript, \"blah\", \"(x => x)\")\npub fn one(x: Int) -> Int {\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn erlang_only() {\n    assert_js!(\n        r#\"\npub fn should_be_generated(x: Int) -> Int {\n  x\n}\n\n@external(erlang, \"one\", \"one\")\npub fn should_not_be_generated(x: Int) -> Int\n\"#\n    );\n}\n\n#[test]\nfn both_externals_no_valid_impl() {\n    assert_js!(\n        r#\"\n@external(javascript, \"one\", \"one\")\npub fn js() -> Nil\n\n@external(erlang, \"one\", \"one\")\npub fn erl() -> Nil\n\npub fn should_not_be_generated() {\n  js()\n  erl()\n}\n\"#\n    );\n}\n\n#[test]\nfn discarded_names_in_external_are_passed_correctly() {\n    assert_js!(\n        r#\"\n@external(javascript, \"wibble\", \"wobble\")\npub fn woo(_ignored: a) -> Nil\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/functions.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn exported_functions() {\n    assert_js!(\n        r#\"\npub fn add(x, y) {\n    x + y\n}\"#,\n    );\n}\n\n#[test]\nfn calling_functions() {\n    assert_js!(\n        r#\"\npub fn twice(f: fn(t) -> t, x: t) -> t {\n  f(f(x))\n}\npub fn add_one(x: Int) -> Int {\n  x + 1\n}\npub fn add_two(x: Int) -> Int {\n  twice(add_one, x)\n}\n\npub fn take_two(x: Int) -> Int {\n  twice(fn(y) {y - 1}, x)\n}\n\"#,\n    );\n}\n\n#[test]\nfn function_formatting() {\n    assert_js!(\n        r#\"\npub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {\n  the_first_variable_that_should_be_added + the_second_variable_that_should_be_added\n}\"#,\n    );\n}\n\n#[test]\nfn function_formatting1() {\n    assert_js!(\n        r#\"\npub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {\nx + y\n}\"#,\n    );\n}\n\n#[test]\nfn function_formatting2() {\n    assert_js!(\n        r#\"\npub fn add(x, y) {\nx + y\n}\n\npub fn long() {\n  add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, 1)))))))))))))))\n}\"#,\n    );\n}\n\n#[test]\nfn function_formatting3() {\n    assert_js!(\n        r#\"\npub fn math(x, y) {\n  fn() {\n    x + y\n    x - y\n    2 * x\n  }\n}\"#,\n    );\n}\n\n#[test]\nfn function_formatting_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {\n  the_first_variable_that_should_be_added + the_second_variable_that_should_be_added\n}\"#,\n    );\n}\n\n#[test]\nfn function_formatting_typescript1() {\n    assert_ts_def!(\n        r#\"\npub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {\nx + y\n}\"#,\n    );\n}\n\n#[test]\nfn tail_call() {\n    assert_js!(\n        r#\"\npub fn count(xs, n) {\n  case xs {\n    [] -> n\n    [_, ..xs] -> count(xs, n + 1)\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn tail_call_doesnt_clobber_tail_position_tracking() {\n    assert_js!(\n        r#\"\npub fn loop(indentation) {\n  case indentation > 0 {\n    True -> loop(indentation - 1)\n    False -> Nil\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn pipe_last() {\n    assert_js!(\n        r#\"fn id(x) { x }\npub fn main() {\n  1\n  |> id\n}\n\"#,\n    );\n}\n\n#[test]\nfn calling_fn_literal() {\n    assert_js!(\n        r#\"pub fn main() {\n  fn(x) { x }(1)\n}\n\"#,\n    );\n}\n\n// Don't mistake calling a function with the same name as the current function\n// as tail recursion\n#[test]\nfn shadowing_current() {\n    assert_js!(\n        r#\"pub fn main() {\n  let main = fn() { 0 }\n  main()\n}\n\"#,\n    );\n}\n\n#[test]\nfn recursion_with_discards() {\n    assert_js!(\n        r#\"pub fn main(f, _) {\n  f()\n  main(f, 1)\n}\n\"#,\n    );\n}\n\n#[test]\nfn no_recur_in_anon_fn() {\n    assert_js!(\n        r#\"pub fn main() {\n  fn() { main() }\n  1\n}\n\"#,\n    );\n}\n\n#[test]\nfn case_in_call() {\n    assert_js!(\n        r#\"pub fn main(f, x) {\n  f(case x {\n    1 -> 2\n    _ -> 0\n  })\n}\n\"#,\n    );\n}\n\n#[test]\nfn reserved_word_fn() {\n    assert_js!(\n        r#\"pub fn class() {\n  Nil\n}\n\"#,\n    );\n}\n\n#[test]\nfn reserved_word_imported() {\n    assert_js!(\n        (\"for\", \"pub fn class() { 1 }\"),\n        r#\"import for.{class}\n\npub fn export() {\n  class()\n}\n\"#,\n    );\n}\n\n#[test]\nfn reserved_word_imported_alias() {\n    assert_js!(\n        (\"for\", \"pub fn class() { 1 }\"),\n        r#\"import for.{class as while} as function\n\npub fn export() {\n  let delete = function.class\n  while()\n}\n\"#,\n    );\n}\n\n#[test]\nfn reserved_word_const() {\n    assert_js!(\n        r#\"const in = 1\n\npub fn export() {\n  in\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1208\n#[test]\nfn reserved_word_argument() {\n    assert_js!(\n        r#\"pub fn main(with) {\n  with\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1186\n#[test]\nfn multiple_discard() {\n    assert_js!(\n        r#\"pub fn main(_, _, _) {\n  1\n}\n\"#,\n    );\n}\n\n#[test]\nfn keyword_in_recursive_function() {\n    assert_js!(\n        r#\"pub fn main(with: Int) -> Nil {\n  main(with - 1)\n}\n\"#,\n    );\n}\n\n#[test]\nfn reserved_word_in_function_arguments() {\n    assert_js!(\n        r#\"pub fn main(arguments, eval) {\n  #(arguments, eval)\n}\n\"#,\n    );\n}\n\n#[test]\nfn let_last() {\n    assert_js!(\n        r#\"pub fn main() {\n  let x = 1\n}\n\"#,\n    );\n}\n\n#[test]\nfn assert_last() {\n    assert_js!(\n        r#\"pub fn main() {\n  let assert x = 1\n}\n\"#,\n    );\n}\n\n#[test]\nfn fn_return_fn_typescript() {\n    assert_ts_def!(\n        r#\"pub fn main(f: fn(Int) -> Int) {\n  let func = fn(x, y) { f(x) + f(y) }\n  func\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1637\n#[test]\nfn variable_rewriting_in_anon_fn_with_matching_parameter() {\n    assert_js!(\n        r#\"pub fn bad() {\n  fn(state) {\n    let state = state\n    state\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1637\n#[test]\nfn variable_rewriting_in_anon_fn_with_matching_parameter_in_case() {\n    assert_js!(\n        r#\"pub fn bad() {\n  fn(state) {\n    let state = case Nil {\n      _ -> state\n    }\n    state\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1508\n#[test]\nfn pipe_variable_rebinding() {\n    assert_js!(\n        \"\npub fn main() {\n  let version = 1 |> version()\n  version\n}\n\npub fn version(n) {\n  Ok(1)\n}\"\n    )\n}\n\n#[test]\nfn pipe_shadow_import() {\n    assert_js!(\n        (\"wibble\", \"pub fn println(x: String) {  }\"),\n        r#\"\n        import wibble.{println}\n        pub fn main() {\n          let println =\n            \"oh dear\"\n            |> println\n          println\n        }\"#\n    );\n}\n\n#[test]\nfn module_const_fn() {\n    assert_js!(\n        r#\"\npub fn int_identity(i: Int) -> Int { i }\npub const int_identity_alias: fn(Int) -> Int = int_identity\npub fn use_int_identity_alias() { int_identity_alias(42) }\n\npub const compound: #(fn(Int) -> Int, fn(Int) -> Int) = #(int_identity, int_identity_alias)\npub fn use_compound() { compound.0(compound.1(42)) }\"#\n    );\n}\n\n#[test]\nfn module_const_fn1() {\n    assert_ts_def!(\n        r#\"\npub fn int_identity(i: Int) -> Int { i }\npub const int_identity_alias: fn(Int) -> Int = int_identity\npub const compound: #(fn(Int) -> Int, fn(Int) -> Int) =\n    #(int_identity, int_identity_alias)\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2399\n#[test]\nfn bad_comma() {\n    assert_js!(\n        r#\"\nfn function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit() {\n  Nil\n}\n\nfn identity(x) {\n  x\n}\n\npub fn main() {\n  function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit()\n  |> identity\n}\n\"#\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2518\n#[test]\nfn function_literals_get_properly_wrapped_1() {\n    assert_js!(\n        r#\"pub fn main() {\n  fn(n) { n + 1 }(10)\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2518\n#[test]\nfn function_literals_get_properly_wrapped_2() {\n    assert_js!(\n        r#\"pub fn main() {\n  { fn(n) { n + 1 } }(10)\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2518\n#[test]\nfn function_literals_get_properly_wrapped_3() {\n    assert_js!(\n        r#\"pub fn main() {\n  { let a = fn(n) { n + 1 } }(10)\n}\n\"#\n    );\n}\n\n#[test]\nfn labelled_argument_ordering() {\n    // https://github.com/gleam-lang/gleam/issues/3671\n    assert_js!(\n        \"\ntype A { A }\ntype B { B }\ntype C { C }\ntype D { D }\n\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\n  Nil\n}\n\npub fn main() {\n  wibble(A, C, D, b: B)\n  wibble(A, C, D, b: B)\n  wibble(B, C, D, a: A)\n  wibble(B, C, a: A, d: D)\n  wibble(B, C, d: D, a: A)\n  wibble(B, D, a: A, c: C)\n  wibble(B, D, c: C, a: A)\n  wibble(C, D, b: B, a: A)\n}\n\"\n    );\n}\n\n// During the implementation of https://github.com/gleam-lang/gleam/pull/4337,\n// a bug was found where this code would compile incorrectly.\n#[test]\nfn two_pipes_in_a_row() {\n    assert_js!(\n        \"\npub type Function(a) {\n  Function(fn() -> a)\n}\n\npub fn main() {\n  [fn() { 1 } |> Function, fn() { 2 } |> Function]\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4472\n#[test]\nfn pipe_into_block() {\n    assert_js!(\n        \"\nfn side_effects(x) { x }\n\npub fn main() {\n  1\n  |> side_effects\n  |> {\n    side_effects(2)\n    side_effects\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4472\n#[test]\nfn pipe_with_block_in_the_middle() {\n    assert_js!(\n        \"\nfn side_effects(x) { x }\n\npub fn main() {\n  1\n  |> side_effects\n  |> {\n    side_effects(2)\n    side_effects\n  }\n  |> side_effects\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4533\n#[test]\nfn immediately_invoked_function_expressions_include_statement_level() {\n    assert_js!(\n        \"\nfn identity(x) { x }\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let w = Wibble(1, 2)\n  identity(Wibble(..w |> identity, b: 4)) |> identity\n}\n\"\n    );\n}\n\n#[test]\nfn public_function_gets_jsdoc() {\n    assert_js!(\n        \"\n/// Hello! This is the documentation of the `main`\n/// function.\n///\npub fn main() { 1 }\n\"\n    );\n}\n\n#[test]\nfn internal_function_gets_ignored_jsdoc() {\n    assert_js!(\n        \"\n/// Hello! This is the documentation of the `main`\n/// function, which is internal!\n///\n@internal\npub fn main() { 1 }\n\"\n    );\n}\n\n#[test]\nfn star_slash_in_jsdoc() {\n    assert_js!(\n        \"\n/// */\n///\npub fn main() { 1 }\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/generics.rs",
    "content": "use crate::assert_ts_def;\n\n#[test]\nfn fn_generics_typescript() {\n    assert_ts_def!(\n        r#\"pub fn identity(a) -> a {\n  a\n}\n\"#,\n    );\n}\n\n#[test]\nfn record_generics_typescript() {\n    assert_ts_def!(\n        r#\"pub type Animal(t) {\n  Cat(type_: t)\n  Dog(type_: t)\n}\n\npub fn main() {\n  Cat(type_: 6)\n}\n\"#,\n    );\n}\n\n#[test]\nfn tuple_generics_typescript() {\n    assert_ts_def!(\n        r#\"pub fn make_tuple(x: t) -> #(Int, t, Int) {\n  #(0, x, 1)\n}\n\"#,\n    );\n}\n\n#[test]\nfn result_typescript() {\n    assert_ts_def!(\n        r#\"pub fn map(result, fun) {\n            case result {\n              Ok(a) -> Ok(fun(a))\n              Error(e) -> Error(e)\n            }\n          }\"#,\n    );\n}\n\n#[test]\nfn task_typescript() {\n    assert_ts_def!(\n        r#\"pub type Promise(value)\n    pub type Task(a) = fn() -> Promise(a)\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/inlining.rs",
    "content": "use crate::assert_js;\n\nconst BOOL_MODULE: &str = \"\npub fn guard(\n  when condition: Bool,\n  return value: a,\n  otherwise callback: fn() -> a,\n) -> a {\n  case condition {\n    True -> value\n    False -> callback()\n  }\n}\n\npub fn lazy_guard(\n  when condition: Bool,\n  return consequence: fn() -> a,\n  otherwise alternative: fn() -> a,\n) -> a {\n  case condition {\n    True -> consequence()\n    False -> alternative()\n  }\n}\n\";\n\nconst RESULT_MODULE: &str = \"\npub fn try(result: Result(a, e), apply f: fn(a) -> Result(b, e)) -> Result(b, e) {\n  case result {\n    Ok(value) -> f(value)\n    Error(error) -> Error(error)\n  }\n}\n\npub fn map(over result: Result(a, e), with f: fn(a) -> b) -> Result(b, e) {\n  case result {\n    Ok(value) -> Ok(f(value))\n    Error(error) -> Error(error)\n  }\n}\n\";\n\n#[test]\nfn inline_higher_order_function() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn main() {\n  result.map(over: Ok(10), with: double)\n}\n\nfn double(x) { x + x }\n\"\n    );\n}\n\n#[test]\nfn inline_higher_order_function_with_capture() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), divide(_, 2))\n}\n\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inline_higher_order_function_anonymous() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), fn(value) {\n    Ok({ value + 2 } * 4)\n  })\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_which_calls_other_function() {\n    // This function calls `result.try`, meaning this must be inlined twice to\n    // achieve the desired result.\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        (\n            \"gleam_stdlib\",\n            \"testing\",\n            \"\nimport gleam/result.{try}\n\npub fn always_inline(result, f) -> Result(b, e) {\n  try(result, f)\n}\n\"\n        ),\n        \"\nimport testing\n\npub fn main() {\n  testing.always_inline(Ok(10), Error)\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_with_use() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/bool\", BOOL_MODULE),\n        \"\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.guard(when: b == 0, return: 0)\n  a / b\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_with_use_and_anonymous() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/bool\", BOOL_MODULE),\n        r#\"\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.lazy_guard(b == 0, fn() { panic as \"Cannot divide by 0\" })\n  a / b\n}\n\"#\n    );\n}\n\n#[test]\nfn inline_function_with_use_becomes_tail_recursive() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/bool\", BOOL_MODULE),\n        \"\nimport gleam/bool\n\npub fn count(from: Int, to: Int) -> Int {\n  use <- bool.guard(when: from >= to, return: from)\n  echo from\n  count(from + 1, to)\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_inline_parameters_used_more_than_once() {\n    // Since the `something` parameter is used more than once in the body of the\n    // function, it should not be inlined, and should be assigned once at the\n    // beginning of the function.\n    assert_js!(\n        (\n            \"gleam_stdlib\",\n            \"testing\",\n            \"\npub fn always_inline(something) {\n  case something {\n    True -> something\n    False -> False\n  }\n}\n\"\n        ),\n        \"\nimport testing\n\npub fn main() {\n  testing.always_inline(True)\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_inline_parameters_that_have_side_effects() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        r#\"\nimport gleam/result\n\npub fn main() {\n  result.map(Ok(10), do_side_effects())\n}\n\nfn do_side_effects() {\n  let function = fn(x) { x + 1 }\n  panic as \"Side effects\"\n  function\n}\n\"#\n    );\n}\n\n#[test]\nfn inline_anonymous_function_call() {\n    assert_js!(\n        \"\npub fn main() {\n  fn(a, b) { #(a, b) }(42, False)\n}\n\"\n    );\n}\n\n#[test]\nfn inline_anonymous_function_in_pipe() {\n    assert_js!(\n        \"\npub fn main() {\n  1 |> fn(x) { x + 1 } |> fn(y) { y * y }\n}\n\"\n    );\n}\n\n#[test]\nfn inline_function_capture_in_pipe() {\n    // The function capture is desugared to an anonymous function, so it should\n    // be turned into a direct call to `add`\n    assert_js!(\n        \"\npub fn main() {\n  1 |> add(4, _)\n}\n\nfn add(a, b) { a + b }\n\"\n    );\n}\n\n#[test]\nfn inlining_works_through_blocks() {\n    assert_js!(\n        \"\npub fn main() {\n    { fn(x) { Ok(x + 1) } }(41)\n}\n\"\n    );\n}\n\n#[test]\nfn blocks_get_preserved_when_needed() {\n    assert_js!(\n        \"\npub fn main() {\n    { 4 |> make_adder }(6)\n}\n\nfn make_adder(a) {\n  fn(b) { a + b }\n}\n\"\n    );\n}\n\n#[test]\nfn blocks_get_preserved_when_needed2() {\n    assert_js!(\n        \"\npub fn main() {\n    fn(x) { 1 + x }(2) * 3\n}\n\"\n    );\n}\n\n#[test]\nfn parameters_from_nested_functions_are_correctly_inlined() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub fn halve_all(a, b, c) {\n  use x <- result.try(divide(a, 2))\n  use y <- result.try(divide(b, 2))\n  use z <- result.map(divide(c, 2))\n\n  #(x, y, z)\n}\n\nfn divide(a, b) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4852\n#[test]\nfn inlining_works_properly_with_record_updates() {\n    assert_js!(\n        (\"gleam_stdlib\", \"gleam/result\", RESULT_MODULE),\n        \"\nimport gleam/result\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let w = Wibble(1, 2)\n  use b <- result.map(Ok(3))\n  Wibble(..w, b:)\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4877\n#[test]\nfn inline_shadowed_variable() {\n    assert_js!(\n        \"\npub fn main() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn inline_variable_shadowing_parameter() {\n    assert_js!(\n        \"\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn inline_shadowed_variable_nested() {\n    assert_js!(\n        \"\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    fn(y) {\n      let a = 10\n      y - a\n    }(x + a)\n\n    a\n  }(a + b)\n\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn inline_variable_shadowed_in_case_pattern() {\n    assert_js!(\n        \"\npub fn sum() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    case 7, 8 {\n      a, b -> a + b + x\n    }\n  }(a + b)\n\n  a + b\n}\n\"\n    );\n}\n\n#[test]\nfn inline_variable_shadowing_case_pattern() {\n    assert_js!(\n        \"\npub fn sum() {\n  case 1, 2 {\n    a, b -> fn(x) {\n      let a = 7\n      x + a\n    }(a + b)\n  }\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/lists.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn list_literals() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  []\n  [1]\n  [1, 2]\n  [1, 2, ..x]\n}\n\"#,\n    );\n}\n\n#[test]\nfn long_list_literals() {\n    assert_js!(\n        r#\"\npub fn go() {\n  [111111111111111111111111111111111111111111111111111111111111111111111111]\n  [11111111111111111111111111111111111111111111, 1111111111111111111111111111111111111111111]\n}\n\"#,\n    );\n}\n\n#[test]\nfn multi_line_list_literals() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n    [{True 1}]\n}\n\"#,\n    );\n}\n\n#[test]\nfn list_constants() {\n    assert_js!(\n        r#\"\npub const a = []\npub const b = [1, 2, 3]\n\"#,\n    );\n}\n\n#[test]\nfn list_constants_typescript() {\n    assert_ts_def!(\n        r#\"\npub const a = []\npub const b = [1, 2, 3]\n\"#,\n    );\n}\n\n#[test]\nfn list_destructuring() {\n    assert_js!(\n        r#\"\npub fn go(x, y) {\n  let assert [] = x\n  let assert [a] = x\n  let assert [1, 2] = x\n  let assert [_, #(3, b)] = y\n  let assert [head, ..tail] = y\n}\n\"#,\n    );\n}\n\n#[test]\nfn equality() {\n    assert_js!(\n        r#\"\npub fn go() {\n  [] == [1]\n  [] != [1]\n}\n\"#,\n    );\n}\n\n#[test]\nfn case() {\n    assert_js!(\n        r#\"\npub fn go(xs) {\n  case xs {\n    [] -> 0\n    [_] -> 1\n    [_, _] -> 2\n    _ -> 9999\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2904\n#[test]\nfn tight_empty_list() {\n    assert_js!(\n        r#\"\npub fn go(func) {\n  let huuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuge_variable = []\n}\n\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/modules.rs",
    "content": "use crate::assert_js;\nuse crate::javascript::tests::CURRENT_PACKAGE;\n\n#[test]\nfn empty_module() {\n    // Renders an export statement to ensure it's an ESModule\n    assert_js!(\"\", \"export {}\\n\");\n}\n\n#[test]\nfn unqualified_fn_call() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub fn launch() { 1 }\"#),\n        r#\"import rocket_ship.{launch}\npub fn go() { launch() }\n\"#,\n    );\n}\n\n#[test]\nfn aliased_unqualified_fn_call() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub fn launch() { 1 }\"#),\n        r#\"import rocket_ship.{launch as boom_time}\npub fn go() { boom_time() }\n\"#,\n    );\n}\n\n#[test]\nfn multiple_unqualified_fn_call() {\n    assert_js!(\n        (\n            CURRENT_PACKAGE,\n            \"rocket_ship\",\n            r#\"\npub fn a() { 1 }\npub fn b() { 2 }\"#\n        ),\n        r#\"import rocket_ship.{a,b as bb}\npub fn go() { a() + bb() }\n\"#,\n    );\n}\n\n#[test]\nfn constant() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub const x = 1\"#),\n        r#\"\nimport rocket_ship\npub fn go() { rocket_ship.x }\n\"#,\n    );\n}\n\n#[test]\nfn alias_aliased_constant() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub const x = 1\"#),\n        r#\"\nimport rocket_ship.{ x as y }\npub const z = y\n\"#,\n    );\n}\n\n#[test]\nfn renamed_module() {\n    assert_js!(\n        (\"x\", r#\"pub const v = 1\"#),\n        r#\"\nimport x as y\npub const z = y.v\n\"#,\n    );\n}\n\n#[test]\nfn nested_module_constant() {\n    assert_js!(\n        (\n            CURRENT_PACKAGE,\n            \"rocket_ship/launcher\",\n            r#\"pub const x = 1\"#\n        ),\n        r#\"\nimport rocket_ship/launcher\npub fn go() { launcher.x }\n\"#,\n    );\n}\n\n#[test]\nfn alias_constant() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub const x = 1\"#),\n        r#\"\nimport rocket_ship as boop\npub fn go() { boop.x }\n\"#,\n    );\n}\n\n#[test]\nfn alias_fn_call() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub fn go() { 1 }\"#),\n        r#\"\nimport rocket_ship as boop\npub fn go() { boop.go() }\n\"#,\n    );\n}\n\n#[test]\nfn nested_fn_call() {\n    assert_js!(\n        (\"one/two\", r#\"pub fn go() { 1 }\"#),\n        r#\"import one/two\npub fn go() { two.go() }\"#,\n    );\n}\n\n#[test]\nfn nested_nested_fn_call() {\n    assert_js!(\n        (\"one/two/three\", r#\"pub fn go() { 1 }\"#),\n        r#\"import one/two/three\npub fn go() { three.go() }\"#,\n    );\n}\n\n#[test]\nfn different_package_import() {\n    assert_js!(\n        (\"other_package\", \"one\", r#\"pub fn go() { 1 }\"#),\n        r#\"import one\npub fn go() { one.go() }\n\"#,\n    );\n}\n\n#[test]\nfn nested_same_package() {\n    assert_js!(\n        (\"one/two/three\", r#\"pub fn go() { 1 }\"#),\n        r#\"import one/two/three\npub fn go() { three.go() }\n\"#,\n    );\n}\n\n#[test]\nfn discarded_duplicate_import() {\n    assert_js!(\n        (\"esa/rocket_ship\", r#\"pub fn go() { 1 }\"#),\n        (\"nasa/rocket_ship\", r#\"pub fn go() { 1 }\"#),\n        r#\"\nimport esa/rocket_ship\nimport nasa/rocket_ship as _nasa_rocket\npub fn go() { rocket_ship.go() }\n\"#\n    );\n}\n\n#[test]\nfn discarded_duplicate_import_with_unqualified() {\n    assert_js!(\n        (\"esa/rocket_ship\", r#\"pub fn go() { 1 }\"#),\n        (\"nasa/rocket_ship\", r#\"pub fn go() { 1 }\"#),\n        r#\"\nimport esa/rocket_ship\nimport nasa/rocket_ship.{go} as _nasa_rocket\npub fn esa_go() { rocket_ship.go() }\npub fn nasa_go() { go() }\n\"#\n    );\n}\n\n#[test]\nfn import_with_keyword() {\n    assert_js!(\n        (\n            CURRENT_PACKAGE,\n            \"rocket_ship\",\n            r#\"\npub const class = 1\npub const in = 2\n\"#\n        ),\n        r#\"\nimport rocket_ship.{class, in as while}\npub fn main() {\n  #(class, while)\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3004\n#[test]\nfn constant_module_access_with_keyword() {\n    assert_js!(\n        (\"rocket_ship\", r#\"pub const class = 1\"#),\n        r#\"\nimport rocket_ship\npub const variable = rocket_ship.class\n\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/numbers.rs",
    "content": "use crate::{assert_js, assert_js_module_error};\n\n#[test]\nfn int_literals() {\n    assert_js!(\n        r#\"\npub fn go() {\n  1\n  2\n  -3\n  4001\n  0b00001111\n  0o17\n  0xF\n  1_000\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_literals() {\n    assert_js!(\n        r#\"\npub fn go() {\n  1.5\n  2.0\n  -0.1\n  1.\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_scientific_literals() {\n    assert_js!(\n        r#\"\npub fn go() {\n  0.01e-1\n  0.01e-0\n  -10.01e-1\n  -10.01e-0\n  -100.001e-523\n  -100.001e-123_456_789\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_operators() {\n    assert_js!(\n        r#\"\npub fn go() {\n  1 + 1 // => 2\n  5 - 1 // => 4\n  5 / 2 // => 2\n  3 * 3 // => 9\n  5 % 2 // => 1\n  2 > 1  // => True\n  2 < 1  // => False\n  2 >= 1 // => True\n  2 <= 1 // => False\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_divide_complex_expr() {\n    assert_js!(\n        r#\"\npub fn go() {\n  case 1 >= 0 {\n    True -> 2\n    False -> 4\n  } / 2\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_mod_complex_expr() {\n    assert_js!(\n        r#\"\npub fn go() {\n  case 1 >= 0 {\n    True -> 2\n    False -> 4\n  } % 2\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_operators() {\n    assert_js!(\n        r#\"\npub fn go() {\n    1.0 +. 1.4 // => 2.4\n    5.0 -. 1.5 // => 3.5\n    5.0 /. 2.0 // => 2.5\n    3.0 *. 3.1 // => 9.3\n\n    2.0 >. 1.0  // => True\n    2.0 <. 1.0  // => False\n    2.0 >=. 1.0 // => True\n    2.0 <=. 1.0 // => False\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_divide_complex_expr() {\n    assert_js!(\n        r#\"\npub fn go() {\n  case 1.0 >=. 0.0 {\n    True -> 2.0\n    False -> 4.0\n  } /. 2.0\n}\n\"#,\n    );\n}\n\n#[test]\nfn wide_float_div() {\n    assert_js!(\n        r#\"\npub fn go() {\n  111111111111111111111111111111. /. 22222222222222222222222222222222222.\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_patterns() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert 4 = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_equality() {\n    assert_js!(\n        r#\"\npub fn go() {\n  1 != 2\n  1 == 2\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_equality1() {\n    assert_js!(\n        r#\"\npub fn go(y) {\n  let x = 1\n  x == y\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_equality() {\n    assert_js!(\n        r#\"\npub fn go() {\n  1.0 != 2.0\n  1.0 == 2.0\n}\n\"#,\n    );\n}\n\n#[test]\nfn float_equality1() {\n    assert_js!(\n        r#\"\npub fn go(y) {\n  let x = 1.0\n  x == y\n}\n\"#,\n    );\n}\n\n#[test]\nfn operator_precedence() {\n    assert_js!(\n        r#\"\npub fn go() {\n  2.4 *. { 3.5 +. 6.0 }\n}\n\"#,\n    )\n}\n\n#[test]\nfn remainder() {\n    assert_js!(\n        r#\"\npub fn go() {\n  5 % 0 // => 0\n}\n\"#,\n    );\n}\n\n#[test]\nfn int_negation() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let a = 3\n  let b = -a\n}\n\"#,\n    );\n}\n\n#[test]\nfn repeated_int_negation() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let a = 3\n  let b = --a\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2412\n#[test]\nfn preceeding_zeros_int() {\n    assert_js!(\n        r#\"\npub fn main() {\n  09_179\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5459\n#[test]\nfn many_preceeding_zeros_int() {\n    assert_js!(\n        r#\"\npub fn main() {\n  0000_000_00_9_179\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2412\n#[test]\nfn preceeding_zeros_float() {\n    assert_js!(\n        r#\"\npub fn main() {\n  09_179.1\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5459\n#[test]\nfn many_preceeding_zeros_float() {\n    assert_js!(\n        r#\"\npub fn main() {\n  0000_000_00_9_179.1\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2412\n#[test]\nfn preceeding_zeros_int_const() {\n    assert_js!(\n        r#\"\npub const x = 09_179\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5459\n#[test]\nfn many_preceeding_zeros_int_const() {\n    assert_js!(\n        r#\"\npub const x = 0000_000_00_9_179\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2412\n#[test]\nfn preceeding_zeros_float_const() {\n    assert_js!(\n        r#\"\npub const x = 09_179.1\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5459\n#[test]\nfn many_preceeding_zeros_float_const() {\n    assert_js!(\n        r#\"\npub const x = 0000_000_00_9_179.1\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2412\n#[test]\nfn preceeding_zeros_int_pattern() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  let assert 09_179 = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5459\n#[test]\nfn many_preceeding_zeros_int_pattern() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  let assert 0000_000_00_9_179 = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2412\n#[test]\nfn preceeding_zeros_float_pattern() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  let assert 09_179.1 = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5459\n#[test]\nfn many_preceeding_zeros_float_pattern() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  let assert 0000_000_00_9_179.1 = x\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4459\n#[test]\nfn underscore_after_hexadecimal_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0x_12_34\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4459\n#[test]\nfn underscore_after_octal_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0o_12_34\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4459\n#[test]\nfn underscore_after_binary_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0b_10_01\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4481\n#[test]\nfn underscore_after_zero_after_hex_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0x0_1_2_3\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4481\n#[test]\nfn underscore_after_zero_after_octal_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0o0_1_2_3\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4481\n#[test]\nfn underscore_after_zero_after_binary_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0b0_1_0_1\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4481\n#[test]\nfn underscore_after_zero() {\n    assert_js!(\n        \"\npub fn main() {\n  0_1_2_3\n}\n\"\n    );\n}\n\n#[test]\nfn zero_after_underscore_after_hex_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0x_0_1_2_3\n}\n\"\n    );\n}\n\n#[test]\nfn zero_after_underscore_after_octal_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0o_0_1_2_3\n}\n\"\n    );\n}\n\n#[test]\nfn zero_after_underscore_after_binary_prefix() {\n    assert_js!(\n        \"\npub fn main() {\n  0b_0_1_0_1\n}\n\"\n    );\n}\n\n#[test]\nfn underscore_after_decimal_point() {\n    assert_js!(\n        \"\npub fn main() {\n  0._1\n}\n\"\n    );\n}\n\n#[test]\nfn underscore_after_decimal_point_case_statement() {\n    assert_js!(\n        \"\npub fn main(x) {\n  case x {\n    0._1 -> \\\"wobble\\\"\n    _ -> \\\"wibble\\\"\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inf_float_case_statement() {\n    assert_js_module_error!(\n        \"\npub fn main(x) {\n  case x {\n  100.001e123_456_789 -> \\\"wobble\\\"\n    _ -> \\\"wibble\\\"\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn division_inf_by_inf_float() {\n    assert_js_module_error!(\n        \"\npub fn main(x) {\n  -100.001e123_456_789 /. 100.001e123_456_789\n}\n\"\n    );\n}\n\n#[test]\nfn division_by_zero_float() {\n    assert_js!(\n        \"pub fn main() {\n  1.1 /. 0.0\n}\"\n    )\n}\n\n#[test]\nfn division_by_non_zero_float() {\n    assert_js!(\n        \"pub fn main() {\n  1.1 /. 2.3\n}\"\n    )\n}\n\n#[test]\nfn complex_division_by_non_zero_float() {\n    assert_js!(\n        \"pub fn main() {\n  { 1.1 +. 2.0 } /. 2.3\n}\"\n    )\n}\n\n#[test]\nfn division_by_zero_int() {\n    assert_js!(\n        \"pub fn main() {\n  1 / 0\n}\"\n    )\n}\n\n#[test]\nfn division_by_non_zero_int() {\n    assert_js!(\n        \"pub fn main() {\n  1 / 2\n}\"\n    )\n}\n\n#[test]\nfn complex_division_by_non_zero_int() {\n    assert_js!(\n        \"pub fn main() {\n  { 1 + 2 } / 3\n}\"\n    )\n}\n\n#[test]\nfn remainder_by_zero_int() {\n    assert_js!(\n        \"pub fn main() {\n  1 % 0\n}\"\n    )\n}\n\n#[test]\nfn remainder_by_non_zero_int() {\n    assert_js!(\n        \"pub fn main() {\n  1 % 2\n}\"\n    )\n}\n\n#[test]\nfn complex_remainder_by_non_zero_int() {\n    assert_js!(\n        \"pub fn main() {\n  { 1 + 2 } % 3\n}\"\n    )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/panic.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn bare() {\n    assert_js!(\n        r#\"\npub fn go() {\n  panic\n}\n\"#,\n    );\n}\n\n#[test]\nfn panic_as() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = \"wibble\"\n  panic as x\n}\n\"#,\n    );\n}\n\n#[test]\nfn bare_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn go() {\n  panic\n}\n\"#,\n    );\n}\n\n#[test]\nfn as_expression() {\n    assert_js!(\n        r#\"\npub fn go(f) {\n  let boop = panic\n  f(panic)\n}\n\"#,\n    );\n}\n\n#[test]\nfn pipe() {\n    assert_js!(\n        r#\"\npub fn go(f) {\n  f |> panic\n}\n\"#,\n    );\n}\n\n#[test]\nfn sequence() {\n    assert_js!(\n        r#\"\npub fn go(at_the_disco) {\n  panic\n  at_the_disco\n}\n\"#,\n    );\n}\n\n#[test]\nfn case() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    _ -> panic\n  }\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4471\n#[test]\nfn case_message() {\n    assert_js!(\n        r#\"\npub fn crash(message) {\n  panic as case message {\n    Ok(message) -> message\n    Error(_) -> \"No message provided\"\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/prelude.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn qualified_ok() {\n    assert_js!(\n        r#\"import gleam\npub fn go() { gleam.Ok(1) }\n\"#,\n    );\n}\n\n#[test]\nfn qualified_ok_typescript() {\n    assert_ts_def!(\n        r#\"import gleam\npub fn go() { gleam.Ok(1) }\n\"#,\n    );\n}\n\n#[test]\nfn qualified_error() {\n    assert_js!(\n        r#\"import gleam\npub fn go() { gleam.Error(1) }\n\"#,\n    );\n}\n\n#[test]\nfn qualified_nil() {\n    assert_js!(\n        r#\"import gleam\npub fn go() { gleam.Nil }\n\"#,\n    );\n}\n\n#[test]\nfn qualified_nil_typescript() {\n    assert_ts_def!(\n        r#\"import gleam\npub fn go() { gleam.Nil }\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4756\n#[test]\nfn qualified_prelude_value_does_not_conflict_with_local_value() {\n    assert_js!(\n        \"\nimport gleam\n\npub type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\npub fn main() {\n  gleam.Ok(10)\n}\n\",\n    );\n}\n\n#[test]\nfn qualified_prelude_value_does_not_conflict_with_local_value_constant() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\npub const error = gleam.Error(\"Bad\")\n\"#,\n    );\n}\n\n#[test]\nfn qualified_prelude_value_does_not_conflict_with_local_value_pattern() {\n    assert_js!(\n        r#\"\nimport gleam\n\npub type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\npub fn go(x) {\n  case x {\n    gleam.Ok(x) -> x\n    gleam.Error(_) -> 0\n  }\n}\n\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/records.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn record_accessors() {\n    // We can use record accessors for types with only one constructor\n    assert_js!(\n        r#\"\npub type Person { Person(name: String, age: Int) }\npub fn get_age(person: Person) { person.age }\npub fn get_name(person: Person) { person.name }\n\"#\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants() {\n    // We can access fields on custom types with multiple variants\n    assert_js!(\n        \"\npub type Person {\n    Teacher(name: String, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\"\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants_positions_other_than_first() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_js!(\n        \"\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn record_accessor_multiple_with_first_position_different_types() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_js!(\n        \"\npub type Person {\n    Teacher(name: Nil, age: Int)\n    Student(name: String, age: Int)\n}\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants_parameterised_types() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_js!(\n        \"\npub type Person {\n    Teacher(name: String, age: List(Int), title: String)\n    Student(name: String, age: List(Int))\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4603\n#[test]\nfn field_named_x0() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(Int, x0: String)\n}\n\"\n    );\n}\n\n#[test]\nfn field_named_then_is_escaped() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(then: fn() -> Int)\n}\n\"\n    );\n}\n\n#[test]\nfn field_named_constructor_is_escaped() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(constructor: fn() -> Wibble)\n}\n\"\n    );\n}\n\n#[test]\nfn field_named_prototype_is_escaped() {\n    assert_js!(\n        \"\npub type Wibble {\n  Wibble(prototype: String)\n}\n\"\n    );\n}\n\n#[test]\nfn const_record_update_generic_respecialization() {\n    assert_js!(\n        \"\npub type Box(a) {\n  Box(name: String, value: a)\n}\n\npub const base = Box(\\\"score\\\", 50)\npub const updated = Box(..base, value: \\\"Hello\\\")\n\npub fn main() {\n  #(base, updated)\n}\n\",\n    );\n}\n\n#[test]\nfn record_update_with_unlabelled_fields() {\n    assert_js!(\n        r#\"\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub fn main() {\n  let record = Wibble(1, 3.14, True, \"Hello\")\n  Wibble(..record, b: False)\n}\n\"#\n    );\n}\n\n#[test]\nfn constant_record_update_with_unlabelled_fields() {\n    assert_js!(\n        r#\"\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub const record = Wibble(1, 3.14, True, \"Hello\")\npub const updated = Wibble(..record, b: False)\n\npub fn main() {\n  updated\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/recursion.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn tco() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  case x {\n    0 -> Nil\n    _ -> main(x - 1)\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn tco_case_block() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  case x {\n    0 -> Nil\n    _ -> {\n      let y = x\n      main(y - 1)\n    }\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1779\n#[test]\nfn not_tco_due_to_assignment() {\n    assert_js!(\n        r#\"\npub fn main(x) {\n  let z = {\n    let y = x\n    main(y - 1)\n  }\n  z\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2400\n#[test]\nfn shadowing_so_not_recursive() {\n    // This funtion is calling an argument with the same name as itself, so it is not recursive\n    assert_js!(\n        r#\"\npub fn map(map) {\n  map()\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/results.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn ok() {\n    assert_js!(r#\"pub fn main() { Ok(1) }\"#);\n}\n\n#[test]\nfn error() {\n    assert_js!(r#\"pub fn main() { Error(1) }\"#);\n}\n\n#[test]\nfn ok_fn() {\n    assert_js!(r#\"pub fn main() { Ok }\"#);\n}\n\n#[test]\nfn error_fn() {\n    assert_js!(r#\"pub fn main() { Error }\"#);\n}\n\n#[test]\nfn qualified_ok() {\n    assert_js!(\n        r#\"import gleam\npub fn main() { gleam.Ok(1) }\"#\n    );\n}\n\n#[test]\nfn qualified_error() {\n    assert_js!(\n        r#\"import gleam\npub fn main() { gleam.Error(1) }\"#\n    );\n}\n\n#[test]\nfn qualified_ok_fn() {\n    assert_js!(\n        r#\"import gleam\npub fn main() { gleam.Ok }\"#\n    );\n}\n\n#[test]\nfn qualified_error_fn() {\n    assert_js!(\n        r#\"import gleam\npub fn main() { gleam.Error }\"#\n    );\n}\n\n#[test]\nfn aliased_ok() {\n    assert_js!(\n        r#\"import gleam.{Ok as Thing}\npub fn main() { Thing(1) }\"#\n    );\n}\n\n#[test]\nfn aliased_error() {\n    assert_js!(\n        r#\"import gleam.{Error as Thing}\npub fn main() { Thing(1) }\"#\n    );\n}\n\n#[test]\nfn aliased_ok_fn() {\n    assert_js!(\n        r#\"import gleam.{Ok as Thing}\npub fn main() { Thing }\"#\n    );\n}\n\n#[test]\nfn aliased_error_fn() {\n    assert_js!(\n        r#\"import gleam.{Error as Thing}\npub fn main() { Thing }\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_binary_operation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 28\nexpression: \"\\npub fn main() {\\n  let x = True\\n  assert x || False\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = True\n  assert x || False\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let x = true;\n  \n  if (!(x || false)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"||\",\n        left: { kind: \"expression\", value: false, start: 41, end: 42 },\n        right: { kind: \"literal\", value: false, start: 46, end: 51 },\n        start: 34,\n        end: 51,\n        expression_start: 41\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_binary_operation2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 40\nexpression: \"\\npub fn eq(a, b) {\\n  assert a == b\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn eq(a, b) {\n  assert a == b\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, isEqual } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function eq(a, b) {\n  if (!(isEqual(a, b))) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"eq\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"==\",\n        left: { kind: \"expression\", value: a, start: 28, end: 29 },\n        right: { kind: \"expression\", value: b, start: 33, end: 34 },\n        start: 21,\n        end: 34,\n        expression_start: 28\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_binary_operation3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 51\nexpression: \"\\npub fn assert_answer(x) {\\n  assert x == 42\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn assert_answer(x) {\n  assert x == 42\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function assert_answer(x) {\n  let $ = 42;\n  if (!(x === $)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"assert_answer\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"==\",\n        left: { kind: \"expression\", value: x, start: 36, end: 37 },\n        right: { kind: \"literal\", value: $, start: 41, end: 43 },\n        start: 29,\n        end: 43,\n        expression_start: 36\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_binary_operator_with_side_effects.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\nfn wibble(a, b) {\\n  let result = a + b\\n  result == 10\\n}\\n\\npub fn go(x) {\\n  assert True && wibble(1, 4)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert True && wibble(1, 4)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction wibble(a, b) {\n  let result = a + b;\n  return result === 10;\n}\n\nexport function go(x) {\n  if (true) {\n    if (!wibble(1, 4)) {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        8,\n        \"go\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"literal\", value: true, start: 82, end: 86 },\n          right: { kind: \"expression\", value: false, start: 90, end: 102 },\n          start: 75,\n          end: 102,\n          expression_start: 82\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      8,\n      \"go\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"literal\", value: false, start: 82, end: 86 },\n        right: { kind: \"unevaluated\", start: 90, end: 102 },\n        start: 75,\n        end: 102,\n        expression_start: 82\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_binary_operator_with_side_effects2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\nfn wibble(a, b) {\\n  let result = a + b\\n  result == 10\\n}\\n\\npub fn go(x) {\\n  assert wibble(5, 5) && wibble(4, 6)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(a, b) {\n  let result = a + b\n  result == 10\n}\n\npub fn go(x) {\n  assert wibble(5, 5) && wibble(4, 6)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction wibble(a, b) {\n  let result = a + b;\n  return result === 10;\n}\n\nexport function go(x) {\n  if (wibble(5, 5)) {\n    if (!wibble(4, 6)) {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        8,\n        \"go\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"expression\", value: true, start: 82, end: 94 },\n          right: { kind: \"expression\", value: false, start: 98, end: 110 },\n          start: 75,\n          end: 110,\n          expression_start: 82\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      8,\n      \"go\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"expression\", value: false, start: 82, end: 94 },\n        right: { kind: \"unevaluated\", start: 98, end: 110 },\n        start: 75,\n        end: 110,\n        expression_start: 82\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_function_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 62\nexpression: \"\\nfn bool() {\\n  True\\n}\\n\\npub fn main() {\\n  assert bool()\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn bool() {\n  True\n}\n\npub fn main() {\n  assert bool()\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction bool() {\n  return true;\n}\n\nexport function main() {\n  if (!bool()) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      7,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"function_call\",\n        arguments: [],\n        start: 41,\n        end: 54,\n        expression_start: 48\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_function_call2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 77\nexpression: \"\\nfn and(a, b) {\\n  a && b\\n}\\n\\npub fn go(x) {\\n  assert and(True, x)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn and(a, b) {\n  a && b\n}\n\npub fn go(x) {\n  assert and(True, x)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction and(a, b) {\n  return a && b;\n}\n\nexport function go(x) {\n  if (!and(true, x)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      7,\n      \"go\",\n      \"Assertion failed.\",\n      {\n        kind: \"function_call\",\n        arguments: [\n          { kind: \"literal\", value: true, start: 56, end: 60 },\n          { kind: \"expression\", value: x, start: 62, end: 63 },\n        ],\n        start: 45,\n        end: 64,\n        expression_start: 52\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_literal.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 17\nexpression: \"\\npub fn main() {\\n  assert False\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert False\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (!false) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"expression\",\n        expression: { kind: \"literal\", value: false, start: 26, end: 31 },\n        start: 19,\n        end: 31,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_nested_function_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 92\nexpression: \"\\nfn and(x, y) {\\n  x && y\\n}\\n\\npub fn main() {\\n  assert and(and(True, False), True)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn and(x, y) {\n  x && y\n}\n\npub fn main() {\n  assert and(and(True, False), True)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction and(x, y) {\n  return x && y;\n}\n\nexport function main() {\n  let $ = and(true, false);\n  if (!and($, true)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      7,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"function_call\",\n        arguments: [\n          { kind: \"expression\", value: $, start: 57, end: 73 },\n          { kind: \"literal\", value: true, start: 75, end: 79 },\n        ],\n        start: 46,\n        end: 80,\n        expression_start: 53\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_nil_always_throws.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn go(x: Nil) {\\n  let assert Nil = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x: Nil) {\n  let assert Nil = x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  \n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_variable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 5\nexpression: \"\\npub fn main() {\\n  let x = True\\n  assert x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = True\n  assert x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let x = true;\n  if (!x) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"expression\",\n        expression: { kind: \"expression\", value: false, start: 41, end: 42 },\n        start: 34,\n        end: 42,\n        expression_start: 41\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_block_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 150\nexpression: \"\\nfn identity(a) {\\n  a\\n}\\n\\npub fn main() {\\n  assert identity(True) as {\\n    let message = identity(\\\"This shouldn't fail\\\")\\n    message\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn identity(a) {\n  a\n}\n\npub fn main() {\n  assert identity(True) as {\n    let message = identity(\"This shouldn't fail\")\n    message\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction identity(a) {\n  return a;\n}\n\nexport function main() {\n  if (!identity(true)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      7,\n      \"main\",\n      (() => {\n        let message = identity(\"This shouldn't fail\");\n        return message;\n      })(),\n      {\n        kind: \"function_call\",\n        arguments: [{ kind: \"literal\", value: true, start: 59, end: 63 }],\n        start: 43,\n        end: 64,\n        expression_start: 50\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_case_rhs.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True && case 1 > 2 {\\n    True -> True\\n    False -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True && case 1 > 2 {\n    True -> True\n    False -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (true) {\n    if (!(() => {\n        let $ = 1 > 2;\n        if ($) {\n          return $;\n        } else {\n          return $;\n        }\n      })()) {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"literal\", value: true, start: 26, end: 30 },\n          right: { kind: \"expression\", value: false, start: 34, end: 86 },\n          start: 19,\n          end: 86,\n          expression_start: 26\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"literal\", value: false, start: 26, end: 30 },\n        right: { kind: \"unevaluated\", start: 34, end: 86 },\n        start: 19,\n        end: 86,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_logical_and_binary_rhs_1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True && 3 < 4\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True && 3 < 4\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (true) {\n    if (3 >= 4) {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"literal\", value: true, start: 26, end: 30 },\n          right: { kind: \"expression\", value: false, start: 34, end: 39 },\n          start: 19,\n          end: 39,\n          expression_start: 26\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"literal\", value: false, start: 26, end: 30 },\n        right: { kind: \"unevaluated\", start: 34, end: 39 },\n        start: 19,\n        end: 39,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_logical_and_binary_rhs_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True && \\\"wibble\\\" == \\\"wibble\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True && \"wibble\" == \"wibble\"\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (true) {\n    if (\"wibble\" !== \"wibble\") {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"literal\", value: true, start: 26, end: 30 },\n          right: { kind: \"expression\", value: false, start: 34, end: 54 },\n          start: 19,\n          end: 54,\n          expression_start: 26\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"literal\", value: false, start: 26, end: 30 },\n        right: { kind: \"unevaluated\", start: 34, end: 54 },\n        start: 19,\n        end: 54,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_logical_and_binary_rhs_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True && \\\"wobble\\\" != \\\"wobble\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True && \"wobble\" != \"wobble\"\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (true) {\n    if (\"wobble\" === \"wobble\") {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"literal\", value: true, start: 26, end: 30 },\n          right: { kind: \"expression\", value: false, start: 34, end: 54 },\n          start: 19,\n          end: 54,\n          expression_start: 26\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"literal\", value: false, start: 26, end: 30 },\n        right: { kind: \"unevaluated\", start: 34, end: 54 },\n        start: 19,\n        end: 54,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nassertion_line: 139\nexpression: \"\\npub fn main() {\\n  assert True as \\\"This shouldn't fail\\\"\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True as \"This shouldn't fail\"\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (!true) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"This shouldn't fail\",\n      {\n        kind: \"expression\",\n        expression: { kind: \"literal\", value: false, start: 26, end: 30 },\n        start: 19,\n        end: 30,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_negated_case_rhs.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True && !case 3 - 2 {\\n    1 -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True && !case 3 - 2 {\n    1 -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  if (true) {\n    if ((() => {\n        let $ = 3 - 2;\n        if ($ === 1) {\n          return true;\n        } else {\n          return false;\n        }\n      })()) {\n      throw makeError(\n        \"assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Assertion failed.\",\n        {\n          kind: \"binary_operator\",\n          operator: \"&&\",\n          left: { kind: \"literal\", value: true, start: 26, end: 30 },\n          right: { kind: \"expression\", value: false, start: 34, end: 80 },\n          start: 19,\n          end: 80,\n          expression_start: 26\n        }\n      )\n    }\n  } else {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"&&\",\n        left: { kind: \"literal\", value: false, start: 26, end: 30 },\n        right: { kind: \"unevaluated\", start: 34, end: 80 },\n        start: 19,\n        end: 80,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__assert_with_pipe_on_right.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\nfn add(a, b) { a + b }\\n\\npub fn main() {\\n  assert 3 == 1 |> add(2)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(a, b) { a + b }\n\npub fn main() {\n  assert 3 == 1 |> add(2)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction add(a, b) {\n  return a + b;\n}\n\nexport function main() {\n  let _block;\n  let $ = 3;\n  let _pipe = 1;\n  _block = add(_pipe, 2);\n  let $1 = _block;\n  if (!($ === $1)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      5,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"==\",\n        left: { kind: \"literal\", value: $, start: 50, end: 51 },\n        right: { kind: \"expression\", value: $1, start: 55, end: 66 },\n        start: 43,\n        end: 66,\n        expression_start: 50\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assert__prova.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert Ok([]) == Ok([] |> id)\\n}\\n\\nfn id(x) { x }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert Ok([]) == Ok([] |> id)\n}\n\nfn id(x) { x }\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, toList, makeError, isEqual } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction id(x) {\n  return x;\n}\n\nexport function main() {\n  let $ = new Ok(toList([]));\n  let $1 = new Ok(\n    (() => {\n      let _pipe = toList([]);\n      return id(_pipe);\n    })(),\n  );\n  if (!(isEqual($, $1))) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"==\",\n        left: { kind: \"literal\", value: $, start: 26, end: 32 },\n        right: { kind: \"expression\", value: $1, start: 36, end: 48 },\n        start: 19,\n        end: 48,\n        expression_start: 26\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__assert.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn go(x) { let assert 1 = x }\"\n---\n----- SOURCE CODE\npub fn go(x) { let assert 1 = x }\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x === 1)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      1,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 15, end: 31, pattern_start: 26, pattern_end: 27 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__assert1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn go(x) { let assert #(1, 2) = x }\"\n---\n----- SOURCE CODE\npub fn go(x) { let assert #(1, 2) = x }\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = x[0];\n  if ($ === 1) {\n    let $1 = x[1];\n    if (!($1 === 2)) {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        1,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: x, start: 15, end: 37, pattern_start: 26, pattern_end: 33 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      1,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 15, end: 37, pattern_start: 26, pattern_end: 33 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__assert_that_always_fails.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(Int)\\n    Wobble(Int)\\n}\\n\\npub fn go() {\\n  let assert Wobble(n) = Wibble(1)\\n  n\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n}\n\npub fn go() {\n  let assert Wobble(n) = Wibble(1)\n  n\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nclass Wibble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nexport function go() {\n  let $ = new Wibble(1);\n  let n;\n  throw makeError(\n    \"let_assert\",\n    FILEPATH,\n    \"my/mod\",\n    8,\n    \"go\",\n    \"Pattern match failed, no pattern matched the value.\",\n    { value: $, start: 66, end: 98, pattern_start: 77, pattern_end: 86 }\n  )\n  return n;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__assert_that_always_succeeds.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(Int)\\n}\\n\\npub fn go() {\\n  let assert Wibble(n) = Wibble(1)\\n  n\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    Wibble(Int)\n}\n\npub fn go() {\n  let assert Wibble(n) = Wibble(1)\n  n\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nclass Wibble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nexport function go() {\n  let $ = new Wibble(1);\n  let n;\n  n = $[0];\n  return n;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__assert_with_multiple_variants.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(Int)\\n    Wobble(Int)\\n    Woo(Int)\\n}\\n\\npub fn go() {\\n  let assert Wobble(n) = todo\\n  n\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n    Woo(Int)\n}\n\npub fn go() {\n  let assert Wobble(n) = todo\n  n\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nclass Wibble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Woo extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nexport function go() {\n  let _block;\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    9,\n    \"go\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n  let $ = _block;\n  let n;\n  if ($ instanceof Wobble) {\n    n = $[0];\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      9,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 79, end: 106, pattern_start: 90, pattern_end: 99 }\n    )\n  }\n  return n;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__case_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn expect(value, message) {\\n  let assert Ok(inner) = value as case message {\\n    Ok(message) -> message\\n    Error(_) -> \\\"No message provided\\\"\\n  }\\n  inner\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn expect(value, message) {\n  let assert Ok(inner) = value as case message {\n    Ok(message) -> message\n    Error(_) -> \"No message provided\"\n  }\n  inner\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function expect(value, message) {\n  let inner;\n  if (value instanceof Ok) {\n    inner = value[0];\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"expect\",\n      (() => {\n        if (message instanceof Ok) {\n          let message$1 = message[0];\n          return message$1;\n        } else {\n          return \"No message provided\";\n        }\n      })(),\n      { value: value, start: 35, end: 63, pattern_start: 46, pattern_end: 55 }\n    )\n  }\n  return inner;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__catch_all_assert.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(Int)\\n    Wobble(Int)\\n}\\n\\npub fn go() {\\n  let assert _ = Wibble(1)\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n}\n\npub fn go() {\n  let assert _ = Wibble(1)\n  1\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nclass Wibble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nexport function go() {\n  let $ = new Wibble(1);\n  \n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__constant_assignments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nassertion_line: 63\nexpression: \"\\nconst a = True\\n\\npub fn go() {\\n  a\\n  let a = 10\\n  a + 20\\n}\\n\\nfn second() {\\n  let a = 10\\n  a + 20\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nconst a = True\n\npub fn go() {\n  a\n  let a = 10\n  a + 20\n}\n\nfn second() {\n  let a = 10\n  a + 20\n}\n\n\n----- COMPILED JAVASCRIPT\nconst a = true;\n\nexport function go() {\n  a;\n  let a$1 = 10;\n  return a$1 + 20;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__correct_variable_renaming_in_assigned_functions.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn debug(x) {\\n  let x = x\\n  fn(x) { x + 1 }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn debug(x) {\n  let x = x\n  fn(x) { x + 1 }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function debug(x) {\n  let x$1 = x;\n  return (x) => { return x + 1; };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__escaped_variables_in_constants.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub const class = 5\\npub const something = class\\n\"\n---\n----- SOURCE CODE\n\npub const class = 5\npub const something = class\n\n\n----- COMPILED JAVASCRIPT\nexport const class$ = 5;\n\nexport const something = class$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__keyword_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn main() {\\n  let class = 10\\n  let debugger = 50\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let class = 10\n  let debugger = 50\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let class$ = 10;\n  let debugger$ = 50;\n  return debugger$;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__let_assert_nested_string_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: String)\\n}\\n\\npub fn main() {\\n  let assert Wibble(wibble: \\\"w\\\" as prefix <> rest) = Wibble(\\\"wibble\\\")\\n  prefix <> rest\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble(wibble: String)\n}\n\npub fn main() {\n  let assert Wibble(wibble: \"w\" as prefix <> rest) = Wibble(\"wibble\")\n  prefix <> rest\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nclass Wibble extends $CustomType {\n  constructor(wibble) {\n    super();\n    this.wibble = wibble;\n  }\n}\n\nexport function main() {\n  let $ = new Wibble(\"wibble\");\n  let prefix;\n  let rest;\n  let $1 = $.wibble;\n  if ($1.startsWith(\"w\")) {\n    prefix = \"w\";\n    rest = $1.slice(1);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      7,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 61, end: 128, pattern_start: 72, pattern_end: 109 }\n    )\n  }\n  return prefix + rest;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__let_assert_string_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn main() {\\n  let assert \\\"Game \\\" <> id = \\\"Game 1\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert \"Game \" <> id = \"Game 1\"\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = \"Game 1\";\n  let id;\n  if ($.startsWith(\"Game \")) {\n    id = $.slice(5);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 19, end: 54, pattern_start: 30, pattern_end: 43 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn unwrap_or_panic(value) {\\n  let assert Ok(inner) = value as \\\"Oops, there was an error\\\"\\n  inner\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn unwrap_or_panic(value) {\n  let assert Ok(inner) = value as \"Oops, there was an error\"\n  inner\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function unwrap_or_panic(value) {\n  let inner;\n  if (value instanceof Ok) {\n    inner = value[0];\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"unwrap_or_panic\",\n      \"Oops, there was an error\",\n      { value: value, start: 35, end: 63, pattern_start: 46, pattern_end: 55 }\n    )\n  }\n  return inner;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__module_const_var.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub const int = 42\\npub const int_alias = int\\npub fn use_int_alias() { int_alias }\\n\\npub const compound: #(Int, Int) = #(int, int_alias)\\npub fn use_compound() { compound.0 + compound.1 }\\n\"\n---\n----- SOURCE CODE\n\npub const int = 42\npub const int_alias = int\npub fn use_int_alias() { int_alias }\n\npub const compound: #(Int, Int) = #(int, int_alias)\npub fn use_compound() { compound.0 + compound.1 }\n\n\n----- COMPILED JAVASCRIPT\nexport const int = 42;\n\nexport const int_alias = int;\n\nexport const compound = [int, int_alias];\n\nexport function use_int_alias() {\n  return int_alias;\n}\n\nexport function use_compound() {\n  return compound[0] + compound[1];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__module_const_var1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub const int = 42\\npub const int_alias = int\\npub const compound: #(Int, Int) = #(int, int_alias)\\n\"\n---\n----- SOURCE CODE\n\npub const int = 42\npub const int_alias = int\npub const compound: #(Int, Int) = #(int, int_alias)\n\n\n----- TYPESCRIPT DEFINITIONS\nexport const int: number;\n\nexport const int_alias: number;\n\nexport const compound: [number, number];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__nested_binding.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn go(x) {\\n  let assert #(a, #(b, c, 2) as t, _, 1) = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert #(a, #(b, c, 2) as t, _, 1) = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let t;\n  let b;\n  let c;\n  let $ = x[3];\n  if ($ === 1) {\n    let $1 = x[1][2];\n    if ($1 === 2) {\n      a = x[0];\n      t = x[1];\n      b = x[1][0];\n      c = x[1][1];\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: x, start: 18, end: 60, pattern_start: 29, pattern_end: 56 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 60, pattern_start: 29, pattern_end: 56 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__rebound_argument.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn main(x) {\\n  let x = False\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x) {\n  let x = False\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x) {\n  let x$1 = false;\n  return x$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__rebound_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn x() {\\n  Nil\\n}\\n\\npub fn main() {\\n  let x = False\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\npub fn x() {\n  Nil\n}\n\npub fn main() {\n  let x = False\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function x() {\n  return undefined;\n}\n\nexport function main() {\n  let x$1 = false;\n  return x$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__rebound_function_and_arg.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn x() {\\n  Nil\\n}\\n\\npub fn main(x) {\\n  let x = False\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\npub fn x() {\n  Nil\n}\n\npub fn main(x) {\n  let x = False\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function x() {\n  return undefined;\n}\n\nexport function main(x) {\n  let x$1 = false;\n  return x$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__returning_literal_subject.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn go(x) { let assert 1 = x + 1 }\"\n---\n----- SOURCE CODE\npub fn go(x) { let assert 1 = x + 1 }\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = x + 1;\n  if (!($ === 1)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      1,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 15, end: 35, pattern_start: 26, pattern_end: 27 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__tuple_matching.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn go(x) {\\n  let assert #(1, 2) = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert #(1, 2) = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = x[0];\n  if ($ === 1) {\n    let $1 = x[1];\n    if (!($1 === 2)) {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: x, start: 18, end: 40, pattern_start: 29, pattern_end: 36 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 40, pattern_start: 29, pattern_end: 36 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__use_discard_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(Int)\\n    Wobble(Int)\\n    Woo(Int)\\n}\\n\\nfn fun(f) { f(Wibble(1)) }\\n\\npub fn go() {\\n  use _ <- fun\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    Wibble(Int)\n    Wobble(Int)\n    Woo(Int)\n}\n\nfn fun(f) { f(Wibble(1)) }\n\npub fn go() {\n  use _ <- fun\n  1\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nclass Wibble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Woo extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nfunction fun(f) {\n  return f(new Wibble(1));\n}\n\nexport function go() {\n  return fun((_) => { return 1; });\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__use_matching_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\nfn fun(f) { f(#(2, 4)) }\\n\\npub fn go() {\\n  use #(_, n) <- fun\\n  n\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn fun(f) { f(#(2, 4)) }\n\npub fn go() {\n  use #(_, n) <- fun\n  n\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction fun(f) {\n  return f([2, 4]);\n}\n\nexport function go() {\n  return fun(\n    (_use0) => {\n      let n;\n      n = _use0[1];\n      return n;\n    },\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__variable_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\npub fn expect(value, message) {\\n  let assert Ok(inner) = value as message\\n  inner\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn expect(value, message) {\n  let assert Ok(inner) = value as message\n  inner\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function expect(value, message) {\n  let inner;\n  if (value instanceof Ok) {\n    inner = value[0];\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"expect\",\n      message,\n      { value: value, start: 35, end: 63, pattern_start: 46, pattern_end: 55 }\n    )\n  }\n  return inner;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__variable_renaming.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"\\n\\npub fn go(x, wibble) {\\n  let a = 1\\n  wibble(a)\\n  let a = 2\\n  wibble(a)\\n  let assert #(a, 3) = x\\n  let b = a\\n  wibble(b)\\n  let c = {\\n    let a = a\\n    #(a, b)\\n  }\\n  wibble(a)\\n  // make sure arguments are counted in initial state\\n  let x = c\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\n\n\npub fn go(x, wibble) {\n  let a = 1\n  wibble(a)\n  let a = 2\n  wibble(a)\n  let assert #(a, 3) = x\n  let b = a\n  wibble(b)\n  let c = {\n    let a = a\n    #(a, b)\n  }\n  wibble(a)\n  // make sure arguments are counted in initial state\n  let x = c\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x, wibble) {\n  let a = 1;\n  wibble(a);\n  let a$1 = 2;\n  wibble(a$1);\n  let a$2;\n  let $ = x[1];\n  if ($ === 3) {\n    a$2 = x[0];\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      8,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 75, end: 97, pattern_start: 86, pattern_end: 93 }\n    )\n  }\n  let b = a$2;\n  wibble(b);\n  let _block;\n  {\n    let a$3 = a$2;\n    _block = [a$3, b];\n  }\n  let c = _block;\n  wibble(a$2);\n  let x$1 = c;\n  return x$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__variable_used_in_pattern_and_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/assignments.rs\nexpression: \"pub fn main(x) {\\n  let #(x) = #(x)\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x) {\n  let #(x) = #(x)\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x) {\n  let $ = [x];\n  let x$1;\n  x$1 = $[0];\n  return x$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__alternative_patterns_with_variable_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1918\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_, n, rest:size(n)>> |\\n    <<n, _, rest:size(n)>> -> True\\n    _ -> False\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_, n, rest:size(n)>> |\n    <<n, _, rest:size(n)>> -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 8 && x.bitSize >= 16) {\n    let n = x.byteAt(1);\n    if (x.bitSize === 16 + n) {\n      let n$1 = n;\n      let rest = bitArraySliceToInt(x, 16, 16 + n$1, true, false);\n      return true;\n    } else {\n      let n = x.byteAt(0);\n      if (x.bitSize === 16 + n) {\n        let n$1 = n;\n        let rest = bitArraySliceToInt(x, 16, 16 + n$1, true, false);\n        return true;\n      } else {\n        return false;\n      }\n    }\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__as_module_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\n          pub const data = <<\\n            0x1,\\n            2,\\n            2:size(16),\\n            0x4:size(32),\\n            -1:32,\\n            \\\"Gleam\\\":utf8,\\n            4.2:float,\\n            4.2:32-float,\\n            <<0xFA>>:bits-6,\\n            -1:64,\\n            <<\\n              <<1, 2, 3>>:bits,\\n              \\\"Gleam\\\":utf8,\\n              1024\\n            >>:bits\\n          >>\\n        \"\n---\n----- SOURCE CODE\n\n          pub const data = <<\n            0x1,\n            2,\n            2:size(16),\n            0x4:size(32),\n            -1:32,\n            \"Gleam\":utf8,\n            4.2:float,\n            4.2:32-float,\n            <<0xFA>>:bits-6,\n            -1:64,\n            <<\n              <<1, 2, 3>>:bits,\n              \"Gleam\":utf8,\n              1024\n            >>:bits\n          >>\n        \n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice, sizedInt, stringBits, sizedFloat } from \"../gleam.mjs\";\n\nexport const data = /* @__PURE__ */ toBitArray([\n  1,\n  2,\n  0, 2,\n  0, 0, 0, 4,\n  255, 255, 255, 255,\n  stringBits(\"Gleam\"),\n  sizedFloat(4.2, 64, true),\n  sizedFloat(4.2, 32, true),\n  bitArraySlice(/* @__PURE__ */ toBitArray([250]), 0, 6),\n  sizedInt(-1, 64, true),\n  /* @__PURE__ */ toBitArray([\n    /* @__PURE__ */ toBitArray([1, 2, 3]),\n    stringBits(\"Gleam\"),\n    0,\n  ]),\n]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_assignment_discard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n let assert <<_ as number>> = <<10>>\\n number\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n let assert <<_ as number>> = <<10>>\n number\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([10]);\n  let number;\n  if ($.bitSize === 8) {\n    number = $.byteAt(0);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 53, pattern_start: 29, pattern_end: 44 }\n    )\n  }\n  return number;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_assignment_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n let assert <<3.14 as pi:float>> = <<3.14>>\\n pi\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n let assert <<3.14 as pi:float>> = <<3.14>>\n pi\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySliceToFloat, sizedFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([sizedFloat(3.14, 64, true)]);\n  let pi;\n  if ($.bitSize === 64 && bitArraySliceToFloat($, 0, 64, true) === 3.14) {\n    pi = 3.14;\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 60, pattern_start: 29, pattern_end: 49 }\n    )\n  }\n  return pi;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_assignment_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n let assert <<1 as a>> = <<1>>\\n a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n let assert <<1 as a>> = <<1>>\n a\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([1]);\n  let a;\n  if ($.bitSize === 8 && $.byteAt(0) === 1) {\n    a = 1;\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 47, pattern_start: 29, pattern_end: 39 }\n    )\n  }\n  return a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_assignment_string.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n let assert <<\\\"Hello, world!\\\" as message:utf8>> = <<\\\"Hello, world!\\\">>\\n message\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n let assert <<\"Hello, world!\" as message:utf8>> = <<\"Hello, world!\">>\n message\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, stringBits } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([stringBits(\"Hello, world!\")]);\n  let message;\n  if (\n    $.bitSize === 104 &&\n    $.byteAt(0) === 72 &&\n      $.byteAt(1) === 101 &&\n      $.byteAt(2) === 108 &&\n      $.byteAt(3) === 108 &&\n      $.byteAt(4) === 111 &&\n      $.byteAt(5) === 44 &&\n      $.byteAt(6) === 32 &&\n      $.byteAt(7) === 119 &&\n      $.byteAt(8) === 111 &&\n      $.byteAt(9) === 114 &&\n      $.byteAt(10) === 108 &&\n      $.byteAt(11) === 100 &&\n      $.byteAt(12) === 33\n  ) {\n    message = \"Hello, world!\";\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 86, pattern_start: 29, pattern_end: 64 }\n    )\n  }\n  return message;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_dynamic_slice.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 380\nexpression: \"\\npub fn go(x) {\\n  let i = 4\\n  <<<<0xAB>>:bits-size(i)>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let i = 4\n  <<<<0xAB>>:bits-size(i)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let i = 4;\n  return toBitArray([bitArraySlice(toBitArray([171]), 0, i)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_literal_string_constant_is_treated_as_utf8.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1742\nexpression: \"pub const a = <<\\\"hello\\\", \\\" \\\", \\\"world\\\">>\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub const a = <<\"hello\", \" \", \"world\">>\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringBits } from \"../gleam.mjs\";\n\nexport const a = /* @__PURE__ */ toBitArray([\n  stringBits(\"hello\"),\n  stringBits(\" \"),\n  stringBits(\"world\"),\n]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_literal_string_is_treated_as_utf8.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"hello\\\", \\\" \\\", \\\"world\\\">>\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"hello\", \" \", \"world\">>\n}\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringBits } from \"../gleam.mjs\";\n\nexport function main() {\n  return toBitArray([stringBits(\"hello\"), stringBits(\" \"), stringBits(\"world\")]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_literal_string_pattern_is_treated_as_utf8.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  case <<>> {\\n    <<\\\"a\\\", \\\"b\\\", _:bytes>> -> 1\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case <<>> {\n    <<\"a\", \"b\", _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = toBitArray([]);\n  if (\n    $.bitSize >= 8 &&\n    $.byteAt(0) === 97 &&\n    $.bitSize >= 16 &&\n    $.byteAt(1) === 98 &&\n    ($.bitSize - 16) % 8 === 0\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_pattern_match_all_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main(x) {\\n    case x {\\n    <<_, \\\"==\\\">> -> 1\\n    <<_, _, \\\"=\\\">> -> 2\\n    // ^^^ This should be reachable\\n    _ -> 3\\n    }\\n}\\n        \"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n    case x {\n    <<_, \"==\">> -> 1\n    <<_, _, \"=\">> -> 2\n    // ^^^ This should be reachable\n    _ -> 3\n    }\n}\n        \n\n----- COMPILED JAVASCRIPT\nexport function main(x) {\n  if (x.bitSize >= 8 && x.bitSize === 24) {\n    if (x.byteAt(1) === 61 && x.byteAt(2) === 61) {\n      return 1;\n    } else if (x.byteAt(2) === 61) {\n      return 2;\n    } else {\n      return 3;\n    }\n  } else {\n    return 3;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_array_sliced.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 369\nexpression: \"\\npub fn go(x) {\\n  <<<<0xAB>>:bits-4>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<<<0xAB>>:bits-4>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([bitArraySlice(toBitArray([171]), 0, 4)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_string.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 347\nexpression: \"\\npub fn go(x) {\\n  <<x:bits>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:bits>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([x]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bit_string_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  <<x:bits>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:bits>>\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport function go(x: _.BitArray): _.BitArray;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bits.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 358\nexpression: \"\\npub fn go(x) {\\n  <<x:bits>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:bits>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([x]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bits_pattern_requires_v1_9.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<_:bits>> = <<0>>\\n}\\n  \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<_:bits>> = <<0>>\n}\n  \n\n----- WARNING\nwarning: Redundant assertion\n  ┌─ /src/warning/wrn.gleam:3:7\n  │\n3 │   let assert <<_:bits>> = <<0>>\n  │       ^^^^^^ You can remove this\n\nThis assertion is redundant since the pattern covers all possibilities.\n\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:18\n  │\n3 │   let assert <<_:bits>> = <<0>>\n  │                  ^^^^ This requires a Gleam version >= 1.9.0\n\nUse of unaligned bit arrays on the JavaScript target was introduced in\nversion v1.9.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.8.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.9.0\"\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__bits_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  <<x:bits>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:bits>>\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport function go(x: _.BitArray): _.BitArray;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__block_in_pattern_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<len, payload:size({ len - 1 } * 8)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<len, payload:size({ len - 1 } * 8)>> = <<>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([]);\n  let len$1;\n  let payload;\n  if ($.bitSize >= 8) {\n    let len = $.byteAt(0);\n    if ((len - 1) * 8 >= 0 && $.bitSize === 8 + (len - 1) * 8) {\n      len$1 = len;\n      payload = bitArraySliceToInt($, 8, 8 + (len$1 - 1) * 8, true, false);\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: $, start: 19, end: 75, pattern_start: 30, pattern_end: 68 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 19, end: 75, pattern_start: 30, pattern_end: 68 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_bit_array_assignment_discard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n case x {\\n    <<_ as n>>\\n    | <<_ as n, _:bytes>> -> n\\n    _ -> 1\\n }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n case x {\n    <<_ as n>>\n    | <<_ as n, _:bytes>> -> n\n    _ -> 1\n }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 8) {\n    let n = x.byteAt(0);\n    return n;\n  } else if (x.bitSize >= 8 && (x.bitSize - 8) % 8 === 0) {\n    let n = x.byteAt(0);\n    return n;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_bit_array_assignment_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n case x {\\n    <<3.14 as pi:float>>\\n    | <<1.1 as pi:float, _:bytes>> -> pi\\n    _ -> 1.1\\n }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n case x {\n    <<3.14 as pi:float>>\n    | <<1.1 as pi:float, _:bytes>> -> pi\n    _ -> 1.1\n }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (bitArraySliceToFloat(x, 0, 64, true) === 3.14) {\n      let pi = 3.14;\n      return pi;\n    } else if (\n      bitArraySliceToFloat(x, 0, 64, true) === 1.1 &&\n      (x.bitSize - 64) % 8 === 0\n    ) {\n      let pi = 1.1;\n      return pi;\n    } else {\n      return 1.1;\n    }\n  } else if (\n    x.bitSize >= 64 &&\n    bitArraySliceToFloat(x, 0, 64, true) === 1.1 &&\n    (x.bitSize - 64) % 8 === 0\n  ) {\n    let pi = 1.1;\n    return pi;\n  } else {\n    return 1.1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_bit_array_assignment_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n case x {\\n    <<1 as n>>\\n    | <<2 as n, _:bytes>> -> n\\n    _ -> 1\\n }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n case x {\n    <<1 as n>>\n    | <<2 as n, _:bytes>> -> n\n    _ -> 1\n }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 8) {\n    if (x.byteAt(0) === 1) {\n      let n = 1;\n      return n;\n    } else if (x.byteAt(0) === 2 && (x.bitSize - 8) % 8 === 0) {\n      let n = 2;\n      return n;\n    } else {\n      return 1;\n    }\n  } else if (x.bitSize >= 8 && x.byteAt(0) === 2 && (x.bitSize - 8) % 8 === 0) {\n    let n = 2;\n    return n;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_bit_array_assignment_string.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n case x {\\n    <<\\\"Hello\\\" as message>>\\n    | <<\\\"Jak\\\" as message, _:bytes>> -> message\\n    _ -> \\\"wibble\\\"\\n }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n case x {\n    <<\"Hello\" as message>>\n    | <<\"Jak\" as message, _:bytes>> -> message\n    _ -> \"wibble\"\n }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 40) {\n    if (\n      x.byteAt(0) === 72 &&\n        x.byteAt(1) === 101 &&\n        x.byteAt(2) === 108 &&\n        x.byteAt(3) === 108 &&\n        x.byteAt(4) === 111\n    ) {\n      let message = \"Hello\";\n      return message;\n    } else if (\n      x.byteAt(0) === 74 && x.byteAt(1) === 97 && x.byteAt(2) === 107 &&\n      (x.bitSize - 24) % 8 === 0\n    ) {\n      let message = \"Jak\";\n      return message;\n    } else {\n      return \"wibble\";\n    }\n  } else if (\n    x.bitSize >= 24 &&\n    x.byteAt(0) === 74 && x.byteAt(1) === 97 && x.byteAt(2) === 107 &&\n    (x.bitSize - 24) % 8 === 0\n  ) {\n    let message = \"Jak\";\n    return message;\n  } else {\n    return \"wibble\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_discard_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1117\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:16, _:8>> -> 1\\n    _ -> 2\\n  }\\n  case x {\\n    <<_:16-little-signed, _:8>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:16, _:8>> -> 1\n    _ -> 2\n  }\n  case x {\n    <<_:16-little-signed, _:8>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize >= 16 && x.bitSize === 24) {\n    1\n  } else {\n    2\n  }\n  if (x.bitSize >= 16 && x.bitSize === 24) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_dynamic_size_float_pattern_with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let size = 3\\n  case x {\\n    <<1.3:size(size)-unit(2)>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let size = 3\n  case x {\n    <<1.3:size(size)-unit(2)>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let size = 3;\n  if (\n    size * 2 >= 0 &&\n    x.bitSize === size * 2 &&\n    bitArraySliceToFloat(x, 0, size * 2, true) === 1.3\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_dynamic_size_pattern_with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let size = 3\\n  case x {\\n    <<1:size(size)-unit(2)>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let size = 3\n  case x {\n    <<1:size(size)-unit(2)>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let size = 3;\n  if (\n    size * 2 >= 0 &&\n    x.bitSize === size * 2 &&\n    bitArraySliceToInt(x, 0, size * 2, true, false) === 1\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_empty_match.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 425\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 0) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_is_byte_aligned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1904\nexpression: \"\\npub fn is_byte_aligned(x) {\\n  case x {\\n    <<_:bytes>> -> True\\n    _ -> False\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn is_byte_aligned(x) {\n  case x {\n    <<_:bytes>> -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function is_byte_aligned(x) {\n  if (x.bitSize % 8 === 0) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_binary_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1599\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_, a:2-bytes>> -> a\\n    _ -> x\\n  }\\n\\n  case x {\\n    <<_, b:bytes-size(2)>> -> b\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_, a:2-bytes>> -> a\n    _ -> x\n  }\n\n  case x {\n    <<_, b:bytes-size(2)>> -> b\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 8 && x.bitSize === 24) {\n    let a = bitArraySlice(x, 8, 24);\n    a\n  } else {\n    x\n  }\n  if (x.bitSize >= 8 && x.bitSize === 24) {\n    let b = bitArraySlice(x, 8, 24);\n    return b;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_bits_with_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1498\nexpression: \"\\npub fn go(x) {\\n  case <<0x77:7>> {\\n    <<_:4, f:bits-2, _:1>> -> f\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case <<0x77:7>> {\n    <<_:4, f:bits-2, _:1>> -> f\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice, sizedInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let $ = toBitArray([sizedInt(0x77, 7, true)]);\n  if ($.bitSize >= 4 && $.bitSize >= 6 && $.bitSize === 7) {\n    let f = bitArraySlice($, 4, 6);\n    return f;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_bytes.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 450\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1, y>> -> y\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1, y>> -> y\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize >= 8 && x.byteAt(0) === 1 && x.bitSize === 16) {\n    let y = x.byteAt(1);\n    return y;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_bytes_with_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1473\nexpression: \"\\npub fn go(x) {\\n  case <<1, 2>> {\\n    <<f:bytes-2>> -> f\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case <<1, 2>> {\n    <<f:bytes-2>> -> f\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2]);\n  if ($.bitSize === 16) {\n    let f = bitArraySlice($, 0, 16);\n    return f;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_dynamic_bits_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1063\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  case x {\\n    <<a:bits-size(n)>> -> a\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  case x {\n    <<a:bits-size(n)>> -> a\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 16;\n  if (n >= 0 && x.bitSize === n) {\n    let a = bitArraySlice(x, 0, n);\n    return a;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_dynamic_bytes_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 3\\n  case x {\\n    <<a:bytes-size(n)>> -> a\\n    _ -> x\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 3\n  case x {\n    <<a:bytes-size(n)>> -> a\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 3;\n  if (n * 8 >= 0 && x.bitSize === n * 8) {\n    let a = bitArraySlice(x, 0, n * 8);\n    return a;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_dynamic_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 951\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  case x {\\n    <<a:size(n)>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  case x {\n    <<a:size(n)>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 16;\n  if (n >= 0 && x.bitSize === n) {\n    let a = bitArraySliceToInt(x, 0, n, true, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_dynamic_size_literal_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1036\nexpression: \"\\npub fn go(x) {\\n  let n = 8\\n  case x {\\n    <<a:size(n), 0b010101:size(8)>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 8\n  case x {\n    <<a:size(n), 0b010101:size(8)>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 8;\n  if (\n    n >= 0 &&\n    x.bitSize >= n &&\n    x.bitSize === 8 + n &&\n    bitArraySliceToInt(x, n, n + 8, true, false) === 21\n  ) {\n    let a = bitArraySliceToInt(x, 0, n, true, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_dynamic_size_shadowed_variable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1008\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  let n = 5\\n  case x {\\n    <<a:size(n)>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  let n = 5\n  case x {\n    <<a:size(n)>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 16;\n  let n$1 = 5;\n  if (n$1 >= 0 && x.bitSize === n$1) {\n    let a = bitArraySliceToInt(x, 0, n$1, true, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_dynamic_size_with_other_segments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 979\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  let m = 32\\n  case x {\\n    <<first:size(8), a:size(n), b:size(m), rest:bits>> -> first + a + b\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  let m = 32\n  case x {\n    <<first:size(8), a:size(n), b:size(m), rest:bits>> -> first + a + b\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice, bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 16;\n  let m = 32;\n  if (\n    x.bitSize >= 8 &&\n    n >= 0 &&\n    x.bitSize >= 8 + n &&\n    m >= 0 &&\n    x.bitSize >= 8 + m + n\n  ) {\n    let first = x.byteAt(0);\n    let a = bitArraySliceToInt(x, 8, 8 + n, true, false);\n    let b = bitArraySliceToInt(x, 8 + n, 8 + n + m, true, false);\n    let rest = bitArraySlice(x, 8 + m + n);\n    return (first + a) + b;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1196\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float, b:int>> -> #(a, b)\\n    _ -> #(1.1, 2)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 64 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 64, true)) &&\n    x.bitSize === 72\n  ) {\n    let a = bitArraySliceToFloat(x, 0, 64, true);\n    let b = x.byteAt(8);\n    return [a, b];\n  } else {\n    return [1.1, 2];\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float_16_bit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1423\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float-size(16)>> -> a\\n    _ -> 1.1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float-size(16)>> -> a\n    _ -> 1.1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16 && Number.isFinite(bitArraySliceToFloat(x, 0, 16, true))) {\n    let a = bitArraySliceToFloat(x, 0, 16, true);\n    return a;\n  } else {\n    return 1.1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1221\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float-big, b:int>> -> #(a, b)\\n    _ -> #(1.1, 1)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float-big, b:int>> -> #(a, b)\n    _ -> #(1.1, 1)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 64 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 64, true)) &&\n    x.bitSize === 72\n  ) {\n    let a = bitArraySliceToFloat(x, 0, 64, true);\n    let b = x.byteAt(8);\n    return [a, b];\n  } else {\n    return [1.1, 1];\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1246\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float-little, b:int>> -> #(a, b)\\n    _ -> #(1.1, 2)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float-little, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 64 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 64, false)) &&\n    x.bitSize === 72\n  ) {\n    let a = bitArraySliceToFloat(x, 0, 64, false);\n    let b = x.byteAt(8);\n    return [a, b];\n  } else {\n    return [1.1, 2];\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1271\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float-32, b:int>> -> #(a, b)\\n    _ -> #(1.1, 2)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float-32, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 32 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 32, true)) &&\n    x.bitSize === 40\n  ) {\n    let a = bitArraySliceToFloat(x, 0, 32, true);\n    let b = x.byteAt(4);\n    return [a, b];\n  } else {\n    return [1.1, 2];\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float_sized_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1296\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float-32-big, b:int>> -> #(a, b)\\n    _ -> #(1.1, 2)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float-32-big, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 32 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 32, true)) &&\n    x.bitSize === 40\n  ) {\n    let a = bitArraySliceToFloat(x, 0, 32, true);\n    let b = x.byteAt(4);\n    return [a, b];\n  } else {\n    return [1.1, 2];\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_float_sized_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1321\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:float-32-little, b:int>> -> #(a, b)\\n    _ -> #(1.1, 2)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:float-32-little, b:int>> -> #(a, b)\n    _ -> #(1.1, 2)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 32 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 32, false)) &&\n    x.bitSize === 40\n  ) {\n    let a = bitArraySliceToFloat(x, 0, 32, false);\n    let b = x.byteAt(4);\n    return [a, b];\n  } else {\n    return [1.1, 2];\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_literal_aligned_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1398\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_, 1.1, _:int>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_, 1.1, _:int>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 8 &&\n    x.bitSize >= 72 &&\n    bitArraySliceToFloat(x, 8, 72, true) === 1.1 &&\n    x.bitSize === 80\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_literal_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1346\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1.4, b:int>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1.4, b:int>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 64 &&\n    bitArraySliceToFloat(x, 0, 64, true) === 1.4 &&\n    x.bitSize === 72\n  ) {\n    let b = x.byteAt(8);\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_literal_unaligned_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1372\nexpression: \"\\npub fn go(x) {\\n  let n = 1\\n  case x {\\n    <<_:size(n), 1.1, _:int>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 1\n  case x {\n    <<_:size(n), 1.1, _:int>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 1;\n  if (\n    n >= 0 &&\n    x.bitSize >= n &&\n    x.bitSize >= 64 + n &&\n    bitArraySliceToFloat(x, n, n + 64, true) === 1.1 &&\n    x.bitSize === 72 + n\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_rest.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1448\nexpression: \"\\npub fn go(x) {\\n  case <<1, 2, 3>> {\\n    <<_, b:bytes>> -> b\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case <<1, 2, 3>> {\n    <<_, b:bytes>> -> b\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2, 3]);\n  if ($.bitSize >= 8 && ($.bitSize - 8) % 8 === 0) {\n    let b = bitArraySlice($, 8);\n    return b;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_rest_bits.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1548\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_, b:bits>> -> b\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_, b:bits>> -> b\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 8) {\n    let b = bitArraySlice(x, 8);\n    return b;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_rest_bits_unaligned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1573\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:5, b:bits>> -> b\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:5, b:bits>> -> b\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 5) {\n    let b = bitArraySlice(x, 5);\n    return b;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_rest_bytes.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1523\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_, b:bytes>> -> b\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_, b:bytes>> -> b\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 8 && (x.bitSize - 8) % 8 === 0) {\n    let b = bitArraySlice(x, 8);\n    return b;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_signed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 600\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:signed>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:signed>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 8) {\n    let a = bitArraySliceToInt(x, 0, 8, true, true);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_signed_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 625\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<-1:signed>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<-1:signed>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 8 && x.byteAt(0) === 255) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 475\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16, b:8>> -> a + b\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16, b:8>> -> a + b\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 16 && x.bitSize === 24) {\n    let a = bitArraySliceToInt(x, 0, 16, true, false);\n    let b = x.byteAt(2);\n    return a + b;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 650\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16-big>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16-big>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let a = bitArraySliceToInt(x, 0, 16, true, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_big_endian_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 675\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16-big>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16-big>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 4 && x.byteAt(1) === 210) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_big_endian_signed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 800\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16-big-signed>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16-big-signed>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let a = bitArraySliceToInt(x, 0, 16, true, true);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_big_endian_signed_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 825\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16-big-signed>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16-big-signed>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 4 && x.byteAt(1) === 210) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_big_endian_unsigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 750\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16-big-unsigned>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16-big-unsigned>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let a = bitArraySliceToInt(x, 0, 16, true, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_big_endian_unsigned_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 775\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16-big-unsigned>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16-big-unsigned>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 4 && x.byteAt(1) === 210) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 525\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16, 123:8>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16, 123:8>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (\n    x.bitSize >= 16 &&\n    x.byteAt(0) === 4 && x.byteAt(1) === 210 &&\n    x.bitSize === 24 &&\n    x.byteAt(2) === 123\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 700\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16-little>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16-little>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let a = bitArraySliceToInt(x, 0, 16, false, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_little_endian_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 725\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16-little>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16-little>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 210 && x.byteAt(1) === 4) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_little_endian_signed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 900\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16-little-signed>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16-little-signed>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let a = bitArraySliceToInt(x, 0, 16, false, true);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_little_endian_signed_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 925\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16-little-signed>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16-little-signed>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 210 && x.byteAt(1) === 4) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_little_endian_unsigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 850\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:16-little-unsigned>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:16-little-unsigned>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let a = bitArraySliceToInt(x, 0, 16, false, false);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_little_endian_unsigned_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 875\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1234:16-little-unsigned>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1234:16-little-unsigned>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 210 && x.byteAt(1) === 4) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_unaligned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 500\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:17, b:7>> -> b * 2\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:17, b:7>> -> b * 2\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 17 && x.bitSize === 24) {\n    let a = bitArraySliceToInt(x, 0, 17, true, false);\n    let b = bitArraySliceToInt(x, 17, 24, true, false);\n    return b * 2;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1146\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<i:16>> -> i\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<i:16>> -> i\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 16) {\n    let i = bitArraySliceToInt(x, 0, 16, true, false);\n    return i;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_sized_value_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1171\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<258:16>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<258:16>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 16 && x.byteAt(0) === 1 && x.byteAt(1) === 2) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_unsigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 550\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<a:unsigned>> -> a\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<a:unsigned>> -> a\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize === 8) {\n    let a = x.byteAt(0);\n    return a;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_match_unsigned_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<-2:unsigned>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<-2:unsigned>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  return 2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_pattern_with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1804\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<1:size(2)-unit(2), 2:size(3)-unit(4)>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<1:size(2)-unit(2), 2:size(3)-unit(4)>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (\n    x.bitSize >= 4 &&\n    bitArraySliceToInt(x, 0, 4, true, false) === 1 &&\n    x.bitSize === 16 &&\n    bitArraySliceToInt(x, 4, 16, true, false) === 2\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_with_remaining_bytes_after_constant_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1860\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_, _, _:bytes>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_, _, _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.bitSize >= 8 && x.bitSize >= 16 && (x.bitSize - 16) % 8 === 0) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_with_remaining_bytes_after_variable_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1874\nexpression: \"\\npub fn go(x) {\\n  let n = 1\\n  case x {\\n    <<_:size(n), _, _:bytes>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 1\n  case x {\n    <<_:size(n), _, _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let n = 1;\n  if (\n    n >= 0 &&\n    x.bitSize >= n &&\n    x.bitSize >= 8 + n &&\n    (x.bitSize - (8 + n)) % 8 === 0\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__case_with_remaining_bytes_after_variable_size_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1889\nexpression: \"\\npub fn go(x) {\\n  let n = 1\\n  case x {\\n    <<m:size(n), _:size(m), _:bytes>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 1\n  case x {\n    <<m:size(n), _:size(m), _:bytes>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 1;\n  if (n >= 0 && x.bitSize >= n) {\n    let m = bitArraySliceToInt(x, 0, n, true, false);\n    if (x.bitSize >= m + n && (x.bitSize - (m + n)) % 8 === 0) {\n      let m$1 = m;\n      return 1;\n    } else {\n      return 2;\n    }\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__const_utf16.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub const message = <<\\\"Hello, world!\\\":utf16>>\\n\"\n---\n----- SOURCE CODE\n\npub const message = <<\"Hello, world!\":utf16>>\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringToUtf16 } from \"../gleam.mjs\";\n\nexport const message = /* @__PURE__ */ toBitArray([\n  stringToUtf16(\"Hello, world!\", true),\n]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__const_utf32.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub const message = <<\\\"Hello, world!\\\":utf32>>\\n\"\n---\n----- SOURCE CODE\n\npub const message = <<\"Hello, world!\":utf32>>\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringToUtf32 } from \"../gleam.mjs\";\n\nexport const message = /* @__PURE__ */ toBitArray([\n  stringToUtf32(\"Hello, world!\", true),\n]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__discard_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_:16, _:8>> = x\\n  let assert <<_:16-little-signed, _:8>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_:16, _:8>> = x\n  let assert <<_:16-little-signed, _:8>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize >= 16 && x.bitSize === 24)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 46, pattern_start: 29, pattern_end: 42 }\n    )\n  }\n  if (!(x.bitSize >= 16 && x.bitSize === 24)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 49, end: 91, pattern_start: 60, pattern_end: 87 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__dynamic_size_pattern_with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let size = 3\\n  let assert <<1:size(size)-unit(2)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let size = 3\n  let assert <<1:size(size)-unit(2)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let size = 3;\n  if (!(\n    size * 2 >= 0 &&\n    x.bitSize === size * 2 &&\n    bitArraySliceToInt(x, 0, size * 2, true, false) === 1\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 33, end: 72, pattern_start: 44, pattern_end: 68 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__dynamic_size_with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1781\nexpression: \"\\npub fn main() {\\n  let size = 3\\n  <<1:size(size)-unit(2)>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let size = 3\n  <<1:size(size)-unit(2)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function main() {\n  let size = 3;\n  return toBitArray([sizedInt(1, size * 2, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__empty.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 11\nexpression: \"\\npub fn go() {\\n  <<>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__empty_match.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 0)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 37, pattern_start: 29, pattern_end: 33 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__explicit_sized_constant_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 220\nexpression: \"\\npub fn go() {\\n  <<256:size(32)>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256:size(32)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([0, 0, 1, 0]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__explicit_sized_dynamic_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 231\nexpression: \"\\npub fn go(i: Int) {\\n  <<i:size(32)>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(i: Int) {\n  <<i:size(32)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function go(i) {\n  return toBitArray([sizedInt(i, 32, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 55\nexpression: \"\\npub fn go() {\\n  <<1.1:float>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<1.1:float>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedFloat } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedFloat(1.1, 64, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__float_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 66\nexpression: \"\\npub fn go() {\\n  <<1.1:float-big>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<1.1:float-big>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedFloat } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedFloat(1.1, 64, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__float_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 77\nexpression: \"\\npub fn go() {\\n  <<1.1:float-little>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<1.1:float-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedFloat } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedFloat(1.1, 64, false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__float_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 88\nexpression: \"\\npub fn go() {\\n  <<1.1:float-32>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<1.1:float-32>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedFloat } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedFloat(1.1, 32, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__float_sized_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 99\nexpression: \"\\npub fn go() {\\n  <<1.1:float-32-big>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<1.1:float-32-big>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedFloat } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedFloat(1.1, 32, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__float_sized_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 110\nexpression: \"\\npub fn go() {\\n  <<1.1:float-32-little>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<1.1:float-32-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedFloat } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedFloat(1.1, 32, false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__integer.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 44\nexpression: \"\\npub fn go() {\\n  <<256:int>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256:int>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([0]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_binary_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_, a:2-bytes>> = x\\n  let assert <<_, b:bytes-size(2)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_, a:2-bytes>> = x\n  let assert <<_, b:bytes-size(2)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize >= 8 && x.bitSize === 24) {\n    a = bitArraySlice(x, 8, 24);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 49, pattern_start: 29, pattern_end: 45 }\n    )\n  }\n  let b;\n  if (x.bitSize >= 8 && x.bitSize === 24) {\n    b = bitArraySlice(x, 8, 24);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 52, end: 89, pattern_start: 63, pattern_end: 85 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_bits_with_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_:4, f:bits-2, _:1>> = <<0x77:7>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_:4, f:bits-2, _:1>> = <<0x77:7>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySlice, sizedInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = toBitArray([sizedInt(0x77, 7, true)]);\n  let f;\n  if ($.bitSize >= 4 && $.bitSize >= 6 && $.bitSize === 7) {\n    f = bitArraySlice($, 4, 6);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 64, pattern_start: 29, pattern_end: 51 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_bytes.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1, y>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1, y>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let y;\n  if (x.bitSize >= 8 && x.byteAt(0) === 1 && x.bitSize === 16) {\n    y = x.byteAt(1);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 41, pattern_start: 29, pattern_end: 37 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_bytes_with_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<f:bytes-2>> = <<1, 2>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<f:bytes-2>> = <<1, 2>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2]);\n  let f;\n  if ($.bitSize === 16) {\n    f = bitArraySlice($, 0, 16);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 53, pattern_start: 29, pattern_end: 42 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_case_utf8.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 311\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<\\\"Gleam 👍\\\":utf8>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<\"Gleam 👍\":utf8>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (\n    x.bitSize === 80 &&\n    x.byteAt(0) === 71 &&\n      x.byteAt(1) === 108 &&\n      x.byteAt(2) === 101 &&\n      x.byteAt(3) === 97 &&\n      x.byteAt(4) === 109 &&\n      x.byteAt(5) === 32 &&\n      x.byteAt(6) === 240 &&\n      x.byteAt(7) === 159 &&\n      x.byteAt(8) === 145 &&\n      x.byteAt(9) === 141\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_case_utf8_with_escape_chars.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 297\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<\\\"\\\\\\\"\\\\\\\\\\\\r\\\\n\\\\t\\\\f\\\\u{1f600}\\\">> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<\"\\\"\\\\\\r\\n\\t\\f\\u{1f600}\">> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (\n    x.bitSize === 80 &&\n    x.byteAt(0) === 34 &&\n      x.byteAt(1) === 92 &&\n      x.byteAt(2) === 13 &&\n      x.byteAt(3) === 10 &&\n      x.byteAt(4) === 9 &&\n      x.byteAt(5) === 12 &&\n      x.byteAt(6) === 240 &&\n      x.byteAt(7) === 159 &&\n      x.byteAt(8) === 152 &&\n      x.byteAt(9) === 128\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_dynamic_bits_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  let assert <<a:bits-size(n)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  let assert <<a:bits-size(n)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 16;\n  let a;\n  if (n >= 0 && x.bitSize === n) {\n    a = bitArraySlice(x, 0, n);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 31, end: 64, pattern_start: 42, pattern_end: 60 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_dynamic_bytes_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 3\\n  let assert <<a:bytes-size(n)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 3\n  let assert <<a:bytes-size(n)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 3;\n  let a;\n  if (n * 8 >= 0 && x.bitSize === n * 8) {\n    a = bitArraySlice(x, 0, n * 8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 30, end: 64, pattern_start: 41, pattern_end: 60 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_dynamic_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  let assert <<a:size(n)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  let assert <<a:size(n)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 16;\n  let a;\n  if (n >= 0 && x.bitSize === n) {\n    a = bitArraySliceToInt(x, 0, n, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 31, end: 59, pattern_start: 42, pattern_end: 55 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_dynamic_size_literal_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 8\\n  let assert <<a:size(n), 0b010101:size(8)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 8\n  let assert <<a:size(n), 0b010101:size(8)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 8;\n  let a;\n  if (\n    n >= 0 &&\n    x.bitSize >= n &&\n    x.bitSize === 8 + n &&\n    bitArraySliceToInt(x, n, n + 8, true, false) === 21\n  ) {\n    a = bitArraySliceToInt(x, 0, n, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 30, end: 76, pattern_start: 41, pattern_end: 72 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_dynamic_size_shadowed_variable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  let n = 5\\n  let assert <<a:size(n)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  let n = 5\n  let assert <<a:size(n)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 16;\n  let n$1 = 5;\n  let a;\n  if (n$1 >= 0 && x.bitSize === n$1) {\n    a = bitArraySliceToInt(x, 0, n$1, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      5,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 43, end: 71, pattern_start: 54, pattern_end: 67 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_dynamic_size_with_other_segments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 16\\n  let m = 32\\n  let assert <<first:size(8), a:size(n), b:size(m), rest:bits>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 16\n  let m = 32\n  let assert <<first:size(8), a:size(n), b:size(m), rest:bits>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySlice, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 16;\n  let m = 32;\n  let first;\n  let a;\n  let b;\n  let rest;\n  if (\n    x.bitSize >= 8 &&\n    n >= 0 &&\n    x.bitSize >= 8 + n &&\n    m >= 0 &&\n    x.bitSize >= 8 + m + n\n  ) {\n    first = x.byteAt(0);\n    a = bitArraySliceToInt(x, 8, 8 + n, true, false);\n    b = bitArraySliceToInt(x, 8 + n, 8 + n + m, true, false);\n    rest = bitArraySlice(x, 8 + m + n);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      5,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 44, end: 109, pattern_start: 55, pattern_end: 105 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (\n    x.bitSize >= 64 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 64, true)) &&\n    x.bitSize === 72\n  ) {\n    a = bitArraySliceToFloat(x, 0, 64, true);\n    b = x.byteAt(8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 51, pattern_start: 29, pattern_end: 47 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float_16_bit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float-size(16)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float-size(16)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16 && Number.isFinite(bitArraySliceToFloat(x, 0, 16, true))) {\n    a = bitArraySliceToFloat(x, 0, 16, true);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 53, pattern_start: 29, pattern_end: 49 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float-big, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float-big, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (\n    x.bitSize >= 64 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 64, true)) &&\n    x.bitSize === 72\n  ) {\n    a = bitArraySliceToFloat(x, 0, 64, true);\n    b = x.byteAt(8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 55, pattern_start: 29, pattern_end: 51 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float-little, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float-little, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (\n    x.bitSize >= 64 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 64, false)) &&\n    x.bitSize === 72\n  ) {\n    a = bitArraySliceToFloat(x, 0, 64, false);\n    b = x.byteAt(8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 58, pattern_start: 29, pattern_end: 54 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float-32, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float-32, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (\n    x.bitSize >= 32 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 32, true)) &&\n    x.bitSize === 40\n  ) {\n    a = bitArraySliceToFloat(x, 0, 32, true);\n    b = x.byteAt(4);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 54, pattern_start: 29, pattern_end: 50 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float_sized_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float-32-big, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float-32-big, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (\n    x.bitSize >= 32 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 32, true)) &&\n    x.bitSize === 40\n  ) {\n    a = bitArraySliceToFloat(x, 0, 32, true);\n    b = x.byteAt(4);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 58, pattern_start: 29, pattern_end: 54 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_float_sized_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:float-32-little, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:float-32-little, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (\n    x.bitSize >= 32 &&\n    Number.isFinite(bitArraySliceToFloat(x, 0, 32, false)) &&\n    x.bitSize === 40\n  ) {\n    a = bitArraySliceToFloat(x, 0, 32, false);\n    b = x.byteAt(4);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 61, pattern_start: 29, pattern_end: 57 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_literal_aligned_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_, 1.1, _:bits>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_, 1.1, _:bits>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 8 &&\n    x.bitSize >= 72 &&\n    bitArraySliceToFloat(x, 8, 72, true) === 1.1\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 51, pattern_start: 29, pattern_end: 47 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_literal_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1.4, b:int>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1.4, b:int>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let b;\n  if (\n    x.bitSize >= 64 &&\n    bitArraySliceToFloat(x, 0, 64, true) === 1.4 &&\n    x.bitSize === 72\n  ) {\n    b = x.byteAt(8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 47, pattern_start: 29, pattern_end: 43 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_literal_unaligned_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let n = 1\\n  let assert <<_:size(n), 1.1, _:bits>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 1\n  let assert <<_:size(n), 1.1, _:bits>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToFloat } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let n = 1;\n  if (!(\n    n >= 0 &&\n    x.bitSize >= n &&\n    x.bitSize >= 64 + n &&\n    bitArraySliceToFloat(x, n, n + 64, true) === 1.1\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 30, end: 71, pattern_start: 41, pattern_end: 67 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_rest.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_, b:bytes>> = <<1,2,3>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_, b:bytes>> = <<1,2,3>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2, 3]);\n  let b;\n  if ($.bitSize >= 8 && ($.bitSize - 8) % 8 === 0) {\n    b = bitArraySlice($, 8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 55, pattern_start: 29, pattern_end: 43 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_rest_bits.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_, b:bits>> = <<1,2,3>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_, b:bits>> = <<1,2,3>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2, 3]);\n  let b;\n  if ($.bitSize >= 8) {\n    b = bitArraySlice($, 8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 54, pattern_start: 29, pattern_end: 42 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_rest_bits_unaligned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_:5, b:bits>> = <<1,2,3>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_:5, b:bits>> = <<1,2,3>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2, 3]);\n  let b;\n  if ($.bitSize >= 5) {\n    b = bitArraySlice($, 5);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 56, pattern_start: 29, pattern_end: 44 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_rest_bytes.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<_, b:bytes>> = <<1,2,3>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<_, b:bytes>> = <<1,2,3>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = toBitArray([1, 2, 3]);\n  let b;\n  if ($.bitSize >= 8 && ($.bitSize - 8) % 8 === 0) {\n    b = bitArraySlice($, 8);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 18, end: 55, pattern_start: 29, pattern_end: 43 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_signed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:signed>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:signed>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 8) {\n    a = bitArraySliceToInt(x, 0, 8, true, true);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 45, pattern_start: 29, pattern_end: 41 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_signed_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<-1:signed>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<-1:signed>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 8 && x.byteAt(0) === 255)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 46, pattern_start: 29, pattern_end: 42 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16, b:8>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16, b:8>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (x.bitSize >= 16 && x.bitSize === 24) {\n    a = bitArraySliceToInt(x, 0, 16, true, false);\n    b = x.byteAt(2);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 46, pattern_start: 29, pattern_end: 42 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_big_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16-big>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16-big>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16) {\n    a = bitArraySliceToInt(x, 0, 16, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 45, pattern_start: 29, pattern_end: 41 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_big_endian_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16-big>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16-big>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 4 && x.byteAt(1) === 210)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 48, pattern_start: 29, pattern_end: 44 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_big_endian_signed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16-big-signed>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16-big-signed>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16) {\n    a = bitArraySliceToInt(x, 0, 16, true, true);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 52, pattern_start: 29, pattern_end: 48 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_big_endian_signed_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16-big-signed>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16-big-signed>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 4 && x.byteAt(1) === 210)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 55, pattern_start: 29, pattern_end: 51 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_big_endian_unsigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16-big-unsigned>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16-big-unsigned>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16) {\n    a = bitArraySliceToInt(x, 0, 16, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 54, pattern_start: 29, pattern_end: 50 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_big_endian_unsigned_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16-big-unsigned>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16-big-unsigned>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 4 && x.byteAt(1) === 210)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 57, pattern_start: 29, pattern_end: 53 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16, 123:8>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16, 123:8>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 16 &&\n    x.byteAt(0) === 4 && x.byteAt(1) === 210 &&\n    x.bitSize === 24 &&\n    x.byteAt(2) === 123\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 51, pattern_start: 29, pattern_end: 47 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16-little>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16-little>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16) {\n    a = bitArraySliceToInt(x, 0, 16, false, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 48, pattern_start: 29, pattern_end: 44 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_little_endian_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16-little>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16-little>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 210 && x.byteAt(1) === 4)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 51, pattern_start: 29, pattern_end: 47 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_little_endian_signed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16-little-signed>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16-little-signed>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16) {\n    a = bitArraySliceToInt(x, 0, 16, false, true);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 55, pattern_start: 29, pattern_end: 51 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_little_endian_signed_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16-little-signed>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16-little-signed>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 210 && x.byteAt(1) === 4)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 58, pattern_start: 29, pattern_end: 54 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_little_endian_unsigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:16-little-unsigned>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:16-little-unsigned>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 16) {\n    a = bitArraySliceToInt(x, 0, 16, false, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 57, pattern_start: 29, pattern_end: 53 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_little_endian_unsigned_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1234:16-little-unsigned>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1234:16-little-unsigned>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 210 && x.byteAt(1) === 4)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 60, pattern_start: 29, pattern_end: 56 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_unaligned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:17, b:7>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:17, b:7>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  let b;\n  if (x.bitSize >= 17 && x.bitSize === 24) {\n    a = bitArraySliceToInt(x, 0, 17, true, false);\n    b = bitArraySliceToInt(x, 17, 24, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 46, pattern_start: 29, pattern_end: 42 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<i:16>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<i:16>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let i;\n  if (x.bitSize === 16) {\n    i = bitArraySliceToInt(x, 0, 16, true, false);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 41, pattern_start: 29, pattern_end: 37 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_sized_value_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<258:16>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<258:16>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x.bitSize === 16 && x.byteAt(0) === 1 && x.byteAt(1) === 2)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 43, pattern_start: 29, pattern_end: 39 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_unsigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<a:unsigned>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<a:unsigned>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let a;\n  if (x.bitSize === 8) {\n    a = x.byteAt(0);\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 47, pattern_start: 29, pattern_end: 43 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_unsigned_constant_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<-2:unsigned>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<-2:unsigned>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  throw makeError(\n    \"let_assert\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"go\",\n    \"Pattern match failed, no pattern matched the value.\",\n    { value: x, start: 18, end: 48, pattern_start: 29, pattern_end: 44 }\n  )\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_utf8.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<\\\"Gleam 👍\\\":utf8>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<\"Gleam 👍\":utf8>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize === 80 &&\n    x.byteAt(0) === 71 &&\n      x.byteAt(1) === 108 &&\n      x.byteAt(2) === 101 &&\n      x.byteAt(3) === 97 &&\n      x.byteAt(4) === 109 &&\n      x.byteAt(5) === 32 &&\n      x.byteAt(6) === 240 &&\n      x.byteAt(7) === 159 &&\n      x.byteAt(8) === 145 &&\n      x.byteAt(9) === 141\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 54, pattern_start: 29, pattern_end: 50 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__match_utf8_with_escape_chars.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<\\\"\\\\\\\"\\\\\\\\\\\\r\\\\n\\\\t\\\\f\\\\u{1f600}\\\">> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<\"\\\"\\\\\\r\\n\\t\\f\\u{1f600}\">> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize === 80 &&\n    x.byteAt(0) === 34 &&\n      x.byteAt(1) === 92 &&\n      x.byteAt(2) === 13 &&\n      x.byteAt(3) === 10 &&\n      x.byteAt(4) === 9 &&\n      x.byteAt(5) === 12 &&\n      x.byteAt(6) === 240 &&\n      x.byteAt(7) === 159 &&\n      x.byteAt(8) === 152 &&\n      x.byteAt(9) === 128\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 60, pattern_start: 29, pattern_end: 56 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__multiple_variable_size_segments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<a, b:size(a), c:size(b)>> = <<1, 2, 3, 4>>\\n  a + b + c\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<a, b:size(a), c:size(b)>> = <<1, 2, 3, 4>>\n  a + b + c\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([1, 2, 3, 4]);\n  let a$1;\n  let b$1;\n  let c;\n  if ($.bitSize >= 8) {\n    let a = $.byteAt(0);\n    if ($.bitSize >= 8 + a) {\n      let b = bitArraySliceToInt($, 8, 8 + a, true, false);\n      if ($.bitSize === 8 + a + b) {\n        a$1 = a;\n        b$1 = b;\n        c = bitArraySliceToInt($, 8 + a, 8 + a + b$1, true, false);\n      } else {\n        throw makeError(\n          \"let_assert\",\n          FILEPATH,\n          \"my/mod\",\n          3,\n          \"main\",\n          \"Pattern match failed, no pattern matched the value.\",\n          { value: $, start: 19, end: 74, pattern_start: 30, pattern_end: 57 }\n        )\n      }\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: $, start: 19, end: 74, pattern_start: 30, pattern_end: 57 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 19, end: 74, pattern_start: 30, pattern_end: 57 }\n    )\n  }\n  return (a$1 + b$1) + c;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__negative_size_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1962\nexpression: \"\\npub fn go(x) {\\n  let n = -10\\n  case x {\\n    <<int:size(n)>> -> int\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = -10\n  case x {\n    <<int:size(n)>> -> int\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = -10;\n  if (n >= 0 && x.bitSize === n) {\n    let int = bitArraySliceToInt(x, 0, n, true, false);\n    return int;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__negative_size_pattern_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1977\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<n:signed, int:size(n)>> -> int\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<n:signed, int:size(n)>> -> int\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 8) {\n    let n = bitArraySliceToInt(x, 0, 8, true, true);\n    if (n >= 0 && x.bitSize === 8 + n) {\n      let n$1 = n;\n      let int = bitArraySliceToInt(x, 8, 8 + n$1, true, false);\n      return int;\n    } else {\n      return 2;\n    }\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__non_byte_aligned_size_calculation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  case <<>> {\\n    <<a:1, b:3, c:size(b - 2)>> -> c + b\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case <<>> {\n    <<a:1, b:3, c:size(b - 2)>> -> c + b\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = toBitArray([]);\n  if ($.bitSize >= 1 && $.bitSize >= 4) {\n    let b = bitArraySliceToInt($, 1, 4, true, false);\n    if (b - 2 >= 0 && $.bitSize === 4 + b - 2) {\n      let a = bitArraySliceToInt($, 0, 1, true, false);\n      let b$1 = b;\n      let c = bitArraySliceToInt($, 4, 4 + b$1 - 2, true, false);\n      return c + b$1;\n    } else {\n      return 1;\n    }\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__one.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 22\nexpression: \"\\npub fn go() {\\n  <<256>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([0]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__operator_in_pattern_size.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<len, payload:size(len * 8)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<len, payload:size(len * 8)>> = <<>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([]);\n  let len$1;\n  let payload;\n  if ($.bitSize >= 8) {\n    let len = $.byteAt(0);\n    if ($.bitSize === 8 + len * 8) {\n      len$1 = len;\n      payload = bitArraySliceToInt($, 8, 8 + len$1 * 8, true, false);\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: $, start: 19, end: 67, pattern_start: 30, pattern_end: 60 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 19, end: 67, pattern_start: 30, pattern_end: 60 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__operator_in_pattern_size2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<len, payload:size(len / 8 - 1)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<len, payload:size(len / 8 - 1)>> = <<>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, divideInt, toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([]);\n  let len$1;\n  let payload;\n  if ($.bitSize >= 8) {\n    let len = $.byteAt(0);\n    if (\n      (divideInt(len, 8)) - 1 >= 0 &&\n      $.bitSize === 8 + (divideInt(len, 8)) - 1\n    ) {\n      len$1 = len;\n      payload = bitArraySliceToInt($, 8, 8 + (divideInt(len$1, 8)) - 1, true, false);\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: $, start: 19, end: 71, pattern_start: 30, pattern_end: 64 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 19, end: 71, pattern_start: 30, pattern_end: 64 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__operator_in_pattern_size3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let additional = 10\\n  let assert <<len, payload:size(len + additional * 8)>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let additional = 10\n  let assert <<len, payload:size(len + additional * 8)>> = <<>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let additional = 10;\n  let $ = toBitArray([]);\n  let len$1;\n  let payload;\n  if ($.bitSize >= 8) {\n    let len = $.byteAt(0);\n    if (len + (additional * 8) >= 0 && $.bitSize === 8 + len + additional * 8) {\n      len$1 = len;\n      payload = bitArraySliceToInt($, 8, 8 + len$1 + (additional * 8), true, false);\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        4,\n        \"main\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: $, start: 41, end: 102, pattern_start: 52, pattern_end: 95 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 41, end: 102, pattern_start: 52, pattern_end: 95 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__operator_in_size_for_bit_array_segment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  <<x:bits-size(4 + 1)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:bits-size(4 + 1)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([bitArraySlice(x, 0, 4 + 1)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_on_negative_size_calculation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<a, b:size(a - 100000), c:size(b)>> = <<1, 2, 3, 4, 5>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<a, b:size(a - 100000), c:size(b)>> = <<1, 2, 3, 4, 5>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let $ = toBitArray([1, 2, 3, 4, 5]);\n  let a$1;\n  let b$1;\n  let c;\n  if ($.bitSize >= 8) {\n    let a = $.byteAt(0);\n    if (a - 100000 >= 0 && $.bitSize >= 8 + a - 100000) {\n      let b = bitArraySliceToInt($, 8, 8 + a - 100000, true, false);\n      if ($.bitSize === 8 + b + a - 100000) {\n        a$1 = a;\n        b$1 = b;\n        c = bitArraySliceToInt($, 8 + a - 100000, 8 + a - 100000 + b$1, true, false);\n      } else {\n        throw makeError(\n          \"let_assert\",\n          FILEPATH,\n          \"my/mod\",\n          3,\n          \"main\",\n          \"Pattern match failed, no pattern matched the value.\",\n          { value: $, start: 19, end: 86, pattern_start: 30, pattern_end: 66 }\n        )\n      }\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"main\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: $, start: 19, end: 86, pattern_start: 30, pattern_end: 66 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 19, end: 86, pattern_start: 30, pattern_end: 66 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_size_arithmetic.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn wibble(bits, wobble) {\\n  case bits {\\n    <<_:size(1), _:size(wobble - 1), _:bits>> -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn wibble(bits, wobble) {\n  case bits {\n    <<_:size(1), _:size(wobble - 1), _:bits>> -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function wibble(bits, wobble) {\n  if (bits.bitSize >= 1 && wobble - 1 >= 0 && bits.bitSize >= 1 + wobble - 1) {\n    return 0;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_unknown_size_and_literal_string.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x, n) {\\n  case x {\\n    <<_:size(n), \\\"\\\\r\\\\n\\\">> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, n) {\n  case x {\n    <<_:size(n), \"\\r\\n\">> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x, n) {\n  if (\n    n >= 0 &&\n    x.bitSize >= n &&\n    x.bitSize === 16 + n &&\n    bitArraySliceToInt(x, n, 8 + n, true, false) === 13 &&\n      bitArraySliceToInt(x, 8 + n, 16 + n, true, false) === 10\n  ) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_utf16.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<\\\"Hello\\\":utf16, _rest:bytes>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<\"Hello\":utf16, _rest:bytes>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 80 &&\n    x.byteAt(0) === 0 &&\n      x.byteAt(1) === 72 &&\n      x.byteAt(2) === 0 &&\n      x.byteAt(3) === 101 &&\n      x.byteAt(4) === 0 &&\n      x.byteAt(5) === 108 &&\n      x.byteAt(6) === 0 &&\n      x.byteAt(7) === 108 &&\n      x.byteAt(8) === 0 &&\n      x.byteAt(9) === 111 &&\n    (x.bitSize - 80) % 8 === 0\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 63, pattern_start: 29, pattern_end: 59 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_utf16_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<\\\"Hello\\\":utf16-little, _rest:bytes>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<\"Hello\":utf16-little, _rest:bytes>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 80 &&\n    x.byteAt(0) === 72 &&\n      x.byteAt(1) === 0 &&\n      x.byteAt(2) === 101 &&\n      x.byteAt(3) === 0 &&\n      x.byteAt(4) === 108 &&\n      x.byteAt(5) === 0 &&\n      x.byteAt(6) === 108 &&\n      x.byteAt(7) === 0 &&\n      x.byteAt(8) === 111 &&\n      x.byteAt(9) === 0 &&\n    (x.bitSize - 80) % 8 === 0\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 70, pattern_start: 29, pattern_end: 66 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_utf32.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<\\\"Hello\\\":utf32, _rest:bytes>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<\"Hello\":utf32, _rest:bytes>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 160 &&\n    x.byteAt(0) === 0 &&\n      x.byteAt(1) === 0 &&\n      x.byteAt(2) === 0 &&\n      x.byteAt(3) === 72 &&\n      x.byteAt(4) === 0 &&\n      x.byteAt(5) === 0 &&\n      x.byteAt(6) === 0 &&\n      x.byteAt(7) === 101 &&\n      x.byteAt(8) === 0 &&\n      x.byteAt(9) === 0 &&\n      x.byteAt(10) === 0 &&\n      x.byteAt(11) === 108 &&\n      x.byteAt(12) === 0 &&\n      x.byteAt(13) === 0 &&\n      x.byteAt(14) === 0 &&\n      x.byteAt(15) === 108 &&\n      x.byteAt(16) === 0 &&\n      x.byteAt(17) === 0 &&\n      x.byteAt(18) === 0 &&\n      x.byteAt(19) === 111 &&\n    (x.bitSize - 160) % 8 === 0\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 63, pattern_start: 29, pattern_end: 59 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_match_utf32_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<\\\"Hello\\\":utf32-little, _rest:bytes>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<\"Hello\":utf32-little, _rest:bytes>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 160 &&\n    x.byteAt(0) === 72 &&\n      x.byteAt(1) === 0 &&\n      x.byteAt(2) === 0 &&\n      x.byteAt(3) === 0 &&\n      x.byteAt(4) === 101 &&\n      x.byteAt(5) === 0 &&\n      x.byteAt(6) === 0 &&\n      x.byteAt(7) === 0 &&\n      x.byteAt(8) === 108 &&\n      x.byteAt(9) === 0 &&\n      x.byteAt(10) === 0 &&\n      x.byteAt(11) === 0 &&\n      x.byteAt(12) === 108 &&\n      x.byteAt(13) === 0 &&\n      x.byteAt(14) === 0 &&\n      x.byteAt(15) === 0 &&\n      x.byteAt(16) === 111 &&\n      x.byteAt(17) === 0 &&\n      x.byteAt(18) === 0 &&\n      x.byteAt(19) === 0 &&\n    (x.bitSize - 160) % 8 === 0\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 70, pattern_start: 29, pattern_end: 66 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_32_float_minus_infinity_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:32-float>> -> \\\"Float\\\"\\n    <<0xff800000:32>> -> \\\"-Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0xff800000:32>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 32) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 32, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 255 &&\n        x.byteAt(1) === 128 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0\n    ) {\n      return \"-Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_32_float_minus_infinity_still_reachable_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:32-float>> -> \\\"Float\\\"\\n    <<0xff80:16, 0x0000:16>> -> \\\"-Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0xff80:16, 0x0000:16>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 32) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 32, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 255 && x.byteAt(1) === 128 &&\n      x.byteAt(2) === 0 && x.byteAt(3) === 0\n    ) {\n      return \"-Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_32_float_nan_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:32-float>> -> \\\"Float\\\"\\n    <<0x7fc00000:32>> -> \\\"NaN\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7fc00000:32>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 32) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 32, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 &&\n        x.byteAt(1) === 192 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0\n    ) {\n      return \"NaN\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_32_float_nan_still_reachable_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:32-float>> -> \\\"Float\\\"\\n    <<0x7fc0:16, 0x0000:16>> -> \\\"NaN\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7fc0:16, 0x0000:16>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 32) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 32, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 && x.byteAt(1) === 192 &&\n      x.byteAt(2) === 0 && x.byteAt(3) === 0\n    ) {\n      return \"NaN\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_32_float_plus_infinity_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:32-float>> -> \\\"Float\\\"\\n    <<0x7f800000:32>> -> \\\"+Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7f800000:32>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 32) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 32, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 &&\n        x.byteAt(1) === 128 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0\n    ) {\n      return \"+Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_32_float_plus_infinity_still_reachable_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:32-float>> -> \\\"Float\\\"\\n    <<0x7f80:16, 0x0000:16>> -> \\\"+Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7f80:16, 0x0000:16>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 32) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 32, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 && x.byteAt(1) === 128 &&\n      x.byteAt(2) === 0 && x.byteAt(3) === 0\n    ) {\n      return \"+Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_float_is_unreachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<_:64-float>> -> \\\"unreachable\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-float>> -> \"unreachable\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64 && Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n    return \"Float\";\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_int_is_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<_:64-int>> -> \\\"Int\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-int>> -> \"Int\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else {\n      return \"Int\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_minus_infinity_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<0xfff0000000000000:64>> -> \\\"-Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0xfff0000000000000:64>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 255 &&\n        x.byteAt(1) === 240 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0 &&\n        x.byteAt(4) === 0 &&\n        x.byteAt(5) === 0 &&\n        x.byteAt(6) === 0 &&\n        x.byteAt(7) === 0\n    ) {\n      return \"-Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_minus_infinity_still_reachable_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<0xfff00000:32, 0x00000000:32>> -> \\\"-Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0xfff00000:32, 0x00000000:32>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 255 &&\n        x.byteAt(1) === 240 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0 &&\n      x.byteAt(4) === 0 &&\n        x.byteAt(5) === 0 &&\n        x.byteAt(6) === 0 &&\n        x.byteAt(7) === 0\n    ) {\n      return \"-Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_nan_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<0x7ff8000000000000:64>> -> \\\"NaN\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff8000000000000:64>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 &&\n        x.byteAt(1) === 248 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0 &&\n        x.byteAt(4) === 0 &&\n        x.byteAt(5) === 0 &&\n        x.byteAt(6) === 0 &&\n        x.byteAt(7) === 0\n    ) {\n      return \"NaN\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_nan_still_reachable_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<0x7ff80000:32, 0x00000000:32>> -> \\\"NaN\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff80000:32, 0x00000000:32>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 &&\n        x.byteAt(1) === 248 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0 &&\n      x.byteAt(4) === 0 &&\n        x.byteAt(5) === 0 &&\n        x.byteAt(6) === 0 &&\n        x.byteAt(7) === 0\n    ) {\n      return \"NaN\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_plus_infinity_still_reachable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<0x7ff0000000000000:64>> -> \\\"+Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff0000000000000:64>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 &&\n        x.byteAt(1) === 240 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0 &&\n        x.byteAt(4) === 0 &&\n        x.byteAt(5) === 0 &&\n        x.byteAt(6) === 0 &&\n        x.byteAt(7) === 0\n    ) {\n      return \"+Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_matching_on_64_float_plus_infinity_still_reachable_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<0x7ff00000:32, 0x00000000:32>> -> \\\"+Infinity\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff00000:32, 0x00000000:32>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToFloat } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize === 64) {\n    if (Number.isFinite(bitArraySliceToFloat(x, 0, 64, true))) {\n      return \"Float\";\n    } else if (\n      x.byteAt(0) === 127 &&\n        x.byteAt(1) === 240 &&\n        x.byteAt(2) === 0 &&\n        x.byteAt(3) === 0 &&\n      x.byteAt(4) === 0 &&\n        x.byteAt(5) === 0 &&\n        x.byteAt(6) === 0 &&\n        x.byteAt(7) === 0\n    ) {\n      return \"+Infinity\";\n    } else {\n      return \"Other\";\n    }\n  } else {\n    return \"Other\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__pattern_with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert <<1:size(2)-unit(2), 2:size(3)-unit(4)>> = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert <<1:size(2)-unit(2), 2:size(3)-unit(4)>> = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, bitArraySliceToInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(\n    x.bitSize >= 4 &&\n    bitArraySliceToInt(x, 0, 4, true, false) === 1 &&\n    x.bitSize === 16 &&\n    bitArraySliceToInt(x, 4, 16, true, false) === 2\n  )) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 73, pattern_start: 29, pattern_end: 69 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__segments_shadowing_each_other.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1947\nexpression: \"\\npub fn go(x) {\\n  let n = 1\\n  case x {\\n    <<n, rest:size(n)>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let n = 1\n  case x {\n    <<n, rest:size(n)>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  let n = 1;\n  if (x.bitSize >= 8) {\n    let n$1 = x.byteAt(0);\n    if (x.bitSize === 8 + n$1) {\n      let n$2 = n$1;\n      let rest = bitArraySliceToInt(x, 8, 8 + n$2, true, false);\n      return 1;\n    } else {\n      return 2;\n    }\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_big_endian_constant_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 176\nexpression: \"\\npub fn go() {\\n  <<256:16-big>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256:16-big>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([1, 0]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_big_endian_dynamic_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 187\nexpression: \"\\npub fn go(i: Int) {\\n  <<i:16-big>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(i: Int) {\n  <<i:16-big>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function go(i) {\n  return toBitArray([sizedInt(i, 16, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_bits_expression_requires_v1_9.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<<<0>>:bits-5>>\\n}\\n  \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<<<0>>:bits-5>>\n}\n  \n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:16\n  │\n3 │   <<<<0>>:bits-5>>\n  │                ^ This requires a Gleam version >= 1.9.0\n\nUse of unaligned bit arrays on the JavaScript target was introduced in\nversion v1.9.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.8.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.9.0\"\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_constant_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 121\nexpression: \"\\npub fn go() {\\n  <<256:64>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256:64>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([sizedInt(256, 64, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_constant_value_max_size_for_compile_time_evaluation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 165\nexpression: \"\\npub fn go() {\\n  <<-1:48>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<-1:48>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([255, 255, 255, 255, 255, 255]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_constant_value_negative_overflow.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 154\nexpression: \"\\npub fn go() {\\n  <<-80_000:16>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<-80_000:16>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([199, 128]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_constant_value_positive_overflow.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 143\nexpression: \"\\npub fn go() {\\n  <<80_000:16>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<80_000:16>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([56, 128]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_dynamic_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 132\nexpression: \"\\npub fn go(i: Int) {\\n  <<i:64>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(i: Int) {\n  <<i:64>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function go(i) {\n  return toBitArray([sizedInt(i, 64, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_little_endian_constant_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 198\nexpression: \"\\npub fn go() {\\n  <<256:16-little>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256:16-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([0, 1]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__sized_little_endian_dynamic_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 209\nexpression: \"\\npub fn go(i: Int) {\\n  <<i:16-little>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(i: Int) {\n  <<i:16-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function go(i) {\n  return toBitArray([sizedInt(i, 16, false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__tuple_bit_array.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert #(<<>>) = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert #(<<>>) = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = x[0];\n  if (!($.bitSize === 0)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 40, pattern_start: 29, pattern_end: 36 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__tuple_bit_array_case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    #(<<>>) -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    #(<<>>) -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let $ = x[0];\n  if ($.bitSize === 0) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__tuple_multiple_bit_arrays.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  let assert #(<<>>, <<1>>, <<2, 3>>) = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert #(<<>>, <<1>>, <<2, 3>>) = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  let $ = x[0];\n  if ($.bitSize === 0) {\n    let $1 = x[1];\n    if ($1.bitSize === 8) {\n      let $2 = x[2];\n      if (!(\n        $2.bitSize >= 8 &&\n        $1.byteAt(0) === 1 &&\n        $2.byteAt(0) === 2 &&\n        $2.bitSize === 16 &&\n        $2.byteAt(1) === 3\n      )) {\n        throw makeError(\n          \"let_assert\",\n          FILEPATH,\n          \"my/mod\",\n          3,\n          \"go\",\n          \"Pattern match failed, no pattern matched the value.\",\n          { value: x, start: 18, end: 57, pattern_start: 29, pattern_end: 53 }\n        )\n      }\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        3,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: x, start: 18, end: 57, pattern_start: 29, pattern_end: 53 }\n      )\n    }\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 57, pattern_start: 29, pattern_end: 53 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__tuple_multiple_bit_arrays_case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    #(<<>>, <<1>>, <<2, 3>>) -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    #(<<>>, <<1>>, <<2, 3>>) -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let $ = x[0];\n  if ($.bitSize === 0) {\n    let $1 = x[1];\n    if ($1.bitSize === 8) {\n      let $2 = x[2];\n      if (\n        $2.bitSize >= 8 &&\n        $1.byteAt(0) === 1 &&\n        $2.byteAt(0) === 2 &&\n        $2.bitSize === 16 &&\n        $2.byteAt(1) === 3\n      ) {\n        return true;\n      } else {\n        return false;\n      }\n    } else {\n      return false;\n    }\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__two.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 33\nexpression: \"\\npub fn go() {\\n  <<256, 4>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<256, 4>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go() {\n  return toBitArray([0, 4]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__unaligned_int_expression_requires_v1_9.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<0:1>>\\n}\\n  \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<0:1>>\n}\n  \n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:7\n  │\n3 │   <<0:1>>\n  │       ^ This requires a Gleam version >= 1.9.0\n\nUse of unaligned bit arrays on the JavaScript target was introduced in\nversion v1.9.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.8.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.9.0\"\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__unaligned_int_pattern_requires_v1_9.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  let assert <<_:3>> = <<0>>\\n}\\n  \"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<_:3>> = <<0>>\n}\n  \n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:18\n  │\n3 │   let assert <<_:3>> = <<0>>\n  │                  ^ This requires a Gleam version >= 1.9.0\n\nUse of unaligned bit arrays on the JavaScript target was introduced in\nversion v1.9.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.8.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.9.0\"\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__unit_with_bits_option.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  <<x:bits-size(4)-unit(8)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:bits-size(4)-unit(8)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([bitArraySlice(x, 0, 32)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__unit_with_bits_option_constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub const bits = <<1, 2, 3>>\\npub const more_bits = <<bits:bits-size(3)-unit(8)>>\\n\"\n---\n----- SOURCE CODE\n\npub const bits = <<1, 2, 3>>\npub const more_bits = <<bits:bits-size(3)-unit(8)>>\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, bitArraySlice } from \"../gleam.mjs\";\n\nexport const bits = /* @__PURE__ */ toBitArray([1, 2, 3]);\n\nexport const more_bits = /* @__PURE__ */ toBitArray([bitArraySlice(bits, 0, 24)]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf16.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"Hello, world!\\\":utf16>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"Hello, world!\":utf16>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringToUtf16 } from \"../gleam.mjs\";\n\nexport function main() {\n  return toBitArray([stringToUtf16(\"Hello, world!\", true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf16_codepoint.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 2114\nexpression: \"\\nfn codepoint() -> UtfCodepoint { todo }\\n\\npub fn main() {\\n  let my_codepoint = codepoint()\\n  <<my_codepoint:utf16_codepoint>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn codepoint() -> UtfCodepoint { todo }\n\npub fn main() {\n  let my_codepoint = codepoint()\n  <<my_codepoint:utf16_codepoint>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, codepointToUtf16 } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction codepoint() {\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    2,\n    \"codepoint\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n}\n\nexport function main() {\n  let my_codepoint = codepoint();\n  return toBitArray([codepointToUtf16(my_codepoint, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf16_codepoint_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(codepoint) {\\n  <<codepoint:utf16_codepoint-little>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(codepoint) {\n  <<codepoint:utf16_codepoint-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, codepointToUtf16 } from \"../gleam.mjs\";\n\nexport function go(codepoint) {\n  return toBitArray([codepointToUtf16(codepoint, false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf16_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"Hello, world!\\\":utf16-little>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"Hello, world!\":utf16-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringToUtf16 } from \"../gleam.mjs\";\n\nexport function main() {\n  return toBitArray([stringToUtf16(\"Hello, world!\", false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf32.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"Hello, world!\\\":utf32>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"Hello, world!\":utf32>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringToUtf32 } from \"../gleam.mjs\";\n\nexport function main() {\n  return toBitArray([stringToUtf32(\"Hello, world!\", true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf32_codepoint.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 2139\nexpression: \"\\nfn codepoint() -> UtfCodepoint { todo }\\n\\npub fn main() {\\n  let my_codepoint = codepoint()\\n  <<my_codepoint:utf32_codepoint>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\nfn codepoint() -> UtfCodepoint { todo }\n\npub fn main() {\n  let my_codepoint = codepoint()\n  <<my_codepoint:utf32_codepoint>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError, toBitArray, codepointToUtf32 } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction codepoint() {\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    2,\n    \"codepoint\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n}\n\nexport function main() {\n  let my_codepoint = codepoint();\n  return toBitArray([codepointToUtf32(my_codepoint, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf32_codepoint_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(codepoint) {\\n  <<codepoint:utf32_codepoint-little>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(codepoint) {\n  <<codepoint:utf32_codepoint-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, codepointToUtf32 } from \"../gleam.mjs\";\n\nexport function go(codepoint) {\n  return toBitArray([codepointToUtf32(codepoint, false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf32_little_endian.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"Hello, world!\\\":utf32-little>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"Hello, world!\":utf32-little>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringToUtf32 } from \"../gleam.mjs\";\n\nexport function main() {\n  return toBitArray([stringToUtf32(\"Hello, world!\", false)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf8.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 264\nexpression: \"\\npub fn go(x) {\\n  <<256, 4, x, \\\"Gleam\\\":utf8>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<256, 4, x, \"Gleam\":utf8>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringBits } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([0, 4, x, stringBits(\"Gleam\")]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf8_codepoint.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 325\nexpression: \"\\npub fn go(x) {\\n  <<x:utf8_codepoint, \\\"Gleam\\\":utf8>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:utf8_codepoint, \"Gleam\":utf8>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, stringBits, codepointBits } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([codepointBits(x), stringBits(\"Gleam\")]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__utf8_codepoint_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nexpression: \"\\npub fn go(x) {\\n  <<x:utf8_codepoint, \\\"Gleam\\\":utf8>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<x:utf8_codepoint, \"Gleam\":utf8>>\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport function go(x: _.UtfCodepoint): _.BitArray;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__variable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 253\nexpression: \"\\npub fn go(x) {\\n  <<256, 4, x>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  <<256, 4, x>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toBitArray([0, 4, x]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__variable_sized.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 242\nexpression: \"\\npub fn go(x, y) {\\n  <<x:size(y)>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  <<x:size(y)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function go(x, y) {\n  return toBitArray([sizedInt(x, y, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__variable_sized_segment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1933\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<n, rest:size(n)>> -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<n, rest:size(n)>> -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { bitArraySliceToInt } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.bitSize >= 8) {\n    let n = x.byteAt(0);\n    if (x.bitSize === 8 + n) {\n      let n$1 = n;\n      let rest = bitArraySliceToInt(x, 8, 8 + n$1, true, false);\n      return 1;\n    } else {\n      return 2;\n    }\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__with_unit.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bit_arrays.rs\nassertion_line: 1770\nexpression: \"\\npub fn main() {\\n  <<1:size(2)-unit(2), 2:size(3)-unit(4)>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<1:size(2)-unit(2), 2:size(3)-unit(4)>>\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toBitArray, sizedInt } from \"../gleam.mjs\";\n\nexport function main() {\n  return toBitArray([sizedInt(1, 4, true), sizedInt(2, 12, true)]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__assignment_last_in_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn main() {\\n  let a = {\\n    let b = 1\\n    let c = b + 1\\n  }\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = {\n    let b = 1\n    let c = b + 1\n  }\n  a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let _block;\n  {\n    let b = 1;\n    let c = b + 1;\n    _block = c;\n  }\n  let a = _block;\n  return a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 5\nexpression: \"\\npub fn go() {\\n  let x = {\\n    1\\n    2\\n  }\\n  x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = {\n    1\n    2\n  }\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let _block;\n  {\n    1;\n    _block = 2;\n  }\n  let x = _block;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__block_in_tail_position_is_not_an_iife.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 221\nexpression: \"\\npub fn b() {\\n  let x = 1\\n  {\\n    Nil\\n    x + 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn b() {\n  let x = 1\n  {\n    Nil\n    x + 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function b() {\n  let x = 1;\n  {\n    undefined;\n    return x + 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__block_in_tail_position_shadowing_variables.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 236\nexpression: \"\\npub fn b() {\\n  let x = 1\\n  {\\n    let x = 2\\n    x + 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn b() {\n  let x = 1\n  {\n    let x = 2\n    x + 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function b() {\n  let x = 1;\n  {\n    let x$1 = 2;\n    return x$1 + 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__block_in_tail_position_with_just_an_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 251\nexpression: \"\\npub fn b() {\\n  let x = 1\\n  {\\n    let x = x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn b() {\n  let x = 1\n  {\n    let x = x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function b() {\n  let x = 1;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__block_with_parenthesised_expression_returning_from_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 208\nexpression: \"\\npub fn b() {\\n  {\\n    1 + 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn b() {\n  {\n    1 + 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function b() {\n  return 1 + 2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__blocks_returning_functions.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn b() {\\n  {\\n    fn(cb) { cb(1) }\\n  }\\n  {\\n    fn(cb) { cb(2) }\\n  }\\n  3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn b() {\n  {\n    fn(cb) { cb(1) }\n  }\n  {\n    fn(cb) { cb(2) }\n  }\n  3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function b() {\n  (cb) => { return cb(1); };\n  (cb) => { return cb(2); };\n  return 3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__blocks_returning_use.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn b() {\\n  {\\n    use a <- fn(cb) { cb(1) }\\n    a\\n  }\\n  {\\n    use b <- fn(cb) { cb(2) }\\n    b\\n  }\\n  3\\n}\\n    \"\n---\n----- SOURCE CODE\n\npub fn b() {\n  {\n    use a <- fn(cb) { cb(1) }\n    a\n  }\n  {\n    use b <- fn(cb) { cb(2) }\n    b\n  }\n  3\n}\n    \n\n----- COMPILED JAVASCRIPT\nexport function b() {\n  1;\n  2;\n  return 3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__blocks_whose_values_are_unused_do_not_generate_assignments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn main() {\\n  {\\n    let x = 10\\n    echo x\\n  }\\n\\n  {\\n    let a = 1\\n    let b = 2\\n    a + b\\n  }\\n\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  {\n    let x = 10\n    echo x\n  }\n\n  {\n    let a = 1\n    let b = 2\n    a + b\n  }\n\n  Nil\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  {\n    let x = 10;\n    echo(x, undefined, \"src/module.gleam\", 5)\n  };\n  {\n    let a = 1;\n    let b = 2;\n    a + b\n  };\n  return undefined;\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__concat_blocks.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 155\nexpression: \"\\npub fn main(f, a, b) {\\n  {\\n    a\\n    |> f\\n  } <> {\\n    b\\n    |> f\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main(f, a, b) {\n  {\n    a\n    |> f\n  } <> {\n    b\n    |> f\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(f, a, b) {\n  return (() => {\n    let _pipe = a;\n    return f(_pipe);\n  })() + (() => {\n    let _pipe = b;\n    return f(_pipe);\n  })();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__left_operator_sequence.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 127\nexpression: \"\\npub fn go() {\\n  1 == {\\n    1\\n    2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  1 == {\n    1\n    2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return 1 === (() => {\n    1;\n    return 2;\n  })();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__let_assert_message_no_lifted.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\nfn side_effects(x) {\\n  // Some side effects\\n  x\\n}\\n\\npub fn main() {\\n  let assert Error(Nil) = side_effects(Ok(10))\\n    as {\\n    let message = side_effects(\\\"some message\\\")\\n    message\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn side_effects(x) {\n  // Some side effects\n  x\n}\n\npub fn main() {\n  let assert Error(Nil) = side_effects(Ok(10))\n    as {\n    let message = side_effects(\"some message\")\n    message\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, Error, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction side_effects(x) {\n  return x;\n}\n\nexport function main() {\n  let $ = side_effects(new Ok(10));\n  if (!($ instanceof Error)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      8,\n      \"main\",\n      (() => {\n        let message = side_effects(\"some message\");\n        return message;\n      })(),\n      { value: $, start: 70, end: 114, pattern_start: 81, pattern_end: 91 }\n    )\n  }\n  return $;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__let_assert_only_statement_in_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 284\nexpression: \"\\npub fn main() {\\n  {\\n    let assert Ok(1) = Error(Nil)\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  {\n    let assert Ok(1) = Error(Nil)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Error, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  {\n    let $ = new Error(undefined);\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: $, start: 25, end: 54, pattern_start: 36, pattern_end: 41 }\n    )\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__nested_multiexpr_blocks.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 36\nexpression: \"\\npub fn go() {\\n  let x = {\\n    1\\n    {\\n      2\\n      3\\n    }\\n  }\\n  x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      3\n    }\n  }\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let _block;\n  {\n    1;\n    {\n      2;\n      _block = 3;\n    }\n  }\n  let x = _block;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__nested_multiexpr_blocks_with_case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 94\nexpression: \"\\npub fn go() {\\n  let x = {\\n    1\\n    {\\n      2\\n      case True {\\n        _ -> 3\\n      }\\n    }\\n  }\\n  x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      case True {\n        _ -> 3\n      }\n    }\n  }\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let _block;\n  {\n    1;\n    {\n      2;\n      let $ = true;\n      _block = 3;\n    }\n  }\n  let x = _block;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__nested_multiexpr_blocks_with_pipe.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 54\nexpression: \"\\npub fn add1(a) {\\n  a + 1\\n}\\npub fn go() {\\n  let x = {\\n    1\\n    {\\n      2\\n      3 |> add1\\n    } |> add1\\n  }\\n  x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn add1(a) {\n  a + 1\n}\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      3 |> add1\n    } |> add1\n  }\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function add1(a) {\n  return a + 1;\n}\n\nexport function go() {\n  let _block;\n  {\n    1;\n    let _block$1;\n    {\n      2;\n      let _pipe = 3;\n      _block$1 = add1(_pipe);\n    }\n    let _pipe = _block$1;\n    _block = add1(_pipe);\n  }\n  let x = _block;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__nested_multiexpr_non_ending_blocks.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn go() {\\n  let x = {\\n    1\\n    {\\n      2\\n      3\\n    }\\n    4\\n  }\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = {\n    1\n    {\n      2\n      3\n    }\n    4\n  }\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let _block;\n  {\n    1;\n    {\n      2;\n      3\n    };\n    _block = 4;\n  }\n  let x = _block;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__nested_simple_blocks.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 20\nexpression: \"\\npub fn go() {\\n  let x = {\\n    {\\n      3\\n    }\\n  }\\n  x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = {\n    {\n      3\n    }\n  }\n  x\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let x = 3;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__pattern_assignment_last_in_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn main() {\\n  let a = {\\n    let b = #(1, 2)\\n    let #(x, y) = b\\n  }\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = {\n    let b = #(1, 2)\n    let #(x, y) = b\n  }\n  a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let _block;\n  {\n    let b = [1, 2];\n    let x;\n    let y;\n    x = b[0];\n    y = b[1];\n    _block = b;\n  }\n  let a = _block;\n  return a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__right_operator_sequence.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 141\nexpression: \"\\npub fn go() {\\n  {\\n    1\\n    2\\n  } == 1\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  {\n    1\n    2\n  } == 1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return (() => {\n    1;\n    return 2;\n  })() === 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__sequences.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nassertion_line: 114\nexpression: \"\\npub fn go() {\\n  \\\"one\\\"\\n  \\\"two\\\"\\n  \\\"three\\\"\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  \"one\"\n  \"two\"\n  \"three\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  \"one\";\n  \"two\";\n  return \"three\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__shadowed_variable_in_nested_scope.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/blocks.rs\nexpression: \"\\npub fn main() {\\n  {\\n    let x = 1\\n    let _ = {\\n      let x = 2\\n      x\\n    }\\n    x\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  {\n    let x = 1\n    let _ = {\n      let x = 2\n      x\n    }\n    x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  {\n    let x = 1;\n    let _block;\n    {\n      let x$1 = 2;\n      _block = x$1;\n    }\n    let $ = _block;\n    \n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__assigning.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nexpression: \"\\npub fn go(x, y) {\\n  let assert True = x\\n  let assert False = x\\n  let assert Nil = y\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  let assert True = x\n  let assert False = x\n  let assert Nil = y\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x, y) {\n  if (!(x)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 21, end: 40, pattern_start: 32, pattern_end: 36 }\n    )\n  }\n  throw makeError(\n    \"let_assert\",\n    FILEPATH,\n    \"my/mod\",\n    4,\n    \"go\",\n    \"Pattern match failed, no pattern matched the value.\",\n    { value: x, start: 43, end: 63, pattern_start: 54, pattern_end: 59 }\n  )\n  \n  return y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_panic_left.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 171\nexpression: \"pub fn negate(x) {\\n    panic && x\\n}\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn negate(x) {\n    panic && x\n}\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function negate(x) {\n  return (() => {\n    throw makeError(\n      \"panic\",\n      FILEPATH,\n      \"my/mod\",\n      2,\n      \"negate\",\n      \"`panic` expression evaluated.\",\n      {}\n    )\n  })() && x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_panic_right.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 162\nexpression: \"pub fn negate(x) {\\n    x && panic\\n}\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn negate(x) {\n    x && panic\n}\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function negate(x) {\n  return x && (() => {\n    throw makeError(\n      \"panic\",\n      FILEPATH,\n      \"my/mod\",\n      2,\n      \"negate\",\n      \"`panic` expression evaluated.\",\n      {}\n    )\n  })();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_todo_left.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 189\nexpression: \"pub fn negate(x) {\\n    todo && x\\n}\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn negate(x) {\n    todo && x\n}\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function negate(x) {\n  return (() => {\n    throw makeError(\n      \"todo\",\n      FILEPATH,\n      \"my/mod\",\n      2,\n      \"negate\",\n      \"`todo` expression evaluated. This code has not yet been implemented.\",\n      {}\n    )\n  })() && x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_todo_right.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 180\nexpression: \"pub fn negate(x) {\\n    x && todo\\n}\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn negate(x) {\n    x && todo\n}\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function negate(x) {\n  return x && (() => {\n    throw makeError(\n      \"todo\",\n      FILEPATH,\n      \"my/mod\",\n      2,\n      \"negate\",\n      \"`todo` expression evaluated. This code has not yet been implemented.\",\n      {}\n    )\n  })();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 114\nexpression: \"\\npub fn go(a) {\\n  case a {\\n    True -> 1\\n    False -> 0\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  case a {\n    True -> 1\n    False -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(a) {\n  if (a) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__constants.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 18\nexpression: \"\\npub const a = True\\npub const b = False\\npub const c = Nil\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const a = True\npub const b = False\npub const c = Nil\n\n\n----- COMPILED JAVASCRIPT\nexport const a = true;\n\nexport const b = false;\n\nexport const c = undefined;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__constants_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nexpression: \"\\npub const a = True\\npub const b = False\\npub const c = Nil\\n\"\n---\n----- SOURCE CODE\n\npub const a = True\npub const b = False\npub const c = Nil\n\n\n----- TYPESCRIPT DEFINITIONS\nexport const a: boolean;\n\nexport const b: boolean;\n\nexport const c: undefined;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 95\nexpression: \"\\npub fn go(a, b) {\\n  a == True\\n  a != True\\n  a == False\\n  a != False\\n  a == a\\n  a != a\\n  b == Nil\\n  b != Nil\\n  b == b\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(a, b) {\n  a == True\n  a != True\n  a == False\n  a != False\n  a == a\n  a != a\n  b == Nil\n  b != Nil\n  b == b\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(a, b) {\n  a === true;\n  a !== true;\n  a === false;\n  a !== false;\n  a === a;\n  a !== a;\n  b === undefined;\n  b !== undefined;\n  return b === b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__expressions.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 5\nexpression: \"\\npub fn go() {\\n    True\\n    False\\n    Nil\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n    True\n    False\n    Nil\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  true;\n  false;\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negate_panic.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 198\nexpression: \"pub fn negate(x) {\\n  !panic\\n}\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn negate(x) {\n  !panic\n}\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function negate(x) {\n  let _block;\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    2,\n    \"negate\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n  return !_block;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negate_todo.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 207\nexpression: \"pub fn negate(x) {\\n  !todo\\n}\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn negate(x) {\n  !todo\n}\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function negate(x) {\n  let _block;\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    2,\n    \"negate\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n  return !_block;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nexpression: \"pub fn negate(x) {\\n    !x\\n}\"\n---\n----- SOURCE CODE\npub fn negate(x) {\n    !x\n}\n\n----- COMPILED JAVASCRIPT\nexport function negate(x) {\n  return !x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negation_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nexpression: \"pub fn negate(x) {\\n  !{\\n    123\\n    x\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn negate(x) {\n  !{\n    123\n    x\n  }\n}\n\n----- COMPILED JAVASCRIPT\nexport function negate(x) {\n  let _block;\n  {\n    123;\n    _block = x;\n  }\n  return !_block;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__nil_case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 128\nexpression: \"\\npub fn go(a) {\\n  case a {\\n    Nil -> 0\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  case a {\n    Nil -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(a) {\n  return 0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__operators.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 40\nexpression: \"\\npub fn go() {\\n    True && True\\n    False || False\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n    True && True\n    False || False\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  true && true;\n  return false || false;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__shadowed_bools_and_nil.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nexpression: \"\\npub type True { True False Nil }\\npub fn go(x, y) {\\n  let assert True = x\\n  let assert False = x\\n  let assert Nil = y\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type True { True False Nil }\npub fn go(x, y) {\n  let assert True = x\n  let assert False = x\n  let assert Nil = y\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport class True extends $CustomType {}\nexport const True$True = () => new True();\nexport const True$isTrue = (value) => value instanceof True;\n\nexport class False extends $CustomType {}\nexport const True$False = () => new False();\nexport const True$isFalse = (value) => value instanceof False;\n\nexport class Nil extends $CustomType {}\nexport const True$Nil = () => new Nil();\nexport const True$isNil = (value) => value instanceof Nil;\n\nexport function go(x, y) {\n  if (!(x instanceof True)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 54, end: 73, pattern_start: 65, pattern_end: 69 }\n    )\n  }\n  throw makeError(\n    \"let_assert\",\n    FILEPATH,\n    \"my/mod\",\n    5,\n    \"go\",\n    \"Pattern match failed, no pattern matched the value.\",\n    { value: x, start: 76, end: 96, pattern_start: 87, pattern_end: 92 }\n  )\n  if (!(y instanceof Nil)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      6,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: y, start: 99, end: 117, pattern_start: 110, pattern_end: 113 }\n    )\n  }\n  return y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__shadowed_bools_and_nil_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/bools.rs\nassertion_line: 81\nexpression: \"\\npub type True { True False Nil }\\npub fn go(x, y) {\\n  let assert True = x\\n  let assert False = x\\n  let assert Nil = y\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type True { True False Nil }\npub fn go(x, y) {\n  let assert True = x\n  let assert False = x\n  let assert Nil = y\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class True extends _.CustomType {}\nexport function True$True(): True$;\nexport function True$isTrue(value: any): value is True$;\n\nexport class False extends _.CustomType {}\nexport function True$False(): True$;\nexport function True$isFalse(value: any): value is True$;\n\nexport class Nil extends _.CustomType {}\nexport function True$Nil(): True$;\nexport function True$isNil(value: any): value is True$;\n\nexport type True$ = True | False | Nil;\n\nexport function go(x: True$, y: True$): True$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 152\nexpression: \"\\npub fn go(x) {\\n  let y = case x {\\n    True -> 1\\n    _ -> 0\\n  }\\n  y\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let y = case x {\n    True -> 1\n    _ -> 0\n  }\n  y\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let _block;\n  if (x) {\n    _block = 1;\n  } else {\n    _block = 0;\n  }\n  let y = _block;\n  return y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__called_case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 212\nexpression: \"\\npub fn go(x, y) {\\n  case x {\\n    0 -> y\\n    _ -> y\\n  }()\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  case x {\n    0 -> y\n    _ -> y\n  }()\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x, y) {\n  let _block;\n  if (x === 0) {\n    _block = y;\n  } else {\n    _block = y;\n  }\n  return _block();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_branches_guards_are_wrapped_in_parentheses.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn anything() -> a {\\n  case [] {\\n    [a] if False || True -> a\\n    _ -> anything()\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn anything() -> a {\n  case [] {\n    [a] if False || True -> a\n    _ -> anything()\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList, Empty as $Empty } from \"../gleam.mjs\";\n\nexport function anything() {\n  while (true) {\n    let $ = toList([]);\n    if (!($ instanceof $Empty)) {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty && false || true) {\n        let a = $.head;\n        return a;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_list_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"pub fn go(x) {\\n   case x {\\n     [] -> []\\n     [a, b] -> [a, b]\\n     [1, ..rest] -> [1, ..rest]\\n     _ -> x\\n   }\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n   case x {\n     [] -> []\n     [a, b] -> [a, b]\n     [1, ..rest] -> [1, ..rest]\n     _ -> x\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof $Empty) {\n    return x;\n  } else {\n    let $ = x.tail;\n    if ($ instanceof $Empty) {\n      let $1 = x.head;\n      if ($1 === 1) {\n        return x;\n      } else {\n        return x;\n      }\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        return x;\n      } else {\n        let $2 = x.head;\n        if ($2 === 1) {\n          return x;\n        } else {\n          return x;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_no_variant_record.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn go(x) {\\n   case x {\\n     Ok(Nil) -> Ok(Nil)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n   case x {\n     Ok(Nil) -> Ok(Nil)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    return x;\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_no_variant_record_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(gleam.Nil) -> Ok(Nil)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(gleam.Nil) -> Ok(Nil)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    return x;\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_no_variant_record_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(Nil) -> Ok(gleam.Nil)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(Nil) -> Ok(gleam.Nil)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    return x;\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_no_variant_record_4.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(gleam.Nil) -> Ok(gleam.Nil)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(gleam.Nil) -> Ok(gleam.Nil)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    return x;\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_string_1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     \\\"a\\\" <> rest -> \\\"a\\\" <> rest\\n     _ -> \\\"\\\"\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     \"a\" <> rest -> \"a\" <> rest\n     _ -> \"\"\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.startsWith(\"a\")) {\n    return x;\n  } else {\n    return \"\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_string_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     \\\"a\\\" as a <> rest -> a <> rest\\n     _ -> \\\"\\\"\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     \"a\" as a <> rest -> a <> rest\n     _ -> \"\"\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x.startsWith(\"a\")) {\n    return x;\n  } else {\n    return \"\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_value_alias.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(_) as a -> a\\n     Error(Nil) -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(_) as a -> a\n     Error(Nil) -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    return x;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_value_alias_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(1) as a -> Ok(1)\\n     Ok(_) -> Ok(2)\\n     Error(Nil) -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(1) as a -> Ok(1)\n     Ok(_) -> Ok(2)\n     Error(Nil) -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    let $ = x[0];\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Ok(2);\n    }\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_value_alias_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(1 as a) -> Ok(a)\\n     Ok(_) -> Ok(2)\\n     Error(Nil) -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(1 as a) -> Ok(a)\n     Ok(_) -> Ok(2)\n     Error(Nil) -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    let $ = x[0];\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Ok(2);\n    }\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_matched_value_wrapped_in_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     1 -> { 1 }\\n     _ -> 2\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     1 -> { 1 }\n     _ -> 2\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x === 1) {\n    return x;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"pub fn go(x) {\\n   case x {\\n     Ok(1) -> Ok(1)\\n     Ok(n) -> Ok(n)\\n     Error(_) -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n   case x {\n     Ok(1) -> Ok(1)\n     Ok(n) -> Ok(n)\n     Error(_) -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    let $ = x[0];\n    if ($ === 1) {\n      return x;\n    } else {\n      return x;\n    }\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_labels_matched_by_pattern_1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(int: Int, string: String)\\n  Wobble(Int)\\n}\\n\\npub fn go(x) {\\n   case x {\\n     Wibble(1, s) -> Wibble(1, s)\\n     _ -> Wobble(1)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(1, s) -> Wibble(1, s)\n     _ -> Wobble(1)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(int, string) {\n    super();\n    this.int = int;\n    this.string = string;\n  }\n}\nexport const Wibble$Wibble = (int, string) => new Wibble(int, string);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$int = (value) => value.int;\nexport const Wibble$Wibble$0 = (value) => value.int;\nexport const Wibble$Wibble$string = (value) => value.string;\nexport const Wibble$Wibble$1 = (value) => value.string;\n\nexport class Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Wibble$Wobble = ($0) => new Wobble($0);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof Wibble) {\n    let $ = x.int;\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Wobble(1);\n    }\n  } else {\n    return new Wobble(1);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_labels_matched_by_pattern_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(int: Int, string: String)\\n  Wobble(Int)\\n}\\n\\npub fn go(x) {\\n   case x {\\n     Wibble(string:, int:) -> Wibble(string:, int:)\\n     _ -> Wobble(1)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(string:, int:) -> Wibble(string:, int:)\n     _ -> Wobble(1)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(int, string) {\n    super();\n    this.int = int;\n    this.string = string;\n  }\n}\nexport const Wibble$Wibble = (int, string) => new Wibble(int, string);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$int = (value) => value.int;\nexport const Wibble$Wibble$0 = (value) => value.int;\nexport const Wibble$Wibble$string = (value) => value.string;\nexport const Wibble$Wibble$1 = (value) => value.string;\n\nexport class Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Wibble$Wobble = ($0) => new Wobble($0);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof Wibble) {\n    return x;\n  } else {\n    return new Wobble(1);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_labels_matched_by_pattern_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(int: Int, string: String)\\n  Wobble(Int)\\n}\\n\\npub fn go(x) {\\n   case x {\\n     // This should not be optimised away!\\n     Wibble(string:, int:) -> Wibble(string:, int: 1)\\n     _ -> Wobble(1)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     // This should not be optimised away!\n     Wibble(string:, int:) -> Wibble(string:, int: 1)\n     _ -> Wobble(1)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(int, string) {\n    super();\n    this.int = int;\n    this.string = string;\n  }\n}\nexport const Wibble$Wibble = (int, string) => new Wibble(int, string);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$int = (value) => value.int;\nexport const Wibble$Wibble$0 = (value) => value.int;\nexport const Wibble$Wibble$string = (value) => value.string;\nexport const Wibble$Wibble$1 = (value) => value.string;\n\nexport class Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Wibble$Wobble = ($0) => new Wobble($0);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof Wibble) {\n    let int = x.int;\n    let string = x.string;\n    return new Wibble(1, string);\n  } else {\n    return new Wobble(1);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_labels_matched_by_pattern_4.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(int: Int, string: String)\\n  Wobble(Int)\\n}\\n\\npub fn go(x) {\\n   case x {\\n     Wibble(string:, int:) -> Wibble(int:, string:)\\n     _ -> Wobble(1)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(string:, int:) -> Wibble(int:, string:)\n     _ -> Wobble(1)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(int, string) {\n    super();\n    this.int = int;\n    this.string = string;\n  }\n}\nexport const Wibble$Wibble = (int, string) => new Wibble(int, string);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$int = (value) => value.int;\nexport const Wibble$Wibble$0 = (value) => value.int;\nexport const Wibble$Wibble$string = (value) => value.string;\nexport const Wibble$Wibble$1 = (value) => value.string;\n\nexport class Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Wibble$Wobble = ($0) => new Wobble($0);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof Wibble) {\n    return x;\n  } else {\n    return new Wobble(1);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_labels_matched_by_pattern_5.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(int: Int, string: String)\\n  Wobble(Int)\\n}\\n\\npub fn go(x) {\\n   case x {\\n     Wibble(string:, int: 1) -> Wibble(1, string:)\\n     _ -> Wobble(1)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(string:, int: 1) -> Wibble(1, string:)\n     _ -> Wobble(1)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(int, string) {\n    super();\n    this.int = int;\n    this.string = string;\n  }\n}\nexport const Wibble$Wibble = (int, string) => new Wibble(int, string);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$int = (value) => value.int;\nexport const Wibble$Wibble$0 = (value) => value.int;\nexport const Wibble$Wibble$string = (value) => value.string;\nexport const Wibble$Wibble$1 = (value) => value.string;\n\nexport class Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Wibble$Wobble = ($0) => new Wobble($0);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof Wibble) {\n    let $ = x.int;\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Wobble(1);\n    }\n  } else {\n    return new Wobble(1);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_labels_matched_by_pattern_6.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(int: Int, string: String)\\n  Wobble(Int)\\n}\\n\\npub fn go(x) {\\n   case x {\\n     Wibble(1, string:) -> Wibble(string:, int: 1)\\n     _ -> Wobble(1)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(int: Int, string: String)\n  Wobble(Int)\n}\n\npub fn go(x) {\n   case x {\n     Wibble(1, string:) -> Wibble(string:, int: 1)\n     _ -> Wobble(1)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(int, string) {\n    super();\n    this.int = int;\n    this.string = string;\n  }\n}\nexport const Wibble$Wibble = (int, string) => new Wibble(int, string);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$int = (value) => value.int;\nexport const Wibble$Wibble$0 = (value) => value.int;\nexport const Wibble$Wibble$string = (value) => value.string;\nexport const Wibble$Wibble$1 = (value) => value.string;\n\nexport class Wobble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Wibble$Wobble = ($0) => new Wobble($0);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof Wibble) {\n    let $ = x.int;\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Wobble(1);\n    }\n  } else {\n    return new Wobble(1);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_select_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     Ok(1) -> gleam.Ok(1)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     Ok(1) -> gleam.Ok(1)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    let $ = x[0];\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Error(undefined);\n    }\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_select_matched_by_pattern_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     gleam.Ok(1) -> gleam.Ok(1)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     gleam.Ok(1) -> gleam.Ok(1)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof $gleam.Ok) {\n    let $ = x[0];\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Error(undefined);\n    }\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_record_with_select_matched_by_pattern_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x) {\\n   case x {\\n     gleam.Ok(1) -> Ok(1)\\n     _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x) {\n   case x {\n     gleam.Ok(1) -> Ok(1)\n     _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Error } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof $gleam.Ok) {\n    let $ = x[0];\n    if ($ === 1) {\n      return x;\n    } else {\n      return new Error(undefined);\n    }\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_building_simple_value_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"pub fn go(x) {\\n   case x {\\n     1 -> 2\\n     n -> n\\n   }\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n   case x {\n     1 -> 2\n     n -> n\n   }\n}\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x === 1) {\n    return 2;\n  } else {\n    return x;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_local_var_in_tuple.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn go(x, y) {\\n  let z = False\\n  case True {\\n    x if #(x, z) == #(True, False) -> x\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  let z = False\n  case True {\n    x if #(x, z) == #(True, False) -> x\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { isEqual } from \"../gleam.mjs\";\n\nexport function go(x, y) {\n  let z = false;\n  let $ = true;\n  let x$1 = $;\n  if (isEqual([x$1, z], [true, false])) {\n    return $;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_on_error.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nfn a_result() { Error(1) }\\n\\npub fn main() {\\n  case a_result() {\\n    Error(_) -> 1\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\n\nfn a_result() { Error(1) }\n\npub fn main() {\n  case a_result() {\n    Error(_) -> 1\n    _ -> 2\n  }\n}\n\n----- COMPILED JAVASCRIPT\nimport { Error } from \"../gleam.mjs\";\n\nfunction a_result() {\n  return new Error(1);\n}\n\nexport function main() {\n  let $ = a_result();\n  if ($ instanceof Error) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_list_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"pub fn go(n, x) {\\n   case n, x {\\n     1, [] -> []\\n     _, [a, b] -> [a, b]\\n     3, [1, ..rest] -> [1, ..rest]\\n     _, _ -> x\\n   }\\n}\"\n---\n----- SOURCE CODE\npub fn go(n, x) {\n   case n, x {\n     1, [] -> []\n     _, [a, b] -> [a, b]\n     3, [1, ..rest] -> [1, ..rest]\n     _, _ -> x\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function go(n, x) {\n  if (x instanceof $Empty) {\n    if (n === 1) {\n      return x;\n    } else {\n      return x;\n    }\n  } else {\n    let $ = x.tail;\n    if ($ instanceof $Empty) {\n      if (n === 3) {\n        let $1 = x.head;\n        if ($1 === 1) {\n          return x;\n        } else {\n          return x;\n        }\n      } else {\n        return x;\n      }\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        return x;\n      } else if (n === 3) {\n        let $2 = x.head;\n        if ($2 === 1) {\n          return x;\n        } else {\n          return x;\n        }\n      } else {\n        return x;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_record_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"pub fn go(x, y) {\\n   case x, y {\\n     Ok(1), Error(_) -> Ok(1)\\n     Error(_), Ok(n) -> Ok(n)\\n     _, _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\npub fn go(x, y) {\n   case x, y {\n     Ok(1), Error(_) -> Ok(1)\n     Error(_), Ok(n) -> Ok(n)\n     _, _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x, y) {\n  if (x instanceof Ok) {\n    if (y instanceof Error) {\n      let $ = x[0];\n      if ($ === 1) {\n        return x;\n      } else {\n        return new Error(undefined);\n      }\n    } else {\n      return new Error(undefined);\n    }\n  } else if (y instanceof Ok) {\n    return y;\n  } else {\n    return new Error(undefined);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_same_value_as_two_subjects_one_is_picked.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam\\n\\npub fn go(x, y) {\\n   case x, y {\\n     gleam.Ok(1), Ok(1) -> Ok(1)\\n     _, Error(Nil) -> Error(Nil)\\n     _, _ -> Error(Nil)\\n   }\\n}\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub fn go(x, y) {\n   case x, y {\n     gleam.Ok(1), Ok(1) -> Ok(1)\n     _, Error(Nil) -> Error(Nil)\n     _, _ -> Error(Nil)\n   }\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function go(x, y) {\n  if (y instanceof Ok) {\n    if (x instanceof $gleam.Ok) {\n      let $ = y[0];\n      if ($ === 1) {\n        let $1 = x[0];\n        if ($1 === 1) {\n          return x;\n        } else {\n          return new Error(undefined);\n        }\n      } else {\n        return new Error(undefined);\n      }\n    } else {\n      return new Error(undefined);\n    }\n  } else {\n    return y;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_simple_value_matched_by_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"pub fn go(x) {\\n   case x, x + 1 {\\n     1, _ -> 2\\n     _, n -> n\\n   }\\n}\"\n---\n----- SOURCE CODE\npub fn go(x) {\n   case x, x + 1 {\n     1, _ -> 2\n     _, n -> n\n   }\n}\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let $ = x + 1;\n  if (x === 1) {\n    return 2;\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__deeply_nested_string_prefix_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(Wobble)\\n}\\ntype Wobble {\\n  Wobble(wabble: Wabble)\\n}\\ntype Wabble {\\n  Wabble(tuple: #(Int, String))\\n}\\n\\npub fn main() {\\n  let tmp = Wibble(Wobble(Wabble(#(42, \\\"wibble\\\"))))\\n  case tmp {\\n    Wibble(Wobble(Wabble(#(_int, \\\"w\\\" as wibble <> rest)))) -> wibble <> rest\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble(Wobble)\n}\ntype Wobble {\n  Wobble(wabble: Wabble)\n}\ntype Wabble {\n  Wabble(tuple: #(Int, String))\n}\n\npub fn main() {\n  let tmp = Wibble(Wobble(Wabble(#(42, \"wibble\"))))\n  case tmp {\n    Wibble(Wobble(Wabble(#(_int, \"w\" as wibble <> rest)))) -> wibble <> rest\n    _ -> panic\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nclass Wibble extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nclass Wobble extends $CustomType {\n  constructor(wabble) {\n    super();\n    this.wabble = wabble;\n  }\n}\n\nclass Wabble extends $CustomType {\n  constructor(tuple) {\n    super();\n    this.tuple = tuple;\n  }\n}\n\nexport function main() {\n  let tmp = new Wibble(new Wobble(new Wabble([42, \"wibble\"])));\n  let $ = tmp[0].wabble.tuple[1];\n  if ($.startsWith(\"w\")) {\n    let wibble = \"w\";\n    let rest = $.slice(1);\n    return wibble + rest;\n  } else {\n    throw makeError(\n      \"panic\",\n      FILEPATH,\n      \"my/mod\",\n      16,\n      \"main\",\n      \"`panic` expression evaluated.\",\n      {}\n    )\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__directly_matching_case_subject.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn go() {\\n  let x = \\\"ABC\\\"\\n  case True {\\n    True -> {\\n      let x = 79\\n      0\\n    }\\n    False -> {\\n      let x = True\\n      0\\n    }\\n  }\\n  x\\n}\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = \"ABC\"\n  case True {\n    True -> {\n      let x = 79\n      0\n    }\n    False -> {\n      let x = True\n      0\n    }\n  }\n  x\n}\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let x = \"ABC\";\n  let $ = true;\n  let x$1 = 79;\n  0\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__duplicate_name_for_variables_used_in_guards.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn wibble() {\\n  let a = case 1337 {\\n    n if n == 1347 -> Nil\\n    _ -> Nil\\n  }\\n  let b = case 1337 {\\n    n -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble() {\n  let a = case 1337 {\n    n if n == 1347 -> Nil\n    _ -> Nil\n  }\n  let b = case 1337 {\n    n -> Nil\n  }\n}\n\n----- COMPILED JAVASCRIPT\nexport function wibble() {\n  let _block;\n  let $ = 1337;\n  {\n    let n = $;\n    if (n === 1347) {\n      _block = undefined;\n    } else {\n      _block = undefined;\n    }\n  }\n  let a = _block;\n  let _block$1;\n  let $1 = 1337;\n  let n = $1;\n  _block$1 = undefined;\n  let b = _block$1;\n  return b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__duplicate_name_for_variables_used_in_guards_shadowing_outer_name.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn wibble() {\\n  let n = 1\\n  let a = case 1337 {\\n    n if n == 1347 -> n\\n    _ -> n\\n  }\\n  let b = case 1337 {\\n    n -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble() {\n  let n = 1\n  let a = case 1337 {\n    n if n == 1347 -> n\n    _ -> n\n  }\n  let b = case 1337 {\n    n -> Nil\n  }\n}\n\n----- COMPILED JAVASCRIPT\nexport function wibble() {\n  let n = 1;\n  let _block;\n  let $ = 1337;\n  {\n    let n$1 = $;\n    if (n$1 === 1347) {\n      _block = $;\n    } else {\n      _block = n;\n    }\n  }\n  let a = _block;\n  let _block$1;\n  let $1 = 1337;\n  let n$1 = $1;\n  _block$1 = undefined;\n  let b = _block$1;\n  return b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__following_todo.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 81\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    True -> todo\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    True -> todo\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (x) {\n    throw makeError(\n      \"todo\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"`todo` expression evaluated. This code has not yet been implemented.\",\n      {}\n    )\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__guard_variable_only_brought_into_scope_when_needed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 34\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    // We want `a` to be defined before the guard check, and\\n    // `b` to be defined only if the predicate on a matches!\\n    [a, b] if a == 1 -> a + b\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    // We want `a` to be defined before the guard check, and\n    // `b` to be defined only if the predicate on a matches!\n    [a, b] if a == 1 -> a + b\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof $Empty) {\n    return 2;\n  } else {\n    let $ = x.tail;\n    if ($ instanceof $Empty) {\n      return 2;\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        let a = x.head;\n        if (a === 1) {\n          let b = $.head;\n          return a + b;\n        } else {\n          return 2;\n        }\n      } else {\n        return 2;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__guard_variable_only_brought_into_scope_when_needed_1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  case 1 {\\n    i if i == 1 -> True\\n    i if i < 2 -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 1 {\n    i if i == 1 -> True\n    i if i < 2 -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let $ = 1;\n  let i = $;\n  if (i === 1) {\n    return true;\n  } else {\n    let i = $;\n    if (i < 2) {\n      return true;\n    } else {\n      return false;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__interfering_string_pattern_succeeds_if_succeeding.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn wibble(bits) {\\n  case bits {\\n    <<\\\"aaa\\\", 0, _:bits>> -> 1\\n    // If the first one succeeds, so will the second check, so it won't be\\n    // performed twice inside the first if branch!\\n    <<\\\"aaa\\\", 1, _:bits>> -> 2\\n    _ -> 3\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble(bits) {\n  case bits {\n    <<\"aaa\", 0, _:bits>> -> 1\n    // If the first one succeeds, so will the second check, so it won't be\n    // performed twice inside the first if branch!\n    <<\"aaa\", 1, _:bits>> -> 2\n    _ -> 3\n  }\n}\n\n----- COMPILED JAVASCRIPT\nexport function wibble(bits) {\n  if (\n    bits.bitSize >= 24 &&\n    bits.byteAt(0) === 97 && bits.byteAt(1) === 97 && bits.byteAt(2) === 97 &&\n    bits.bitSize >= 32\n  ) {\n    if (bits.byteAt(3) === 0) {\n      return 1;\n    } else if (bits.byteAt(3) === 1) {\n      return 2;\n    } else {\n      return 3;\n    }\n  } else {\n    return 3;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__list_with_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    [] -> 0\\n    [first, ..] if first < 10 -> first * 2\\n    [first, ..] -> first\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    [] -> 0\n    [first, ..] if first < 10 -> first * 2\n    [first, ..] -> first\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof $Empty) {\n    return 0;\n  } else {\n    let first = x.head;\n    if (first < 10) {\n      return first * 2;\n    } else {\n      let first = x.head;\n      return first;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__list_with_guard_no_binding.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    [] -> 0\\n    [first, ..] if 1 < 10 -> first * 2\\n    [first, ..] -> first\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    [] -> 0\n    [first, ..] if 1 < 10 -> first * 2\n    [first, ..] -> first\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof $Empty) {\n    return 0;\n  } else if (1 < 10) {\n    let first = x.head;\n    return first * 2;\n  } else {\n    let first = x.head;\n    return first;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__multi_subject_catch_all.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn go(x, y) {\\n  case x, y {\\n    True, True -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  case x, y {\n    True, True -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x, y) {\n  if (x && y) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__multi_subject_no_catch_all.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 123\nexpression: \"\\npub fn go(x, y) {\\n  case x, y {\\n    True, _ -> 1\\n    _, True -> 2\\n    False, False -> 0\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  case x, y {\n    True, _ -> 1\n    _, True -> 2\n    False, False -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x, y) {\n  if (x) {\n    return 1;\n  } else if (y) {\n    return 2;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__multi_subject_or.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 109\nexpression: \"\\npub fn go(x, y) {\\n  case x, y {\\n    True, _ | _, True -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  case x, y {\n    True, _ | _, True -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x, y) {\n  if (x) {\n    return 1;\n  } else if (y) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__multi_subject_subject_assignments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 138\nexpression: \"\\npub fn go() {\\n  case True, False {\\n    True, True -> 1\\n    _, _ -> 0\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  case True, False {\n    True, True -> 1\n    _, _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let $ = true;\n  let $1 = false;\n  return 0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__nested_string_prefix_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wobble: String)\\n}\\n\\npub fn main() {\\n  let tmp = Wibble(wobble: \\\"wibble\\\")\\n  case tmp {\\n    Wibble(wobble: \\\"w\\\" as wibble <> rest) -> wibble <> rest\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble(wobble: String)\n}\n\npub fn main() {\n  let tmp = Wibble(wobble: \"wibble\")\n  case tmp {\n    Wibble(wobble: \"w\" as wibble <> rest) -> wibble <> rest\n    _ -> panic\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nclass Wibble extends $CustomType {\n  constructor(wobble) {\n    super();\n    this.wobble = wobble;\n  }\n}\n\nexport function main() {\n  let tmp = new Wibble(\"wibble\");\n  let $ = tmp.wobble;\n  if ($.startsWith(\"w\")) {\n    let wibble = \"w\";\n    let rest = $.slice(1);\n    return wibble + rest;\n  } else {\n    throw makeError(\n      \"panic\",\n      FILEPATH,\n      \"my/mod\",\n      10,\n      \"main\",\n      \"`panic` expression evaluated.\",\n      {}\n    )\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__nested_string_prefix_match.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  case Ok([\\\"a\\\", \\\"b c\\\", \\\"d\\\"]) {\\n    Ok([\\\"a\\\", \\\"b \\\" <> _, \\\"d\\\"]) -> 1\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Ok([\"a\", \"b c\", \"d\"]) {\n    Ok([\"a\", \"b \" <> _, \"d\"]) -> 1\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, toList, Empty as $Empty } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = new Ok(toList([\"a\", \"b c\", \"d\"]));\n  let $1 = $[0];\n  if ($1 instanceof $Empty) {\n    return 1;\n  } else {\n    let $2 = $1.tail;\n    if ($2 instanceof $Empty) {\n      return 1;\n    } else {\n      let $3 = $2.tail;\n      if ($3 instanceof $Empty) {\n        return 1;\n      } else {\n        let $4 = $3.tail;\n        if ($4 instanceof $Empty) {\n          let $5 = $1.head;\n          if ($5 === \"a\") {\n            let $6 = $2.head;\n            if ($6.startsWith(\"b \")) {\n              let $7 = $3.head;\n              if ($7 === \"d\") {\n                return 1;\n              } else {\n                return 1;\n              }\n            } else {\n              return 1;\n            }\n          } else {\n            return 1;\n          }\n        } else {\n          return 1;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__nested_string_prefix_match_that_would_crash_on_js.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  case Ok([\\\"b c\\\", \\\"d\\\"]) {\\n    Ok([\\\"b \\\" <> _, \\\"d\\\"]) -> 1\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Ok([\"b c\", \"d\"]) {\n    Ok([\"b \" <> _, \"d\"]) -> 1\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, toList, Empty as $Empty } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = new Ok(toList([\"b c\", \"d\"]));\n  let $1 = $[0];\n  if ($1 instanceof $Empty) {\n    return 1;\n  } else {\n    let $2 = $1.tail;\n    if ($2 instanceof $Empty) {\n      return 1;\n    } else {\n      let $3 = $2.tail;\n      if ($3 instanceof $Empty) {\n        let $4 = $1.head;\n        if ($4.startsWith(\"b \")) {\n          let $5 = $2.head;\n          if ($5 === \"d\") {\n            return 1;\n          } else {\n            return 1;\n          }\n        } else {\n          return 1;\n        }\n      } else {\n        return 1;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__pattern_matching_on_aliased_result_constructor.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nimport gleam.{Error as E, Ok as O}\\n\\npub fn go(x) {\\n  case x {\\n    E(_) -> 1\\n    O(_) -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam.{Error as E, Ok as O}\n\npub fn go(x) {\n  case x {\n    E(_) -> 1\n    O(_) -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Error as E, Ok as O, Ok } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof O) {\n    return 2;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__pipe.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 183\nexpression: \"\\npub fn go(x, f) {\\n  case x |> f {\\n    0 -> 1\\n    _ -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x, f) {\n  case x |> f {\n    0 -> 1\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x, f) {\n  let $ = (() => {\n    let _pipe = x;\n    return f(_pipe);\n  })();\n  if ($ === 0) {\n    return 1;\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__pointless.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 67\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    _ -> x\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    _ -> x\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__preassign_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 167\nexpression: \"\\npub fn go(x) {\\n  let y = case x() {\\n    True -> 1\\n    _ -> 0\\n  }\\n  y\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let y = case x() {\n    True -> 1\n    _ -> 0\n  }\n  y\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let _block;\n  let $ = x();\n  if ($) {\n    _block = 1;\n  } else {\n    _block = 0;\n  }\n  let y = _block;\n  return y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__record_update_in_pipeline_in_case_clause.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Int)\\n}\\n\\nfn identity(x) {\\n  x\\n}\\n\\npub fn go(x) {\\n  case x {\\n    Wibble(1, _) -> Wibble(..x, wibble: 4) |> identity\\n    Wibble(_, 3) -> Wibble(..x, wobble: 10) |> identity\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int)\n}\n\nfn identity(x) {\n  x\n}\n\npub fn go(x) {\n  case x {\n    Wibble(1, _) -> Wibble(..x, wibble: 4) |> identity\n    Wibble(_, 3) -> Wibble(..x, wobble: 10) |> identity\n    _ -> panic\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport class Wibble extends $CustomType {\n  constructor(wibble, wobble) {\n    super();\n    this.wibble = wibble;\n    this.wobble = wobble;\n  }\n}\nexport const Wibble$Wibble = (wibble, wobble) => new Wibble(wibble, wobble);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$wibble = (value) => value.wibble;\nexport const Wibble$Wibble$0 = (value) => value.wibble;\nexport const Wibble$Wibble$wobble = (value) => value.wobble;\nexport const Wibble$Wibble$1 = (value) => value.wobble;\n\nfunction identity(x) {\n  return x;\n}\n\nexport function go(x) {\n  let $ = x.wibble;\n  if ($ === 1) {\n    let _pipe = new Wibble(4, x.wobble);\n    return identity(_pipe);\n  } else {\n    let $1 = x.wobble;\n    if ($1 === 3) {\n      let _pipe = new Wibble(x.wibble, 10);\n      return identity(_pipe);\n    } else {\n      throw makeError(\n        \"panic\",\n        FILEPATH,\n        \"my/mod\",\n        14,\n        \"go\",\n        \"`panic` expression evaluated.\",\n        {}\n      )\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__result.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 197\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    Ok(_) -> 1\\n    Error(_) -> 0\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    Ok(_) -> 1\n    Error(_) -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok } from \"../gleam.mjs\";\n\nexport function go(x) {\n  if (x instanceof Ok) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__single_clause_variables.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  let text = \\\"first defined\\\"\\n  case \\\"defined again\\\" {\\n    text -> Nil\\n  }\\n  let text = \\\"a third time\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let text = \"first defined\"\n  case \"defined again\" {\n    text -> Nil\n  }\n  let text = \"a third time\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let text = \"first defined\";\n  let $ = \"defined again\";\n  let text$1 = $;\n  undefined\n  let text$2 = \"a third time\";\n  return text$2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__single_clause_variables_assigned.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  let text = \\\"first defined\\\"\\n  let other = case \\\"defined again\\\" {\\n    text -> Nil\\n  }\\n  let text = \\\"a third time\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let text = \"first defined\"\n  let other = case \"defined again\" {\n    text -> Nil\n  }\n  let text = \"a third time\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let text = \"first defined\";\n  let _block;\n  let $ = \"defined again\";\n  let text$1 = $;\n  _block = undefined;\n  let other = _block;\n  let text$2 = \"a third time\";\n  return text$2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__slicing_is_handled_properly_with_multiple_branches.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  case \\\"12345\\\" {\\n    \\\"0\\\" <> rest -> rest\\n    \\\"123\\\" <> rest -> rest\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case \"12345\" {\n    \"0\" <> rest -> rest\n    \"123\" <> rest -> rest\n    _ -> \"\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let $ = \"12345\";\n  if ($.startsWith(\"0\")) {\n    let rest = $.slice(1);\n    return rest;\n  } else if ($.startsWith(\"123\")) {\n    let rest = $.slice(3);\n    return rest;\n  } else {\n    return \"\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__string_concatenation_in_clause_guards.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\npub fn main() {\\n  let wibble = \\\"wob\\\"\\n  case wibble {\\n    x if x <> \\\"ble\\\" == \\\"wobble\\\" -> 1\\n    _ -> 0\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let wibble = \"wob\"\n  case wibble {\n    x if x <> \"ble\" == \"wobble\" -> 1\n    _ -> 0\n  }\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let wibble = \"wob\";\n  let x = wibble;\n  if ((x + \"ble\") === \"wobble\") {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__tuple_and_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nassertion_line: 20\nexpression: \"\\npub fn go(x) {\\n  case #(1, 2) {\\n    #(1, a) if a == 2 -> 1\\n    #(_, _) -> 2\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case #(1, 2) {\n    #(1, a) if a == 2 -> 1\n    #(_, _) -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let $ = [1, 2];\n  let $1 = $[0];\n  if ($1 === 1) {\n    let a = $[1];\n    if (a === 2) {\n      return 1;\n    } else {\n      return 2;\n    }\n  } else {\n    return 2;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__var_true.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case.rs\nexpression: \"\\nfn true() { True }\\npub fn main() {\\n    let true_ = true()\\n    assert 0 == case Nil {\\n        _ if true_ -> 0\\n        _ -> 1\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn true() { True }\npub fn main() {\n    let true_ = true()\n    assert 0 == case Nil {\n        _ if true_ -> 0\n        _ -> 1\n    }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction true$() {\n  return true;\n}\n\nexport function main() {\n  let true_ = true$();\n  let $ = 0;\n  let _block;\n  let $1 = undefined;\n  {\n    if (true_) {\n      _block = 0;\n    } else {\n      _block = 1;\n    }\n  }\n  let $2 = _block;\n  if (!($ === $2)) {\n    throw makeError(\n      \"assert\",\n      FILEPATH,\n      \"my/mod\",\n      5,\n      \"main\",\n      \"Assertion failed.\",\n      {\n        kind: \"binary_operator\",\n        operator: \"==\",\n        left: { kind: \"literal\", value: $, start: 70, end: 71 },\n        right: { kind: \"expression\", value: $2, start: 75, end: 130 },\n        start: 63,\n        end: 130,\n        expression_start: 70\n      }\n    )\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs) {\\n  case xs {\\n    1 | 2 -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs) {\n  case xs {\n    1 | 2 -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs) {\n  if (xs === 1) {\n    return 0;\n  } else if (xs === 2) {\n    return 0;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__alternative_patterns_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs) -> Int {\\n  case xs {\\n    [x] | [_, x] -> x\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs) -> Int {\n  case xs {\n    [x] | [_, x] -> x\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function main(xs) {\n  if (xs instanceof $Empty) {\n    return 1;\n  } else {\n    let $ = xs.tail;\n    if ($ instanceof $Empty) {\n      let x = xs.head;\n      return x;\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        let x = $.head;\n        return x;\n      } else {\n        return 1;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__alternative_patterns_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs) -> Int {\\n  case xs {\\n    [x] | [_, x] if x == 1 -> x\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs) -> Int {\n  case xs {\n    [x] | [_, x] if x == 1 -> x\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function main(xs) {\n  if (xs instanceof $Empty) {\n    return 0;\n  } else {\n    let $ = xs.tail;\n    if ($ instanceof $Empty) {\n      let x = xs.head;\n      if (x === 1) {\n        return x;\n      } else {\n        return 0;\n      }\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        let x = $.head;\n        if (x === 1) {\n          return x;\n        } else {\n          return 0;\n        }\n      } else {\n        return 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__alternative_patterns_list.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs) -> Int {\\n  case xs {\\n    [1] | [1, 2] -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs) -> Int {\n  case xs {\n    [1] | [1, 2] -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function main(xs) {\n  if (xs instanceof $Empty) {\n    return 1;\n  } else {\n    let $ = xs.tail;\n    if ($ instanceof $Empty) {\n      let $1 = xs.head;\n      if ($1 === 1) {\n        return 0;\n      } else {\n        return 1;\n      }\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        let $2 = xs.head;\n        if ($2 === 1) {\n          let $3 = $.head;\n          if ($3 === 2) {\n            return 0;\n          } else {\n            return 1;\n          }\n        } else {\n          return 1;\n        }\n      } else {\n        return 1;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__bit_array_referencing_shadowed_variable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n  let a = 2\\n\\n  case Nil {\\n    _ if <<a>> == <<1>> -> False\\n    _ if <<a>> == <<2>> -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 1\n  let a = 2\n\n  case Nil {\n    _ if <<a>> == <<1>> -> False\n    _ if <<a>> == <<2>> -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { isEqual, toBitArray } from \"../gleam.mjs\";\n\nexport function main() {\n  let a = 1;\n  let a$1 = 2;\n  let $ = undefined;\n  if (isEqual(toBitArray([a$1]), toBitArray([1]))) {\n    return false;\n  } else if (isEqual(toBitArray([a$1]), toBitArray([2]))) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__bitarray_with_var.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main() {\\n  case 5 {\\n    z if <<z>> == <<z>> -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  case 5 {\n    z if <<z>> == <<z>> -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { isEqual, toBitArray } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = 5;\n  let z = $;\n  if (isEqual(toBitArray([z]), toBitArray([z]))) {\n    return undefined;\n  } else {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs) {\\n  case xs {\\n    #(x) if x == 1 -> x\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs) {\n  case xs {\n    #(x) if x == 1 -> x\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs) {\n  let x = xs[0];\n  if (x === 1) {\n    return x;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__constructor_function_in_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nassertion_line: 524\nexpression: \"pub fn func(x) {\\n    case [] {\\n        _ if [] == [ Ok ] -> True\\n        _ -> False\\n    }\\n}\\n    \"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub fn func(x) {\n    case [] {\n        _ if [] == [ Ok ] -> True\n        _ -> False\n    }\n}\n    \n\n----- COMPILED JAVASCRIPT\nimport { Ok, toList, isEqual } from \"../gleam.mjs\";\n\nexport function func(x) {\n  let $ = toList([]);\n  if (isEqual(toList([]), toList([(var0) => { return new Ok(var0); }]))) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__custom_type_constructor_imported_and_aliased.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"import other_module.{A as B}\\npub fn func() {\\n  case B {\\n    x if x == B -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\nimport other_module.{A as B}\npub fn func() {\n  case B {\n    x if x == B -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../../package/other_module.mjs\";\nimport { A as B } from \"../../package/other_module.mjs\";\n\nexport function func() {\n  let $ = new B();\n  let x = $;\n  if (x instanceof B) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__eq_complex.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs, y) {\\n  case xs {\\n    #(x) if xs == y -> x\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs, y) {\n  case xs {\n    #(x) if xs == y -> x\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { isEqual } from \"../gleam.mjs\";\n\nexport function main(xs, y) {\n  if (isEqual(xs, y)) {\n    let x = xs[0];\n    return x;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__eq_scalar.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs, y: Int) {\\n  case xs {\\n    #(x) if x == y -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs, y: Int) {\n  case xs {\n    #(x) if x == y -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs, y) {\n  let x = xs[0];\n  if (x === y) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__field_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n        pub type Person {\\n          Person(username: String, name: String, age: Int)\\n        }\\n        pub fn main() {\\n          let given_name = \\\"jack\\\"\\n          let raiden = Person(\\\"raiden\\\", \\\"jack\\\", 31)\\n          case given_name {\\n            name if name == raiden.name -> \\\"It's jack\\\"\\n            _ -> \\\"It's not jack\\\"\\n          }\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub type Person {\n          Person(username: String, name: String, age: Int)\n        }\n        pub fn main() {\n          let given_name = \"jack\"\n          let raiden = Person(\"raiden\", \"jack\", 31)\n          case given_name {\n            name if name == raiden.name -> \"It's jack\"\n            _ -> \"It's not jack\"\n          }\n        }\n        \n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Person extends $CustomType {\n  constructor(username, name, age) {\n    super();\n    this.username = username;\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Person = (username, name, age) =>\n  new Person(username, name, age);\nexport const Person$isPerson = (value) => value instanceof Person;\nexport const Person$Person$username = (value) => value.username;\nexport const Person$Person$0 = (value) => value.username;\nexport const Person$Person$name = (value) => value.name;\nexport const Person$Person$1 = (value) => value.name;\nexport const Person$Person$age = (value) => value.age;\nexport const Person$Person$2 = (value) => value.age;\n\nexport function main() {\n  let given_name = \"jack\";\n  let raiden = new Person(\"raiden\", \"jack\", 31);\n  let name = given_name;\n  if (name === raiden.name) {\n    return \"It's jack\";\n  } else {\n    return \"It's not jack\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__float_division.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub fn main() {\\n  case 5.1 /. 0.0 {\\n    x if x == 5.1 /. 0.0 -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 5.1 /. 0.0 {\n    x if x == 5.1 /. 0.0 -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { divideFloat } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = 0.0;\n  let x = $;\n  if (x === (divideFloat(5.1, 0.0))) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__guard_pattern_does_not_shadow_outer_scope.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub type Option(a) {\\n  Some(a)\\n  None\\n}\\n\\npub type Container {\\n  Container(x: Option(Int))\\n}\\n\\npub fn main() {\\n  let x: Option(Int) = Some(42)\\n  case Some(1) {\\n    Some(x) if x < 0 -> Container(None)\\n    _ -> {\\n      Container(x:)\\n    }\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Option(a) {\n  Some(a)\n  None\n}\n\npub type Container {\n  Container(x: Option(Int))\n}\n\npub fn main() {\n  let x: Option(Int) = Some(42)\n  case Some(1) {\n    Some(x) if x < 0 -> Container(None)\n    _ -> {\n      Container(x:)\n    }\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Some extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Option$Some = ($0) => new Some($0);\nexport const Option$isSome = (value) => value instanceof Some;\nexport const Option$Some$0 = (value) => value[0];\n\nexport class None extends $CustomType {}\nexport const Option$None = () => new None();\nexport const Option$isNone = (value) => value instanceof None;\n\nexport class Container extends $CustomType {\n  constructor(x) {\n    super();\n    this.x = x;\n  }\n}\nexport const Container$Container = (x) => new Container(x);\nexport const Container$isContainer = (value) => value instanceof Container;\nexport const Container$Container$x = (value) => value.x;\nexport const Container$Container$0 = (value) => value.x;\n\nexport function main() {\n  let x = new Some(42);\n  let $ = new Some(1);\n  let x$1 = $[0];\n  if (x$1 < 0) {\n    return new Container(new None());\n  } else {\n    return new Container(x);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__imported_aliased_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"import gleam.{Ok as Y}\\npub type X {\\n  Ok\\n}\\npub fn func() {\\n  case Y {\\n    y if y == Y -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\nimport gleam.{Ok as Y}\npub type X {\n  Ok\n}\npub fn func() {\n  case Y {\n    y if y == Y -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok as Y, CustomType as $CustomType, isEqual } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {}\nexport const X$Ok = () => new Ok();\nexport const X$isOk = (value) => value instanceof Ok;\n\nexport function func() {\n  let $ = (var0) => { return new Y(var0); };\n  let y = $;\n  if (isEqual(y, (var0) => { return new Y(var0); })) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__imported_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"import gleam\\npub type X {\\n  Ok\\n}\\npub fn func(x) {\\n  case gleam.Ok {\\n    _ if [] == [ gleam.Ok ] -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\nimport gleam\npub type X {\n  Ok\n}\npub fn func(x) {\n  case gleam.Ok {\n    _ if [] == [ gleam.Ok ] -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, toList, CustomType as $CustomType, isEqual } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {}\nexport const X$Ok = () => new Ok();\nexport const X$isOk = (value) => value instanceof Ok;\n\nexport function func(x) {\n  let $ = (var0) => { return new $gleam.Ok(var0); };\n  if (isEqual(toList([]), toList([(var0) => { return new Ok(var0); }]))) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__int_division.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub fn main() {\\n  case 5 / 2 {\\n    x if x == 5 / 2 -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 5 / 2 {\n    x if x == 5 / 2 -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { divideInt } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = globalThis.Math.trunc(5 / 2);\n  let x = $;\n  if (x === (divideInt(5, 2))) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__int_remainder.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub fn main() {\\n  case 4 % 0 {\\n    x if x == 4 % 0 -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 4 % 0 {\n    x if x == 4 % 0 -> True\n    _ -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { remainderInt } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = 0;\n  let x = $;\n  if (x === (remainderInt(4, 0))) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__keyword_var.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub const function = 5\\npub const do = 10\\npub fn main() {\\n  let class = 5\\n  let while = 10\\n  let var = 7\\n  case var {\\n    _ if class == while -> True\\n    _ if [class] == [5] -> True\\n    function if #(function) == #(5) -> False\\n    _ if do == function -> True\\n    while if while > 5 -> False\\n    class -> False\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub const function = 5\npub const do = 10\npub fn main() {\n  let class = 5\n  let while = 10\n  let var = 7\n  case var {\n    _ if class == while -> True\n    _ if [class] == [5] -> True\n    function if #(function) == #(5) -> False\n    _ if do == function -> True\n    while if while > 5 -> False\n    class -> False\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList, isEqual } from \"../gleam.mjs\";\n\nexport const function$ = 5;\n\nexport const do$ = 10;\n\nexport function main() {\n  let class$ = 5;\n  let while$ = 10;\n  let var$ = 7;\n  if (class$ === while$) {\n    return true;\n  } else if (isEqual(toList([class$]), toList([5]))) {\n    return true;\n  } else {\n    let function$1 = var$;\n    if (isEqual([function$1], [5])) {\n      return false;\n    } else if (10 === 5) {\n      return true;\n    } else {\n      let while$1 = var$;\n      if (while$1 > 5) {\n        return false;\n      } else {\n        let class$1 = var$;\n        return false;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == hero.ironman.name -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman.name -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $hero from \"../../package/hero.mjs\";\n\nexport function main() {\n  let name = \"Tony Stark\";\n  let n = name;\n  if (n === $hero.ironman.name) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_access_aliased.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero/submodule as myhero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == myhero.ironman.name -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero/submodule as myhero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == myhero.ironman.name -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $myhero from \"../../package/hero/submodule.mjs\";\n\nexport function main() {\n  let name = \"Tony Stark\";\n  let n = name;\n  if (n === $myhero.ironman.name) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_access_submodule.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero/submodule\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == submodule.ironman.name -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero/submodule\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == submodule.ironman.name -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $submodule from \"../../package/hero/submodule.mjs\";\n\nexport function main() {\n  let name = \"Tony Stark\";\n  let n = name;\n  if (n === $submodule.ironman.name) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_list_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let names = [\\\"Tony Stark\\\", \\\"Bruce Wayne\\\"]\\n            case names {\\n              n if n == hero.heroes -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let names = [\"Tony Stark\", \"Bruce Wayne\"]\n            case names {\n              n if n == hero.heroes -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $hero from \"../../package/hero.mjs\";\nimport { toList, isEqual } from \"../gleam.mjs\";\n\nexport function main() {\n  let names = toList([\"Tony Stark\", \"Bruce Wayne\"]);\n  let n = names;\n  if (isEqual(n, $hero.heroes)) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_nested_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Bruce Wayne\\\"\\n            case name {\\n              n if n == hero.batman.secret_identity.name -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Bruce Wayne\"\n            case name {\n              n if n == hero.batman.secret_identity.name -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $hero from \"../../package/hero.mjs\";\n\nexport function main() {\n  let name = \"Bruce Wayne\";\n  let n = name;\n  if (n === $hero.batman.secret_identity.name) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_string_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == hero.ironman -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.ironman -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $hero from \"../../package/hero.mjs\";\n\nexport function main() {\n  let name = \"Tony Stark\";\n  let n = name;\n  if (n === ($hero.ironman)) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__module_tuple_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\n          import hero\\n          pub fn main() {\\n            let name = \\\"Tony Stark\\\"\\n            case name {\\n              n if n == hero.hero.1 -> True\\n              _ -> False\\n            }\\n          }\\n        \"\n---\n----- SOURCE CODE\n\n          import hero\n          pub fn main() {\n            let name = \"Tony Stark\"\n            case name {\n              n if n == hero.hero.1 -> True\n              _ -> False\n            }\n          }\n        \n\n----- COMPILED JAVASCRIPT\nimport * as $hero from \"../../package/hero.mjs\";\n\nexport function main() {\n  let name = \"Tony Stark\";\n  let n = name;\n  if (n === $hero.hero[1]) {\n    return true;\n  } else {\n    return false;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__nested_record_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"\\npub type A {\\n  A(b: B)\\n}\\n\\npub type B {\\n  B(c: C)\\n}\\n\\npub type C {\\n  C(d: Bool)\\n}\\n\\npub fn a(a: A) {\\n  case a {\\n    _ if a.b.c.d -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type A {\n  A(b: B)\n}\n\npub type B {\n  B(c: C)\n}\n\npub type C {\n  C(d: Bool)\n}\n\npub fn a(a: A) {\n  case a {\n    _ if a.b.c.d -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class A extends $CustomType {\n  constructor(b) {\n    super();\n    this.b = b;\n  }\n}\nexport const A$A = (b) => new A(b);\nexport const A$isA = (value) => value instanceof A;\nexport const A$A$b = (value) => value.b;\nexport const A$A$0 = (value) => value.b;\n\nexport class B extends $CustomType {\n  constructor(c) {\n    super();\n    this.c = c;\n  }\n}\nexport const B$B = (c) => new B(c);\nexport const B$isB = (value) => value instanceof B;\nexport const B$B$c = (value) => value.c;\nexport const B$B$0 = (value) => value.c;\n\nexport class C extends $CustomType {\n  constructor(d) {\n    super();\n    this.d = d;\n  }\n}\nexport const C$C = (d) => new C(d);\nexport const C$isC = (value) => value instanceof C;\nexport const C$C$d = (value) => value.d;\nexport const C$C$0 = (value) => value.d;\n\nexport function a(a) {\n  if (a.b.c.d) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__not.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(x, y) {\\n  case x {\\n    _ if !y -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x, y) {\n  case x {\n    _ if !y -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x, y) {\n  if (!y) {\n    return 0;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__not_eq_complex.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs, y) {\\n  case xs {\\n    #(x) if xs != y -> x\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs, y) {\n  case xs {\n    #(x) if xs != y -> x\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { isEqual } from \"../gleam.mjs\";\n\nexport function main(xs, y) {\n  if (!isEqual(xs, y)) {\n    let x = xs[0];\n    return x;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__not_eq_scalar.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs, y: Int) {\\n  case xs {\\n    #(x) if x != y -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs, y: Int) {\n  case xs {\n    #(x) if x != y -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs, y) {\n  let x = xs[0];\n  if (x !== y) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__not_two.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(x, y) {\\n  case x {\\n    _ if !y && !x -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x, y) {\n  case x {\n    _ if !y && !x -> 0\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x, y) {\n  if (!y && !x) {\n    return 0;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__operator_wrapping_left.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs, y: Bool, z: Bool) {\\n  case xs {\\n    #(x) if { x == y } == z -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs, y: Bool, z: Bool) {\n  case xs {\n    #(x) if { x == y } == z -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs, y, z) {\n  let x = xs[0];\n  if ((x === y) === z) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__operator_wrapping_right.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs, y: Bool, z: Bool) {\\n  case xs {\\n    #(x) if x == { y == z } -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs, y: Bool, z: Bool) {\n  case xs {\n    #(x) if x == { y == z } -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs, y, z) {\n  let x = xs[0];\n  if (x === (y === z)) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__rebound_var.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main() {\\n  let x = False\\n  let x = True\\n  case x {\\n    _ if x -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let x = False\n  let x = True\n  case x {\n    _ if x -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let x = false;\n  let x$1 = true;\n  if (x$1) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__referencing_pattern_var.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(xs) {\\n  case xs {\\n    #(x) if x -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(xs) {\n  case xs {\n    #(x) if x -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(xs) {\n  let x = xs[0];\n  if (x) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__tuple_index.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/case_clause_guards.rs\nexpression: \"pub fn main(x, xs: #(Bool, Bool, Bool)) {\\n  case x {\\n    _ if xs.2 -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(x, xs: #(Bool, Bool, Bool)) {\n  case x {\n    _ if xs.2 -> 1\n    _ -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x, xs) {\n  if (xs[2]) {\n    return 1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__constant_constructor_gets_pure_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\npub type X {\\n  X(Int, List(String))\\n}\\n\\npub const x = X(1, [\\\"1\\\"])\\npub const y = X(1, [])\\n        \"\n---\n----- SOURCE CODE\n\npub type X {\n  X(Int, List(String))\n}\n\npub const x = X(1, [\"1\"])\npub const y = X(1, [])\n        \n\n----- COMPILED JAVASCRIPT\nimport { toList, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class X extends $CustomType {\n  constructor($0, $1) {\n    super();\n    this[0] = $0;\n    this[1] = $1;\n  }\n}\nexport const X$X = ($0, $1) => new X($0, $1);\nexport const X$isX = (value) => value instanceof X;\nexport const X$X$0 = (value) => value[0];\nexport const X$X$1 = (value) => value[1];\n\nexport const x = /* @__PURE__ */ new X(1, /* @__PURE__ */ toList([\"1\"]));\n\nexport const y = /* @__PURE__ */ new X(1, /* @__PURE__ */ toList([]));\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__constant_list_with_constructors_gets_pure_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\npub type X {\\n  X(Int, List(String))\\n}\\n\\npub const x = [X(1, [\\\"1\\\"])]\\npub const y = [X(1, [\\\"1\\\"])]\\n        \"\n---\n----- SOURCE CODE\n\npub type X {\n  X(Int, List(String))\n}\n\npub const x = [X(1, [\"1\"])]\npub const y = [X(1, [\"1\"])]\n        \n\n----- COMPILED JAVASCRIPT\nimport { toList, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class X extends $CustomType {\n  constructor($0, $1) {\n    super();\n    this[0] = $0;\n    this[1] = $1;\n  }\n}\nexport const X$X = ($0, $1) => new X($0, $1);\nexport const X$isX = (value) => value instanceof X;\nexport const X$X$0 = (value) => value[0];\nexport const X$X$1 = (value) => value[1];\n\nexport const x = /* @__PURE__ */ toList([\n  /* @__PURE__ */ new X(1, /* @__PURE__ */ toList([\"1\"])),\n]);\n\nexport const y = /* @__PURE__ */ toList([\n  /* @__PURE__ */ new X(1, /* @__PURE__ */ toList([\"1\"])),\n]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__constant_tuple_with_constructors_gets_pure_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\npub type X {\\n  X(Int, List(String))\\n}\\n\\npub const x = #(X(1, [\\\"1\\\"]))\\npub const y = #(X(1, [\\\"1\\\"]))\\n        \"\n---\n----- SOURCE CODE\n\npub type X {\n  X(Int, List(String))\n}\n\npub const x = #(X(1, [\"1\"]))\npub const y = #(X(1, [\"1\"]))\n        \n\n----- COMPILED JAVASCRIPT\nimport { toList, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class X extends $CustomType {\n  constructor($0, $1) {\n    super();\n    this[0] = $0;\n    this[1] = $1;\n  }\n}\nexport const X$X = ($0, $1) => new X($0, $1);\nexport const X$isX = (value) => value instanceof X;\nexport const X$X$0 = (value) => value[0];\nexport const X$X$1 = (value) => value[1];\n\nexport const x = [/* @__PURE__ */ new X(1, /* @__PURE__ */ toList([\"1\"]))];\n\nexport const y = [/* @__PURE__ */ new X(1, /* @__PURE__ */ toList([\"1\"]))];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__constants_get_their_own_jsdoc_comment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\n/// 11 is clearly the best number!\\npub const jaks_favourite_number = 11\\n\"\n---\n----- SOURCE CODE\n\n/// 11 is clearly the best number!\npub const jaks_favourite_number = 11\n\n\n----- COMPILED JAVASCRIPT\n/**\n * 11 is clearly the best number!\n */\nexport const jaks_favourite_number = 11;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__constructor_function_in_constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: pub const a = Ok\n---\n----- SOURCE CODE\npub const a = Ok\n\n----- COMPILED JAVASCRIPT\nimport { Ok } from \"../gleam.mjs\";\n\nexport const a = (var0) => { return new Ok(var0); };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__custom_type_constructor_imported_and_aliased.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"import other_module.{A as B}\\n\\npub const local = B\\n\"\n---\n----- SOURCE CODE\nimport other_module.{A as B}\n\npub const local = B\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../../package/other_module.mjs\";\nimport { A as B } from \"../../package/other_module.mjs\";\n\nexport const local = /* @__PURE__ */ new B();\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__imported_aliased_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"import gleam.{Ok as Y}\\n\\npub type X {\\n  Ok\\n}\\n\\npub const y = Y\\n\"\n---\n----- SOURCE CODE\nimport gleam.{Ok as Y}\n\npub type X {\n  Ok\n}\n\npub const y = Y\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok as Y, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {}\nexport const X$Ok = () => new Ok();\nexport const X$isOk = (value) => value instanceof Ok;\n\nexport const y = (var0) => { return new Y(var0); };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__imported_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"import gleam\\n\\npub type X {\\n  Ok\\n}\\n\\npub const y = gleam.Ok\\n\"\n---\n----- SOURCE CODE\nimport gleam\n\npub type X {\n  Ok\n}\n\npub const y = gleam.Ok\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {}\nexport const X$Ok = () => new Ok();\nexport const X$isOk = (value) => value instanceof Ok;\n\nexport const y = (var0) => { return new Ok(var0); };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__list_prepend.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\nconst wibble = [2, 3, 4]\\npub const wobble = [0, 1, ..wibble]\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [2, 3, 4]\npub const wobble = [0, 1, ..wibble]\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nconst wibble = /* @__PURE__ */ toList([2, 3, 4]);\n\nexport const wobble = /* @__PURE__ */ toList([0, 1, 2, 3, 4]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__list_prepend_from_other_module.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\nimport mod\\n\\npub const wobble = [0, 1, ..mod.wibble]\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub const wibble = [2, 3, 4]\n\n-- main.gleam\n\nimport mod\n\npub const wobble = [0, 1, ..mod.wibble]\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\nimport * as $mod from \"../mod.mjs\";\n\nexport const wobble = /* @__PURE__ */ toList([0, 1, 2, 3, 4]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__list_prepend_literal.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\npub const wibble = [0, 1, ..[2, 3, 4]]\\n\"\n---\n----- SOURCE CODE\n\npub const wibble = [0, 1, ..[2, 3, 4]]\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nexport const wibble = /* @__PURE__ */ toList([0, 1, 2, 3, 4]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_bool_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"\\n        pub const a = True\\n        pub const b = False\\n    \"\n---\n----- SOURCE CODE\n\n        pub const a = True\n        pub const b = False\n    \n\n----- COMPILED JAVASCRIPT\nexport const a = true;\n\nexport const b = false;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_float_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: pub const a = 1.1\n---\n----- SOURCE CODE\npub const a = 1.1\n\n----- COMPILED JAVASCRIPT\nexport const a = 1.1;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_int_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: pub const a = 1\n---\n----- SOURCE CODE\npub const a = 1\n\n----- COMPILED JAVASCRIPT\nexport const a = 1;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_list_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"pub const a = [1, 2, 3]\"\n---\n----- SOURCE CODE\npub const a = [1, 2, 3]\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nexport const a = /* @__PURE__ */ toList([1, 2, 3]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_nil_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: pub const a = Nil\n---\n----- SOURCE CODE\npub const a = Nil\n\n----- COMPILED JAVASCRIPT\nexport const a = undefined;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_string_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"pub const a = \\\"1\\\"\"\n---\n----- SOURCE CODE\npub const a = \"1\"\n\n----- COMPILED JAVASCRIPT\nexport const a = \"1\";\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__consts__literal_tuple_does_not_get_constant_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/consts.rs\nexpression: \"pub const a = #(1, 2, 3)\"\n---\n----- SOURCE CODE\npub const a = #(1, 2, 3)\n\n----- COMPILED JAVASCRIPT\nexport const a = [1, 2, 3];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_imported_ignoring_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub const main = other.Two(1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other\npub const main = other.Two(1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new $other.Two(1);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_imported_multiple_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub const main = other.Two(b: 2, c: 3, a: 1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other\npub const main = other.Two(b: 2, c: 3, a: 1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new $other.Two(1, 2, 3);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_imported_no_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub const main = other.Two(1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(Int) }\n\n-- main.gleam\nimport other\npub const main = other.Two(1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new $other.Two(1);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_imported_using_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub const main = other.Two(field: 1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other\npub const main = other.Two(field: 1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new $other.Two(1);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_unqualified_imported_ignoring_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub const main = Two(1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other.{Two}\npub const main = Two(1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new Two(1);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_unqualified_imported_multiple_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub const main = Two(b: 2, c: 3, a: 1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other.{Two}\npub const main = Two(b: 2, c: 3, a: 1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new Two(1, 2, 3);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_unqualified_imported_no_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub const main = Two(1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(Int) }\n\n-- main.gleam\nimport other.{Two}\npub const main = Two(1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new Two(1);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_unqualified_imported_using_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub const main = Two(field: 1)\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other.{Two}\npub const main = Two(field: 1)\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport const main = /* @__PURE__ */ new Two(1);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_with_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Mine {\\n  Mine(a: Int, b: Int)\\n}\\n\\npub const labels = Mine(b: 2, a: 1)\\npub const no_labels = Mine(3, 4)\\n\"\n---\n----- SOURCE CODE\n\npub type Mine {\n  Mine(a: Int, b: Int)\n}\n\npub const labels = Mine(b: 2, a: 1)\npub const no_labels = Mine(3, 4)\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Mine extends $CustomType {\n  constructor(a, b) {\n    super();\n    this.a = a;\n    this.b = b;\n  }\n}\nexport const Mine$Mine = (a, b) => new Mine(a, b);\nexport const Mine$isMine = (value) => value instanceof Mine;\nexport const Mine$Mine$a = (value) => value.a;\nexport const Mine$Mine$0 = (value) => value.a;\nexport const Mine$Mine$b = (value) => value.b;\nexport const Mine$Mine$1 = (value) => value.b;\n\nexport const labels = /* @__PURE__ */ new Mine(1, 2);\n\nexport const no_labels = /* @__PURE__ */ new Mine(3, 4);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_with_fields_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 138\nexpression: \"\\npub type Mine {\\n  Mine(a: Int, b: Int)\\n}\\n\\npub const labels = Mine(b: 2, a: 1)\\npub const no_labels = Mine(3, 4)\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Mine {\n  Mine(a: Int, b: Int)\n}\n\npub const labels = Mine(b: 2, a: 1)\npub const no_labels = Mine(3, 4)\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class Mine extends _.CustomType {\n  /** @deprecated */\n  constructor(a: number, b: number);\n  /** @deprecated */\n  a: number;\n  /** @deprecated */\n  b: number;\n}\nexport function Mine$Mine(a: number, b: number): Mine$;\nexport function Mine$isMine(value: any): value is Mine$;\nexport function Mine$Mine$0(value: Mine$): number;\nexport function Mine$Mine$a(value: Mine$): number;\nexport function Mine$Mine$1(value: Mine$): number;\nexport function Mine$Mine$b(value: Mine$): number;\n\nexport type Mine$ = Mine;\n\nexport const labels: Mine$;\n\nexport const no_labels: Mine$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_zero_arity_imported.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 104\nexpression: \"import other\\npub const x = other.Two\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two }\n\n-- main.gleam\nimport other\npub const x = other.Two\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport const x = /* @__PURE__ */ new $other.Two();\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__const_zero_arity_imported_unqualified.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 114\nexpression: \"import other.{Two}\\npub const a = Two\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two }\n\n-- main.gleam\nimport other.{Two}\npub const a = Two\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport const a = /* @__PURE__ */ new Two();\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__constructor_as_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other\npub fn main() {\n  other.Two\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return (var0, var1, var2) => { return new $other.Two(var0, var1, var2); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__constructors_get_their_own_jsdoc.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 678\nexpression: \"\\npub type Wibble {\\n  /// Wibbling!!\\n  Wibble(field: Int)\\n\\n  /// Wobbling!!\\n  Wobble(field: Int)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Wibble {\n  /// Wibbling!!\n  Wibble(field: Int)\n\n  /// Wobbling!!\n  Wobble(field: Int)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\n/**\n * Wibbling!!\n */\nexport class Wibble extends $CustomType {\n  constructor(field) {\n    super();\n    this.field = field;\n  }\n}\nexport const Wibble$Wibble = (field) => new Wibble(field);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$field = (value) => value.field;\nexport const Wibble$Wibble$0 = (value) => value.field;\n\n/**\n * Wobbling!!\n */\nexport class Wobble extends $CustomType {\n  constructor(field) {\n    super();\n    this.field = field;\n  }\n}\nexport const Wibble$Wobble = (field) => new Wobble(field);\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\nexport const Wibble$Wobble$field = (value) => value.field;\nexport const Wibble$Wobble$0 = (value) => value.field;\n\nexport const Wibble$field = (value) => value.field;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__custom_type_with_named_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Cat {\\n  Cat(name: String, cuteness: Int)\\n}\\n\\npub type Box {\\n  Box(occupant: Cat)\\n}\\n\\npub const felix = Cat(\\\"Felix\\\", 12)\\npub const tom = Cat(cuteness: 1, name: \\\"Tom\\\")\\n\\npub fn go() {\\n  Cat(\\\"Nubi\\\", 1)\\n  Cat(2, name: \\\"Nubi\\\")\\n  Cat(cuteness: 3, name: \\\"Nubi\\\")\\n}\\n\\npub fn update(cat) {\\n  Cat(..cat, name: \\\"Sid\\\")\\n  Cat(..cat, name: \\\"Bartholemew Wonder Puss the Fourth !!!!!!!!!!!!!!!!\\\")\\n  Cat(..new_cat(), name: \\\"Molly\\\")\\n  let box = Box(occupant: cat)\\n  Cat(..box.occupant, cuteness: box.occupant.cuteness + 1)\\n}\\n\\npub fn access(cat: Cat) {\\n  cat.cuteness\\n}\\n\\npub fn new_cat() {\\n  Cat(name: \\\"Beau\\\", cuteness: 11)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Cat {\n  Cat(name: String, cuteness: Int)\n}\n\npub type Box {\n  Box(occupant: Cat)\n}\n\npub const felix = Cat(\"Felix\", 12)\npub const tom = Cat(cuteness: 1, name: \"Tom\")\n\npub fn go() {\n  Cat(\"Nubi\", 1)\n  Cat(2, name: \"Nubi\")\n  Cat(cuteness: 3, name: \"Nubi\")\n}\n\npub fn update(cat) {\n  Cat(..cat, name: \"Sid\")\n  Cat(..cat, name: \"Bartholemew Wonder Puss the Fourth !!!!!!!!!!!!!!!!\")\n  Cat(..new_cat(), name: \"Molly\")\n  let box = Box(occupant: cat)\n  Cat(..box.occupant, cuteness: box.occupant.cuteness + 1)\n}\n\npub fn access(cat: Cat) {\n  cat.cuteness\n}\n\npub fn new_cat() {\n  Cat(name: \"Beau\", cuteness: 11)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Cat extends $CustomType {\n  constructor(name, cuteness) {\n    super();\n    this.name = name;\n    this.cuteness = cuteness;\n  }\n}\nexport const Cat$Cat = (name, cuteness) => new Cat(name, cuteness);\nexport const Cat$isCat = (value) => value instanceof Cat;\nexport const Cat$Cat$name = (value) => value.name;\nexport const Cat$Cat$0 = (value) => value.name;\nexport const Cat$Cat$cuteness = (value) => value.cuteness;\nexport const Cat$Cat$1 = (value) => value.cuteness;\n\nexport class Box extends $CustomType {\n  constructor(occupant) {\n    super();\n    this.occupant = occupant;\n  }\n}\nexport const Box$Box = (occupant) => new Box(occupant);\nexport const Box$isBox = (value) => value instanceof Box;\nexport const Box$Box$occupant = (value) => value.occupant;\nexport const Box$Box$0 = (value) => value.occupant;\n\nexport const felix = /* @__PURE__ */ new Cat(\"Felix\", 12);\n\nexport const tom = /* @__PURE__ */ new Cat(\"Tom\", 1);\n\nexport function go() {\n  new Cat(\"Nubi\", 1);\n  new Cat(\"Nubi\", 2);\n  return new Cat(\"Nubi\", 3);\n}\n\nexport function access(cat) {\n  return cat.cuteness;\n}\n\nexport function new_cat() {\n  return new Cat(\"Beau\", 11);\n}\n\nexport function update(cat) {\n  new Cat(\"Sid\", cat.cuteness)\n  new Cat(\"Bartholemew Wonder Puss the Fourth !!!!!!!!!!!!!!!!\", cat.cuteness)\n  let _record = new_cat();\n  new Cat(\"Molly\", _record.cuteness)\n  let box = new Box(cat);\n  let _record$1 = box.occupant;\n  return new Cat(_record$1.name, box.occupant.cuteness + 1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__destructure_custom_type_with_mixed_fields_first_unlabelled.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Cat {\\n  Cat(String, cuteness: Int)\\n}\\n\\npub fn go(cat) {\\n  let Cat(x, y) = cat\\n  let Cat(cuteness: y, ..) = cat\\n  let Cat(x, cuteness: y) = cat\\n  x\\n}\\n\\n\"\n---\n----- SOURCE CODE\n\npub type Cat {\n  Cat(String, cuteness: Int)\n}\n\npub fn go(cat) {\n  let Cat(x, y) = cat\n  let Cat(cuteness: y, ..) = cat\n  let Cat(x, cuteness: y) = cat\n  x\n}\n\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Cat extends $CustomType {\n  constructor($0, cuteness) {\n    super();\n    this[0] = $0;\n    this.cuteness = cuteness;\n  }\n}\nexport const Cat$Cat = ($0, cuteness) => new Cat($0, cuteness);\nexport const Cat$isCat = (value) => value instanceof Cat;\nexport const Cat$Cat$0 = (value) => value[0];\nexport const Cat$Cat$cuteness = (value) => value.cuteness;\nexport const Cat$Cat$1 = (value) => value.cuteness;\n\nexport function go(cat) {\n  let x;\n  let y;\n  x = cat[0];\n  y = cat.cuteness;\n  let y$1;\n  y$1 = cat.cuteness;\n  let x$1;\n  let y$2;\n  x$1 = cat[0];\n  y$2 = cat.cuteness;\n  return x$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__destructure_custom_type_with_named_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Cat {\\n  Cat(name: String, cuteness: Int)\\n}\\n\\npub fn go(cat) {\\n  let Cat(x, y) = cat\\n  let Cat(name: x, ..) = cat\\n  let assert Cat(cuteness: 4, name: x) = cat\\n  x\\n}\\n\\n\"\n---\n----- SOURCE CODE\n\npub type Cat {\n  Cat(name: String, cuteness: Int)\n}\n\npub fn go(cat) {\n  let Cat(x, y) = cat\n  let Cat(name: x, ..) = cat\n  let assert Cat(cuteness: 4, name: x) = cat\n  x\n}\n\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport class Cat extends $CustomType {\n  constructor(name, cuteness) {\n    super();\n    this.name = name;\n    this.cuteness = cuteness;\n  }\n}\nexport const Cat$Cat = (name, cuteness) => new Cat(name, cuteness);\nexport const Cat$isCat = (value) => value instanceof Cat;\nexport const Cat$Cat$name = (value) => value.name;\nexport const Cat$Cat$0 = (value) => value.name;\nexport const Cat$Cat$cuteness = (value) => value.cuteness;\nexport const Cat$Cat$1 = (value) => value.cuteness;\n\nexport function go(cat) {\n  let x;\n  let y;\n  x = cat.name;\n  y = cat.cuteness;\n  let x$1;\n  x$1 = cat.name;\n  let x$2;\n  let $ = cat.cuteness;\n  if ($ === 4) {\n    x$2 = cat.name;\n  } else {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      9,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: cat, start: 124, end: 166, pattern_start: 135, pattern_end: 160 }\n    )\n  }\n  return x$2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__equality_with_non_singleton_variant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Thing {\\n  Variant\\n  Other(String)\\n}\\n\\npub fn check_other(x: Thing) -> Bool {\\n  x == Other(\\\"hello\\\")\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Variant\n  Other(String)\n}\n\npub fn check_other(x: Thing) -> Bool {\n  x == Other(\"hello\")\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, isEqual } from \"../gleam.mjs\";\n\nexport class Variant extends $CustomType {}\nexport const Thing$Variant = () => new Variant();\nexport const Thing$isVariant = (value) => value instanceof Variant;\n\nexport class Other extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Thing$Other = ($0) => new Other($0);\nexport const Thing$isOther = (value) => value instanceof Other;\nexport const Thing$Other$0 = (value) => value[0];\n\nexport function check_other(x) {\n  return isEqual(x, new Other(\"hello\"));\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__external_annotated_type_used_in_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\n@external(javascript, \\\"./gleam_stdlib.d.ts\\\", \\\"Dict\\\")\\npub type Dict(key, value)\\n\\n@external(javascript, \\\"./gleam_stdlib.mjs\\\", \\\"get\\\")\\npub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./gleam_stdlib.d.ts\", \"Dict\")\npub type Dict(key, value)\n\n@external(javascript, \"./gleam_stdlib.mjs\", \"get\")\npub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\nimport type { Dict as Dict$ } from \"./gleam_stdlib.d.ts\";\n\nexport type { Dict$ };\n\nexport function get<K, L>(dict: Dict$<K, L>, key: K): _.Result<L, undefined>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__external_annotation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\n@external(javascript, \\\"./gleam_stdlib.d.ts\\\", \\\"Dict\\\")\\npub type Dict(key, value)\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./gleam_stdlib.d.ts\", \"Dict\")\npub type Dict(key, value)\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type { Dict as Dict$ } from \"./gleam_stdlib.d.ts\";\n\nexport type { Dict$ };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__generic_type_parameter_used_in_field.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 983\nexpression: \"\\npub type Wibble(value, error) {\\n  Wibble(\\n    wibble: value,\\n    wobble: Result(value, error),\\n    wubble: error,\\n  )\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Wibble(value, error) {\n  Wibble(\n    wibble: value,\n    wobble: Result(value, error),\n    wubble: error,\n  )\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class Wibble<I, J> extends _.CustomType {\n  /** @deprecated */\n  constructor(wibble: I, wobble: _.Result<I, J>, wubble: J);\n  /** @deprecated */\n  wibble: I;\n  /** @deprecated */\n  wobble: _.Result<I, J>;\n  /** @deprecated */\n  wubble: J;\n}\nexport function Wibble$Wibble<I, J>(\n  wibble: I,\n  wobble: _.Result<I, J>,\n  wubble: J,\n): Wibble$<I, J>;\nexport function Wibble$isWibble<I, J>(\n  value: any,\n): value is Wibble$<unknown, unknown>;\nexport function Wibble$Wibble$0<I, J>(value: Wibble$<I, J>): I;\nexport function Wibble$Wibble$wibble<I, J>(value: Wibble$<I, J>): I;\nexport function Wibble$Wibble$1<I, J>(value: Wibble$<I, J>): _.Result<I, J>;\nexport function Wibble$Wibble$wobble<I, J>(value: Wibble$<I, J>): _.Result<I, J>;\nexport function Wibble$Wibble$2<I, J>(\n  value: Wibble$<I, J>,\n): J;\nexport function Wibble$Wibble$wubble<I, J>(value: Wibble$<I, J>): J;\n\nexport type Wibble$<I, J> = Wibble<I, J>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__guard_equality_with_non_singleton_variant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Thing {\\n  Variant\\n  Other(String)\\n}\\n\\npub fn process(e: Thing) -> String {\\n  case e {\\n    value if value == Other(\\\"hello\\\") -> \\\"match\\\"\\n    _ -> \\\"no match\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Variant\n  Other(String)\n}\n\npub fn process(e: Thing) -> String {\n  case e {\n    value if value == Other(\"hello\") -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, isEqual } from \"../gleam.mjs\";\n\nexport class Variant extends $CustomType {}\nexport const Thing$Variant = () => new Variant();\nexport const Thing$isVariant = (value) => value instanceof Variant;\n\nexport class Other extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Thing$Other = ($0) => new Other($0);\nexport const Thing$isOther = (value) => value instanceof Other;\nexport const Thing$Other$0 = (value) => value[0];\n\nexport function process(e) {\n  let value = e;\n  if (isEqual(value, new Other(\"hello\"))) {\n    return \"match\";\n  } else {\n    return \"no match\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__imported_ignoring_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two(1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other\npub fn main() {\n  other.Two(1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return new $other.Two(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__imported_multiple_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two(b: 2, c: 3, a: 1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other\npub fn main() {\n  other.Two(b: 2, c: 3, a: 1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return new $other.Two(1, 2, 3);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__imported_no_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two(1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(Int) }\n\n-- main.gleam\nimport other\npub fn main() {\n  other.Two(1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return new $other.Two(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__imported_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\n\\npub fn main(x) {\\n  case x {\\n    Two(a: 1, ..) -> 1\\n    other.Two(b: 2, c: c, ..) -> c\\n    _ -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other.{Two}\n\npub fn main(x) {\n  case x {\n    Two(a: 1, ..) -> 1\n    other.Two(b: 2, c: c, ..) -> c\n    _ -> 3\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main(x) {\n  let $ = x.a;\n  if ($ === 1) {\n    return 1;\n  } else {\n    let $1 = x.b;\n    if ($1 === 2) {\n      let c = x.c;\n      return c;\n    } else {\n      return 3;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__imported_using_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two(field: 1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other\npub fn main() {\n  other.Two(field: 1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return new $other.Two(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__keyword_label_name.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"pub type Thing {\\n  Thing(in: Int, class: Nil)\\n}\\n\"\n---\n----- SOURCE CODE\npub type Thing {\n  Thing(in: Int, class: Nil)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Thing extends $CustomType {\n  constructor(in$, class$) {\n    super();\n    this.in = in$;\n    this.class = class$;\n  }\n}\nexport const Thing$Thing = (in$, class$) => new Thing(in$, class$);\nexport const Thing$isThing = (value) => value instanceof Thing;\nexport const Thing$Thing$in = (value) => value.in;\nexport const Thing$Thing$0 = (value) => value.in;\nexport const Thing$Thing$class = (value) => value.class;\nexport const Thing$Thing$1 = (value) => value.class;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__long_name_variant_mixed_labels_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 209\nexpression: \"\\npub type TypeWithALongNameAndSeveralArguments{\\n  TypeWithALongNameAndSeveralArguments(String, String, String, a: String, b: String)\\n}\\n\\npub const local = TypeWithALongNameAndSeveralArguments(\\\"one\\\", \\\"two\\\", \\\"three\\\", \\\"four\\\", \\\"five\\\")\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type TypeWithALongNameAndSeveralArguments{\n  TypeWithALongNameAndSeveralArguments(String, String, String, a: String, b: String)\n}\n\npub const local = TypeWithALongNameAndSeveralArguments(\"one\", \"two\", \"three\", \"four\", \"five\")\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class TypeWithALongNameAndSeveralArguments extends _.CustomType {\n  /** @deprecated */\n  constructor(\n    argument$0: string,\n    argument$1: string,\n    argument$2: string,\n    a: string,\n    b: string\n  );\n  /** @deprecated */\n  0: string;\n  /** @deprecated */\n  1: string;\n  /** @deprecated */\n  2: string;\n  /** @deprecated */\n  a: string;\n  /** @deprecated */\n  b: string;\n}\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments(\n  $0: string,\n  $1: string,\n  $2: string,\n  a: string,\n  b: string,\n): TypeWithALongNameAndSeveralArguments$;\nexport function TypeWithALongNameAndSeveralArguments$isTypeWithALongNameAndSeveralArguments(\n  value: any,\n): value is TypeWithALongNameAndSeveralArguments$;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$0(value: TypeWithALongNameAndSeveralArguments$): string;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$1(\n  value: TypeWithALongNameAndSeveralArguments$,\n): string;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$2(value: TypeWithALongNameAndSeveralArguments$): string;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$3(\n  value: TypeWithALongNameAndSeveralArguments$,\n): string;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$a(value: TypeWithALongNameAndSeveralArguments$): string;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$4(\n  value: TypeWithALongNameAndSeveralArguments$,\n): string;\nexport function TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$b(value: TypeWithALongNameAndSeveralArguments$): string;\n\nexport type TypeWithALongNameAndSeveralArguments$ = TypeWithALongNameAndSeveralArguments;\n\nexport const local: TypeWithALongNameAndSeveralArguments$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__long_name_variant_without_labels.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type TypeWithALongNameAndSeveralArguments{\\n  TypeWithALongNameAndSeveralArguments(String, String, String, String, String)\\n}\\n\\n\\npub fn go() {\\n  TypeWithALongNameAndSeveralArguments\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type TypeWithALongNameAndSeveralArguments{\n  TypeWithALongNameAndSeveralArguments(String, String, String, String, String)\n}\n\n\npub fn go() {\n  TypeWithALongNameAndSeveralArguments\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class TypeWithALongNameAndSeveralArguments extends $CustomType {\n  constructor($0, $1, $2, $3, $4) {\n    super();\n    this[0] = $0;\n    this[1] = $1;\n    this[2] = $2;\n    this[3] = $3;\n    this[4] = $4;\n  }\n}\nexport const TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments = ($0, $1, $2, $3, $4) =>\n  new TypeWithALongNameAndSeveralArguments($0, $1, $2, $3, $4);\nexport const TypeWithALongNameAndSeveralArguments$isTypeWithALongNameAndSeveralArguments = (value) =>\n  value instanceof TypeWithALongNameAndSeveralArguments;\nexport const TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$0 = (value) =>\n  value[0];\nexport const TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$1 = (value) =>\n  value[1];\nexport const TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$2 = (value) =>\n  value[2];\nexport const TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$3 = (value) =>\n  value[3];\nexport const TypeWithALongNameAndSeveralArguments$TypeWithALongNameAndSeveralArguments$4 = (value) =>\n  value[4];\n\nexport function go() {\n  return (var0, var1, var2, var3, var4) => {\n    return new TypeWithALongNameAndSeveralArguments(\n      var0,\n      var1,\n      var2,\n      var3,\n      var4,\n    );\n  };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__mixed_singleton_and_non_singleton.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Result {\\n  Ok(value: Int)\\n  Error\\n}\\n\\npub fn is_error(r: Result) -> Bool {\\n  r == Error\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Result {\n  Ok(value: Int)\n  Error\n}\n\npub fn is_error(r: Result) -> Bool {\n  r == Error\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {\n  constructor(value) {\n    super();\n    this.value = value;\n  }\n}\nexport const Result$Ok = (value) => new Ok(value);\nexport const Result$isOk = (value) => value instanceof Ok;\nexport const Result$Ok$value = (value) => value.value;\nexport const Result$Ok$0 = (value) => value.value;\n\nexport class Error extends $CustomType {}\nexport const Result$Error = () => new Error();\nexport const Result$isError = (value) => value instanceof Error;\n\nexport function is_error(r) {\n  return r instanceof Error;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__multiple_singleton_constructors.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Status {\\n  Loading\\n  Success\\n  Error\\n}\\n\\npub fn is_loading(s: Status) -> Bool {\\n  s == Loading\\n}\\n\\npub fn is_success(s: Status) -> Bool {\\n  s == Success\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Status {\n  Loading\n  Success\n  Error\n}\n\npub fn is_loading(s: Status) -> Bool {\n  s == Loading\n}\n\npub fn is_success(s: Status) -> Bool {\n  s == Success\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Loading extends $CustomType {}\nexport const Status$Loading = () => new Loading();\nexport const Status$isLoading = (value) => value instanceof Loading;\n\nexport class Success extends $CustomType {}\nexport const Status$Success = () => new Success();\nexport const Status$isSuccess = (value) => value instanceof Success;\n\nexport class Error extends $CustomType {}\nexport const Status$Error = () => new Error();\nexport const Status$isError = (value) => value instanceof Error;\n\nexport function is_loading(s) {\n  return s instanceof Loading;\n}\n\nexport function is_success(s) {\n  return s instanceof Success;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__nested_pattern_with_labels.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"pub type Box(x) { Box(a: Int, b: x) }\\npub fn go(x) {\\n  case x {\\n    Box(a: _, b: Box(a: a, b: b)) -> a + b\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub type Box(x) { Box(a: Int, b: x) }\npub fn go(x) {\n  case x {\n    Box(a: _, b: Box(a: a, b: b)) -> a + b\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Box extends $CustomType {\n  constructor(a, b) {\n    super();\n    this.a = a;\n    this.b = b;\n  }\n}\nexport const Box$Box = (a, b) => new Box(a, b);\nexport const Box$isBox = (value) => value instanceof Box;\nexport const Box$Box$a = (value) => value.a;\nexport const Box$Box$0 = (value) => value.a;\nexport const Box$Box$b = (value) => value.b;\nexport const Box$Box$1 = (value) => value.b;\n\nexport function go(x) {\n  let a = x.b.a;\n  let b = x.b.b;\n  return a + b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__new_type_import_syntax.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport a.{type A, A}\\n\\npub fn main() {\\n  A\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport a.{type A, A}\n\npub fn main() {\n  A\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $a from \"../../package/a.mjs\";\nimport { A } from \"../../package/a.mjs\";\n\nexport function main() {\n  return new A();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__non_singleton_record_equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Person {\\n  Person(name: String, age: Int)\\n}\\n\\npub fn same_person(p1: Person, p2: Person) -> Bool {\\n  p1 == p2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Person {\n  Person(name: String, age: Int)\n}\n\npub fn same_person(p1: Person, p2: Person) -> Bool {\n  p1 == p2\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType, isEqual } from \"../gleam.mjs\";\n\nexport class Person extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Person = (name, age) => new Person(name, age);\nexport const Person$isPerson = (value) => value instanceof Person;\nexport const Person$Person$name = (value) => value.name;\nexport const Person$Person$0 = (value) => value.name;\nexport const Person$Person$age = (value) => value.age;\nexport const Person$Person$1 = (value) => value.age;\n\nexport function same_person(p1, p2) {\n  return isEqual(p1, p2);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__opaque_types_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 567\nexpression: \"pub opaque type Animal {\\n  Cat(goes_outside: Bool)\\n  Dog(plays_fetch: Bool)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub opaque type Animal {\n  Cat(goes_outside: Bool)\n  Dog(plays_fetch: Bool)\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\ndeclare class Cat extends _.CustomType {\n  /** @deprecated */\n  constructor(goes_outside: boolean);\n  /** @deprecated */\n  goes_outside: boolean;\n}\n\ndeclare class Dog extends _.CustomType {\n  /** @deprecated */\n  constructor(plays_fetch: boolean);\n  /** @deprecated */\n  plays_fetch: boolean;\n}\n\nexport type Animal$ = Cat | Dog;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__qualified.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\n\\npub fn main() {\\n  other.One\\n}\\n\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { One }\n\n-- main.gleam\nimport other\n\npub fn main() {\n  other.One\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return new $other.One();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_access_in_guard_with_reserved_field_name.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Thing {\\n  Thing(constructor: Nil)\\n}\\n\\npub fn main() {\\n  let a = Thing(constructor: Nil)\\n  case Nil {\\n      Nil if a.constructor == Nil -> a.constructor\\n      _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(constructor: Nil)\n}\n\npub fn main() {\n  let a = Thing(constructor: Nil)\n  case Nil {\n      Nil if a.constructor == Nil -> a.constructor\n      _ -> Nil\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Thing extends $CustomType {\n  constructor(constructor) {\n    super();\n    this.constructor$ = constructor;\n  }\n}\nexport const Thing$Thing = (constructor) => new Thing(constructor);\nexport const Thing$isThing = (value) => value instanceof Thing;\nexport const Thing$Thing$constructor = (value) => value.constructor$;\nexport const Thing$Thing$0 = (value) => value.constructor$;\n\nexport function main() {\n  let a = new Thing(undefined);\n  let $ = undefined;\n  if (a.constructor$ === undefined) {\n    return a.constructor$;\n  } else {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_access_in_pattern_with_reserved_field_name.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Thing {\\n  Thing(constructor: Nil)\\n}\\n\\npub fn main() {\\n  let a = Thing(constructor: Nil)\\n  let Thing(constructor: ctor) = a\\n  case a {\\n      a if a.constructor == ctor -> Nil\\n      Thing(constructor:) if ctor == constructor -> Nil\\n      _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(constructor: Nil)\n}\n\npub fn main() {\n  let a = Thing(constructor: Nil)\n  let Thing(constructor: ctor) = a\n  case a {\n      a if a.constructor == ctor -> Nil\n      Thing(constructor:) if ctor == constructor -> Nil\n      _ -> Nil\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Thing extends $CustomType {\n  constructor(constructor) {\n    super();\n    this.constructor$ = constructor;\n  }\n}\nexport const Thing$Thing = (constructor) => new Thing(constructor);\nexport const Thing$isThing = (value) => value instanceof Thing;\nexport const Thing$Thing$constructor = (value) => value.constructor$;\nexport const Thing$Thing$0 = (value) => value.constructor$;\n\nexport function main() {\n  let a = new Thing(undefined);\n  let ctor;\n  ctor = a.constructor$;\n  let a$1 = a;\n  if (a$1.constructor$ === ctor) {\n    return undefined;\n  } else {\n    let constructor = a.constructor$;\n    if (ctor === constructor) {\n      return undefined;\n    } else {\n      return undefined;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_with_field_named_constructor.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Thing {\\n  Thing(constructor: Nil)\\n}\\n\\npub fn main() {\\n  let a = Thing(constructor: Nil)\\n  let b = Thing(..a, constructor: Nil)\\n  b.constructor\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(constructor: Nil)\n}\n\npub fn main() {\n  let a = Thing(constructor: Nil)\n  let b = Thing(..a, constructor: Nil)\n  b.constructor\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Thing extends $CustomType {\n  constructor(constructor) {\n    super();\n    this.constructor$ = constructor;\n  }\n}\nexport const Thing$Thing = (constructor) => new Thing(constructor);\nexport const Thing$isThing = (value) => value instanceof Thing;\nexport const Thing$Thing$constructor = (value) => value.constructor$;\nexport const Thing$Thing$0 = (value) => value.constructor$;\n\nexport function main() {\n  let a = new Thing(undefined);\n  let b = new Thing(undefined);\n  return b.constructor$;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_with_field_named_then.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Thing {\\n  Thing(then: Nil)\\n}\\n\\npub fn main() {\\n  let a = Thing(then: Nil)\\n  let b = Thing(..a, then: Nil)\\n  b.then\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(then: Nil)\n}\n\npub fn main() {\n  let a = Thing(then: Nil)\n  let b = Thing(..a, then: Nil)\n  b.then\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Thing extends $CustomType {\n  constructor(then$) {\n    super();\n    this.then$ = then$;\n  }\n}\nexport const Thing$Thing = (then$) => new Thing(then$);\nexport const Thing$isThing = (value) => value instanceof Thing;\nexport const Thing$Thing$then = (value) => value.then$;\nexport const Thing$Thing$0 = (value) => value.then$;\n\nexport function main() {\n  let a = new Thing(undefined);\n  let b = new Thing(undefined);\n  return b.then$;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__singleton_in_case_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type State {\\n  Active\\n  Inactive\\n}\\n\\npub fn process(s: State) -> String {\\n  case s {\\n    state if state == Active -> \\\"active\\\"\\n    _ -> \\\"inactive\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type State {\n  Active\n  Inactive\n}\n\npub fn process(s: State) -> String {\n  case s {\n    state if state == Active -> \"active\"\n    _ -> \"inactive\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Active extends $CustomType {}\nexport const State$Active = () => new Active();\nexport const State$isActive = (value) => value instanceof Active;\n\nexport class Inactive extends $CustomType {}\nexport const State$Inactive = () => new Inactive();\nexport const State$isInactive = (value) => value instanceof Inactive;\n\nexport function process(s) {\n  let state = s;\n  if (state instanceof Active) {\n    return \"active\";\n  } else {\n    return \"inactive\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__singleton_record_equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\npub fn is_wibble(w: Wibble) -> Bool {\\n  w == Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn is_wibble(w: Wibble) -> Bool {\n  w == Wibble\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {}\nexport const Wibble$Wibble = () => new Wibble();\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\n\nexport class Wobble extends $CustomType {}\nexport const Wibble$Wobble = () => new Wobble();\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\n\nexport function is_wibble(w) {\n  return w instanceof Wibble;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__singleton_record_inequality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\npub fn is_not_wibble(w: Wibble) -> Bool {\\n  w != Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn is_not_wibble(w: Wibble) -> Bool {\n  w != Wibble\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {}\nexport const Wibble$Wibble = () => new Wibble();\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\n\nexport class Wobble extends $CustomType {}\nexport const Wibble$Wobble = () => new Wobble();\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\n\nexport function is_not_wibble(w) {\n  return !(w instanceof Wibble);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__singleton_record_reverse_order.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\npub fn is_wibble_reverse(w: Wibble) -> Bool {\\n  Wibble == w\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn is_wibble_reverse(w: Wibble) -> Bool {\n  Wibble == w\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {}\nexport const Wibble$Wibble = () => new Wibble();\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\n\nexport class Wobble extends $CustomType {}\nexport const Wibble$Wobble = () => new Wobble();\nexport const Wibble$isWobble = (value) => value instanceof Wobble;\n\nexport function is_wibble_reverse(w) {\n  return w instanceof Wibble;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__types_must_be_rendered_before_functions.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub fn one() { One }\\npub type One { One }\\n\"\n---\n----- SOURCE CODE\n\npub fn one() { One }\npub type One { One }\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class One extends $CustomType {}\nexport const One$One = () => new One();\nexport const One$isOne = (value) => value instanceof One;\n\nexport function one() {\n  return new One();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unapplied_record_constructors_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 555\nexpression: \"pub type Cat { Cat(name: String) }\\n\\npub fn return_unapplied_cat() {\\n  Cat\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub type Cat { Cat(name: String) }\n\npub fn return_unapplied_cat() {\n  Cat\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class Cat extends _.CustomType {\n  /** @deprecated */\n  constructor(name: string);\n  /** @deprecated */\n  name: string;\n}\nexport function Cat$Cat(name: string): Cat$;\nexport function Cat$isCat(value: any): value is Cat$;\nexport function Cat$Cat$0(value: Cat$): string;\nexport function Cat$Cat$name(value: Cat$): string;\n\nexport type Cat$ = Cat;\n\nexport function return_unapplied_cat(): (x0: string) => Cat$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unnamed_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Ip {\\n    Ip(String)\\n}\\n\\npub const local = Ip(\\\"0.0.0.0\\\")\\n\\npub fn build(x) {\\n    x(\\\"1.2.3.4\\\")\\n}\\n\\npub fn go() {\\n    build(Ip)\\n    Ip(\\\"5.6.7.8\\\")\\n}\\n\\npub fn destructure(x) {\\n  let Ip(raw) = x\\n  raw\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Ip {\n    Ip(String)\n}\n\npub const local = Ip(\"0.0.0.0\")\n\npub fn build(x) {\n    x(\"1.2.3.4\")\n}\n\npub fn go() {\n    build(Ip)\n    Ip(\"5.6.7.8\")\n}\n\npub fn destructure(x) {\n  let Ip(raw) = x\n  raw\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ip extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Ip$Ip = ($0) => new Ip($0);\nexport const Ip$isIp = (value) => value instanceof Ip;\nexport const Ip$Ip$0 = (value) => value[0];\n\nexport const local = /* @__PURE__ */ new Ip(\"0.0.0.0\");\n\nexport function build(x) {\n  return x(\"1.2.3.4\");\n}\n\nexport function go() {\n  build((var0) => { return new Ip(var0); });\n  return new Ip(\"5.6.7.8\");\n}\n\nexport function destructure(x) {\n  let raw;\n  raw = x[0];\n  return raw;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unnamed_fields_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nassertion_line: 179\nexpression: \"\\npub type Ip{\\n    Ip(String)\\n}\\n\\npub const local = Ip(\\\"0.0.0.0\\\")\\n\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Ip{\n    Ip(String)\n}\n\npub const local = Ip(\"0.0.0.0\")\n\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class Ip extends _.CustomType {\n  /** @deprecated */\n  constructor(argument$0: string);\n  /** @deprecated */\n  0: string;\n}\nexport function Ip$Ip($0: string): Ip$;\nexport function Ip$isIp(value: any): value is Ip$;\nexport function Ip$Ip$0(value: Ip$): string;\n\nexport type Ip$ = Ip;\n\nexport const local: Ip$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unqualified_constructor_as_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other.{Two}\npub fn main() {\n  Two\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main() {\n  return (var0, var1, var2) => { return new Two(var0, var1, var2); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unqualified_imported_ignoring_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two(1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other.{Two}\npub fn main() {\n  Two(1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main() {\n  return new Two(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unqualified_imported_multiple_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two(b: 2, c: 3, a: 1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(a: Int, b: Int, c: Int) }\n\n-- main.gleam\nimport other.{Two}\npub fn main() {\n  Two(b: 2, c: 3, a: 1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main() {\n  return new Two(1, 2, 3);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unqualified_imported_no_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two(1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(Int) }\n\n-- main.gleam\nimport other.{Two}\npub fn main() {\n  Two(1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main() {\n  return new Two(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unqualified_imported_no_label_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two(1)\\n}\"\n---\n----- SOURCE CODE\nimport other.{Two}\npub fn main() {\n  Two(1)\n}\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as $other from \"../other.d.mts\";\n\nexport function main(): $other.One$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unqualified_imported_using_label.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two(field: 1)\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two(field: Int) }\n\n-- main.gleam\nimport other.{Two}\npub fn main() {\n  Two(field: 1)\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main() {\n  return new Two(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__unused_opaque_constructor_is_generated_correctly.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\ntype Wibble {\\n  Wibble\\n}\\n\\npub opaque type Wobble {\\n  Wobble(Wibble)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble\n}\n\npub opaque type Wobble {\n  Wobble(Wibble)\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\ndeclare class Wibble extends _.CustomType {}\n\ntype Wibble$ = Wibble;\n\ndeclare class Wobble extends _.CustomType {\n  /** @deprecated */\n  constructor(argument$0: Wibble$);\n  /** @deprecated */\n  0: Wibble$;\n}\n\nexport type Wobble$ = Wobble;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__variant_defined_in_another_module_aliased_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport other_module.{Variant as Aliased}\\n\\npub fn process(e) -> String {\\n  case e {\\n    value if value == Aliased -> \\\"match\\\"\\n    _ -> \\\"no match\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- other_module.gleam\npub type Thingy { Variant Other(Int) }\n\n-- main.gleam\n\nimport other_module.{Variant as Aliased}\n\npub fn process(e) -> String {\n  case e {\n    value if value == Aliased -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../other_module.mjs\";\nimport { Variant as Aliased } from \"../other_module.mjs\";\n\nexport function process(e) {\n  let value = e;\n  if (value instanceof Aliased) {\n    return \"match\";\n  } else {\n    return \"no match\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__variant_defined_in_another_module_aliased_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport other_module.{Variant as Aliased}\\n\\npub fn check(x) -> Bool {\\n  x == Aliased\\n}\\n\"\n---\n----- SOURCE CODE\n-- other_module.gleam\npub type Thingy { Variant Other(Int) }\n\n-- main.gleam\n\nimport other_module.{Variant as Aliased}\n\npub fn check(x) -> Bool {\n  x == Aliased\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../other_module.mjs\";\nimport { Variant as Aliased } from \"../other_module.mjs\";\n\nexport function check(x) {\n  return x instanceof Variant;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__variant_defined_in_another_module_qualified_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport other_module\\n\\npub fn process(e) -> String {\\n  case e {\\n    value if value == other_module.Variant -> \\\"match\\\"\\n    _ -> \\\"no match\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- other_module.gleam\npub type Thingy { Variant Other(Int) }\n\n-- main.gleam\n\nimport other_module\n\npub fn process(e) -> String {\n  case e {\n    value if value == other_module.Variant -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../other_module.mjs\";\n\nexport function process(e) {\n  let value = e;\n  if (value instanceof $other_module.Variant) {\n    return \"match\";\n  } else {\n    return \"no match\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__variant_defined_in_another_module_qualified_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport other_module\\n\\npub fn check(x) -> Bool {\\n  x == other_module.Variant\\n}\\n\"\n---\n----- SOURCE CODE\n-- other_module.gleam\npub type Thingy { Variant OtherVariant }\n\n-- main.gleam\n\nimport other_module\n\npub fn check(x) -> Bool {\n  x == other_module.Variant\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../other_module.mjs\";\n\nexport function check(x) {\n  return x instanceof $other_module.Variant;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__variant_defined_in_another_module_unqualified_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport other_module.{Variant}\\n\\npub fn process(e) -> String {\\n  case e {\\n    value if value == Variant -> \\\"match\\\"\\n    _ -> \\\"no match\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- other_module.gleam\npub type Thingy { Variant Other(Int) }\n\n-- main.gleam\n\nimport other_module.{Variant}\n\npub fn process(e) -> String {\n  case e {\n    value if value == Variant -> \"match\"\n    _ -> \"no match\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../other_module.mjs\";\nimport { Variant } from \"../other_module.mjs\";\n\nexport function process(e) {\n  let value = e;\n  if (value instanceof Variant) {\n    return \"match\";\n  } else {\n    return \"no match\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__variant_defined_in_another_module_unqualified_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\nimport other_module.{Variant}\\n\\npub fn check(x) -> Bool {\\n  x == Variant\\n}\\n\"\n---\n----- SOURCE CODE\n-- other_module.gleam\npub type Thingy { Variant Other(Int) }\n\n-- main.gleam\n\nimport other_module.{Variant}\n\npub fn check(x) -> Bool {\n  x == Variant\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $other_module from \"../other_module.mjs\";\nimport { Variant } from \"../other_module.mjs\";\n\nexport function check(x) {\n  return x instanceof Variant;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Mine {\\n    This\\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\\n}\\n\\npub const this = This\\npub const that = ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\\n\"\n---\n----- SOURCE CODE\n\npub type Mine {\n    This\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n}\n\npub const this = This\npub const that = ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class This extends $CustomType {}\nexport const Mine$This = () => new This();\nexport const Mine$isThis = (value) => value instanceof This;\n\nexport class ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant extends $CustomType {}\nexport const Mine$ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant = () =>\n  new ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant();\nexport const Mine$isThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant = (value) =>\n  value instanceof ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant;\n\nexport const this$ = /* @__PURE__ */ new This();\n\nexport const that = /* @__PURE__ */ new ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant();\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_imported.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two }\n\n-- main.gleam\nimport other\npub fn main() {\n  other.Two\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\n\nexport function main() {\n  return new $other.Two();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_imported_typscript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other\\npub fn main() {\\n  other.Two\\n}\"\n---\n----- SOURCE CODE\nimport other\npub fn main() {\n  other.Two\n}\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as $other from \"../other.d.mts\";\n\nexport function main(): $other.One$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_imported_unqualified.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two }\n\n-- main.gleam\nimport other.{Two}\npub fn main() {\n  Two\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two } from \"../other.mjs\";\n\nexport function main() {\n  return new Two();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_imported_unqualified_aliased.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two as Three}\\npub fn main() {\\n  Three\\n}\"\n---\n----- SOURCE CODE\n-- other.gleam\npub type One { Two }\n\n-- main.gleam\nimport other.{Two as Three}\npub fn main() {\n  Three\n}\n\n----- COMPILED JAVASCRIPT\nimport * as $other from \"../other.mjs\";\nimport { Two as Three } from \"../other.mjs\";\n\nexport function main() {\n  return new Three();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_imported_unqualified_aliased_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two as Three}\\npub fn main() {\\n  Three\\n}\"\n---\n----- SOURCE CODE\nimport other.{Two as Three}\npub fn main() {\n  Three\n}\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as $other from \"../other.d.mts\";\n\nexport function main(): $other.One$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_imported_unqualified_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"import other.{Two}\\npub fn main() {\\n  Two\\n}\"\n---\n----- SOURCE CODE\nimport other.{Two}\npub fn main() {\n  Two\n}\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as $other from \"../other.d.mts\";\n\nexport function main(): $other.One$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__zero_arity_literal.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/custom_types.rs\nexpression: \"\\npub type Mine {\\n    This\\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\\n}\\n\\npub fn go() {\\n    This\\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Mine {\n    This\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n}\n\npub fn go() {\n    This\n    ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class This extends $CustomType {}\nexport const Mine$This = () => new This();\nexport const Mine$isThis = (value) => value instanceof This;\n\nexport class ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant extends $CustomType {}\nexport const Mine$ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant = () =>\n  new ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant();\nexport const Mine$isThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant = (value) =>\n  value instanceof ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant;\n\nexport function go() {\n  new This();\n  return new ThatOneIsAMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchMuchLongerVariant();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_evaluates_printed_value_before_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo name() as case name() {\\n    \\\"Giacomo\\\" -> \\\"hello Jak!\\\"\\n    _ -> \\\"hello!\\\"\\n  }\\n}\\n\\nfn name() { \\\"Giacomo\\\" }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo name() as case name() {\n    \"Giacomo\" -> \"hello Jak!\"\n    _ -> \"hello!\"\n  }\n}\n\nfn name() { \"Giacomo\" }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nfunction name() {\n  return \"Giacomo\";\n}\n\nexport function main() {\n  return echo(\n    name(),\n    (() => {\n      let $ = name();\n      if ($ === \"Giacomo\") {\n        return \"hello Jak!\";\n      } else {\n        return \"hello!\";\n      }\n    })(),\n    \"src/module.gleam\",\n    3,\n  );\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_in_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> echo\\n  |> wibble\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  toList,\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function wibble(n) {\n  return n;\n}\n\nexport function main() {\n  let _pipe = toList([1, 2, 3]);\n  echo(_pipe, undefined, \"src/module.gleam\", 4)\n  return wibble(_pipe);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_in_a_pipeline_with_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> echo as \\\"message!!\\\"\\n  |> wibble\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, 2, 3]\n  |> echo as \"message!!\"\n  |> wibble\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  toList,\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function wibble(n) {\n  return n;\n}\n\nexport function main() {\n  let _pipe = toList([1, 2, 3]);\n  echo(_pipe, \"message!!\", \"src/module.gleam\", 4)\n  return wibble(_pipe);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo {\\n    Nil\\n    1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo {\n    Nil\n    1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  let _block;\n  {\n    undefined;\n    _block = 1;\n  }\n  return echo(_block, undefined, \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_block_as_a_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1 as {\\n    let name = \\\"Giacomo\\\"\\n    \\\"Hello, \\\" <> name\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1 as {\n    let name = \"Giacomo\"\n    \"Hello, \" <> name\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  return echo(\n    1,\n    (() => {\n      let name = \"Giacomo\";\n      return \"Hello, \" + name;\n    })(),\n    \"src/module.gleam\",\n    3,\n  );\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_case_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo case 1 {\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo case 1 {\n    _ -> 2\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  let _block;\n  let $ = 1;\n  _block = 2;\n  return echo(_block, undefined, \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_function_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo wibble(1, 2)\\n}\\n\\nfn wibble(n: Int, m: Int) { n + m }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo wibble(1, 2)\n}\n\nfn wibble(n: Int, m: Int) { n + m }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nfunction wibble(n, m) {\n  return n + m;\n}\n\nexport function main() {\n  return echo(wibble(1, 2), undefined, \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_function_call_and_a_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo wibble(1, 2) as message()\\n}\\n\\nfn wibble(n: Int, m: Int) { n + m }\\nfn message() { \\\"Hello!\\\" }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo wibble(1, 2) as message()\n}\n\nfn wibble(n: Int, m: Int) { n + m }\nfn message() { \"Hello!\" }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nfunction wibble(n, m) {\n  return n + m;\n}\n\nfunction message() {\n  return \"Hello!\";\n}\n\nexport function main() {\n  return echo(wibble(1, 2), message(), \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_panic.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo panic\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo panic\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  makeError,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let _block;\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"main\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n  return echo(_block, undefined, \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_simple_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  return echo(1, undefined, \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_simple_expression_and_a_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1 as \\\"hello!\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1 as \"hello!\"\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  return echo(1, \"hello!\", \"src/module.gleam\", 3);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_complex_expression_as_a_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1 as case name() {\\n    \\\"Giacomo\\\" -> \\\"hello Jak!\\\"\\n    _ -> \\\"hello!\\\"\\n  }\\n}\\n\\nfn name() { \\\"Giacomo\\\" }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1 as case name() {\n    \"Giacomo\" -> \"hello Jak!\"\n    _ -> \"hello!\"\n  }\n}\n\nfn name() { \"Giacomo\" }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nfunction name() {\n  return \"Giacomo\";\n}\n\nexport function main() {\n  return echo(\n    1,\n    (() => {\n      let $ = name();\n      if ($ === \"Giacomo\") {\n        return \"hello Jak!\";\n      } else {\n        return \"hello!\";\n      }\n    })(),\n    \"src/module.gleam\",\n    3,\n  );\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__module_named_inspect.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\nimport other/inspect\\n\\npub fn main() {\\n  echo inspect.x\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport other/inspect\n\npub fn main() {\n  echo inspect.x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport * as $inspect from \"../../other/other/inspect.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  return echo($inspect.x, undefined, \"src/module.gleam\", 5);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__multiple_echos_in_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> echo\\n  |> wibble\\n  |> echo\\n  |> wibble\\n  |> echo\\n}\\n\\npub fn wibble(n) { n }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n  |> echo\n  |> wibble\n  |> echo\n}\n\npub fn wibble(n) { n }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  toList,\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function wibble(n) {\n  return n;\n}\n\nexport function main() {\n  let _pipe = toList([1, 2, 3]);\n  echo(_pipe, undefined, \"src/module.gleam\", 4)\n  let _pipe$1 = wibble(_pipe);\n  echo(_pipe$1, undefined, \"src/module.gleam\", 6)\n  let _pipe$2 = wibble(_pipe$1);\n  return echo(_pipe$2, undefined, \"src/module.gleam\", 8);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__multiple_echos_inside_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/echo.rs\nexpression: \"\\npub fn main() {\\n  echo 1\\n  echo 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo 1\n  echo 2\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function main() {\n  echo(1, undefined, \"src/module.gleam\", 3);\n  return echo(2, undefined, \"src/module.gleam\", 4);\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__at_namespace_module.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"@namespace/package\\\", \\\"inspect\\\")\\nfn show(x: anything) -> Nil\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"@namespace/package\", \"inspect\")\nfn show(x: anything) -> Nil\n\n----- COMPILED JAVASCRIPT\nimport { inspect as show } from \"@namespace/package\";\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__attribute_erlang.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nassertion_line: 141\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one_erl\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\\npub fn main() {\\n  one(1)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one_erl\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function one(x) {\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    4,\n    \"one\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n}\n\nexport function main() {\n  return one(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__attribute_javascript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"./one.mjs\\\", \\\"oneJs\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\\npub fn main() {\\n  one(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./one.mjs\", \"oneJs\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { oneJs as one } from \"./one.mjs\";\n\nexport { one };\n\nexport function main() {\n  return one(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__both_externals_no_valid_impl.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn js() -> Nil\\n\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn erl() -> Nil\\n\\npub fn should_not_be_generated() {\\n  js()\\n  erl()\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"one\", \"one\")\npub fn js() -> Nil\n\n@external(erlang, \"one\", \"one\")\npub fn erl() -> Nil\n\npub fn should_not_be_generated() {\n  js()\n  erl()\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { one as js } from \"one\";\n\nexport { js };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__discarded_names_in_external_are_passed_correctly.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"wibble\\\", \\\"wobble\\\")\\npub fn woo(_ignored: a) -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"wibble\", \"wobble\")\npub fn woo(_ignored: a) -> Nil\n\n\n----- COMPILED JAVASCRIPT\nimport { wobble as woo } from \"wibble\";\n\nexport { woo };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__duplicate_import.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"./the/module.mjs\\\", \\\"dup\\\")\\npub fn one() -> Nil\\n\\n@external(javascript, \\\"./the/module.mjs\\\", \\\"dup\\\")\\npub fn two() -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./the/module.mjs\", \"dup\")\npub fn one() -> Nil\n\n@external(javascript, \"./the/module.mjs\", \"dup\")\npub fn two() -> Nil\n\n\n----- COMPILED JAVASCRIPT\nimport { dup as one, dup as two } from \"./the/module.mjs\";\n\nexport { one, two };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__erlang_and_javascript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\n@external(javascript, \\\"./one.mjs\\\", \\\"oneJs\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\\npub fn main() {\\n  one(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\n@external(javascript, \"./one.mjs\", \"oneJs\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { oneJs as one } from \"./one.mjs\";\n\nexport { one };\n\nexport function main() {\n  return one(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__erlang_only.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\npub fn should_be_generated(x: Int) -> Int {\\n  x\\n}\\n\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\npub fn should_not_be_generated(x: Int) -> Int\\n\"\n---\n----- SOURCE CODE\n\npub fn should_be_generated(x: Int) -> Int {\n  x\n}\n\n@external(erlang, \"one\", \"one\")\npub fn should_not_be_generated(x: Int) -> Int\n\n\n----- COMPILED JAVASCRIPT\nexport function should_be_generated(x) {\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__external_fn_escaping.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"./ffi.js\\\", \\\"then\\\")\\npub fn then(a: a) -> b\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./ffi.js\", \"then\")\npub fn then(a: a) -> b\n\n----- COMPILED JAVASCRIPT\nimport { then as then$ } from \"./ffi.js\";\n\nexport { then$ };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__external_type_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"pub type Queue(a)\\n\\n@external(javascript, \\\"queue\\\", \\\"new\\\")\\npub fn new() -> Queue(a)\\n\"\n---\n----- SOURCE CODE\npub type Queue(a)\n\n@external(javascript, \"queue\", \"new\")\npub fn new() -> Queue(a)\n\n\n----- TYPESCRIPT DEFINITIONS\nexport type Queue$<I> = any;\n\nexport function new$(): Queue$<any>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__inline_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"blah\\\", \\\"(x => x)\\\")\\npub fn one(x: Int) -> Int {\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"blah\", \"(x => x)\")\npub fn one(x: Int) -> Int {\n  1\n}\n\n\n----- ERROR\nerror: Invalid JavaScript function\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub fn one(x: Int) -> Int {\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe function `one` has an external JavaScript implementation but the\nfunction name `(x => x)` is not valid.\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__module_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"utils\\\", \\\"inspect\\\")\\nfn show(x: anything) -> Nil\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"utils\", \"inspect\")\nfn show(x: anything) -> Nil\n\n----- COMPILED JAVASCRIPT\nimport { inspect as show } from \"utils\";\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__name_to_escape.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"./the/module.mjs\\\", \\\"one\\\")\\npub fn class() -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./the/module.mjs\", \"one\")\npub fn class() -> Nil\n\n\n----- COMPILED JAVASCRIPT\nimport { one as class$ } from \"./the/module.mjs\";\n\nexport { class$ };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__no_body.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"one\\\", \\\"one\\\")\\npub fn one(x: Int) -> Int\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"one\", \"one\")\npub fn one(x: Int) -> Int\n\n\n----- COMPILED JAVASCRIPT\nimport { one } from \"one\";\n\nexport { one };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__no_module.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"\\\", \\\"one\\\")\\npub fn one(x: Int) -> Int {\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"\", \"one\")\npub fn one(x: Int) -> Int {\n  1\n}\n\n\n----- ERROR\nerror: Invalid JavaScript module\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub fn one(x: Int) -> Int {\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe function `one` has an external JavaScript implementation but the module\npath `` is not valid.\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__pipe_variable_shadow.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"module\\\", \\\"string\\\")\\nfn name() -> String\\n\\npub fn main() {\\n  let name = name()\\n  name\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"module\", \"string\")\nfn name() -> String\n\npub fn main() {\n  let name = name()\n  name\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { string as name } from \"module\";\n\nexport function main() {\n  let name$1 = name();\n  return name$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__private_attribute_erlang.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nassertion_line: 190\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one_erl\\\")\\nfn one(x: Int) -> Int {\\n  todo\\n}\\n\\npub fn main() {\\n  one(1)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one_erl\")\nfn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction one(x) {\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    4,\n    \"one\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n}\n\nexport function main() {\n  return one(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__private_attribute_javascript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"./one.mjs\\\", \\\"oneJs\\\")\\nfn one(x: Int) -> Int {\\n  todo\\n}\\n\\npub fn main() {\\n  one(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./one.mjs\", \"oneJs\")\nfn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { oneJs as one } from \"./one.mjs\";\n\nexport function main() {\n  return one(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__private_erlang_and_javascript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"one\\\")\\n@external(javascript, \\\"./one.mjs\\\", \\\"oneJs\\\")\\nfn one(x: Int) -> Int {\\n  todo\\n}\\n\\npub fn main() {\\n  one(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"one\")\n@external(javascript, \"./one.mjs\", \"oneJs\")\nfn one(x: Int) -> Int {\n  todo\n}\n\npub fn main() {\n  one(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { oneJs as one } from \"./one.mjs\";\n\nexport function main() {\n  return one(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__pub_module_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"utils\\\", \\\"inspect\\\")\\npub fn show(x: anything) -> Nil\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"utils\", \"inspect\")\npub fn show(x: anything) -> Nil\n\n----- COMPILED JAVASCRIPT\nimport { inspect as show } from \"utils\";\n\nexport { show };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__pub_module_fn_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"utils\\\", \\\"inspect\\\")\\npub fn show(x: anything) -> Nil\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"utils\", \"inspect\")\npub fn show(x: anything) -> Nil\n\n----- TYPESCRIPT DEFINITIONS\nexport function show(x: any): undefined;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__same_module_multiple_imports.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"./the/module.mjs\\\", \\\"one\\\")\\npub fn one() -> Nil\\n\\n@external(javascript, \\\"./the/module.mjs\\\", \\\"two\\\")\\npub fn two() -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./the/module.mjs\", \"one\")\npub fn one() -> Nil\n\n@external(javascript, \"./the/module.mjs\", \"two\")\npub fn two() -> Nil\n\n\n----- COMPILED JAVASCRIPT\nimport { one, two } from \"./the/module.mjs\";\n\nexport { one, two };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__same_name_external.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\n@external(javascript, \\\"thingy\\\", \\\"fetch\\\")\\npub fn fetch(request: Nil) -> Nil\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"thingy\", \"fetch\")\npub fn fetch(request: Nil) -> Nil\n\n----- COMPILED JAVASCRIPT\nimport { fetch } from \"thingy\";\n\nexport { fetch };\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__tf_type_name_usage.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: \"\\npub type TESTitem\\n\\n@external(javascript, \\\"it\\\", \\\"one\\\")\\npub fn one(a: TESTitem) -> TESTitem\\n\"\n---\n----- SOURCE CODE\n\npub type TESTitem\n\n@external(javascript, \"it\", \"one\")\npub fn one(a: TESTitem) -> TESTitem\n\n\n----- TYPESCRIPT DEFINITIONS\nexport type TESTitem$ = any;\n\nexport function one(a: TESTitem$): TESTitem$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__externals__type_.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/externals.rs\nexpression: pub type Thing\n---\n----- SOURCE CODE\npub type Thing\n\n----- COMPILED JAVASCRIPT\nexport {}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__assert_last.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  let assert x = 1\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let assert x = 1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let x = 1;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__bad_comma.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\nfn function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit() {\\n  Nil\\n}\\n\\nfn identity(x) {\\n  x\\n}\\n\\npub fn main() {\\n  function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit()\\n  |> identity\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit() {\n  Nil\n}\n\nfn identity(x) {\n  x\n}\n\npub fn main() {\n  function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit()\n  |> identity\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit() {\n  return undefined;\n}\n\nfunction identity(x) {\n  return x;\n}\n\nexport function main() {\n  let _pipe = function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit();\n  return identity(_pipe);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__calling_fn_literal.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  fn(x) { x }(1)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  fn(x) { x }(1)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__calling_functions.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn twice(f: fn(t) -> t, x: t) -> t {\\n  f(f(x))\\n}\\npub fn add_one(x: Int) -> Int {\\n  x + 1\\n}\\npub fn add_two(x: Int) -> Int {\\n  twice(add_one, x)\\n}\\n\\npub fn take_two(x: Int) -> Int {\\n  twice(fn(y) {y - 1}, x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn twice(f: fn(t) -> t, x: t) -> t {\n  f(f(x))\n}\npub fn add_one(x: Int) -> Int {\n  x + 1\n}\npub fn add_two(x: Int) -> Int {\n  twice(add_one, x)\n}\n\npub fn take_two(x: Int) -> Int {\n  twice(fn(y) {y - 1}, x)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function twice(f, x) {\n  return f(f(x));\n}\n\nexport function add_one(x) {\n  return x + 1;\n}\n\nexport function add_two(x) {\n  return twice(add_one, x);\n}\n\nexport function take_two(x) {\n  return twice((y) => { return y - 1; }, x);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__case_in_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(f, x) {\\n  f(case x {\\n    1 -> 2\\n    _ -> 0\\n  })\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(f, x) {\n  f(case x {\n    1 -> 2\n    _ -> 0\n  })\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(f, x) {\n  return f(\n    (() => {\n      if (x === 1) {\n        return 2;\n      } else {\n        return 0;\n      }\n    })(),\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__exported_functions.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn add(x, y) {\\n    x + y\\n}\"\n---\n----- SOURCE CODE\n\npub fn add(x, y) {\n    x + y\n}\n\n----- COMPILED JAVASCRIPT\nexport function add(x, y) {\n  return x + y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__fn_return_fn_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(f: fn(Int) -> Int) {\\n  let func = fn(x, y) { f(x) + f(y) }\\n  func\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(f: fn(Int) -> Int) {\n  let func = fn(x, y) { f(x) + f(y) }\n  func\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function main(f: (x0: number) => number): (x0: number, x1: number) => number;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_formatting.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {\\n  the_first_variable_that_should_be_added + the_second_variable_that_should_be_added\\n}\"\n---\n----- SOURCE CODE\n\npub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {\n  the_first_variable_that_should_be_added + the_second_variable_that_should_be_added\n}\n\n----- COMPILED JAVASCRIPT\nexport function add(\n  the_first_variable_that_should_be_added,\n  the_second_variable_that_should_be_added\n) {\n  return the_first_variable_that_should_be_added + the_second_variable_that_should_be_added;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_formatting1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {\\nx + y\\n}\"\n---\n----- SOURCE CODE\n\npub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {\nx + y\n}\n\n----- COMPILED JAVASCRIPT\nexport function this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(\n  x,\n  y\n) {\n  return x + y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_formatting2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn add(x, y) {\\nx + y\\n}\\n\\npub fn long() {\\n  add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, 1)))))))))))))))\\n}\"\n---\n----- SOURCE CODE\n\npub fn add(x, y) {\nx + y\n}\n\npub fn long() {\n  add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, 1)))))))))))))))\n}\n\n----- COMPILED JAVASCRIPT\nexport function add(x, y) {\n  return x + y;\n}\n\nexport function long() {\n  return add(\n    1,\n    add(\n      1,\n      add(\n        1,\n        add(\n          1,\n          add(\n            1,\n            add(\n              1,\n              add(\n                1,\n                add(\n                  1,\n                  add(1, add(1, add(1, add(1, add(1, add(1, add(1, 1))))))),\n                ),\n              ),\n            ),\n          ),\n        ),\n      ),\n    ),\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_formatting3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn math(x, y) {\\n  fn() {\\n    x + y\\n    x - y\\n    2 * x\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn math(x, y) {\n  fn() {\n    x + y\n    x - y\n    2 * x\n  }\n}\n\n----- COMPILED JAVASCRIPT\nexport function math(x, y) {\n  return () => {\n    x + y;\n    x - y;\n    return 2 * x;\n  };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_formatting_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {\\n  the_first_variable_that_should_be_added + the_second_variable_that_should_be_added\\n}\"\n---\n----- SOURCE CODE\n\npub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {\n  the_first_variable_that_should_be_added + the_second_variable_that_should_be_added\n}\n\n----- TYPESCRIPT DEFINITIONS\nexport function add(\n  the_first_variable_that_should_be_added: number,\n  the_second_variable_that_should_be_added: number\n): number;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_formatting_typescript1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {\\nx + y\\n}\"\n---\n----- SOURCE CODE\n\npub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {\nx + y\n}\n\n----- TYPESCRIPT DEFINITIONS\nexport function this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(\n  x: number,\n  y: number\n): number;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_literals_get_properly_wrapped_1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  fn(n) { n + 1 }(10)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  fn(n) { n + 1 }(10)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 10 + 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_literals_get_properly_wrapped_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  { fn(n) { n + 1 } }(10)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  { fn(n) { n + 1 } }(10)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 10 + 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__function_literals_get_properly_wrapped_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  { let a = fn(n) { n + 1 } }(10)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  { let a = fn(n) { n + 1 } }(10)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return ((n) => { return n + 1; })(10);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__immediately_invoked_function_expressions_include_statement_level.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\nfn identity(x) { x }\\n\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n}\\n\\npub fn main() {\\n  let w = Wibble(1, 2)\\n  identity(Wibble(..w |> identity, b: 4)) |> identity\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn identity(x) { x }\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let w = Wibble(1, 2)\n  identity(Wibble(..w |> identity, b: 4)) |> identity\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(a, b) {\n    super();\n    this.a = a;\n    this.b = b;\n  }\n}\nexport const Wibble$Wibble = (a, b) => new Wibble(a, b);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$a = (value) => value.a;\nexport const Wibble$Wibble$0 = (value) => value.a;\nexport const Wibble$Wibble$b = (value) => value.b;\nexport const Wibble$Wibble$1 = (value) => value.b;\n\nfunction identity(x) {\n  return x;\n}\n\nexport function main() {\n  let w = new Wibble(1, 2);\n  let _pipe = identity((() => { let _block;\n      let _pipe = w;\n      _block = identity(_pipe);\n      let _record = _block;\n      return new Wibble(_record.a, 4); })());\n  return identity(_pipe);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__internal_function_gets_ignored_jsdoc.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\n/// Hello! This is the documentation of the `main`\\n/// function, which is internal!\\n///\\n@internal\\npub fn main() { 1 }\\n\"\n---\n----- SOURCE CODE\n\n/// Hello! This is the documentation of the `main`\n/// function, which is internal!\n///\n@internal\npub fn main() { 1 }\n\n\n----- COMPILED JAVASCRIPT\n/**\n * Hello! This is the documentation of the `main`\n * function, which is internal!\n * \n * @ignore\n */\nexport function main() {\n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__keyword_in_recursive_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(with: Int) -> Nil {\\n  main(with - 1)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(with: Int) -> Nil {\n  main(with - 1)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(loop$with) {\n  while (true) {\n    let with$ = loop$with;\n    loop$with = with$ - 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__labelled_argument_ordering.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\ntype A { A }\\ntype B { B }\\ntype C { C }\\ntype D { D }\\n\\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\\n  Nil\\n}\\n\\npub fn main() {\\n  wibble(A, C, D, b: B)\\n  wibble(A, C, D, b: B)\\n  wibble(B, C, D, a: A)\\n  wibble(B, C, a: A, d: D)\\n  wibble(B, C, d: D, a: A)\\n  wibble(B, D, a: A, c: C)\\n  wibble(B, D, c: C, a: A)\\n  wibble(C, D, b: B, a: A)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype A { A }\ntype B { B }\ntype C { C }\ntype D { D }\n\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\n  Nil\n}\n\npub fn main() {\n  wibble(A, C, D, b: B)\n  wibble(A, C, D, b: B)\n  wibble(B, C, D, a: A)\n  wibble(B, C, a: A, d: D)\n  wibble(B, C, d: D, a: A)\n  wibble(B, D, a: A, c: C)\n  wibble(B, D, c: C, a: A)\n  wibble(C, D, b: B, a: A)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nclass A extends $CustomType {}\n\nclass B extends $CustomType {}\n\nclass C extends $CustomType {}\n\nclass D extends $CustomType {}\n\nfunction wibble(a, b, c, d) {\n  return undefined;\n}\n\nexport function main() {\n  wibble(new A(), new B(), new C(), new D());\n  wibble(new A(), new B(), new C(), new D());\n  wibble(new A(), new B(), new C(), new D());\n  wibble(new A(), new B(), new C(), new D());\n  wibble(new A(), new B(), new C(), new D());\n  wibble(new A(), new B(), new C(), new D());\n  wibble(new A(), new B(), new C(), new D());\n  return wibble(new A(), new B(), new C(), new D());\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__let_last.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  let x = 1\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let x = 1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let x = 1;\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__module_const_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn int_identity(i: Int) -> Int { i }\\npub const int_identity_alias: fn(Int) -> Int = int_identity\\npub fn use_int_identity_alias() { int_identity_alias(42) }\\n\\npub const compound: #(fn(Int) -> Int, fn(Int) -> Int) = #(int_identity, int_identity_alias)\\npub fn use_compound() { compound.0(compound.1(42)) }\"\n---\n----- SOURCE CODE\n\npub fn int_identity(i: Int) -> Int { i }\npub const int_identity_alias: fn(Int) -> Int = int_identity\npub fn use_int_identity_alias() { int_identity_alias(42) }\n\npub const compound: #(fn(Int) -> Int, fn(Int) -> Int) = #(int_identity, int_identity_alias)\npub fn use_compound() { compound.0(compound.1(42)) }\n\n----- COMPILED JAVASCRIPT\nexport const int_identity_alias = int_identity;\n\nexport const compound = [int_identity, int_identity_alias];\n\nexport function int_identity(i) {\n  return i;\n}\n\nexport function use_int_identity_alias() {\n  return int_identity_alias(42);\n}\n\nexport function use_compound() {\n  return compound[0](compound[1](42));\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__module_const_fn1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn int_identity(i: Int) -> Int { i }\\npub const int_identity_alias: fn(Int) -> Int = int_identity\\npub const compound: #(fn(Int) -> Int, fn(Int) -> Int) =\\n    #(int_identity, int_identity_alias)\"\n---\n----- SOURCE CODE\n\npub fn int_identity(i: Int) -> Int { i }\npub const int_identity_alias: fn(Int) -> Int = int_identity\npub const compound: #(fn(Int) -> Int, fn(Int) -> Int) =\n    #(int_identity, int_identity_alias)\n\n----- TYPESCRIPT DEFINITIONS\nexport const int_identity_alias: (x0: number) => number;\n\nexport const compound: [(x0: number) => number, (x0: number) => number];\n\nexport function int_identity(i: number): number;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__multiple_discard.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(_, _, _) {\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(_, _, _) {\n  1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(_, _1, _2) {\n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__no_recur_in_anon_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  fn() { main() }\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  fn() { main() }\n  1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  () => { return main(); };\n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__pipe_into_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\nfn side_effects(x) { x }\\n\\npub fn main() {\\n  1\\n  |> side_effects\\n  |> {\\n    side_effects(2)\\n    side_effects\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn side_effects(x) { x }\n\npub fn main() {\n  1\n  |> side_effects\n  |> {\n    side_effects(2)\n    side_effects\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction side_effects(x) {\n  return x;\n}\n\nexport function main() {\n  let _pipe = 1;\n  let _pipe$1 = side_effects(_pipe);\n  let _block;\n  {\n    side_effects(2);\n    _block = side_effects;\n  }\n  return _block(_pipe$1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__pipe_last.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"fn id(x) { x }\\npub fn main() {\\n  1\\n  |> id\\n}\\n\"\n---\n----- SOURCE CODE\nfn id(x) { x }\npub fn main() {\n  1\n  |> id\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction id(x) {\n  return x;\n}\n\nexport function main() {\n  let _pipe = 1;\n  return id(_pipe);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__pipe_shadow_import.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\n        import wibble.{println}\\n        pub fn main() {\\n          let println =\\n            \\\"oh dear\\\"\\n            |> println\\n          println\\n        }\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub fn println(x: String) {  }\n\n-- main.gleam\n\n        import wibble.{println}\n        pub fn main() {\n          let println =\n            \"oh dear\"\n            |> println\n          println\n        }\n\n----- COMPILED JAVASCRIPT\nimport * as $wibble from \"../wibble.mjs\";\nimport { println } from \"../wibble.mjs\";\n\nexport function main() {\n  let _block;\n  let _pipe = \"oh dear\";\n  _block = println(_pipe);\n  let println$1 = _block;\n  return println$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__pipe_variable_rebinding.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  let version = 1 |> version()\\n  version\\n}\\n\\npub fn version(n) {\\n  Ok(1)\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let version = 1 |> version()\n  version\n}\n\npub fn version(n) {\n  Ok(1)\n}\n\n----- COMPILED JAVASCRIPT\nimport { Ok } from \"../gleam.mjs\";\n\nexport function version(n) {\n  return new Ok(1);\n}\n\nexport function main() {\n  let _block;\n  let _pipe = 1;\n  _block = version(_pipe);\n  let version$1 = _block;\n  return version$1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__pipe_with_block_in_the_middle.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\nfn side_effects(x) { x }\\n\\npub fn main() {\\n  1\\n  |> side_effects\\n  |> {\\n    side_effects(2)\\n    side_effects\\n  }\\n  |> side_effects\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn side_effects(x) { x }\n\npub fn main() {\n  1\n  |> side_effects\n  |> {\n    side_effects(2)\n    side_effects\n  }\n  |> side_effects\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction side_effects(x) {\n  return x;\n}\n\nexport function main() {\n  let _pipe = 1;\n  let _pipe$1 = side_effects(_pipe);\n  let _block;\n  {\n    side_effects(2);\n    _block = side_effects;\n  }\n  let _pipe$2 = _block(_pipe$1);\n  return side_effects(_pipe$2);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__public_function_gets_jsdoc.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\n/// Hello! This is the documentation of the `main`\\n/// function.\\n///\\npub fn main() { 1 }\\n\"\n---\n----- SOURCE CODE\n\n/// Hello! This is the documentation of the `main`\n/// function.\n///\npub fn main() { 1 }\n\n\n----- COMPILED JAVASCRIPT\n/**\n * Hello! This is the documentation of the `main`\n * function.\n */\nexport function main() {\n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__recursion_with_discards.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(f, _) {\\n  f()\\n  main(f, 1)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(f, _) {\n  f()\n  main(f, 1)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(loop$f, _) {\n  while (true) {\n    let f = loop$f;\n    f();\n    loop$f = f;\n    1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__reserved_word_argument.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(with) {\\n  with\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(with) {\n  with\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(with$) {\n  return with$;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__reserved_word_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"const in = 1\\n\\npub fn export() {\\n  in\\n}\\n\"\n---\n----- SOURCE CODE\nconst in = 1\n\npub fn export() {\n  in\n}\n\n\n----- COMPILED JAVASCRIPT\nconst in$ = 1;\n\nexport function export$() {\n  return in$;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__reserved_word_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn class() {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\npub fn class() {\n  Nil\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function class$() {\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__reserved_word_imported.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"import for.{class}\\n\\npub fn export() {\\n  class()\\n}\\n\"\n---\n----- SOURCE CODE\n-- for.gleam\npub fn class() { 1 }\n\n-- main.gleam\nimport for.{class}\n\npub fn export() {\n  class()\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $for from \"../for.mjs\";\nimport { class$ } from \"../for.mjs\";\n\nexport function export$() {\n  return class$();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__reserved_word_imported_alias.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"import for.{class as while} as function\\n\\npub fn export() {\\n  let delete = function.class\\n  while()\\n}\\n\"\n---\n----- SOURCE CODE\n-- for.gleam\npub fn class() { 1 }\n\n-- main.gleam\nimport for.{class as while} as function\n\npub fn export() {\n  let delete = function.class\n  while()\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $function from \"../for.mjs\";\nimport { class$ as while$ } from \"../for.mjs\";\n\nexport function export$() {\n  let delete$ = $function.class$;\n  return while$();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__reserved_word_in_function_arguments.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main(arguments, eval) {\\n  #(arguments, eval)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main(arguments, eval) {\n  #(arguments, eval)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(arguments$, eval$) {\n  return [arguments$, eval$];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__shadowing_current.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn main() {\\n  let main = fn() { 0 }\\n  main()\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let main = fn() { 0 }\n  main()\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let main$1 = () => { return 0; };\n  return main$1();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__star_slash_in_jsdoc.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nassertion_line: 591\nexpression: \"\\n/// */\\n///\\npub fn main() { 1 }\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\n/// */\n///\npub fn main() { 1 }\n\n\n----- COMPILED JAVASCRIPT\n/**\n * *\\/\n */\nexport function main() {\n  return 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__tail_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn count(xs, n) {\\n  case xs {\\n    [] -> n\\n    [_, ..xs] -> count(xs, n + 1)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn count(xs, n) {\n  case xs {\n    [] -> n\n    [_, ..xs] -> count(xs, n + 1)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function count(loop$xs, loop$n) {\n  while (true) {\n    let xs = loop$xs;\n    let n = loop$n;\n    if (xs instanceof $Empty) {\n      return n;\n    } else {\n      let xs$1 = xs.tail;\n      loop$xs = xs$1;\n      loop$n = n + 1;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__tail_call_doesnt_clobber_tail_position_tracking.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub fn loop(indentation) {\\n  case indentation > 0 {\\n    True -> loop(indentation - 1)\\n    False -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn loop(indentation) {\n  case indentation > 0 {\n    True -> loop(indentation - 1)\n    False -> Nil\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function loop(loop$indentation) {\n  while (true) {\n    let indentation = loop$indentation;\n    let $ = indentation > 0;\n    if ($) {\n      loop$indentation = indentation - 1;\n    } else {\n      return undefined;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__two_pipes_in_a_row.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"\\npub type Function(a) {\\n  Function(fn() -> a)\\n}\\n\\npub fn main() {\\n  [fn() { 1 } |> Function, fn() { 2 } |> Function]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Function(a) {\n  Function(fn() -> a)\n}\n\npub fn main() {\n  [fn() { 1 } |> Function, fn() { 2 } |> Function]\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Function extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Function$Function = ($0) => new Function($0);\nexport const Function$isFunction = (value) => value instanceof Function;\nexport const Function$Function$0 = (value) => value[0];\n\nexport function main() {\n  return toList([\n    (() => {\n      let _pipe = () => { return 1; };\n      return new Function(_pipe);\n    })(),\n    (() => {\n      let _pipe = () => { return 2; };\n      return new Function(_pipe);\n    })(),\n  ]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__variable_rewriting_in_anon_fn_with_matching_parameter.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn bad() {\\n  fn(state) {\\n    let state = state\\n    state\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn bad() {\n  fn(state) {\n    let state = state\n    state\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function bad() {\n  return (state) => {\n    let state$1 = state;\n    return state$1;\n  };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__variable_rewriting_in_anon_fn_with_matching_parameter_in_case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/functions.rs\nexpression: \"pub fn bad() {\\n  fn(state) {\\n    let state = case Nil {\\n      _ -> state\\n    }\\n    state\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn bad() {\n  fn(state) {\n    let state = case Nil {\n      _ -> state\n    }\n    state\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function bad() {\n  return (state) => {\n    let _block;\n    let $ = undefined;\n    _block = state;\n    let state$1 = _block;\n    return state$1;\n  };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__generics__fn_generics_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/generics.rs\nexpression: \"pub fn identity(a) -> a {\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\npub fn identity(a) -> a {\n  a\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function identity<J>(a: J): J;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__generics__record_generics_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/generics.rs\nassertion_line: 15\nexpression: \"pub type Animal(t) {\\n  Cat(type_: t)\\n  Dog(type_: t)\\n}\\n\\npub fn main() {\\n  Cat(type_: 6)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\npub type Animal(t) {\n  Cat(type_: t)\n  Dog(type_: t)\n}\n\npub fn main() {\n  Cat(type_: 6)\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class Cat<I> extends _.CustomType {\n  /** @deprecated */\n  constructor(type_: I);\n  /** @deprecated */\n  type_: I;\n}\nexport function Animal$Cat<I>(type_: I): Animal$<I>;\nexport function Animal$isCat<I>(value: any): value is Animal$<unknown>;\nexport function Animal$Cat$0<I>(value: Animal$<I>): I;\nexport function Animal$Cat$type_<I>(value: Animal$<I>): I;\n\nexport class Dog<I> extends _.CustomType {\n  /** @deprecated */\n  constructor(type_: I);\n  /** @deprecated */\n  type_: I;\n}\nexport function Animal$Dog<I>(type_: I): Animal$<I>;\nexport function Animal$isDog<I>(value: any): value is Animal$<unknown>;\nexport function Animal$Dog$0<I>(value: Animal$<I>): I;\nexport function Animal$Dog$type_<I>(value: Animal$<I>): I;\n\nexport type Animal$<I> = Cat<I> | Dog<I>;\n\nexport function Animal$type_<I>(value: Animal$<I>): I;\n\nexport function main(): Animal$<number>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__generics__result_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/generics.rs\nexpression: \"pub fn map(result, fun) {\\n            case result {\\n              Ok(a) -> Ok(fun(a))\\n              Error(e) -> Error(e)\\n            }\\n          }\"\n---\n----- SOURCE CODE\npub fn map(result, fun) {\n            case result {\n              Ok(a) -> Ok(fun(a))\n              Error(e) -> Error(e)\n            }\n          }\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport function map<S, T, V>(result: _.Result<T, S>, fun: (x0: T) => V): _.Result<\n  V,\n  S\n>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__generics__task_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/generics.rs\nexpression: \"pub type Promise(value)\\n    pub type Task(a) = fn() -> Promise(a)\"\n---\n----- SOURCE CODE\npub type Promise(value)\n    pub type Task(a) = fn() -> Promise(a)\n\n----- TYPESCRIPT DEFINITIONS\nexport type Promise$<I> = any;\n\nexport type Task = () => Promise$<any>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__generics__tuple_generics_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/generics.rs\nexpression: \"pub fn make_tuple(x: t) -> #(Int, t, Int) {\\n  #(0, x, 1)\\n}\\n\"\n---\n----- SOURCE CODE\npub fn make_tuple(x: t) -> #(Int, t, Int) {\n  #(0, x, 1)\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function make_tuple<I>(x: I): [number, I, number];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__blocks_get_preserved_when_needed.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n    { 4 |> make_adder }(6)\\n}\\n\\nfn make_adder(a) {\\n  fn(b) { a + b }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    { 4 |> make_adder }(6)\n}\n\nfn make_adder(a) {\n  fn(b) { a + b }\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction make_adder(a) {\n  return (b) => { return a + b; };\n}\n\nexport function main() {\n  let _block;\n  let _pipe = 4;\n  _block = make_adder(_pipe);\n  return _block(6);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__blocks_get_preserved_when_needed2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n    fn(x) { 1 + x }(2) * 3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    fn(x) { 1 + x }(2) * 3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return (1 + 2) * 3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__do_not_inline_parameters_that_have_side_effects.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.map(Ok(10), do_side_effects())\\n}\\n\\nfn do_side_effects() {\\n  let function = fn(x) { x + 1 }\\n  panic as \\\"Side effects\\\"\\n  function\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.map(Ok(10), do_side_effects())\n}\n\nfn do_side_effects() {\n  let function = fn(x) { x + 1 }\n  panic as \"Side effects\"\n  function\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $result from \"../../gleam_stdlib/gleam/result.mjs\";\nimport { Ok, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nfunction do_side_effects() {\n  let function$ = (x) => { return x + 1; };\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    10,\n    \"do_side_effects\",\n    \"Side effects\",\n    {}\n  )\n  return function$;\n}\n\nexport function main() {\n  {\n    let f = do_side_effects();\n    let $ = new Ok(10);\n    if ($ instanceof Ok) {\n      let value = $[0];\n      return new Ok(f(value));\n    } else {\n      return $;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__do_not_inline_parameters_used_more_than_once.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport testing\\n\\npub fn main() {\\n  testing.always_inline(True)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport testing\n\npub fn main() {\n  testing.always_inline(True)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $testing from \"../../gleam_stdlib/testing.mjs\";\n\nexport function main() {\n  {\n    let something = true;\n    if (something) {\n      return something;\n    } else {\n      return something;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_anonymous_function_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  fn(a, b) { #(a, b) }(42, False)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  fn(a, b) { #(a, b) }(42, False)\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return [42, false];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_anonymous_function_in_pipe.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  1 |> fn(x) { x + 1 } |> fn(y) { y * y }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1 |> fn(x) { x + 1 } |> fn(y) { y * y }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let _pipe = 1;\n  let _pipe$1 = _pipe + 1;\n  {\n    let y = _pipe$1;\n    return y * y;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_capture_in_pipe.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  1 |> add(4, _)\\n}\\n\\nfn add(a, b) { a + b }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1 |> add(4, _)\n}\n\nfn add(a, b) { a + b }\n\n\n----- COMPILED JAVASCRIPT\nfunction add(a, b) {\n  return a + b;\n}\n\nexport function main() {\n  let _pipe = 1;\n  return add(4, _pipe);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_which_calls_other_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport testing\\n\\npub fn main() {\\n  testing.always_inline(Ok(10), Error)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport testing\n\npub fn main() {\n  testing.always_inline(Ok(10), Error)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $testing from \"../../gleam_stdlib/testing.mjs\";\nimport { Ok, Error } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = new Ok(10);\n  if ($ instanceof Ok) {\n    let value = $[0];\n    return new Error(value);\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_with_use.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/bool\\n\\npub fn divide(a, b) {\\n  use <- bool.guard(when: b == 0, return: 0)\\n  a / b\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.guard(when: b == 0, return: 0)\n  a / b\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $bool from \"../../gleam_stdlib/gleam/bool.mjs\";\nimport { divideInt } from \"../gleam.mjs\";\n\nexport function divide(a, b) {\n  let $ = b === 0;\n  if ($) {\n    return 0;\n  } else {\n    return divideInt(a, b);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_with_use_and_anonymous.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/bool\\n\\npub fn divide(a, b) {\\n  use <- bool.lazy_guard(b == 0, fn() { panic as \\\"Cannot divide by 0\\\" })\\n  a / b\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/bool\n\npub fn divide(a, b) {\n  use <- bool.lazy_guard(b == 0, fn() { panic as \"Cannot divide by 0\" })\n  a / b\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $bool from \"../../gleam_stdlib/gleam/bool.mjs\";\nimport { makeError, divideInt } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function divide(a, b) {\n  let $ = b === 0;\n  if ($) {\n    throw makeError(\n      \"panic\",\n      FILEPATH,\n      \"my/mod\",\n      5,\n      \"divide\",\n      \"Cannot divide by 0\",\n      {}\n    )\n  } else {\n    return divideInt(a, b);\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/bool\\n\\npub fn count(from: Int, to: Int) -> Int {\\n  use <- bool.guard(when: from >= to, return: from)\\n  echo from\\n  count(from + 1, to)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/bool\n\npub fn count(from: Int, to: Int) -> Int {\n  use <- bool.guard(when: from >= to, return: from)\n  echo from\n  count(from + 1, to)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $bool from \"../../gleam_stdlib/gleam/bool.mjs\";\nimport * as $stdlib$dict from \"../../gleam_stdlib/gleam/dict.mjs\";\nimport {\n  Empty as $Empty,\n  NonEmpty as $NonEmpty,\n  CustomType as $CustomType,\n  bitArraySlice,\n  bitArraySliceToInt,\n  BitArray as $BitArray,\n  List as $List,\n  UtfCodepoint as $UtfCodepoint,\n} from \"../gleam.mjs\";\n\nexport function count(loop$from, loop$to) {\n  while (true) {\n    let from = loop$from;\n    let to = loop$to;\n    let $ = from >= to;\n    if ($) {\n      return from;\n    } else {\n      echo(from, undefined, \"src/module.gleam\", 6);\n      loop$from = from + 1;\n      loop$to = to;\n    }\n  }\n}\n\n// ...omitted code from `templates/echo.mjs`...\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_higher_order_function.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.map(over: Ok(10), with: double)\\n}\\n\\nfn double(x) { x + x }\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.map(over: Ok(10), with: double)\n}\n\nfn double(x) { x + x }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $result from \"../../gleam_stdlib/gleam/result.mjs\";\nimport { Ok } from \"../gleam.mjs\";\n\nfunction double(x) {\n  return x + x;\n}\n\nexport function main() {\n  let $ = new Ok(10);\n  if ($ instanceof Ok) {\n    let value = $[0];\n    return new Ok(double(value));\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_higher_order_function_anonymous.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.try(Ok(10), fn(value) {\\n    Ok({ value + 2 } * 4)\\n  })\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), fn(value) {\n    Ok({ value + 2 } * 4)\n  })\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $result from \"../../gleam_stdlib/gleam/result.mjs\";\nimport { Ok } from \"../gleam.mjs\";\n\nexport function main() {\n  let $ = new Ok(10);\n  if ($ instanceof Ok) {\n    let value = $[0];\n    return new Ok((value + 2) * 4);\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_higher_order_function_with_capture.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn main() {\\n  result.try(Ok(10), divide(_, 2))\\n}\\n\\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\\n  case a % b {\\n    0 -> Ok(a / b)\\n    _ -> Error(Nil)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn main() {\n  result.try(Ok(10), divide(_, 2))\n}\n\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $result from \"../../gleam_stdlib/gleam/result.mjs\";\nimport { Ok, Error, remainderInt, divideInt } from \"../gleam.mjs\";\n\nfunction divide(a, b) {\n  let $ = remainderInt(a, b);\n  if ($ === 0) {\n    return new Ok(divideInt(a, b));\n  } else {\n    return new Error(undefined);\n  }\n}\n\nexport function main() {\n  let $ = new Ok(10);\n  if ($ instanceof Ok) {\n    let value = $[0];\n    return divide(value, 2);\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_shadowed_variable.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n  let a = 10\\n  let b = 20\\n\\n  fn(x) {\\n    let a = 7\\n    x + a\\n  }(a + b)\\n\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  let a = 10;\n  let b = 20;\n  {\n    let _inline_a_0 = 7;\n    (a + b) + _inline_a_0\n  };\n  return a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_shadowed_variable_nested.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn sum(a, b) {\\n  fn(x) {\\n    let a = 7\\n    fn(y) {\\n      let a = 10\\n      y - a\\n    }(x + a)\\n\\n    a\\n  }(a + b)\\n\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    fn(y) {\n      let a = 10\n      y - a\n    }(x + a)\n\n    a\n  }(a + b)\n\n  a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function sum(a, b) {\n  {\n    let _inline_a_0 = 7;\n    {\n      let _inline_a_1 = 10;\n      ((a + b) + _inline_a_0) - _inline_a_1\n    };\n    _inline_a_0\n  };\n  return a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_variable_shadowed_in_case_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn sum() {\\n  let a = 10\\n  let b = 20\\n\\n  fn(x) {\\n    case 7, 8 {\\n      a, b -> a + b + x\\n    }\\n  }(a + b)\\n\\n  a + b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum() {\n  let a = 10\n  let b = 20\n\n  fn(x) {\n    case 7, 8 {\n      a, b -> a + b + x\n    }\n  }(a + b)\n\n  a + b\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function sum() {\n  let a = 10;\n  let b = 20;\n  let $ = 7;\n  let $1 = 8;\n  let _inline_a_0 = $;\n  let _inline_b_1 = $1;\n  (_inline_a_0 + _inline_b_1) + (a + b)\n  return a + b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_variable_shadowing_case_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn sum() {\\n  case 1, 2 {\\n    a, b -> fn(x) {\\n      let a = 7\\n      x + a\\n    }(a + b)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum() {\n  case 1, 2 {\n    a, b -> fn(x) {\n      let a = 7\n      x + a\n    }(a + b)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function sum() {\n  let $ = 1;\n  let $1 = 2;\n  let a = $;\n  let b = $1;\n  let _inline_a_0 = 7;\n  return (a + b) + _inline_a_0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_variable_shadowing_parameter.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn sum(a, b) {\\n  fn(x) {\\n    let a = 7\\n    x + a\\n  }(a + b)\\n\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn sum(a, b) {\n  fn(x) {\n    let a = 7\n    x + a\n  }(a + b)\n\n  a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function sum(a, b) {\n  {\n    let _inline_a_0 = 7;\n    (a + b) + _inline_a_0\n  };\n  return a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inlining_works_properly_with_record_updates.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n}\\n\\npub fn main() {\\n  let w = Wibble(1, 2)\\n  use b <- result.map(Ok(3))\\n  Wibble(..w, b:)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let w = Wibble(1, 2)\n  use b <- result.map(Ok(3))\n  Wibble(..w, b:)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $result from \"../../gleam_stdlib/gleam/result.mjs\";\nimport { Ok, CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(a, b) {\n    super();\n    this.a = a;\n    this.b = b;\n  }\n}\nexport const Wibble$Wibble = (a, b) => new Wibble(a, b);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$a = (value) => value.a;\nexport const Wibble$Wibble$0 = (value) => value.a;\nexport const Wibble$Wibble$b = (value) => value.b;\nexport const Wibble$Wibble$1 = (value) => value.b;\n\nexport function main() {\n  let w = new Wibble(1, 2);\n  let $ = new Ok(3);\n  if ($ instanceof Ok) {\n    let value = $[0];\n    return new Ok(new Wibble(w.a, value));\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inlining_works_through_blocks.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\npub fn main() {\\n    { fn(x) { Ok(x + 1) } }(41)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    { fn(x) { Ok(x + 1) } }(41)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok } from \"../gleam.mjs\";\n\nexport function main() {\n  return new Ok(41 + 1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__parameters_from_nested_functions_are_correctly_inlined.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/inlining.rs\nexpression: \"\\nimport gleam/result\\n\\npub fn halve_all(a, b, c) {\\n  use x <- result.try(divide(a, 2))\\n  use y <- result.try(divide(b, 2))\\n  use z <- result.map(divide(c, 2))\\n\\n  #(x, y, z)\\n}\\n\\nfn divide(a, b) {\\n  case a % b {\\n    0 -> Ok(a / b)\\n    _ -> Error(Nil)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam/result\n\npub fn halve_all(a, b, c) {\n  use x <- result.try(divide(a, 2))\n  use y <- result.try(divide(b, 2))\n  use z <- result.map(divide(c, 2))\n\n  #(x, y, z)\n}\n\nfn divide(a, b) {\n  case a % b {\n    0 -> Ok(a / b)\n    _ -> Error(Nil)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $result from \"../../gleam_stdlib/gleam/result.mjs\";\nimport { Ok, Error, remainderInt, divideInt } from \"../gleam.mjs\";\n\nfunction divide(a, b) {\n  let $ = remainderInt(a, b);\n  if ($ === 0) {\n    return new Ok(divideInt(a, b));\n  } else {\n    return new Error(undefined);\n  }\n}\n\nexport function halve_all(a, b, c) {\n  let $ = divide(a, 2);\n  if ($ instanceof Ok) {\n    let value = $[0];\n    let x = value;\n    let $1 = divide(b, 2);\n    if ($1 instanceof Ok) {\n      let _inline_value_0 = $1[0];\n      let y = _inline_value_0;\n      let $2 = divide(c, 2);\n      if ($2 instanceof Ok) {\n        let _inline_value_1 = $2[0];\n        return new Ok([x, y, _inline_value_1]);\n      } else {\n        return $2;\n      }\n    } else {\n      return $1;\n    }\n  } else {\n    return $;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 89\nexpression: \"\\npub fn go(xs) {\\n  case xs {\\n    [] -> 0\\n    [_] -> 1\\n    [_, _] -> 2\\n    _ -> 9999\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(xs) {\n  case xs {\n    [] -> 0\n    [_] -> 1\n    [_, _] -> 2\n    _ -> 9999\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty } from \"../gleam.mjs\";\n\nexport function go(xs) {\n  if (xs instanceof $Empty) {\n    return 0;\n  } else {\n    let $ = xs.tail;\n    if ($ instanceof $Empty) {\n      return 1;\n    } else {\n      let $1 = $.tail;\n      if ($1 instanceof $Empty) {\n        return 2;\n      } else {\n        return 9999;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 77\nexpression: \"\\npub fn go() {\\n  [] == [1]\\n  [] != [1]\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  [] == [1]\n  [] != [1]\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList, isEqual } from \"../gleam.mjs\";\n\nexport function go() {\n  isEqual(toList([]), toList([1]));\n  return !isEqual(toList([]), toList([1]));\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__list_constants.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 42\nexpression: \"\\npub const a = []\\npub const b = [1, 2, 3]\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const a = []\npub const b = [1, 2, 3]\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nexport const a = /* @__PURE__ */ toList([]);\n\nexport const b = /* @__PURE__ */ toList([1, 2, 3]);\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__list_constants_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nexpression: \"\\npub const a = []\\npub const b = [1, 2, 3]\\n\"\n---\n----- SOURCE CODE\n\npub const a = []\npub const b = [1, 2, 3]\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport const a: _.List<any>;\n\nexport const b: _.List<number>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__list_destructuring.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nexpression: \"\\npub fn go(x, y) {\\n  let assert [] = x\\n  let assert [a] = x\\n  let assert [1, 2] = x\\n  let assert [_, #(3, b)] = y\\n  let assert [head, ..tail] = y\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x, y) {\n  let assert [] = x\n  let assert [a] = x\n  let assert [1, 2] = x\n  let assert [_, #(3, b)] = y\n  let assert [head, ..tail] = y\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Empty as $Empty, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x, y) {\n  if (!(x instanceof $Empty)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 21, end: 38, pattern_start: 32, pattern_end: 34 }\n    )\n  }\n  let a;\n  if (x instanceof $Empty) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      4,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 41, end: 59, pattern_start: 52, pattern_end: 55 }\n    )\n  } else {\n    let $ = x.tail;\n    if ($ instanceof $Empty) {\n      a = x.head;\n    } else {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        4,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: x, start: 41, end: 59, pattern_start: 52, pattern_end: 55 }\n      )\n    }\n  }\n  if (x instanceof $Empty) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      5,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 62, end: 83, pattern_start: 73, pattern_end: 79 }\n    )\n  } else {\n    let $1 = x.tail;\n    if ($1 instanceof $Empty) {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        5,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: x, start: 62, end: 83, pattern_start: 73, pattern_end: 79 }\n      )\n    } else {\n      let $2 = $1.tail;\n      if ($2 instanceof $Empty) {\n        let $3 = x.head;\n        if ($3 === 1) {\n          let $4 = $1.head;\n          if (!($4 === 2)) {\n            throw makeError(\n              \"let_assert\",\n              FILEPATH,\n              \"my/mod\",\n              5,\n              \"go\",\n              \"Pattern match failed, no pattern matched the value.\",\n              {\n                value: x,\n                start: 62,\n                end: 83,\n                pattern_start: 73,\n                pattern_end: 79\n              }\n            )\n          }\n        } else {\n          throw makeError(\n            \"let_assert\",\n            FILEPATH,\n            \"my/mod\",\n            5,\n            \"go\",\n            \"Pattern match failed, no pattern matched the value.\",\n            { value: x, start: 62, end: 83, pattern_start: 73, pattern_end: 79 }\n          )\n        }\n      } else {\n        throw makeError(\n          \"let_assert\",\n          FILEPATH,\n          \"my/mod\",\n          5,\n          \"go\",\n          \"Pattern match failed, no pattern matched the value.\",\n          { value: x, start: 62, end: 83, pattern_start: 73, pattern_end: 79 }\n        )\n      }\n    }\n  }\n  let b;\n  if (y instanceof $Empty) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      6,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: y, start: 86, end: 113, pattern_start: 97, pattern_end: 109 }\n    )\n  } else {\n    let $5 = y.tail;\n    if ($5 instanceof $Empty) {\n      throw makeError(\n        \"let_assert\",\n        FILEPATH,\n        \"my/mod\",\n        6,\n        \"go\",\n        \"Pattern match failed, no pattern matched the value.\",\n        { value: y, start: 86, end: 113, pattern_start: 97, pattern_end: 109 }\n      )\n    } else {\n      let $6 = $5.tail;\n      if ($6 instanceof $Empty) {\n        let $7 = $5.head[0];\n        if ($7 === 3) {\n          b = $5.head[1];\n        } else {\n          throw makeError(\n            \"let_assert\",\n            FILEPATH,\n            \"my/mod\",\n            6,\n            \"go\",\n            \"Pattern match failed, no pattern matched the value.\",\n            {\n              value: y,\n              start: 86,\n              end: 113,\n              pattern_start: 97,\n              pattern_end: 109\n            }\n          )\n        }\n      } else {\n        throw makeError(\n          \"let_assert\",\n          FILEPATH,\n          \"my/mod\",\n          6,\n          \"go\",\n          \"Pattern match failed, no pattern matched the value.\",\n          { value: y, start: 86, end: 113, pattern_start: 97, pattern_end: 109 }\n        )\n      }\n    }\n  }\n  let head;\n  let tail;\n  if (y instanceof $Empty) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      7,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: y, start: 116, end: 145, pattern_start: 127, pattern_end: 141 }\n    )\n  } else {\n    head = y.head;\n    tail = y.tail;\n  }\n  return y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__list_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 5\nexpression: \"\\npub fn go(x) {\\n  []\\n  [1]\\n  [1, 2]\\n  [1, 2, ..x]\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  []\n  [1]\n  [1, 2]\n  [1, 2, ..x]\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList, prepend as listPrepend } from \"../gleam.mjs\";\n\nexport function go(x) {\n  toList([]);\n  toList([1]);\n  toList([1, 2]);\n  return listPrepend(1, listPrepend(2, x));\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__long_list_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 19\nexpression: \"\\npub fn go() {\\n  [111111111111111111111111111111111111111111111111111111111111111111111111]\\n  [11111111111111111111111111111111111111111111, 1111111111111111111111111111111111111111111]\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  [111111111111111111111111111111111111111111111111111111111111111111111111]\n  [11111111111111111111111111111111111111111111, 1111111111111111111111111111111111111111111]\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nexport function go() {\n  toList([\n    111111111111111111111111111111111111111111111111111111111111111111111111,\n  ]);\n  return toList([\n    11111111111111111111111111111111111111111111,\n    1111111111111111111111111111111111111111111,\n  ]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__multi_line_list_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 31\nexpression: \"\\npub fn go(x) {\\n    [{True 1}]\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n    [{True 1}]\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nexport function go(x) {\n  return toList([\n    (() => {\n      true;\n      return 1;\n    })(),\n  ]);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__tight_empty_list.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/lists.rs\nassertion_line: 106\nexpression: \"\\npub fn go(func) {\\n  let huuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuge_variable = []\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(func) {\n  let huuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuge_variable = []\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { toList } from \"../gleam.mjs\";\n\nexport function go(func) {\n  let huuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuge_variable = toList([]);\n  return huuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuge_variable;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__alias_aliased_constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nassertion_line: 59\nexpression: \"\\nimport rocket_ship.{ x as y }\\npub const z = y\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub const x = 1\n\n-- main.gleam\n\nimport rocket_ship.{ x as y }\npub const z = y\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\nimport { x as y } from \"../rocket_ship.mjs\";\n\nexport const z = y;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__alias_constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport rocket_ship as boop\\npub fn go() { boop.x }\\n\"\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub const x = 1\n\n-- main.gleam\n\nimport rocket_ship as boop\npub fn go() { boop.x }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $boop from \"../rocket_ship.mjs\";\n\nexport function go() {\n  return $boop.x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__alias_fn_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport rocket_ship as boop\\npub fn go() { boop.go() }\\n\"\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub fn go() { 1 }\n\n-- main.gleam\n\nimport rocket_ship as boop\npub fn go() { boop.go() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $boop from \"../rocket_ship.mjs\";\n\nexport function go() {\n  return $boop.go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__aliased_unqualified_fn_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import rocket_ship.{launch as boom_time}\\npub fn go() { boom_time() }\\n\"\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub fn launch() { 1 }\n\n-- main.gleam\nimport rocket_ship.{launch as boom_time}\npub fn go() { boom_time() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\nimport { launch as boom_time } from \"../rocket_ship.mjs\";\n\nexport function go() {\n  return boom_time();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport rocket_ship\\npub fn go() { rocket_ship.x }\\n\"\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub const x = 1\n\n-- main.gleam\n\nimport rocket_ship\npub fn go() { rocket_ship.x }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\n\nexport function go() {\n  return $rocket_ship.x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__constant_module_access_with_keyword.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport rocket_ship\\npub const variable = rocket_ship.class\\n\"\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub const class = 1\n\n-- main.gleam\n\nimport rocket_ship\npub const variable = rocket_ship.class\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\n\nexport const variable = $rocket_ship.class$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__different_package_import.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import one\\npub fn go() { one.go() }\\n\"\n---\n----- SOURCE CODE\nimport one\npub fn go() { one.go() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $one from \"../../other_package/one.mjs\";\n\nexport function go() {\n  return $one.go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__discarded_duplicate_import.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport esa/rocket_ship\\nimport nasa/rocket_ship as _nasa_rocket\\npub fn go() { rocket_ship.go() }\\n\"\n---\n----- SOURCE CODE\n-- esa/rocket_ship.gleam\npub fn go() { 1 }\n\n-- nasa/rocket_ship.gleam\npub fn go() { 1 }\n\n-- main.gleam\n\nimport esa/rocket_ship\nimport nasa/rocket_ship as _nasa_rocket\npub fn go() { rocket_ship.go() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../esa/rocket_ship.mjs\";\n\nexport function go() {\n  return $rocket_ship.go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__discarded_duplicate_import_with_unqualified.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport esa/rocket_ship\\nimport nasa/rocket_ship.{go} as _nasa_rocket\\npub fn esa_go() { rocket_ship.go() }\\npub fn nasa_go() { go() }\\n\"\n---\n----- SOURCE CODE\n-- esa/rocket_ship.gleam\npub fn go() { 1 }\n\n-- nasa/rocket_ship.gleam\npub fn go() { 1 }\n\n-- main.gleam\n\nimport esa/rocket_ship\nimport nasa/rocket_ship.{go} as _nasa_rocket\npub fn esa_go() { rocket_ship.go() }\npub fn nasa_go() { go() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../esa/rocket_ship.mjs\";\nimport { go } from \"../nasa/rocket_ship.mjs\";\n\nexport function esa_go() {\n  return $rocket_ship.go();\n}\n\nexport function nasa_go() {\n  return go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__import_with_keyword.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport rocket_ship.{class, in as while}\\npub fn main() {\\n  #(class, while)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport rocket_ship.{class, in as while}\npub fn main() {\n  #(class, while)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\nimport { class$, in$ as while$ } from \"../rocket_ship.mjs\";\n\nexport function main() {\n  return [class$, while$];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__multiple_unqualified_fn_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import rocket_ship.{a,b as bb}\\npub fn go() { a() + bb() }\\n\"\n---\n----- SOURCE CODE\nimport rocket_ship.{a,b as bb}\npub fn go() { a() + bb() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\nimport { a, b as bb } from \"../rocket_ship.mjs\";\n\nexport function go() {\n  return a() + bb();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__nested_fn_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import one/two\\npub fn go() { two.go() }\"\n---\n----- SOURCE CODE\n-- one/two.gleam\npub fn go() { 1 }\n\n-- main.gleam\nimport one/two\npub fn go() { two.go() }\n\n----- COMPILED JAVASCRIPT\nimport * as $two from \"../one/two.mjs\";\n\nexport function go() {\n  return $two.go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__nested_module_constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"\\nimport rocket_ship/launcher\\npub fn go() { launcher.x }\\n\"\n---\n----- SOURCE CODE\n\nimport rocket_ship/launcher\npub fn go() { launcher.x }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $launcher from \"../rocket_ship/launcher.mjs\";\n\nexport function go() {\n  return $launcher.x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__nested_nested_fn_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import one/two/three\\npub fn go() { three.go() }\"\n---\n----- SOURCE CODE\n-- one/two/three.gleam\npub fn go() { 1 }\n\n-- main.gleam\nimport one/two/three\npub fn go() { three.go() }\n\n----- COMPILED JAVASCRIPT\nimport * as $three from \"../one/two/three.mjs\";\n\nexport function go() {\n  return $three.go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__nested_same_package.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import one/two/three\\npub fn go() { three.go() }\\n\"\n---\n----- SOURCE CODE\n-- one/two/three.gleam\npub fn go() { 1 }\n\n-- main.gleam\nimport one/two/three\npub fn go() { three.go() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $three from \"../one/two/three.mjs\";\n\nexport function go() {\n  return $three.go();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__renamed_module.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nassertion_line: 70\nexpression: \"\\nimport x as y\\npub const z = y.v\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n-- x.gleam\npub const v = 1\n\n-- main.gleam\n\nimport x as y\npub const z = y.v\n\n\n----- COMPILED JAVASCRIPT\nimport * as $y from \"../x.mjs\";\n\nexport const z = $y.v;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__modules__unqualified_fn_call.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/modules.rs\nexpression: \"import rocket_ship.{launch}\\npub fn go() { launch() }\\n\"\n---\n----- SOURCE CODE\n-- rocket_ship.gleam\npub fn launch() { 1 }\n\n-- main.gleam\nimport rocket_ship.{launch}\npub fn go() { launch() }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $rocket_ship from \"../rocket_ship.mjs\";\nimport { launch } from \"../rocket_ship.mjs\";\n\nexport function go() {\n  return launch();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__complex_division_by_non_zero_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  { 1.1 +. 2.0 } /. 2.3\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  { 1.1 +. 2.0 } /. 2.3\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return (1.1 + 2.0) / 2.3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__complex_division_by_non_zero_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  { 1 + 2 } / 3\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  { 1 + 2 } / 3\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return globalThis.Math.trunc((1 + 2) / 3);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__complex_remainder_by_non_zero_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  { 1 + 2 } % 3\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  { 1 + 2 } % 3\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return (1 + 2) % 3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__division_by_non_zero_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  1.1 /. 2.3\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  1.1 /. 2.3\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 1.1 / 2.3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__division_by_non_zero_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  1 / 2\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  1 / 2\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return globalThis.Math.trunc(1 / 2);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__division_by_zero_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  1.1 /. 0.0\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  1.1 /. 0.0\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0.0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__division_by_zero_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  1 / 0\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  1 / 0\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__division_inf_by_inf_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  -100.001e123_456_789 /. 100.001e123_456_789\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  -100.001e123_456_789 /. 100.001e123_456_789\n}\n\n\n----- ERROR\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   -100.001e123_456_789 /. 100.001e123_456_789\n  │   ^^^^^^^^^^^^^^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:3:27\n  │\n3 │   -100.001e123_456_789 /. 100.001e123_456_789\n  │                           ^^^^^^^^^^^^^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_divide_complex_expr.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  case 1.0 >=. 0.0 {\\n    True -> 2.0\\n    False -> 4.0\\n  } /. 2.0\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  case 1.0 >=. 0.0 {\n    True -> 2.0\n    False -> 4.0\n  } /. 2.0\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return (() => {\n    let $ = 1.0 >= 0.0;\n    if ($) {\n      return 2.0;\n    } else {\n      return 4.0;\n    }\n  })() / 2.0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 181\nexpression: \"\\npub fn go() {\\n  1.0 != 2.0\\n  1.0 == 2.0\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  1.0 != 2.0\n  1.0 == 2.0\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  1.0 !== 2.0;\n  return 1.0 === 2.0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_equality1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 193\nexpression: \"\\npub fn go(y) {\\n  let x = 1.0\\n  x == y\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(y) {\n  let x = 1.0\n  x == y\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(y) {\n  let x = 1.0;\n  return x === y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  1.5\\n  2.0\\n  -0.1\\n  1.\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  1.5\n  2.0\n  -0.1\n  1.\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  1.5;\n  2.0;\n  -0.1;\n  return 1.0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_operators.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n    1.0 +. 1.4 // => 2.4\\n    5.0 -. 1.5 // => 3.5\\n    5.0 /. 2.0 // => 2.5\\n    3.0 *. 3.1 // => 9.3\\n\\n    2.0 >. 1.0  // => True\\n    2.0 <. 1.0  // => False\\n    2.0 >=. 1.0 // => True\\n    2.0 <=. 1.0 // => False\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n    1.0 +. 1.4 // => 2.4\n    5.0 -. 1.5 // => 3.5\n    5.0 /. 2.0 // => 2.5\n    3.0 *. 3.1 // => 9.3\n\n    2.0 >. 1.0  // => True\n    2.0 <. 1.0  // => False\n    2.0 >=. 1.0 // => True\n    2.0 <=. 1.0 // => False\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  1.0 + 1.4;\n  5.0 - 1.5;\n  5.0 / 2.0;\n  3.0 * 3.1;\n  2.0 > 1.0;\n  2.0 < 1.0;\n  2.0 >= 1.0;\n  return 2.0 <= 1.0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_scientific_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  0.01e-1\\n  0.01e-0\\n  -10.01e-1\\n  -10.01e-0\\n  -100.001e-523\\n  -100.001e-123_456_789\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  0.01e-1\n  0.01e-0\n  -10.01e-1\n  -10.01e-0\n  -100.001e-523\n  -100.001e-123_456_789\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  0.001;\n  0.01;\n  -1.001;\n  -10.01;\n  -0.0;\n  return -0.0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__inf_float_case_statement.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n  100.001e123_456_789 -> \\\"wobble\\\"\\n    _ -> \\\"wibble\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n  100.001e123_456_789 -> \"wobble\"\n    _ -> \"wibble\"\n  }\n}\n\n\n----- ERROR\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   100.001e123_456_789 -> \"wobble\"\n  │   ^^^^^^^^^^^^^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_divide_complex_expr.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  case 1 >= 0 {\\n    True -> 2\\n    False -> 4\\n  } / 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  case 1 >= 0 {\n    True -> 2\n    False -> 4\n  } / 2\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return globalThis.Math.trunc(\n    (() => {\n      let $ = 1 >= 0;\n      if ($) {\n        return 2;\n      } else {\n        return 4;\n      }\n    })() / 2\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 157\nexpression: \"\\npub fn go() {\\n  1 != 2\\n  1 == 2\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  1 != 2\n  1 == 2\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  1 !== 2;\n  return 1 === 2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_equality1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 169\nexpression: \"\\npub fn go(y) {\\n  let x = 1\\n  x == y\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(y) {\n  let x = 1\n  x == y\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(y) {\n  let x = 1;\n  return x === y;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 5\nexpression: \"\\npub fn go() {\\n  1\\n  2\\n  -3\\n  4001\\n  0b00001111\\n  0o17\\n  0xF\\n  1_000\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  1\n  2\n  -3\n  4001\n  0b00001111\n  0o17\n  0xF\n  1_000\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  1;\n  2;\n  -3;\n  4001;\n  0b1111;\n  0o17;\n  0xF;\n  return 1_000;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_mod_complex_expr.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  case 1 >= 0 {\\n    True -> 2\\n    False -> 4\\n  } % 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  case 1 >= 0 {\n    True -> 2\n    False -> 4\n  } % 2\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return (() => {\n    let $ = 1 >= 0;\n    if ($) {\n      return 2;\n    } else {\n      return 4;\n    }\n  })() % 2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_negation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 227\nexpression: \"\\npub fn go() {\\n  let a = 3\\n  let b = -a\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let a = 3\n  let b = -a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let a = 3;\n  let b = - a;\n  return b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_operators.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  1 + 1 // => 2\\n  5 - 1 // => 4\\n  5 / 2 // => 2\\n  3 * 3 // => 9\\n  5 % 2 // => 1\\n  2 > 1  // => True\\n  2 < 1  // => False\\n  2 >= 1 // => True\\n  2 <= 1 // => False\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  1 + 1 // => 2\n  5 - 1 // => 4\n  5 / 2 // => 2\n  3 * 3 // => 9\n  5 % 2 // => 1\n  2 > 1  // => True\n  2 < 1  // => False\n  2 >= 1 // => True\n  2 <= 1 // => False\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  1 + 1;\n  5 - 1;\n  globalThis.Math.trunc(5 / 2);\n  3 * 3;\n  5 % 2;\n  2 > 1;\n  2 < 1;\n  2 >= 1;\n  return 2 <= 1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_patterns.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go(x) {\\n  let assert 4 = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert 4 = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x === 4)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 34, pattern_start: 29, pattern_end: 30 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__many_preceeding_zeros_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0000_000_00_9_179.1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0000_000_00_9_179.1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 9179.1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__many_preceeding_zeros_float_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub const x = 0000_000_00_9_179.1\\n\"\n---\n----- SOURCE CODE\n\npub const x = 0000_000_00_9_179.1\n\n\n----- COMPILED JAVASCRIPT\nexport const x = 9_179.1;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__many_preceeding_zeros_float_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  let assert 0000_000_00_9_179.1 = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert 0000_000_00_9_179.1 = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main(x) {\n  if (!(x === 9179.1)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 20, end: 54, pattern_start: 31, pattern_end: 50 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__many_preceeding_zeros_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0000_000_00_9_179\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0000_000_00_9_179\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 9_179;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__many_preceeding_zeros_int_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub const x = 0000_000_00_9_179\\n\"\n---\n----- SOURCE CODE\n\npub const x = 0000_000_00_9_179\n\n\n----- COMPILED JAVASCRIPT\nexport const x = 9_179;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__many_preceeding_zeros_int_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  let assert 0000_000_00_9_179 = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert 0000_000_00_9_179 = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main(x) {\n  if (!(x === 9179)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 20, end: 52, pattern_start: 31, pattern_end: 48 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__operator_precedence.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 205\nexpression: \"\\npub fn go() {\\n  2.4 *. { 3.5 +. 6.0 }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  2.4 *. { 3.5 +. 6.0 }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return 2.4 * (3.5 + 6.0);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__preceeding_zeros_float.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  09_179.1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  09_179.1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 9179.1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__preceeding_zeros_float_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 286\nexpression: \"\\npub const x = 09_179.1\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const x = 09_179.1\n\n\n----- COMPILED JAVASCRIPT\nexport const x = 9_179.1;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__preceeding_zeros_float_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  let assert 09_179.1 = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert 09_179.1 = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main(x) {\n  if (!(x === 9179.1)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 20, end: 43, pattern_start: 31, pattern_end: 39 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__preceeding_zeros_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 252\nexpression: \"\\npub fn main() {\\n  09_179\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  09_179\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 9_179;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__preceeding_zeros_int_const.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 276\nexpression: \"\\npub const x = 09_179\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const x = 09_179\n\n\n----- COMPILED JAVASCRIPT\nexport const x = 9_179;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__preceeding_zeros_int_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  let assert 09_179 = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert 09_179 = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main(x) {\n  if (!(x === 9179)) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 20, end: 41, pattern_start: 31, pattern_end: 37 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__remainder.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  5 % 0 // => 0\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  5 % 0 // => 0\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return 0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__remainder_by_non_zero_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  1 % 2\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  1 % 2\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 1 % 2;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__remainder_by_zero_int.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"pub fn main() {\\n  1 % 0\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  1 % 0\n}\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__repeated_int_negation.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nassertion_line: 239\nexpression: \"\\npub fn go() {\\n  let a = 3\\n  let b = --a\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let a = 3\n  let b = --a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  let a = 3;\n  let b = - - a;\n  return b;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_binary_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0b_10_01\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0b_10_01\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0b10_01;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_decimal_point.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0._1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0._1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0.1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_decimal_point_case_statement.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0._1 -> \\\"wobble\\\"\\n    _ -> \\\"wibble\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0._1 -> \"wobble\"\n    _ -> \"wibble\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x) {\n  if (x === 0.1) {\n    return \"wobble\";\n  } else {\n    return \"wibble\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_hexadecimal_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0x_12_34\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0x_12_34\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0x12_34;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_octal_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0o_12_34\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0o_12_34\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0o12_34;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_zero.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0_1_2_3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0_1_2_3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 1_2_3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_zero_after_binary_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0b0_1_0_1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0b0_1_0_1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0b1_0_1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_zero_after_hex_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0x0_1_2_3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0x0_1_2_3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0x1_2_3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__underscore_after_zero_after_octal_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0o0_1_2_3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0o0_1_2_3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0o1_2_3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__wide_float_div.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn go() {\\n  111111111111111111111111111111. /. 22222222222222222222222222222222222.\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  111111111111111111111111111111. /. 22222222222222222222222222222222222.\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return 1.111111111111111e29 / 2.222222222222222e34;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__zero_after_underscore_after_binary_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0b_0_1_0_1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0b_0_1_0_1\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0b1_0_1;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__zero_after_underscore_after_hex_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0x_0_1_2_3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0x_0_1_2_3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0x1_2_3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__zero_after_underscore_after_octal_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/numbers.rs\nexpression: \"\\npub fn main() {\\n  0o_0_1_2_3\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  0o_0_1_2_3\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main() {\n  return 0o1_2_3;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__as_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 39\nexpression: \"\\npub fn go(f) {\\n  let boop = panic\\n  f(panic)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(f) {\n  let boop = panic\n  f(panic)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(f) {\n  let _block;\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"go\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n  let boop = _block;\n  return f(\n    (() => {\n      throw makeError(\n        \"panic\",\n        FILEPATH,\n        \"my/mod\",\n        4,\n        \"go\",\n        \"`panic` expression evaluated.\",\n        {}\n      )\n    })(),\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__bare.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 5\nexpression: \"\\npub fn go() {\\n  panic\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  panic\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go() {\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"go\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__bare_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nexpression: \"\\npub fn go() {\\n  panic\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  panic\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function go(): any;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 74\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    _ -> panic\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    _ -> panic\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    4,\n    \"go\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__case_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 88\nexpression: \"\\npub fn crash(message) {\\n  panic as case message {\\n    Ok(message) -> message\\n    Error(_) -> \\\"No message provided\\\"\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn crash(message) {\n  panic as case message {\n    Ok(message) -> message\n    Error(_) -> \"No message provided\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function crash(message) {\n  let _block;\n  if (message instanceof Ok) {\n    let message$1 = message[0];\n    _block = message$1;\n  } else {\n    _block = \"No message provided\";\n  }\n  throw makeError(\"panic\", FILEPATH, \"my/mod\", 3, \"crash\", _block, {})\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__panic_as.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 16\nexpression: \"\\npub fn go() {\\n  let x = \\\"wibble\\\"\\n  panic as x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = \"wibble\"\n  panic as x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go() {\n  let x = \"wibble\";\n  throw makeError(\"panic\", FILEPATH, \"my/mod\", 4, \"go\", x, {})\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__pipe.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 51\nexpression: \"\\npub fn go(f) {\\n  f |> panic\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(f) {\n  f |> panic\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(f) {\n  let _pipe = f;\n  let _block;\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"go\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n  return _block(_pipe);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__sequence.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/panic.rs\nassertion_line: 62\nexpression: \"\\npub fn go(at_the_disco) {\\n  panic\\n  at_the_disco\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(at_the_disco) {\n  panic\n  at_the_disco\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(at_the_disco) {\n  throw makeError(\n    \"panic\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"go\",\n    \"`panic` expression evaluated.\",\n    {}\n  )\n  return at_the_disco;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_error.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"import gleam\\npub fn go() { gleam.Error(1) }\\n\"\n---\n----- SOURCE CODE\nimport gleam\npub fn go() { gleam.Error(1) }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function go() {\n  return new $gleam.Error(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_nil.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"import gleam\\npub fn go() { gleam.Nil }\\n\"\n---\n----- SOURCE CODE\nimport gleam\npub fn go() { gleam.Nil }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function go() {\n  return undefined;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_nil_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"import gleam\\npub fn go() { gleam.Nil }\\n\"\n---\n----- SOURCE CODE\nimport gleam\npub fn go() { gleam.Nil }\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function go(): undefined;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"import gleam\\npub fn go() { gleam.Ok(1) }\\n\"\n---\n----- SOURCE CODE\nimport gleam\npub fn go() { gleam.Ok(1) }\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function go() {\n  return new $gleam.Ok(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_ok_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"import gleam\\npub fn go() { gleam.Ok(1) }\\n\"\n---\n----- SOURCE CODE\nimport gleam\npub fn go() { gleam.Ok(1) }\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport function go(): _.Result<number, any>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_prelude_value_does_not_conflict_with_local_value.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"\\nimport gleam\\n\\npub type Result(a, e) {\\n  Ok(a)\\n  Error(e)\\n}\\n\\npub fn main() {\\n  gleam.Ok(10)\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\npub fn main() {\n  gleam.Ok(10)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Result$Ok = ($0) => new Ok($0);\nexport const Result$isOk = (value) => value instanceof Ok;\nexport const Result$Ok$0 = (value) => value[0];\n\nexport class Error extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Result$Error = ($0) => new Error($0);\nexport const Result$isError = (value) => value instanceof Error;\nexport const Result$Error$0 = (value) => value[0];\n\nexport function main() {\n  return new $gleam.Ok(10);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_prelude_value_does_not_conflict_with_local_value_constant.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"\\nimport gleam\\n\\npub type Result(a, e) {\\n  Ok(a)\\n  Error(e)\\n}\\n\\npub const error = gleam.Error(\\\"Bad\\\")\\n\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\npub const error = gleam.Error(\"Bad\")\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Result$Ok = ($0) => new Ok($0);\nexport const Result$isOk = (value) => value instanceof Ok;\nexport const Result$Ok$0 = (value) => value[0];\n\nexport class Error extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Result$Error = ($0) => new Error($0);\nexport const Result$isError = (value) => value instanceof Error;\nexport const Result$Error$0 = (value) => value[0];\n\nexport const error = /* @__PURE__ */ new $gleam.Error(\"Bad\");\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__prelude__qualified_prelude_value_does_not_conflict_with_local_value_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/prelude.rs\nexpression: \"\\nimport gleam\\n\\npub type Result(a, e) {\\n  Ok(a)\\n  Error(e)\\n}\\n\\npub fn go(x) {\\n  case x {\\n    gleam.Ok(x) -> x\\n    gleam.Error(_) -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam\n\npub type Result(a, e) {\n  Ok(a)\n  Error(e)\n}\n\npub fn go(x) {\n  case x {\n    gleam.Ok(x) -> x\n    gleam.Error(_) -> 0\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Ok extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Result$Ok = ($0) => new Ok($0);\nexport const Result$isOk = (value) => value instanceof Ok;\nexport const Result$Ok$0 = (value) => value[0];\n\nexport class Error extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\nexport const Result$Error = ($0) => new Error($0);\nexport const Result$isError = (value) => value instanceof Error;\nexport const Result$Error$0 = (value) => value[0];\n\nexport function go(x) {\n  if (x instanceof $gleam.Ok) {\n    let x$1 = x[0];\n    return x$1;\n  } else {\n    return 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__const_record_update_generic_respecialization.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nassertion_line: 119\nexpression: \"\\npub type Box(a) {\\n  Box(name: String, value: a)\\n}\\n\\npub const base = Box(\\\"score\\\", 50)\\npub const updated = Box(..base, value: \\\"Hello\\\")\\n\\npub fn main() {\\n  #(base, updated)\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Box(a) {\n  Box(name: String, value: a)\n}\n\npub const base = Box(\"score\", 50)\npub const updated = Box(..base, value: \"Hello\")\n\npub fn main() {\n  #(base, updated)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Box extends $CustomType {\n  constructor(name, value) {\n    super();\n    this.name = name;\n    this.value = value;\n  }\n}\nexport const Box$Box = (name, value) => new Box(name, value);\nexport const Box$isBox = (value) => value instanceof Box;\nexport const Box$Box$name = (value) => value.name;\nexport const Box$Box$0 = (value) => value.name;\nexport const Box$Box$value = (value) => value.value;\nexport const Box$Box$1 = (value) => value.value;\n\nexport const base = /* @__PURE__ */ new Box(\"score\", 50);\n\nexport const updated = /* @__PURE__ */ new Box(\"score\", \"Hello\");\n\nexport function main() {\n  return [base, updated];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__constant_record_update_with_unlabelled_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int, Float, b: Bool, s: String)\\n}\\n\\npub const record = Wibble(1, 3.14, True, \\\"Hello\\\")\\npub const updated = Wibble(..record, b: False)\\n\\npub fn main() {\\n  updated\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub const record = Wibble(1, 3.14, True, \"Hello\")\npub const updated = Wibble(..record, b: False)\n\npub fn main() {\n  updated\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor($0, $1, b, s) {\n    super();\n    this[0] = $0;\n    this[1] = $1;\n    this.b = b;\n    this.s = s;\n  }\n}\nexport const Wibble$Wibble = ($0, $1, b, s) => new Wibble($0, $1, b, s);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$0 = (value) => value[0];\nexport const Wibble$Wibble$1 = (value) => value[1];\nexport const Wibble$Wibble$b = (value) => value.b;\nexport const Wibble$Wibble$2 = (value) => value.b;\nexport const Wibble$Wibble$s = (value) => value.s;\nexport const Wibble$Wibble$3 = (value) => value.s;\n\nexport const record = /* @__PURE__ */ new Wibble(1, 3.14, true, \"Hello\");\n\nexport const updated = /* @__PURE__ */ new Wibble(1, 3.14, false, \"Hello\");\n\nexport function main() {\n  return updated;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__field_named_constructor_is_escaped.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(constructor: fn() -> Wibble)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(constructor: fn() -> Wibble)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(constructor) {\n    super();\n    this.constructor$ = constructor;\n  }\n}\nexport const Wibble$Wibble = (constructor) => new Wibble(constructor);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$constructor = (value) => value.constructor$;\nexport const Wibble$Wibble$0 = (value) => value.constructor$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__field_named_prototype_is_escaped.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(prototype: String)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(prototype: String)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(prototype) {\n    super();\n    this.prototype$ = prototype;\n  }\n}\nexport const Wibble$Wibble = (prototype) => new Wibble(prototype);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$prototype = (value) => value.prototype$;\nexport const Wibble$Wibble$0 = (value) => value.prototype$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__field_named_then_is_escaped.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(then: fn() -> Int)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(then: fn() -> Int)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor(then$) {\n    super();\n    this.then$ = then$;\n  }\n}\nexport const Wibble$Wibble = (then$) => new Wibble(then$);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$then = (value) => value.then$;\nexport const Wibble$Wibble$0 = (value) => value.then$;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__field_named_x0.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int, x0: String)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int, x0: String)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor($0, x0) {\n    super();\n    this[0] = $0;\n    this.x0 = x0;\n  }\n}\nexport const Wibble$Wibble = ($0, x0) => new Wibble($0, x0);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$0 = (value) => value[0];\nexport const Wibble$Wibble$x0 = (value) => value.x0;\nexport const Wibble$Wibble$1 = (value) => value.x0;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__record_accessor_multiple_variants.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nassertion_line: 18\nexpression: \"\\npub type Person {\\n    Teacher(name: String, title: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_name(person: Person) { person.name }\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Teacher extends $CustomType {\n  constructor(name, title) {\n    super();\n    this.name = name;\n    this.title = title;\n  }\n}\nexport const Person$Teacher = (name, title) => new Teacher(name, title);\nexport const Person$isTeacher = (value) => value instanceof Teacher;\nexport const Person$Teacher$name = (value) => value.name;\nexport const Person$Teacher$0 = (value) => value.name;\nexport const Person$Teacher$title = (value) => value.title;\nexport const Person$Teacher$1 = (value) => value.title;\n\nexport class Student extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Student = (name, age) => new Student(name, age);\nexport const Person$isStudent = (value) => value instanceof Student;\nexport const Person$Student$name = (value) => value.name;\nexport const Person$Student$0 = (value) => value.name;\nexport const Person$Student$age = (value) => value.age;\nexport const Person$Student$1 = (value) => value.age;\n\nexport const Person$name = (value) => value.name;\n\nexport function get_name(person) {\n  return person.name;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__record_accessor_multiple_variants_parameterised_types.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nassertion_line: 61\nexpression: \"\\npub type Person {\\n    Teacher(name: String, age: List(Int), title: String)\\n    Student(name: String, age: List(Int))\\n}\\npub fn get_name(person: Person) { person.name }\\npub fn get_age(person: Person) { person.age }\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, age: List(Int), title: String)\n    Student(name: String, age: List(Int))\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Teacher extends $CustomType {\n  constructor(name, age, title) {\n    super();\n    this.name = name;\n    this.age = age;\n    this.title = title;\n  }\n}\nexport const Person$Teacher = (name, age, title) =>\n  new Teacher(name, age, title);\nexport const Person$isTeacher = (value) => value instanceof Teacher;\nexport const Person$Teacher$name = (value) => value.name;\nexport const Person$Teacher$0 = (value) => value.name;\nexport const Person$Teacher$age = (value) => value.age;\nexport const Person$Teacher$1 = (value) => value.age;\nexport const Person$Teacher$title = (value) => value.title;\nexport const Person$Teacher$2 = (value) => value.title;\n\nexport class Student extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Student = (name, age) => new Student(name, age);\nexport const Person$isStudent = (value) => value instanceof Student;\nexport const Person$Student$name = (value) => value.name;\nexport const Person$Student$0 = (value) => value.name;\nexport const Person$Student$age = (value) => value.age;\nexport const Person$Student$1 = (value) => value.age;\n\nexport const Person$age = (value) => value.age;\nexport const Person$name = (value) => value.name;\n\nexport function get_name(person) {\n  return person.name;\n}\n\nexport function get_age(person) {\n  return person.age;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__record_accessor_multiple_variants_positions_other_than_first.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nassertion_line: 32\nexpression: \"\\npub type Person {\\n    Teacher(name: String, age: Int, title: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_name(person: Person) { person.name }\\npub fn get_age(person: Person) { person.age }\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Teacher extends $CustomType {\n  constructor(name, age, title) {\n    super();\n    this.name = name;\n    this.age = age;\n    this.title = title;\n  }\n}\nexport const Person$Teacher = (name, age, title) =>\n  new Teacher(name, age, title);\nexport const Person$isTeacher = (value) => value instanceof Teacher;\nexport const Person$Teacher$name = (value) => value.name;\nexport const Person$Teacher$0 = (value) => value.name;\nexport const Person$Teacher$age = (value) => value.age;\nexport const Person$Teacher$1 = (value) => value.age;\nexport const Person$Teacher$title = (value) => value.title;\nexport const Person$Teacher$2 = (value) => value.title;\n\nexport class Student extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Student = (name, age) => new Student(name, age);\nexport const Person$isStudent = (value) => value instanceof Student;\nexport const Person$Student$name = (value) => value.name;\nexport const Person$Student$0 = (value) => value.name;\nexport const Person$Student$age = (value) => value.age;\nexport const Person$Student$1 = (value) => value.age;\n\nexport const Person$age = (value) => value.age;\nexport const Person$name = (value) => value.name;\n\nexport function get_name(person) {\n  return person.name;\n}\n\nexport function get_age(person) {\n  return person.age;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__record_accessor_multiple_with_first_position_different_types.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nassertion_line: 47\nexpression: \"\\npub type Person {\\n    Teacher(name: Nil, age: Int)\\n    Student(name: String, age: Int)\\n}\\npub fn get_age(person: Person) { person.age }\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: Nil, age: Int)\n    Student(name: String, age: Int)\n}\npub fn get_age(person: Person) { person.age }\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Teacher extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Teacher = (name, age) => new Teacher(name, age);\nexport const Person$isTeacher = (value) => value instanceof Teacher;\nexport const Person$Teacher$name = (value) => value.name;\nexport const Person$Teacher$0 = (value) => value.name;\nexport const Person$Teacher$age = (value) => value.age;\nexport const Person$Teacher$1 = (value) => value.age;\n\nexport class Student extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Student = (name, age) => new Student(name, age);\nexport const Person$isStudent = (value) => value instanceof Student;\nexport const Person$Student$name = (value) => value.name;\nexport const Person$Student$0 = (value) => value.name;\nexport const Person$Student$age = (value) => value.age;\nexport const Person$Student$1 = (value) => value.age;\n\nexport const Person$age = (value) => value.age;\n\nexport function get_age(person) {\n  return person.age;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__record_accessors.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Person { Person(name: String, age: Int) }\\npub fn get_age(person: Person) { person.age }\\npub fn get_name(person: Person) { person.name }\\n\"\n---\n----- SOURCE CODE\n\npub type Person { Person(name: String, age: Int) }\npub fn get_age(person: Person) { person.age }\npub fn get_name(person: Person) { person.name }\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Person extends $CustomType {\n  constructor(name, age) {\n    super();\n    this.name = name;\n    this.age = age;\n  }\n}\nexport const Person$Person = (name, age) => new Person(name, age);\nexport const Person$isPerson = (value) => value instanceof Person;\nexport const Person$Person$name = (value) => value.name;\nexport const Person$Person$0 = (value) => value.name;\nexport const Person$Person$age = (value) => value.age;\nexport const Person$Person$1 = (value) => value.age;\n\nexport function get_age(person) {\n  return person.age;\n}\n\nexport function get_name(person) {\n  return person.name;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__records__record_update_with_unlabelled_fields.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/records.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int, Float, b: Bool, s: String)\\n}\\n\\npub fn main() {\\n  let record = Wibble(1, 3.14, True, \\\"Hello\\\")\\n  Wibble(..record, b: False)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int, Float, b: Bool, s: String)\n}\n\npub fn main() {\n  let record = Wibble(1, 3.14, True, \"Hello\")\n  Wibble(..record, b: False)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class Wibble extends $CustomType {\n  constructor($0, $1, b, s) {\n    super();\n    this[0] = $0;\n    this[1] = $1;\n    this.b = b;\n    this.s = s;\n  }\n}\nexport const Wibble$Wibble = ($0, $1, b, s) => new Wibble($0, $1, b, s);\nexport const Wibble$isWibble = (value) => value instanceof Wibble;\nexport const Wibble$Wibble$0 = (value) => value[0];\nexport const Wibble$Wibble$1 = (value) => value[1];\nexport const Wibble$Wibble$b = (value) => value.b;\nexport const Wibble$Wibble$2 = (value) => value.b;\nexport const Wibble$Wibble$s = (value) => value.s;\nexport const Wibble$Wibble$3 = (value) => value.s;\n\nexport function main() {\n  let record = new Wibble(1, 3.14, true, \"Hello\");\n  return new Wibble(record[0], record[1], false, record.s);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__recursion__not_tco_due_to_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/recursion.rs\nexpression: \"\\npub fn main(x) {\\n  let z = {\\n    let y = x\\n    main(y - 1)\\n  }\\n  z\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let z = {\n    let y = x\n    main(y - 1)\n  }\n  z\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(x) {\n  let _block;\n  {\n    let y = x;\n    _block = main(y - 1);\n  }\n  let z = _block;\n  return z;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__recursion__shadowing_so_not_recursive.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/recursion.rs\nexpression: \"\\npub fn map(map) {\\n  map()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn map(map) {\n  map()\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function map(map) {\n  return map();\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__recursion__tco.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/recursion.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0 -> Nil\\n    _ -> main(x - 1)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0 -> Nil\n    _ -> main(x - 1)\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(loop$x) {\n  while (true) {\n    let x = loop$x;\n    if (x === 0) {\n      return undefined;\n    } else {\n      loop$x = x - 1;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__recursion__tco_case_block.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/recursion.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0 -> Nil\\n    _ -> {\\n      let y = x\\n      main(y - 1)\\n    }\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0 -> Nil\n    _ -> {\n      let y = x\n      main(y - 1)\n    }\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function main(loop$x) {\n  while (true) {\n    let x = loop$x;\n    if (x === 0) {\n      return undefined;\n    } else {\n      let y = x;\n      loop$x = y - 1;\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__aliased_error.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam.{Error as Thing}\\npub fn main() { Thing(1) }\"\n---\n----- SOURCE CODE\nimport gleam.{Error as Thing}\npub fn main() { Thing(1) }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Error as Thing } from \"../gleam.mjs\";\n\nexport function main() {\n  return new Thing(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__aliased_error_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam.{Error as Thing}\\npub fn main() { Thing }\"\n---\n----- SOURCE CODE\nimport gleam.{Error as Thing}\npub fn main() { Thing }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Error as Thing } from \"../gleam.mjs\";\n\nexport function main() {\n  return (var0) => { return new Thing(var0); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__aliased_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam.{Ok as Thing}\\npub fn main() { Thing(1) }\"\n---\n----- SOURCE CODE\nimport gleam.{Ok as Thing}\npub fn main() { Thing(1) }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok as Thing } from \"../gleam.mjs\";\n\nexport function main() {\n  return new Thing(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__aliased_ok_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam.{Ok as Thing}\\npub fn main() { Thing }\"\n---\n----- SOURCE CODE\nimport gleam.{Ok as Thing}\npub fn main() { Thing }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\nimport { Ok as Thing } from \"../gleam.mjs\";\n\nexport function main() {\n  return (var0) => { return new Thing(var0); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__error.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"pub fn main() { Error(1) }\"\n---\n----- SOURCE CODE\npub fn main() { Error(1) }\n\n----- COMPILED JAVASCRIPT\nimport { Error } from \"../gleam.mjs\";\n\nexport function main() {\n  return new Error(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__error_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"pub fn main() { Error }\"\n---\n----- SOURCE CODE\npub fn main() { Error }\n\n----- COMPILED JAVASCRIPT\nimport { Error } from \"../gleam.mjs\";\n\nexport function main() {\n  return (var0) => { return new Error(var0); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"pub fn main() { Ok(1) }\"\n---\n----- SOURCE CODE\npub fn main() { Ok(1) }\n\n----- COMPILED JAVASCRIPT\nimport { Ok } from \"../gleam.mjs\";\n\nexport function main() {\n  return new Ok(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__ok_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"pub fn main() { Ok }\"\n---\n----- SOURCE CODE\npub fn main() { Ok }\n\n----- COMPILED JAVASCRIPT\nimport { Ok } from \"../gleam.mjs\";\n\nexport function main() {\n  return (var0) => { return new Ok(var0); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__qualified_error.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam\\npub fn main() { gleam.Error(1) }\"\n---\n----- SOURCE CODE\nimport gleam\npub fn main() { gleam.Error(1) }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function main() {\n  return new $gleam.Error(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__qualified_error_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam\\npub fn main() { gleam.Error }\"\n---\n----- SOURCE CODE\nimport gleam\npub fn main() { gleam.Error }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function main() {\n  return (var0) => { return new $gleam.Error(var0); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__qualified_ok.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam\\npub fn main() { gleam.Ok(1) }\"\n---\n----- SOURCE CODE\nimport gleam\npub fn main() { gleam.Ok(1) }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function main() {\n  return new $gleam.Ok(1);\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__results__qualified_ok_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/results.rs\nexpression: \"import gleam\\npub fn main() { gleam.Ok }\"\n---\n----- SOURCE CODE\nimport gleam\npub fn main() { gleam.Ok }\n\n----- COMPILED JAVASCRIPT\nimport * as $gleam from \"../gleam.mjs\";\n\nexport function main() {\n  return (var0) => { return new $gleam.Ok(var0); };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__ascii_as_unicode_escape_sequence.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn y() -> String {\\n  \\\"\\\\u{79}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn y() -> String {\n  \"\\u{79}\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function y() {\n  return \"\\u{79}\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nassertion_line: 84\nexpression: \"\\npub fn go(a) {\\n  case a {\\n    \\\"\\\" -> 0\\n    \\\"one\\\" -> 1\\n    \\\"two\\\" -> 2\\n    _ -> 3\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  case a {\n    \"\" -> 0\n    \"one\" -> 1\n    \"two\" -> 2\n    _ -> 3\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(a) {\n  if (a === \"\") {\n    return 0;\n  } else if (a === \"one\") {\n    return 1;\n  } else if (a === \"two\") {\n    return 2;\n  } else {\n    return 3;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__const_concat.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nassertion_line: 230\nexpression: \"\\npub const cute = \\\"cute\\\"\\npub const cute_bee = cute <> \\\"bee\\\"\\n\\npub fn main() {\\n  cute_bee\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const cute = \"cute\"\npub const cute_bee = cute <> \"bee\"\n\npub fn main() {\n  cute_bee\n}\n\n\n----- COMPILED JAVASCRIPT\nexport const cute = \"cute\";\n\nexport const cute_bee = cute + \"bee\";\n\nexport function main() {\n  return cute_bee;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__const_concat_multiple.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nassertion_line: 244\nexpression: \"\\npub const cute = \\\"cute\\\"\\npub const cute_bee = cute <> \\\"bee\\\"\\npub const cute_cute_bee_buzz = cute <> cute_bee <> \\\"buzz\\\"\\n\\npub fn main() {\\n  cute_cute_bee_buzz\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const cute = \"cute\"\npub const cute_bee = cute <> \"bee\"\npub const cute_cute_bee_buzz = cute <> cute_bee <> \"buzz\"\n\npub fn main() {\n  cute_cute_bee_buzz\n}\n\n\n----- COMPILED JAVASCRIPT\nexport const cute = \"cute\";\n\nexport const cute_bee = cute + \"bee\";\n\nexport const cute_cute_bee_buzz = cute + cute_bee + \"buzz\";\n\nexport function main() {\n  return cute_cute_bee_buzz;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__discard_concat_rest_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" <> _ -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" <> _ -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.startsWith(\"Hello, \")) {\n    return undefined;\n  } else {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__equality.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nassertion_line: 71\nexpression: \"\\npub fn go(a) {\\n  a == \\\"ok\\\"\\n  a != \\\"ok\\\"\\n  a == a\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  a == \"ok\"\n  a != \"ok\"\n  a == a\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(a) {\n  a === \"ok\";\n  a !== \"ok\";\n  return a === a;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_concat.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nassertion_line: 100\nexpression: \"\\npub fn go() {\\n  \\\"Hello, \\\" <> \\\"Joe\\\"\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  \"Hello, \" <> \"Joe\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return \"Hello, \" + \"Joe\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_literals.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nassertion_line: 49\nexpression: \"\\npub fn go() {\\n  \\\"Hello, Gleam!\\\"\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  \"Hello, Gleam!\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return \"Hello, Gleam!\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_patterns.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  let assert \\\"Hello\\\" = x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  let assert \"Hello\" = x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(x) {\n  if (!(x === \"Hello\")) {\n    throw makeError(\n      \"let_assert\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"go\",\n      \"Pattern match failed, no pattern matched the value.\",\n      { value: x, start: 18, end: 40, pattern_start: 29, pattern_end: 36 }\n    )\n  }\n  return x;\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_prefix.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" <> name -> name\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" <> name -> name\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.startsWith(\"Hello, \")) {\n    let name = x.slice(7);\n    return name;\n  } else {\n    return \"Unknown\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_prefix_assignment.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" as greeting <> name -> greeting\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.startsWith(\"Hello, \")) {\n    let greeting = \"Hello, \";\n    let name = x.slice(7);\n    return greeting;\n  } else {\n    return \"Unknown\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_prefix_assignment_with_multiple_subjects.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"1\\\" as prefix <> _ | \\\"11\\\" as prefix <> _ -> prefix\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"1\" as prefix <> _ | \"11\" as prefix <> _ -> prefix\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.startsWith(\"1\")) {\n    let prefix = \"1\";\n    return prefix;\n  } else {\n    return \"Unknown\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_prefix_assignment_with_utf_escape_sequence.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"\\\\u{0032} \\\" as greeting <> name -> greeting\\n    \\\"\\\\u{0007ff} \\\" as greeting <> name -> greeting\\n    \\\"\\\\u{00ffff} \\\" as greeting <> name -> greeting\\n    \\\"\\\\u{10ffff} \\\" as greeting <> name -> greeting\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"\\u{0032} \" as greeting <> name -> greeting\n    \"\\u{0007ff} \" as greeting <> name -> greeting\n    \"\\u{00ffff} \" as greeting <> name -> greeting\n    \"\\u{10ffff} \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.startsWith(\"\\u{0032} \")) {\n    let greeting = \"\\u{0032} \";\n    let name = x.slice(2);\n    return greeting;\n  } else if (x.startsWith(\"\\u{0007ff} \")) {\n    let greeting = \"\\u{0007ff} \";\n    let name = x.slice(2);\n    return greeting;\n  } else if (x.startsWith(\"\\u{00ffff} \")) {\n    let greeting = \"\\u{00ffff} \";\n    let name = x.slice(2);\n    return greeting;\n  } else if (x.startsWith(\"\\u{10ffff} \")) {\n    let greeting = \"\\u{10ffff} \";\n    let name = x.slice(3);\n    return greeting;\n  } else {\n    return \"Unknown\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_prefix_shadowing.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    \\\"Hello, \\\" as x <> name -> x\\n    _ -> \\\"Unknown\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    \"Hello, \" as x <> name -> x\n    _ -> \"Unknown\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  if (x.startsWith(\"Hello, \")) {\n    let x$1 = \"Hello, \";\n    let name = x.slice(7);\n    return x$1;\n  } else {\n    return \"Unknown\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__string_prefix_utf16.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn go(x) {\\n  case \\\"Θ wibble wobble\\\" {\\n    \\\"Θ\\\" <> rest -> rest\\n    _ -> \\\"\\\"\\n  }\\n  case \\\"🫥 is neutral dotted\\\" {\\n    \\\"🫥\\\" <> rest -> rest\\n    _ -> \\\"\\\"\\n  }\\n  case \\\"🇺🇸 is a cluster\\\" {\\n    \\\"🇺🇸\\\" <> rest -> rest\\n    _ -> \\\"\\\"\\n  }\\n  case \\\"\\\\\\\" is a an escaped quote\\\" {\\n    \\\"\\\\\\\"\\\" <> rest -> rest\\n    _ -> \\\"\\\"\\n  }\\n  case \\\"\\\\\\\\ is a an escaped backslash\\\" {\\n    \\\"\\\\\\\\\\\" <> rest -> rest\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case \"Θ wibble wobble\" {\n    \"Θ\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"🫥 is neutral dotted\" {\n    \"🫥\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"🇺🇸 is a cluster\" {\n    \"🇺🇸\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"\\\" is a an escaped quote\" {\n    \"\\\"\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"\\\\ is a an escaped backslash\" {\n    \"\\\\\" <> rest -> rest\n    _ -> \"\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let $ = \"Θ wibble wobble\";\n  if ($.startsWith(\"Θ\")) {\n    let rest = $.slice(1);\n    rest\n  } else {\n    \"\"\n  }\n  let $1 = \"🫥 is neutral dotted\";\n  if ($1.startsWith(\"🫥\")) {\n    let rest = $1.slice(2);\n    rest\n  } else {\n    \"\"\n  }\n  let $2 = \"🇺🇸 is a cluster\";\n  if ($2.startsWith(\"🇺🇸\")) {\n    let rest = $2.slice(4);\n    rest\n  } else {\n    \"\"\n  }\n  let $3 = \"\\\" is a an escaped quote\";\n  if ($3.startsWith(\"\\\"\")) {\n    let rest = $3.slice(1);\n    rest\n  } else {\n    \"\"\n  }\n  let $4 = \"\\\\ is a an escaped backslash\";\n  if ($4.startsWith(\"\\\\\")) {\n    let rest = $4.slice(1);\n    return rest;\n  } else {\n    return \"\";\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__unicode1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn emoji() -> String {\\n  \\\"\\\\u{1f600}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn emoji() -> String {\n  \"\\u{1f600}\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function emoji() {\n  return \"\\u{1f600}\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__unicode2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn y_with_dieresis() -> String {\\n  \\\"\\\\u{0308}y\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn y_with_dieresis() -> String {\n  \"\\u{0308}y\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function y_with_dieresis() {\n  return \"\\u{0308}y\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__strings__unicode_escape_sequence_6_digits.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/strings.rs\nexpression: \"\\npub fn unicode_escape_sequence_6_digits() -> String {\\n  \\\"\\\\u{10abcd}\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn unicode_escape_sequence_6_digits() -> String {\n  \"\\u{10abcd}\"\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function unicode_escape_sequence_6_digits() {\n  return \"\\u{10abcd}\";\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__as_expression.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nassertion_line: 51\nexpression: \"\\npub fn go(f) {\\n  let boop = todo as \\\"I should do this\\\"\\n  f(todo as \\\"Boom\\\")\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(f) {\n  let boop = todo as \"I should do this\"\n  f(todo as \"Boom\")\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go(f) {\n  let _block;\n  throw makeError(\"todo\", FILEPATH, \"my/mod\", 3, \"go\", \"I should do this\", {})\n  let boop = _block;\n  return f(\n    (() => {\n      throw makeError(\"todo\", FILEPATH, \"my/mod\", 4, \"go\", \"Boom\", {})\n    })(),\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__case_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nassertion_line: 64\nexpression: \"\\npub fn unimplemented(message) {\\n  panic as case message {\\n    Ok(message) -> message\\n    Error(_) -> \\\"No message provided\\\"\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn unimplemented(message) {\n  panic as case message {\n    Ok(message) -> message\n    Error(_) -> \"No message provided\"\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { Ok, makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function unimplemented(message) {\n  let _block;\n  if (message instanceof Ok) {\n    let message$1 = message[0];\n    _block = message$1;\n  } else {\n    _block = \"No message provided\";\n  }\n  throw makeError(\"panic\", FILEPATH, \"my/mod\", 3, \"unimplemented\", _block, {})\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__inside_fn.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nassertion_line: 78\nexpression: \"\\npub fn main() {\\n  fn() { todo }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  fn() { todo }\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  return () => {\n    throw makeError(\n      \"todo\",\n      FILEPATH,\n      \"my/mod\",\n      3,\n      \"main\",\n      \"`todo` expression evaluated. This code has not yet been implemented.\",\n      {}\n    )\n  };\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__with_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nassertion_line: 27\nexpression: \"\\npub fn go() {\\n  todo as \\\"I should do this\\\"\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  todo as \"I should do this\"\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go() {\n  throw makeError(\"todo\", FILEPATH, \"my/mod\", 3, \"go\", \"I should do this\", {})\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__with_message_expr.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nassertion_line: 38\nexpression: \"\\npub fn go() {\\n  let x = \\\"I should \\\" <> \\\"do this\\\"\\n  todo as x\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  let x = \"I should \" <> \"do this\"\n  todo as x\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go() {\n  let x = \"I should \" + \"do this\";\n  throw makeError(\"todo\", FILEPATH, \"my/mod\", 4, \"go\", x, {})\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__without_message.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nassertion_line: 5\nexpression: \"\\npub fn go() {\\n    todo\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n    todo\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function go() {\n  throw makeError(\n    \"todo\",\n    FILEPATH,\n    \"my/mod\",\n    3,\n    \"go\",\n    \"`todo` expression evaluated. This code has not yet been implemented.\",\n    {}\n  )\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__without_message_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/todo.rs\nexpression: \"\\npub fn go() {\\n    todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n    todo\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function go(): any;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__case.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 122\nexpression: \"\\npub fn go(a) {\\n  case a {\\n    #(2, a) -> a\\n    #(1, 1) -> 1\\n    #(a, b) -> a + b\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(a) {\n  case a {\n    #(2, a) -> a\n    #(1, 1) -> 1\n    #(a, b) -> a + b\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(a) {\n  let $ = a[0];\n  if ($ === 2) {\n    let a$1 = a[1];\n    return a$1;\n  } else if ($ === 1) {\n    let $1 = a[1];\n    if ($1 === 1) {\n      return 1;\n    } else {\n      let a$1 = $;\n      let b = $1;\n      return a$1 + b;\n    }\n  } else {\n    let a$1 = $;\n    let b = a[1];\n    return a$1 + b;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__constant_tuples.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 85\nexpression: \"\\npub const a = \\\"Hello\\\"\\npub const b = 1\\npub const c = 2.0\\npub const e = #(\\\"bob\\\", \\\"dug\\\")\\n        \"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const a = \"Hello\"\npub const b = 1\npub const c = 2.0\npub const e = #(\"bob\", \"dug\")\n        \n\n----- COMPILED JAVASCRIPT\nexport const a = \"Hello\";\n\nexport const b = 1;\n\nexport const c = 2.0;\n\nexport const e = [\"bob\", \"dug\"];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__constant_tuples1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 97\nexpression: \"\\npub const e = #(\\n  \\\"loooooooooooooong\\\", \\\"loooooooooooong\\\", \\\"loooooooooooooong\\\",\\n  \\\"loooooooooooooong\\\", \\\"loooooooooooong\\\", \\\"loooooooooooooong\\\",\\n)\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub const e = #(\n  \"loooooooooooooong\", \"loooooooooooong\", \"loooooooooooooong\",\n  \"loooooooooooooong\", \"loooooooooooong\", \"loooooooooooooong\",\n)\n\n\n----- COMPILED JAVASCRIPT\nexport const e = [\n  \"loooooooooooooong\",\n  \"loooooooooooong\",\n  \"loooooooooooooong\",\n  \"loooooooooooooong\",\n  \"loooooooooooong\",\n  \"loooooooooooooong\",\n];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__nested_pattern.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 137\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    #(2, #(a, b)) -> a + b\\n    _ -> 1\\n  }\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    #(2, #(a, b)) -> a + b\n    _ -> 1\n  }\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go(x) {\n  let $ = x[0];\n  if ($ === 2) {\n    let a = x[1][0];\n    let b = x[1][1];\n    return a + b;\n  } else {\n    return 1;\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 5\nexpression: \"\\npub fn go() {\\n  #(\\\"1\\\", \\\"2\\\", \\\"3\\\")\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(\"1\", \"2\", \"3\")\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return [\"1\", \"2\", \"3\"];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 16\nexpression: \"\\npub fn go() {\\n  #(\\n    \\\"1111111111111111111111111111111\\\",\\n    #(\\\"1111111111111111111111111111111\\\", \\\"2\\\", \\\"3\\\"),\\n    \\\"3\\\",\\n  )\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(\n    \"1111111111111111111111111111111\",\n    #(\"1111111111111111111111111111111\", \"2\", \"3\"),\n    \"3\",\n  )\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return [\n    \"1111111111111111111111111111111\",\n    [\"1111111111111111111111111111111\", \"2\", \"3\"],\n    \"3\",\n  ];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple_access.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 42\nexpression: \"\\npub fn go() {\\n  #(1, 2).0\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(1, 2).0\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return [1, 2][0];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple_formatting_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nexpression: \"\\npub const e = #(\\n  \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\",\\n  \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\",\\n  \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"a\\\",\\n)\\n\"\n---\n----- SOURCE CODE\n\npub const e = #(\n  \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\",\n  \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\",\n  \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\",\n)\n\n\n----- TYPESCRIPT DEFINITIONS\nexport const e: [\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string,\n  string\n];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple_typescript.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nexpression: \"\\npub fn go() {\\n  #(\\\"1\\\", \\\"2\\\", \\\"3\\\")\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(\"1\", \"2\", \"3\")\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nexport function go(): [string, string, string];\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple_with_block_element.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 53\nexpression: \"\\npub fn go() {\\n  #(\\n    \\\"1\\\",\\n    {\\n      \\\"2\\\"\\n      \\\"3\\\"\\n    },\\n  )\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(\n    \"1\",\n    {\n      \"2\"\n      \"3\"\n    },\n  )\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return [\n    \"1\",\n    (() => {\n      \"2\";\n      return \"3\";\n    })(),\n  ];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple_with_block_element1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/tuples.rs\nassertion_line: 70\nexpression: \"\\npub fn go() {\\n  #(\\n    \\\"1111111111111111111111111111111\\\",\\n    #(\\\"1111111111111111111111111111111\\\", \\\"2\\\", \\\"3\\\"),\\n    \\\"3\\\",\\n  )\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(\n    \"1111111111111111111111111111111\",\n    #(\"1111111111111111111111111111111\", \"2\", \"3\"),\n    \"3\",\n  )\n}\n\n\n----- COMPILED JAVASCRIPT\nexport function go() {\n  return [\n    \"1111111111111111111111111111111\",\n    [\"1111111111111111111111111111111\", \"2\", \"3\"],\n    \"3\",\n  ];\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__type_alias__import_indirect_type_alias.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/type_alias.rs\nexpression: \"\\nimport wobble\\n\\npub fn main(x: wobble.Wobble) {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport wobble\n\npub fn main(x: wobble.Wobble) {\n  Nil\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as $wibble from \"../../wibble/wibble.d.mts\";\n\nexport function main(x: $wibble.Wibble$): undefined;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__type_alias__private_type_in_opaque_type.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/type_alias.rs\nexpression: \"\\ntype PrivateType {\\n  PrivateType\\n}\\n\\npub opaque type OpaqueType {\\n  OpaqueType(PrivateType)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype PrivateType {\n  PrivateType\n}\n\npub opaque type OpaqueType {\n  OpaqueType(PrivateType)\n}\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\ndeclare class PrivateType extends _.CustomType {}\n\ntype PrivateType$ = PrivateType;\n\ndeclare class OpaqueType extends _.CustomType {\n  /** @deprecated */\n  constructor(argument$0: PrivateType$);\n  /** @deprecated */\n  0: PrivateType$;\n}\n\nexport type OpaqueType$ = OpaqueType;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__type_alias__type_alias.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/type_alias.rs\nexpression: \"\\npub type Headers = List(#(String, String))\\n\"\n---\n----- SOURCE CODE\n\npub type Headers = List(#(String, String))\n\n\n----- TYPESCRIPT DEFINITIONS\nimport type * as _ from \"../gleam.d.mts\";\n\nexport type Headers = _.List<[string, string]>;\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__use___arity_1.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- pair()\\n  123\\n}\\n\\nfn pair(f) {\\n  let x = f()\\n  #(x, x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- pair()\n  123\n}\n\nfn pair(f) {\n  let x = f()\n  #(x, x)\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction pair(f) {\n  let x = f();\n  return [x, x];\n}\n\nexport function main() {\n  return pair(() => { return 123; });\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__use___arity_2.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- pair(1.0)\\n  123\\n}\\n\\nfn pair(x, f) {\\n  let y = f()\\n  #(x, y)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- pair(1.0)\n  123\n}\n\nfn pair(x, f) {\n  let y = f()\n  #(x, y)\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction pair(x, f) {\n  let y = f();\n  return [x, y];\n}\n\nexport function main() {\n  return pair(1.0, () => { return 123; });\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__use___arity_3.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- trip(1.0, \\\"\\\")\\n  123\\n}\\n\\nfn trip(x, y, f) {\\n  let z = f()\\n  #(x, y, z)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- trip(1.0, \"\")\n  123\n}\n\nfn trip(x, y, f) {\n  let z = f()\n  #(x, y, z)\n}\n\n\n----- COMPILED JAVASCRIPT\nfunction trip(x, y, f) {\n  let z = f();\n  return [x, y, z];\n}\n\nexport function main() {\n  return trip(1.0, \"\", () => { return 123; });\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__use___no_callback_body.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/use_.rs\nassertion_line: 56\nexpression: \"\\npub fn main() {\\n  let thingy = fn(f) { f() }\\n  use <- thingy()\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let thingy = fn(f) { f() }\n  use <- thingy()\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { makeError } from \"../gleam.mjs\";\n\nconst FILEPATH = \"src/module.gleam\";\n\nexport function main() {\n  let thingy = (f) => { return f(); };\n  return thingy(\n    () => {\n      throw makeError(\n        \"todo\",\n        FILEPATH,\n        \"my/mod\",\n        4,\n        \"main\",\n        \"`todo` expression evaluated. This code has not yet been implemented.\",\n        {}\n      )\n    },\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__use___patterns.snap",
    "content": "---\nsource: compiler-core/src/javascript/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use Box(x) <- apply(Box(1))\\n  x\\n}\\n\\ntype Box(a) {\\n  Box(a)\\n}\\n\\nfn apply(arg, fun) {\\n  fun(arg)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use Box(x) <- apply(Box(1))\n  x\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg)\n}\n\n\n----- COMPILED JAVASCRIPT\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nclass Box extends $CustomType {\n  constructor($0) {\n    super();\n    this[0] = $0;\n  }\n}\n\nfunction apply(arg, fun) {\n  return fun(arg);\n}\n\nexport function main() {\n  return apply(\n    new Box(1),\n    (_use0) => {\n      let x;\n      x = _use0[0];\n      return x;\n    },\n  );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/strings.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn unicode1() {\n    assert_js!(\n        r#\"\npub fn emoji() -> String {\n  \"\\u{1f600}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn unicode2() {\n    assert_js!(\n        r#\"\npub fn y_with_dieresis() -> String {\n  \"\\u{0308}y\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn ascii_as_unicode_escape_sequence() {\n    assert_js!(\n        r#\"\npub fn y() -> String {\n  \"\\u{79}\"\n}\n\"#,\n    )\n}\n\n#[test]\nfn unicode_escape_sequence_6_digits() {\n    assert_js!(\n        r#\"\npub fn unicode_escape_sequence_6_digits() -> String {\n  \"\\u{10abcd}\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_literals() {\n    assert_js!(\n        r#\"\npub fn go() {\n  \"Hello, Gleam!\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_patterns() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  let assert \"Hello\" = x\n}\n\"#,\n    );\n}\n\n#[test]\nfn equality() {\n    assert_js!(\n        r#\"\npub fn go(a) {\n  a == \"ok\"\n  a != \"ok\"\n  a == a\n}\n\"#,\n    );\n}\n\n#[test]\nfn case() {\n    assert_js!(\n        r#\"\npub fn go(a) {\n  case a {\n    \"\" -> 0\n    \"one\" -> 1\n    \"two\" -> 2\n    _ -> 3\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_concat() {\n    assert_js!(\n        r#\"\npub fn go() {\n  \"Hello, \" <> \"Joe\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_prefix() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" <> name -> name\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_prefix_utf16() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case \"Θ wibble wobble\" {\n    \"Θ\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"🫥 is neutral dotted\" {\n    \"🫥\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"🇺🇸 is a cluster\" {\n    \"🇺🇸\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"\\\" is a an escaped quote\" {\n    \"\\\"\" <> rest -> rest\n    _ -> \"\"\n  }\n  case \"\\\\ is a an escaped backslash\" {\n    \"\\\\\" <> rest -> rest\n    _ -> \"\"\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn discard_concat_rest_pattern() {\n    // We can discard the right hand side, it parses and type checks ok\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" <> _ -> Nil\n    _ -> Nil\n  }\n}\n\"#,\n    );\n}\n\n#[test]\nfn string_prefix_assignment() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_assignment_with_utf_escape_sequence() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"\\u{0032} \" as greeting <> name -> greeting\n    \"\\u{0007ff} \" as greeting <> name -> greeting\n    \"\\u{00ffff} \" as greeting <> name -> greeting\n    \"\\u{10ffff} \" as greeting <> name -> greeting\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn string_prefix_shadowing() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"Hello, \" as x <> name -> x\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n// https://github.com/gleam-lang/gleam/issues/2471\n#[test]\nfn string_prefix_assignment_with_multiple_subjects() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    \"1\" as prefix <> _ | \"11\" as prefix <> _ -> prefix\n    _ -> \"Unknown\"\n  }\n}\n\"#,\n    )\n}\n\n#[test]\nfn const_concat() {\n    assert_js!(\n        r#\"\npub const cute = \"cute\"\npub const cute_bee = cute <> \"bee\"\n\npub fn main() {\n  cute_bee\n}\n\"#\n    );\n}\n\n#[test]\nfn const_concat_multiple() {\n    assert_js!(\n        r#\"\npub const cute = \"cute\"\npub const cute_bee = cute <> \"bee\"\npub const cute_cute_bee_buzz = cute <> cute_bee <> \"buzz\"\n\npub fn main() {\n  cute_cute_bee_buzz\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/todo.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn without_message() {\n    assert_js!(\n        r#\"\npub fn go() {\n    todo\n}\n\"#,\n    );\n}\n\n#[test]\nfn without_message_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn go() {\n    todo\n}\n\"#,\n    );\n}\n\n#[test]\nfn with_message() {\n    assert_js!(\n        r#\"\npub fn go() {\n  todo as \"I should do this\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn with_message_expr() {\n    assert_js!(\n        r#\"\npub fn go() {\n  let x = \"I should \" <> \"do this\"\n  todo as x\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1238\n#[test]\nfn as_expression() {\n    assert_js!(\n        r#\"\npub fn go(f) {\n  let boop = todo as \"I should do this\"\n  f(todo as \"Boom\")\n}\n\"#,\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4471\n#[test]\nfn case_message() {\n    assert_js!(\n        r#\"\npub fn unimplemented(message) {\n  panic as case message {\n    Ok(message) -> message\n    Error(_) -> \"No message provided\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn inside_fn() {\n    assert_js!(\n        r#\"\npub fn main() {\n  fn() { todo }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/tuples.rs",
    "content": "use crate::{assert_js, assert_ts_def};\n\n#[test]\nfn tuple() {\n    assert_js!(\n        r#\"\npub fn go() {\n  #(\"1\", \"2\", \"3\")\n}\n\"#,\n    );\n}\n\n#[test]\nfn tuple1() {\n    assert_js!(\n        r#\"\npub fn go() {\n  #(\n    \"1111111111111111111111111111111\",\n    #(\"1111111111111111111111111111111\", \"2\", \"3\"),\n    \"3\",\n  )\n}\n\"#,\n    );\n}\n\n#[test]\nfn tuple_typescript() {\n    assert_ts_def!(\n        r#\"\npub fn go() {\n  #(\"1\", \"2\", \"3\")\n}\n\"#,\n    );\n}\n\n#[test]\nfn tuple_access() {\n    assert_js!(\n        r#\"\npub fn go() {\n  #(1, 2).0\n}\n\"#,\n    )\n}\n\n#[test]\nfn tuple_with_block_element() {\n    assert_js!(\n        r#\"\npub fn go() {\n  #(\n    \"1\",\n    {\n      \"2\"\n      \"3\"\n    },\n  )\n}\n\"#,\n    );\n}\n\n#[test]\nfn tuple_with_block_element1() {\n    assert_js!(\n        r#\"\npub fn go() {\n  #(\n    \"1111111111111111111111111111111\",\n    #(\"1111111111111111111111111111111\", \"2\", \"3\"),\n    \"3\",\n  )\n}\n\"#,\n    );\n}\n\n#[test]\nfn constant_tuples() {\n    assert_js!(\n        r#\"\npub const a = \"Hello\"\npub const b = 1\npub const c = 2.0\npub const e = #(\"bob\", \"dug\")\n        \"#,\n    );\n}\n\n#[test]\nfn constant_tuples1() {\n    assert_js!(\n        r#\"\npub const e = #(\n  \"loooooooooooooong\", \"loooooooooooong\", \"loooooooooooooong\",\n  \"loooooooooooooong\", \"loooooooooooong\", \"loooooooooooooong\",\n)\n\"#\n    );\n}\n\n#[test]\nfn tuple_formatting_typescript() {\n    assert_ts_def!(\n        r#\"\npub const e = #(\n  \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\",\n  \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\",\n  \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\",\n)\n\"#\n    );\n}\n\n#[test]\nfn case() {\n    assert_js!(\n        r#\"\npub fn go(a) {\n  case a {\n    #(2, a) -> a\n    #(1, 1) -> 1\n    #(a, b) -> a + b\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn nested_pattern() {\n    assert_js!(\n        r#\"\npub fn go(x) {\n  case x {\n    #(2, #(a, b)) -> a + b\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/type_alias.rs",
    "content": "use crate::assert_ts_def;\n\n#[test]\nfn type_alias() {\n    assert_ts_def!(\n        r#\"\npub type Headers = List(#(String, String))\n\"#,\n    );\n}\n\n#[test]\nfn private_type_in_opaque_type() {\n    assert_ts_def!(\n        r#\"\ntype PrivateType {\n  PrivateType\n}\n\npub opaque type OpaqueType {\n  OpaqueType(PrivateType)\n}\n\"#,\n    );\n}\n\n#[test]\nfn import_indirect_type_alias() {\n    assert_ts_def!(\n        (\n            \"wibble\",\n            \"wibble\",\n            r#\"\npub type Wibble {\n  Wibble(Int)\n}\n\"#\n        ),\n        (\n            \"wobble\",\n            \"wobble\",\n            r#\"\nimport wibble\npub type Wobble = wibble.Wibble\n\"#\n        ),\n        r#\"\nimport wobble\n\npub fn main(x: wobble.Wobble) {\n  Nil\n}\n\"#,\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests/use_.rs",
    "content": "use crate::assert_js;\n\n#[test]\nfn arity_1() {\n    assert_js!(\n        r#\"\npub fn main() {\n  use <- pair()\n  123\n}\n\nfn pair(f) {\n  let x = f()\n  #(x, x)\n}\n\"#,\n    )\n}\n\n#[test]\nfn arity_2() {\n    assert_js!(\n        r#\"\npub fn main() {\n  use <- pair(1.0)\n  123\n}\n\nfn pair(x, f) {\n  let y = f()\n  #(x, y)\n}\n\"#,\n    )\n}\n\n#[test]\nfn arity_3() {\n    assert_js!(\n        r#\"\npub fn main() {\n  use <- trip(1.0, \"\")\n  123\n}\n\nfn trip(x, y, f) {\n  let z = f()\n  #(x, y, z)\n}\n\"#,\n    )\n}\n\n#[test]\nfn no_callback_body() {\n    assert_js!(\n        r#\"\npub fn main() {\n  let thingy = fn(f) { f() }\n  use <- thingy()\n}\n\"#\n    );\n}\n\n#[test]\nfn patterns() {\n    assert_js!(\n        r#\"\npub fn main() {\n  use Box(x) <- apply(Box(1))\n  x\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg)\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/tests.rs",
    "content": "use crate::{\n    analyse::TargetSupport,\n    build::{Origin, Target},\n    config::PackageConfig,\n    inline,\n    javascript::*,\n    uid::UniqueIdGenerator,\n    warning::{TypeWarningEmitter, WarningEmitter},\n};\nuse camino::{Utf8Path, Utf8PathBuf};\n\nmod assert;\nmod assignments;\nmod bit_arrays;\nmod blocks;\nmod bools;\nmod case;\nmod case_clause_guards;\nmod consts;\nmod custom_types;\nmod echo;\nmod externals;\nmod functions;\nmod generics;\nmod inlining;\nmod lists;\nmod modules;\nmod numbers;\nmod panic;\nmod prelude;\nmod records;\nmod recursion;\nmod results;\nmod strings;\nmod todo;\nmod tuples;\nmod type_alias;\nmod use_;\n\npub static CURRENT_PACKAGE: &str = \"thepackage\";\n\n#[macro_export]\nmacro_rules! assert_js {\n    ($(($name:literal, $module_src:literal)),+, $src:literal $(,)?) => {\n        let compiled =\n            $crate::javascript::tests::compile_js($src, vec![$(($crate::javascript::tests::CURRENT_PACKAGE, $name, $module_src)),*]);\n            let mut output = String::from(\"----- SOURCE CODE\\n\");\n            for (name, src) in [$(($name, $module_src)),*] {\n                output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n            }\n            output.push_str(&format!(\"-- main.gleam\\n{}\\n\\n----- COMPILED JAVASCRIPT\\n{compiled}\", $src));\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n\n    ($(($dep_package:expr, $dep_name:expr, $dep_src:expr)),+, $src:literal $(,)?) => {{\n        let compiled =\n            $crate::javascript::tests::compile_js($src, vec![$(($dep_package, $dep_name, $dep_src)),*]);\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- COMPILED JAVASCRIPT\\n{}\",\n            $src, compiled\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    (($dep_package:expr, $dep_name:expr, $dep_src:expr), $src:expr, $js:expr $(,)?) => {{\n        let output =\n            $crate::javascript::tests::compile_js($src, Some(($dep_package, $dep_name, $dep_src)));\n        assert_eq!(($src, output), ($src, $js.to_string()));\n    }};\n\n    ($src:expr $(,)?) => {{\n        let compiled =\n            $crate::javascript::tests::compile_js($src, vec![]);\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- COMPILED JAVASCRIPT\\n{}\",\n            $src, compiled\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    ($src:expr, $js:expr $(,)?) => {{\n        let output =\n            $crate::javascript::tests::compile_js($src, vec![]);\n        assert_eq!(($src, output), ($src, $js.to_string()));\n    }};\n}\n\n#[macro_export]\nmacro_rules! assert_ts_def {\n    (($dep_1_package:expr, $dep_1_name:expr, $dep_1_src:expr), ($dep_2_package:expr, $dep_2_name:expr, $dep_2_src:expr), $src:expr $(,)?) => {{\n        let compiled = $crate::javascript::tests::compile_ts(\n            $src,\n            vec![\n                ($dep_1_package, $dep_1_name, $dep_1_src),\n                ($dep_2_package, $dep_2_name, $dep_2_src),\n            ],\n        );\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- TYPESCRIPT DEFINITIONS\\n{}\",\n            $src, compiled\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    (($dep_package:expr, $dep_name:expr, $dep_src:expr), $src:expr $(,)?) => {{\n        let compiled =\n            $crate::javascript::tests::compile_ts($src, vec![($dep_package, $dep_name, $dep_src)]);\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- TYPESCRIPT DEFINITIONS\\n{}\",\n            $src, compiled\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    ($src:expr $(,)?) => {{\n        let compiled = $crate::javascript::tests::compile_ts($src, vec![]);\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- TYPESCRIPT DEFINITIONS\\n{}\",\n            $src, compiled\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n}\n\npub fn compile(src: &str, deps: Vec<(&str, &str, &str)>) -> TypedModule {\n    let mut modules = im::HashMap::new();\n    let ids = UniqueIdGenerator::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(\n        PRELUDE_MODULE_NAME.into(),\n        crate::type_::build_prelude(&ids),\n    );\n    let mut direct_dependencies = HashMap::from_iter(vec![]);\n\n    deps.iter().for_each(|(dep_package, dep_name, dep_src)| {\n        let mut dep_config = PackageConfig::default();\n        dep_config.name = (*dep_package).into();\n        let parsed = crate::parse::parse_module(\n            Utf8PathBuf::from(\"test/path\"),\n            dep_src,\n            &WarningEmitter::null(),\n        )\n        .expect(\"dep syntax error\");\n        let mut ast = parsed.module;\n        ast.name = (*dep_name).into();\n        let line_numbers = LineNumbers::new(dep_src);\n\n        let dep = crate::analyse::ModuleAnalyzerConstructor::<()> {\n            target: Target::JavaScript,\n            ids: &ids,\n            origin: Origin::Src,\n            importable_modules: &modules,\n            warnings: &TypeWarningEmitter::null(),\n            direct_dependencies: &HashMap::new(),\n            dev_dependencies: &std::collections::HashSet::new(),\n            target_support: TargetSupport::Enforced,\n            package_config: &dep_config,\n        }\n        .infer_module(ast, line_numbers, \"\".into())\n        .expect(\"should successfully infer\");\n        let _ = modules.insert((*dep_name).into(), dep.type_info);\n        let _ = direct_dependencies.insert((*dep_package).into(), ());\n    });\n\n    let parsed =\n        crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &WarningEmitter::null())\n            .expect(\"syntax error\");\n    let mut ast = parsed.module;\n    ast.name = \"my/mod\".into();\n    let line_numbers = LineNumbers::new(src);\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n\n    let module = crate::analyse::ModuleAnalyzerConstructor::<()> {\n        target: Target::JavaScript,\n        ids: &ids,\n        origin: Origin::Src,\n        importable_modules: &modules,\n        warnings: &TypeWarningEmitter::null(),\n        direct_dependencies: &direct_dependencies,\n        dev_dependencies: &std::collections::HashSet::new(),\n        target_support: TargetSupport::NotEnforced,\n        package_config: &config,\n    }\n    .infer_module(ast, line_numbers, \"src/module.gleam\".into())\n    .expect(\"should successfully infer\");\n\n    inline::module(module, &modules)\n}\n\npub fn compile_js(src: &str, deps: Vec<(&str, &str, &str)>) -> String {\n    let ast = compile(src, deps);\n    let line_numbers = LineNumbers::new(src);\n    let stdlib_package = StdlibPackage::Present;\n    let output = module(ModuleConfig {\n        module: &ast,\n        line_numbers: &line_numbers,\n        src: &\"\".into(),\n        typescript: TypeScriptDeclarations::None,\n        stdlib_package,\n        path: Utf8Path::new(\"src/module.gleam\"),\n        project_root: \"project/root\".into(),\n    });\n\n    output.replace(\n        std::include_str!(\"../../templates/echo.mjs\"),\n        \"// ...omitted code from `templates/echo.mjs`...\",\n    )\n}\n\npub fn compile_ts(src: &str, deps: Vec<(&str, &str, &str)>) -> String {\n    let ast = compile(src, deps);\n    ts_declaration(&ast)\n}\n"
  },
  {
    "path": "compiler-core/src/javascript/typescript.rs",
    "content": "//! This module is responsible for generating TypeScript type declaration files.\n//! This code is run during the code generation phase along side the normal\n//! Javascript code emission. Here we walk through the typed AST and translate\n//! the Gleam statements into their TypeScript equivalent. Unlike the Javascript\n//! code generation, the TypeScript generation only needs to look at the module\n//! statements and not the expressions that may be _inside_ those statements.\n//! This is due to the TypeScript declarations only caring about inputs and outputs\n//! rather than _how_ those outputs are generated.\n//!\n//! ## Links\n//! <https://www.typescriptlang.org/>\n//! <https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html>\n\nuse crate::ast::{\n    AssignName, Publicity, TypedCustomType, TypedFunction, TypedModuleConstant, TypedTypeAlias,\n};\nuse crate::javascript::import::Member;\nuse crate::type_::{PRELUDE_MODULE_NAME, RecordAccessor, is_prelude_module};\nuse crate::{\n    ast::{TypedModule, TypedRecordConstructor},\n    docvec,\n    javascript::JavaScriptCodegenTarget,\n    pretty::{Document, Documentable, break_},\n    type_::{Type, TypeVar},\n};\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse std::{collections::HashMap, ops::Deref, sync::Arc};\n\nuse super::{INDENT, concat, import::Imports, join, line, lines, wrap_arguments};\n\n/// When rendering a type variable to an TypeScript type spec we need all type\n/// variables with the same id to end up with the same name in the generated\n/// TypeScript. This function converts a usize into base 26 A-Z for this purpose.\nfn id_to_type_var(id: u64) -> Document<'static> {\n    if id < 26 {\n        return std::iter::once(\n            std::char::from_u32((id % 26 + 65) as u32).expect(\"id_to_type_var 0\"),\n        )\n        .collect::<EcoString>()\n        .to_doc();\n    }\n    let mut name = vec![];\n    let mut last_char = id;\n    while last_char >= 26 {\n        name.push(std::char::from_u32((last_char % 26 + 65) as u32).expect(\"id_to_type_var 1\"));\n        last_char /= 26;\n    }\n    name.push(std::char::from_u32((last_char % 26 + 64) as u32).expect(\"id_to_type_var 2\"));\n    name.reverse();\n    name.into_iter().collect::<EcoString>().to_doc()\n}\n\nfn name_with_generics<'a>(\n    name: Document<'a>,\n    types: impl IntoIterator<Item = &'a Arc<Type>>,\n) -> Document<'a> {\n    let generic_usages = collect_generic_usages(HashMap::new(), types);\n    let generic_names: Vec<Document<'_>> = generic_usages\n        .keys()\n        .sorted()\n        .map(|id| id_to_type_var(*id))\n        .collect();\n\n    docvec![\n        name,\n        if generic_names.is_empty() {\n            super::nil()\n        } else {\n            wrap_generic_arguments(generic_names)\n        },\n    ]\n}\n\n/// A generic can either be rendered as an actual type variable such as `A` or `B`,\n/// or it can be rendered as `any` depending on how many usages it has. If it\n/// has only 1 usage it is an `any` type. If it has more than 1 usage it is a\n/// TS generic. This function gathers usages for this determination.\n///\n///   Examples:\n///     fn(a) -> String       // `a` is `any`\n///     `fn()` -> Result(a, b)  // `a` and `b` are `any`\n///     fn(a) -> a            // `a` is a generic\nfn collect_generic_usages<'a>(\n    mut ids: HashMap<u64, u64>,\n    types: impl IntoIterator<Item = &'a Arc<Type>>,\n) -> HashMap<u64, u64> {\n    for type_ in types {\n        generic_ids(type_, &mut ids);\n    }\n    ids\n}\n\nfn generic_ids(type_: &Type, ids: &mut HashMap<u64, u64>) {\n    match type_ {\n        Type::Var { type_ } => match type_.borrow().deref() {\n            TypeVar::Unbound { id, .. } | TypeVar::Generic { id, .. } => {\n                let count = ids.entry(*id).or_insert(0);\n                *count += 1;\n            }\n            TypeVar::Link { type_ } => generic_ids(type_, ids),\n        },\n        Type::Named { arguments, .. } => {\n            for argument in arguments {\n                generic_ids(argument, ids)\n            }\n        }\n        Type::Fn { arguments, return_ } => {\n            for argument in arguments {\n                generic_ids(argument, ids)\n            }\n            generic_ids(return_, ids);\n        }\n        Type::Tuple { elements } => {\n            for element in elements {\n                generic_ids(element, ids)\n            }\n        }\n    }\n}\n\n/// Prints a Gleam tuple in the TypeScript equivalent syntax\n///\nfn tuple<'a>(elements: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {\n    break_(\"\", \"\")\n        .append(join(elements, break_(\",\", \", \")))\n        .nest(INDENT)\n        .append(break_(\"\", \"\"))\n        .surround(\"[\", \"]\")\n        .group()\n}\n\nfn wrap_generic_arguments<'a, I>(arguments: I) -> Document<'a>\nwhere\n    I: IntoIterator<Item = Document<'a>>,\n{\n    break_(\"\", \"\")\n        .append(join(arguments, break_(\",\", \", \")))\n        .nest(INDENT)\n        .append(break_(\"\", \"\"))\n        .surround(\"<\", \">\")\n        .group()\n}\n\n/// Returns a name that can be used as a TypeScript type name. If there is a\n/// naming clash a '_' will be appended.\n///\nfn ts_safe_type_name(mut name: String) -> EcoString {\n    if matches!(\n        name.as_str(),\n        \"any\"\n            | \"boolean\"\n            | \"constructor\"\n            | \"declare\"\n            | \"get\"\n            | \"module\"\n            | \"require\"\n            | \"number\"\n            | \"set\"\n            | \"string\"\n            | \"symbol\"\n            | \"type\"\n            | \"from\"\n            | \"of\"\n    ) {\n        name.push('_');\n        EcoString::from(name)\n    } else {\n        super::maybe_escape_identifier_string(&name)\n    }\n}\n\n/// The `TypeScriptGenerator` contains the logic of how to convert Gleam's typed\n/// AST into the equivalent TypeScript type declaration file.\n///\n#[derive(Debug)]\npub struct TypeScriptGenerator<'a> {\n    module: &'a TypedModule,\n    aliased_module_names: HashMap<&'a str, &'a str>,\n    tracker: UsageTracker,\n    current_module_name_segments_count: usize,\n}\n\nimpl<'a> TypeScriptGenerator<'a> {\n    pub fn new(module: &'a TypedModule) -> Self {\n        let current_module_name_segments_count = module.name.split('/').count();\n        Self {\n            module,\n            aliased_module_names: HashMap::new(),\n            tracker: UsageTracker::default(),\n            current_module_name_segments_count,\n        }\n    }\n\n    pub fn compile(&mut self) -> Document<'a> {\n        let mut imports = self.collect_imports();\n        let statements = self.definitions(&mut imports);\n\n        // Two lines between each statement\n        let mut statements = Itertools::intersperse(statements.into_iter(), lines(2)).collect_vec();\n\n        // Put it all together\n\n        if self.prelude_used() {\n            let path = self.import_path(&self.module.type_info.package, PRELUDE_MODULE_NAME);\n            imports.register_module(path, [\"_\".into()], []);\n        }\n\n        if imports.is_empty() && statements.is_empty() {\n            docvec![\"export {}\", line()]\n        } else if imports.is_empty() {\n            statements.push(line());\n            statements.to_doc()\n        } else if statements.is_empty() {\n            imports.into_doc(JavaScriptCodegenTarget::TypeScriptDeclarations)\n        } else {\n            docvec![\n                imports.into_doc(JavaScriptCodegenTarget::TypeScriptDeclarations),\n                line(),\n                statements,\n                line()\n            ]\n        }\n    }\n\n    fn collect_imports(&mut self) -> Imports<'a> {\n        let mut imports = Imports::new();\n\n        for function in &self.module.definitions.functions {\n            for argument in &function.arguments {\n                self.collect_imports_for_type(&argument.type_, &mut imports);\n            }\n            self.collect_imports_for_type(&function.return_type, &mut imports);\n        }\n\n        for type_alias in &self.module.definitions.type_aliases {\n            self.collect_imports_for_type(&type_alias.type_, &mut imports);\n        }\n\n        for custom_type in &self.module.definitions.custom_types {\n            for type_ in &custom_type.typed_parameters {\n                self.collect_imports_for_type(type_, &mut imports);\n            }\n\n            for constructor in &custom_type.constructors {\n                for argument in &constructor.arguments {\n                    self.collect_imports_for_type(&argument.type_, &mut imports);\n                }\n            }\n        }\n\n        for constant in &self.module.definitions.constants {\n            self.collect_imports_for_type(&constant.type_, &mut imports);\n        }\n\n        for import in &self.module.definitions.imports {\n            match &import.as_name {\n                Some((AssignName::Variable(name), _)) => {\n                    let _ = self.aliased_module_names.insert(&import.module, name);\n                }\n                Some((AssignName::Discard(_), _)) | None => (),\n            }\n        }\n\n        imports\n    }\n\n    /// Recurses through a type and any types it references, registering all of their imports.\n    ///\n    fn collect_imports_for_type<'b>(&mut self, type_: &'b Type, imports: &mut Imports<'a>) {\n        match &type_ {\n            Type::Named {\n                package,\n                module,\n                arguments,\n                ..\n            } => {\n                let is_prelude = module == \"gleam\" && package.is_empty();\n                let is_current_module = *module == self.module.name;\n\n                if !is_prelude && !is_current_module {\n                    self.register_import(imports, package, module);\n                }\n\n                for argument in arguments {\n                    self.collect_imports_for_type(argument, imports);\n                }\n            }\n            Type::Fn { arguments, return_ } => {\n                for argument in arguments {\n                    self.collect_imports_for_type(argument, imports);\n                }\n                self.collect_imports_for_type(return_, imports);\n            }\n            Type::Tuple { elements } => {\n                for element in elements {\n                    self.collect_imports_for_type(element, imports);\n                }\n            }\n            Type::Var { type_ } => {\n                if let TypeVar::Link { type_ } = type_\n                    .as_ref()\n                    .try_borrow()\n                    .expect(\"borrow type after inference\")\n                    .deref()\n                {\n                    self.collect_imports_for_type(type_, imports);\n                }\n            }\n        }\n    }\n\n    /// Registers an import of an external module so that it can be added to\n    /// the top of the generated Document. The module names are prefixed with a\n    /// \"$\" symbol to prevent any clashes with other Gleam names that may be\n    /// used in this module.\n    ///\n    fn register_import<'b>(\n        &mut self,\n        imports: &mut Imports<'a>,\n        package: &'b str,\n        module: &'b str,\n    ) {\n        let path = self.import_path(package, module);\n        imports.register_module(path, [self.module_name(module)], []);\n    }\n\n    /// Calculates the path of where to import an external module from\n    ///\n    fn import_path<'b>(&self, package: &'b str, module: &'b str) -> EcoString {\n        // DUPE: current_module_name_segments_count\n        // TODO: strip shared prefixed between current module and imported\n        // module to avoid descending and climbing back out again\n        if package == self.module.type_info.package || package.is_empty() {\n            // Same package\n            match self.current_module_name_segments_count {\n                1 => eco_format!(\"./{module}.d.mts\"),\n                _ => {\n                    let prefix = \"../\".repeat(self.current_module_name_segments_count - 1);\n                    eco_format!(\"{prefix}{module}.d.mts\")\n                }\n            }\n        } else {\n            // Different package\n            let prefix = \"../\".repeat(self.current_module_name_segments_count);\n            eco_format!(\"{prefix}{package}/{module}.d.mts\")\n        }\n    }\n\n    fn definitions(&mut self, imports: &mut Imports<'_>) -> Vec<Document<'a>> {\n        let mut documents = vec![];\n\n        for custom_type in &self.module.definitions.custom_types {\n            if let Some(mut new_documents) = self.custom_type_definition(custom_type, imports) {\n                documents.append(&mut new_documents);\n            }\n        }\n\n        for type_alias in &self.module.definitions.type_aliases {\n            if let Some(document) = self.type_alias(type_alias) {\n                documents.push(document);\n            }\n        }\n\n        for constant in &self.module.definitions.constants {\n            if let Some(document) = self.module_constant(constant) {\n                documents.push(document);\n            }\n        }\n\n        for function in &self.module.definitions.functions {\n            if let Some(document) = self.module_function(function) {\n                documents.push(document);\n            }\n        }\n\n        documents\n    }\n\n    fn type_alias(&mut self, type_alias: &TypedTypeAlias) -> Option<Document<'a>> {\n        if !type_alias.publicity.is_importable() {\n            return None;\n        }\n\n        Some(docvec![\n            \"export type \",\n            ts_safe_type_name(type_alias.alias.to_string()),\n            \" = \",\n            self.print_type(&type_alias.type_),\n            \";\"\n        ])\n    }\n\n    /// Converts a Gleam custom type definition into the TypeScript equivalent.\n    /// In Gleam, all custom types have one to many concrete constructors. This\n    /// function first converts the constructors into TypeScript then finally\n    /// emits a union type to represent the TypeScript type itself. Because in\n    /// Gleam constructors can have the same name as the custom type, here we\n    /// append a \"$\" symbol to the emitted TypeScript type to prevent those\n    /// naming classes.\n    ///\n    fn custom_type_definition(\n        &mut self,\n        custom_type: &'a TypedCustomType,\n        imports: &mut Imports<'_>,\n    ) -> Option<Vec<Document<'a>>> {\n        let TypedCustomType {\n            name,\n            publicity,\n            constructors,\n            opaque,\n            typed_parameters,\n            external_javascript,\n            ..\n        } = custom_type;\n\n        // Constructors for opaque and private types are not exported\n        let constructor_publicity = if publicity.is_private() || *opaque {\n            Publicity::Private\n        } else {\n            Publicity::Public\n        };\n\n        let type_name = name_with_generics(eco_format!(\"{name}$\").to_doc(), typed_parameters);\n\n        let mut definitions = constructors\n            .iter()\n            .map(|constructor| {\n                self.variant_definition(\n                    constructor,\n                    constructor_publicity,\n                    name,\n                    &type_name,\n                    typed_parameters,\n                )\n            })\n            .collect_vec();\n\n        let definition = if constructors.is_empty() {\n            if let Some((module, external_name, _location)) = external_javascript {\n                let member = Member {\n                    name: external_name.to_doc(),\n                    alias: Some(eco_format!(\"{name}$\").to_doc()),\n                };\n                imports.register_export(eco_format!(\"{name}$\"));\n\n                imports.register_module(module.clone(), [], [member]);\n                return Some(Vec::new());\n            } else {\n                \"any\".to_doc()\n            }\n        } else {\n            let constructors = constructors.iter().map(|x| {\n                name_with_generics(\n                    super::maybe_escape_identifier(&x.name).to_doc(),\n                    x.arguments.iter().map(|a| &a.type_),\n                )\n            });\n            join(constructors, break_(\"| \", \" | \"))\n        };\n\n        let head = if publicity.is_private() {\n            \"type \"\n        } else {\n            \"export type \"\n        };\n\n        definitions.push(docvec![head, type_name.clone(), \" = \", definition, \";\",]);\n\n        // Generate getters for fields shared between variants\n        if let Some(accessors_map) = self.module.type_info.accessors.get(name)\n            && !accessors_map.shared_accessors.is_empty()\n            // Don't bother generating shared getters when there's only one variant,\n            // since the specific accessors can always be uses instead.\n            && constructors.len() != 1\n            // Only generate accessors for the API if the constructors are public\n            && constructor_publicity.is_public()\n        {\n            definitions.push(self.shared_custom_type_fields(\n                name,\n                &type_name,\n                typed_parameters,\n                &accessors_map.shared_accessors,\n            ));\n        }\n\n        Some(definitions)\n    }\n\n    fn variant_definition(\n        &mut self,\n        constructor: &'a TypedRecordConstructor,\n        publicity: Publicity,\n        type_name: &'a str,\n        type_name_with_generics: &Document<'a>,\n        type_parameters: &'a [Arc<Type>],\n    ) -> Document<'a> {\n        self.set_prelude_used();\n        let class_definition = self.variant_class_definition(constructor, publicity);\n\n        // If the custom type is private or opaque, we don't need to generate API\n        // functions for it.\n        if publicity.is_private() {\n            return class_definition;\n        }\n\n        let constructor_definition = self.variant_constructor_definition(\n            constructor,\n            type_name,\n            type_name_with_generics,\n            type_parameters,\n        );\n        let variant_check_definition =\n            self.variant_check_definition(constructor, type_name, type_parameters);\n        let fields_definition = self.variant_fields_definition(\n            constructor,\n            type_name,\n            type_name_with_generics,\n            type_parameters,\n        );\n\n        docvec![\n            class_definition,\n            line(),\n            constructor_definition,\n            line(),\n            variant_check_definition,\n            fields_definition,\n        ]\n    }\n\n    fn variant_class_definition(\n        &mut self,\n        constructor: &'a TypedRecordConstructor,\n        publicity: Publicity,\n    ) -> Document<'a> {\n        let head = docvec![\n            if publicity.is_public() {\n                \"export \".to_doc()\n            } else {\n                \"declare \".to_doc()\n            },\n            \"class \",\n            name_with_generics(\n                super::maybe_escape_identifier(&constructor.name).to_doc(),\n                constructor.arguments.iter().map(|a| &a.type_)\n            ),\n            \" extends _.CustomType {\"\n        ];\n\n        if constructor.arguments.is_empty() {\n            return head.append(\"}\");\n        };\n\n        let class_body = docvec![\n            line(),\n            \"/** @deprecated */\",\n            line(),\n            // First add the constructor\n            \"constructor\",\n            wrap_arguments(\n                constructor\n                    .arguments\n                    .iter()\n                    .enumerate()\n                    .map(|(i, argument)| {\n                        let name = argument\n                            .label\n                            .as_ref()\n                            .map(|(_, s)| super::maybe_escape_identifier(s))\n                            .unwrap_or_else(|| eco_format!(\"argument${i}\"))\n                            .to_doc();\n                        docvec![\n                            name,\n                            \": \",\n                            self.do_print_force_generic_param(&argument.type_)\n                        ]\n                    })\n            ),\n            \";\",\n            line(),\n            // Then add each field to the class\n            join(\n                constructor.arguments.iter().enumerate().map(|(i, arg)| {\n                    let name = arg\n                        .label\n                        .as_ref()\n                        .map(|(_, s)| super::maybe_escape_identifier(s))\n                        .unwrap_or_else(|| eco_format!(\"{i}\"))\n                        .to_doc();\n                    docvec![\n                        \"/** @deprecated */\",\n                        line(),\n                        name,\n                        \": \",\n                        self.do_print_force_generic_param(&arg.type_),\n                        \";\"\n                    ]\n                }),\n                line(),\n            ),\n        ]\n        .nest(INDENT);\n\n        docvec![head, class_body, line(), \"}\"]\n    }\n\n    fn variant_constructor_definition(\n        &mut self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n        type_name_with_generics: &Document<'a>,\n        type_parameters: &'a [Arc<Type>],\n    ) -> Document<'a> {\n        let mut arguments = Vec::new();\n\n        for (index, parameter) in constructor.arguments.iter().enumerate() {\n            let name = if let Some((_, label)) = &parameter.label {\n                super::maybe_escape_identifier(label)\n            } else {\n                eco_format!(\"${index}\")\n            };\n\n            arguments.push(docvec![\n                name,\n                \": \",\n                self.do_print_force_generic_param(&parameter.type_)\n            ])\n        }\n\n        let function_name = eco_format!(\n            \"{type_name}${variant_name}\",\n            variant_name = constructor.name\n        )\n        .to_doc();\n\n        let has_arguments = !arguments.is_empty();\n\n        docvec![\n            \"export function \",\n            name_with_generics(function_name, type_parameters),\n            \"(\",\n            docvec![break_(\"\", \"\"), join(arguments, break_(\",\", \", \")),].nest(INDENT),\n            break_(if has_arguments { \",\" } else { \"\" }, \"\"),\n            \"): \",\n            type_name_with_generics.clone(),\n            \";\"\n        ]\n        .group()\n    }\n\n    fn variant_check_definition(\n        &self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n        type_parameters: &'a [Arc<Type>],\n    ) -> Document<'a> {\n        let function_name = eco_format!(\n            \"{type_name}$is{variant_name}\",\n            variant_name = constructor.name\n        )\n        .to_doc();\n        let mut document = docvec![\n            \"export function \",\n            name_with_generics(function_name, type_parameters),\n            \"(\",\n            docvec![break_(\"\", \"\",), \"value: any\"].nest(INDENT),\n            break_(\",\", \"\"),\n            \"): value is \",\n            type_name,\n            \"$\",\n        ];\n        if !type_parameters.is_empty() {\n            for i in 0..type_parameters.len() {\n                if i == 0 {\n                    document = document.append(\"<unknown\");\n                } else {\n                    document = document.append(\", unknown\");\n                }\n            }\n            document = document.append('>');\n        };\n        document = document.append(';');\n        document.group()\n    }\n\n    fn variant_fields_definition(\n        &mut self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n        type_name_with_generics: &Document<'a>,\n        type_parameters: &'a [Arc<Type>],\n    ) -> Document<'a> {\n        let mut functions = Vec::new();\n\n        for (index, argument) in constructor.arguments.iter().enumerate() {\n            // Always generate the accessor for the value at this index. Although\n            // this is not necessary when a label is present, we want to make sure\n            // that adding a label to a record isn't a breaking change. For this\n            // reason, we need to generate an index getter even when a label is\n            // present to ensure consistent behaviour between labelled and unlabelled\n            // field access.\n            let function_name = eco_format!(\n                \"{type_name}${variant_name}${index}\",\n                variant_name = constructor.name\n            )\n            .to_doc();\n\n            functions.push(\n                docvec![\n                    line(),\n                    \"export function \",\n                    name_with_generics(function_name, type_parameters),\n                    \"(\",\n                    docvec![break_(\"\", \"\",), \"value: \", type_name_with_generics.clone(),]\n                        .nest(INDENT),\n                    break_(\",\", \"\"),\n                    \"): \",\n                    self.do_print_force_generic_param(&argument.type_),\n                    \";\",\n                ]\n                .group(),\n            );\n\n            // If the argument is labelled, also generate a getter for the labelled\n            // argument.\n            if let Some((_, label)) = &argument.label {\n                let function_name = eco_format!(\n                    \"{type_name}${variant_name}${label}\",\n                    variant_name = constructor.name\n                )\n                .to_doc();\n\n                functions.push(\n                    docvec![\n                        line(),\n                        \"export function \",\n                        name_with_generics(function_name, type_parameters),\n                        \"(\",\n                        docvec![break_(\"\", \"\",), \"value: \", type_name_with_generics.clone(),]\n                            .nest(INDENT),\n                        break_(\",\", \"\"),\n                        \"): \",\n                        self.do_print_force_generic_param(&argument.type_),\n                        \";\",\n                    ]\n                    .group(),\n                );\n            }\n        }\n\n        concat(functions)\n    }\n\n    fn shared_custom_type_fields(\n        &mut self,\n        type_name: &'a str,\n        type_name_with_generics: &Document<'a>,\n        type_parameters: &'a [Arc<Type>],\n        shared_accessors: &HashMap<EcoString, RecordAccessor>,\n    ) -> Document<'a> {\n        let accessors = shared_accessors\n            .iter()\n            .sorted_by_key(|(name, _)| *name)\n            .map(|(field, accessor)| {\n                let function_name = eco_format!(\"{type_name}${field}\").to_doc();\n\n                docvec![\n                    \"export function \",\n                    name_with_generics(function_name, type_parameters),\n                    \"(\",\n                    docvec![break_(\"\", \"\",), \"value: \", type_name_with_generics.clone(),]\n                        .nest(INDENT),\n                    break_(\",\", \"\"),\n                    \"): \",\n                    self.do_print_force_generic_param(&accessor.type_),\n                    \";\"\n                ]\n                .group()\n            });\n        join(accessors, line())\n    }\n\n    fn module_constant(&mut self, constant: &TypedModuleConstant) -> Option<Document<'a>> {\n        if !constant.publicity.is_importable() {\n            return None;\n        }\n\n        Some(docvec![\n            \"export const \",\n            super::maybe_escape_identifier(&constant.name),\n            \": \",\n            self.print_type(&constant.value.type_()),\n            \";\",\n        ])\n    }\n\n    fn module_function(&mut self, function: &'a TypedFunction) -> Option<Document<'a>> {\n        let TypedFunction {\n            name: Some((_, name)),\n            arguments,\n            publicity,\n            return_type,\n            ..\n        } = function\n        else {\n            return None;\n        };\n\n        if !publicity.is_importable() {\n            return None;\n        }\n\n        let generic_usages = collect_generic_usages(\n            HashMap::new(),\n            std::iter::once(return_type).chain(arguments.iter().map(|a| &a.type_)),\n        );\n        let generic_names: Vec<Document<'_>> = generic_usages\n            .iter()\n            .filter(|(_id, use_count)| **use_count > 1)\n            .sorted_by_key(|x| x.0)\n            .map(|(id, _use_count)| id_to_type_var(*id))\n            .collect();\n\n        Some(docvec![\n            \"export function \",\n            super::maybe_escape_identifier(name),\n            if generic_names.is_empty() {\n                super::nil()\n            } else {\n                wrap_generic_arguments(generic_names)\n            },\n            wrap_arguments(arguments.iter().enumerate().map(|(i, argument)| {\n                match argument.get_variable_name() {\n                    None => {\n                        docvec![\n                            \"x\",\n                            i,\n                            \": \",\n                            self.print_type_with_generic_usages(&argument.type_, &generic_usages)\n                        ]\n                    }\n                    Some(name) => docvec![\n                        super::maybe_escape_identifier(name),\n                        \": \",\n                        self.print_type_with_generic_usages(&argument.type_, &generic_usages)\n                    ],\n                }\n            }),),\n            \": \",\n            self.print_type_with_generic_usages(return_type, &generic_usages),\n            \";\",\n        ])\n    }\n\n    /// Converts a Gleam type into a TypeScript type string\n    ///\n    pub fn print_type(&mut self, type_: &Type) -> Document<'static> {\n        self.do_print(type_, GenericPrinting::AsAny)\n    }\n\n    /// Helper function for generating a TypeScript type string after collecting\n    /// all of the generics used in a statement\n    ///\n    pub fn print_type_with_generic_usages(\n        &mut self,\n        type_: &Type,\n        generic_usages: &HashMap<u64, u64>,\n    ) -> Document<'static> {\n        self.do_print(type_, GenericPrinting::FromUsage(generic_usages))\n    }\n\n    /// Get the locally used name for a module. Either the last segment, or the\n    /// alias if one was given when imported.\n    ///\n    fn module_name(&self, name: &str) -> EcoString {\n        // The prelude is always `_`\n        if name.is_empty() {\n            return \"_\".into();\n        }\n\n        let name = match self.aliased_module_names.get(name) {\n            Some(name) => name,\n            None => name.split('/').next_back().expect(\"Non empty module path\"),\n        };\n\n        eco_format!(\"${name}\")\n    }\n\n    fn do_print(\n        &mut self,\n        type_: &Type,\n        generic_printing: GenericPrinting<'_>,\n    ) -> Document<'static> {\n        match type_ {\n            Type::Var { type_ } => self.print_var(&type_.borrow(), generic_printing),\n\n            Type::Named {\n                name,\n                module,\n                arguments,\n                ..\n            } if is_prelude_module(module) => {\n                self.print_prelude_type(name, arguments, generic_printing)\n            }\n\n            Type::Named {\n                name,\n                arguments,\n                module,\n                ..\n            } => self.print_type_app(name, arguments, module, generic_printing),\n\n            Type::Fn { arguments, return_ } => self.print_fn(arguments, return_, generic_printing),\n\n            Type::Tuple { elements } => tuple(\n                elements\n                    .iter()\n                    .map(|element| self.do_print(element, generic_printing)),\n            ),\n        }\n    }\n\n    fn do_print_force_generic_param(&mut self, type_: &Type) -> Document<'static> {\n        match type_ {\n            Type::Var { type_ } => self.print_var(&type_.borrow(), GenericPrinting::AlwaysGeneric),\n\n            Type::Named {\n                name,\n                module,\n                arguments,\n                ..\n            } if is_prelude_module(module) => {\n                self.print_prelude_type(name, arguments, GenericPrinting::AlwaysGeneric)\n            }\n\n            Type::Named {\n                name,\n                arguments,\n                module,\n                ..\n            } => self.print_type_app(name, arguments, module, GenericPrinting::AlwaysGeneric),\n\n            Type::Fn { arguments, return_ } => {\n                self.print_fn(arguments, return_, GenericPrinting::AlwaysGeneric)\n            }\n\n            Type::Tuple { elements } => tuple(\n                elements\n                    .iter()\n                    .map(|element| self.do_print(element, GenericPrinting::AlwaysGeneric)),\n            ),\n        }\n    }\n\n    fn print_var(\n        &mut self,\n        type_: &TypeVar,\n        generic_printing: GenericPrinting<'_>,\n    ) -> Document<'static> {\n        match type_ {\n            TypeVar::Unbound { id } | TypeVar::Generic { id } => match generic_printing {\n                GenericPrinting::FromUsage(usages) => match usages.get(id) {\n                    Some(&0) => super::nil(),\n                    Some(&1) => \"any\".to_doc(),\n                    _ => id_to_type_var(*id),\n                },\n                GenericPrinting::AlwaysGeneric => id_to_type_var(*id),\n                GenericPrinting::AsAny => \"any\".to_doc(),\n            },\n            TypeVar::Link { type_ } => self.do_print(type_, generic_printing),\n        }\n    }\n\n    /// Prints a type coming from the Gleam prelude module. These are often the\n    /// low level types the rest of the type system are built up from. If there\n    /// is no built-in TypeScript equivalent, the type is prefixed with \"_.\"\n    /// and the Gleam prelude namespace will be imported during the code emission.\n    ///\n    fn print_prelude_type(\n        &mut self,\n        name: &str,\n        arguments: &[Arc<Type>],\n        generic_printing: GenericPrinting<'_>,\n    ) -> Document<'static> {\n        match name {\n            \"Nil\" => \"undefined\".to_doc(),\n            \"Int\" | \"Float\" => \"number\".to_doc(),\n            \"UtfCodepoint\" => {\n                self.tracker.prelude_used = true;\n                \"_.UtfCodepoint\".to_doc()\n            }\n            \"String\" => \"string\".to_doc(),\n            \"Bool\" => \"boolean\".to_doc(),\n            \"BitArray\" => {\n                self.tracker.prelude_used = true;\n                \"_.BitArray\".to_doc()\n            }\n            \"List\" => {\n                self.tracker.prelude_used = true;\n                docvec![\n                    \"_.List\",\n                    wrap_generic_arguments(\n                        arguments\n                            .iter()\n                            .map(|argument| self.do_print(argument, generic_printing))\n                    )\n                ]\n            }\n            \"Result\" => {\n                self.tracker.prelude_used = true;\n                docvec![\n                    \"_.Result\",\n                    wrap_generic_arguments(\n                        arguments.iter().map(|x| self.do_print(x, generic_printing))\n                    )\n                ]\n            }\n            // Getting here should mean we either forgot a built-in type or there is a\n            // compiler error\n            name => panic!(\"{name} is not a built-in type.\"),\n        }\n    }\n\n    /// Prints a \"named\" programmer-defined Gleam type into the TypeScript\n    /// equivalent.\n    ///\n    fn print_type_app(\n        &mut self,\n        name: &str,\n        arguments: &[Arc<Type>],\n        module: &str,\n        generic_printing: GenericPrinting<'_>,\n    ) -> Document<'static> {\n        let name = eco_format!(\"{}$\", ts_safe_type_name(name.to_string()));\n        let name = match module == self.module.name {\n            true => name.to_doc(),\n            false => {\n                // If type comes from a separate module, use that module's name\n                // as a TypeScript namespace prefix\n                docvec![self.module_name(module), \".\", name]\n            }\n        };\n        if arguments.is_empty() {\n            return name;\n        }\n\n        // If the App type takes arguments, pass them in as TypeScript generics\n        docvec![\n            name,\n            wrap_generic_arguments(\n                arguments\n                    .iter()\n                    .map(|argument| self.do_print(argument, generic_printing))\n            )\n        ]\n    }\n\n    /// Prints the TypeScript type for an anonymous function (aka lambda)\n    ///\n    fn print_fn(\n        &mut self,\n        arguments: &[Arc<Type>],\n        return_: &Type,\n        generic_printing: GenericPrinting<'_>,\n    ) -> Document<'static> {\n        docvec![\n            wrap_arguments(arguments.iter().enumerate().map(|(idx, argument)| docvec![\n                \"x\",\n                idx,\n                \": \",\n                self.do_print(argument, generic_printing)\n            ])),\n            \" => \",\n            self.do_print(return_, generic_printing)\n        ]\n    }\n\n    /// Allows an outside module to mark the Gleam prelude as \"used\"\n    ///\n    pub fn set_prelude_used(&mut self) {\n        self.tracker.prelude_used = true\n    }\n\n    /// Returns if the Gleam prelude has been used at all during the process\n    /// of printing the TypeScript types\n    ///\n    pub fn prelude_used(&self) -> bool {\n        self.tracker.prelude_used\n    }\n}\n\n#[derive(Debug, Default)]\npub(crate) struct UsageTracker {\n    pub prelude_used: bool,\n}\n\n/// How to print generic type parameters when generating declarations.\n#[derive(Debug, Clone, Copy)]\nenum GenericPrinting<'a> {\n    /// Print the generic parameters based on how many times they are used:\n    /// - If a parameter isn't used, it is not printed.\n    /// - If a parameter is used exactly once, it is printed as `any`.\n    /// - If a parameter is used more than once, it is printed as a generic.\n    ///\n    /// For example, the following function:\n    ///\n    /// ```gleam\n    /// pub fn wibble(thing: one, other_thing: other) -> one { ... }\n    /// ```\n    ///\n    /// Would result in the following declaration:\n    ///\n    /// ```typescript\n    /// export function wibble<A>(thing: A, other_thing: any): A;\n    /// ```\n    ///\n    FromUsage(&'a HashMap<u64, u64>),\n    /// Print every generic parameter as a generic in TypeScript. This is used in\n    /// custom types where every generic needs to be emitted, even if it is only\n    /// referenced once, or not at all.\n    ///\n    /// For example:\n    ///\n    /// ```gleam\n    /// pub type Wibble(multiple, single, phantom) {\n    ///   Wibble(a: single, b: multiple, b: multiple)\n    /// }\n    /// ```\n    ///\n    /// Generates more or less the following TypeScript:\n    ///\n    /// ```typescript\n    /// export class Wibble<A, B, C> extends CustomType {\n    ///   a: A;\n    ///   b: B;\n    ///   c: B;\n    /// }\n    /// ```\n    ///\n    AlwaysGeneric,\n    /// Print generic parameters as TypeScript `any`. This is used in constants,\n    /// where generics are not allowed.\n    AsAny,\n}\n"
  },
  {
    "path": "compiler-core/src/javascript.rs",
    "content": "mod decision;\nmod expression;\nmod import;\n#[cfg(test)]\nmod tests;\nmod typescript;\n\nuse std::collections::HashMap;\n\nuse num_bigint::BigInt;\nuse num_traits::ToPrimitive;\n\nuse crate::build::Target;\nuse crate::build::package_compiler::StdlibPackage;\nuse crate::codegen::TypeScriptDeclarations;\nuse crate::type_::{PRELUDE_MODULE_NAME, RecordAccessor};\nuse crate::{\n    ast::{Import, *},\n    docvec,\n    line_numbers::LineNumbers,\n    pretty::*,\n};\nuse camino::Utf8Path;\nuse ecow::{EcoString, eco_format};\nuse expression::Context;\nuse itertools::Itertools;\n\nuse self::import::{Imports, Member};\n\nconst INDENT: isize = 2;\n\npub const PRELUDE: &str = include_str!(\"../templates/prelude.mjs\");\npub const PRELUDE_TS_DEF: &str = include_str!(\"../templates/prelude.d.mts\");\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum JavaScriptCodegenTarget {\n    JavaScript,\n    TypeScriptDeclarations,\n}\n\n#[derive(Debug)]\npub struct Generator<'a> {\n    line_numbers: &'a LineNumbers,\n    module: &'a TypedModule,\n    tracker: UsageTracker,\n    module_scope: im::HashMap<EcoString, usize>,\n    current_module_name_segments_count: usize,\n    typescript: TypeScriptDeclarations,\n    stdlib_package: StdlibPackage,\n    /// Relative path to the module, surrounded in `\"`s to make it a string, and with `\\`s escaped\n    /// to `\\\\`.\n    src_path: EcoString,\n}\n\nimpl<'a> Generator<'a> {\n    pub fn new(config: ModuleConfig<'a>) -> Self {\n        let ModuleConfig {\n            typescript,\n            stdlib_package,\n            module,\n            line_numbers,\n            src: _,\n            path: _,\n            project_root,\n        } = config;\n        let current_module_name_segments_count = module.name.split('/').count();\n\n        let src_path = &module.type_info.src_path;\n        let src_path = src_path\n            .strip_prefix(project_root)\n            .unwrap_or(src_path)\n            .as_str();\n        let src_path = eco_format!(\"\\\"{src_path}\\\"\").replace(\"\\\\\", \"\\\\\\\\\");\n\n        Self {\n            current_module_name_segments_count,\n            line_numbers,\n            module,\n            src_path,\n            tracker: UsageTracker::default(),\n            module_scope: Default::default(),\n            typescript,\n            stdlib_package,\n        }\n    }\n\n    fn type_reference(&self) -> Document<'a> {\n        if self.typescript == TypeScriptDeclarations::None {\n            return nil();\n        }\n\n        // Get the name of the module relative the directory (similar to basename)\n        let module = self\n            .module\n            .name\n            .as_str()\n            .split('/')\n            .next_back()\n            .expect(\"JavaScript generator could not identify imported module name.\");\n\n        docvec![\"/// <reference types=\\\"./\", module, \".d.mts\\\" />\", line()]\n    }\n\n    pub fn compile(&mut self) -> Document<'a> {\n        // Determine what JavaScript imports we need to generate\n        let mut imports = self.collect_imports();\n\n        // Determine what names are defined in the module scope so we know to\n        // rename any variables that are defined within functions using the same\n        // names.\n        self.register_module_definitions_in_scope();\n\n        // Generate JavaScript code for each statement.\n        let statements = self.definitions();\n\n        // Two lines between each statement\n        let mut statements = Itertools::intersperse(statements.into_iter(), lines(2)).collect_vec();\n\n        // Import any prelude functions that have been used\n\n        if self.tracker.ok_used {\n            self.register_prelude_usage(&mut imports, \"Ok\", None);\n        };\n\n        if self.tracker.error_used {\n            self.register_prelude_usage(&mut imports, \"Error\", None);\n        };\n\n        if self.tracker.list_used {\n            self.register_prelude_usage(&mut imports, \"toList\", None);\n        };\n\n        if self.tracker.list_empty_class_used || self.tracker.echo_used {\n            self.register_prelude_usage(&mut imports, \"Empty\", Some(\"$Empty\"));\n        };\n\n        if self.tracker.list_non_empty_class_used || self.tracker.echo_used {\n            self.register_prelude_usage(&mut imports, \"NonEmpty\", Some(\"$NonEmpty\"));\n        };\n\n        if self.tracker.prepend_used {\n            self.register_prelude_usage(&mut imports, \"prepend\", Some(\"listPrepend\"));\n        };\n\n        if self.tracker.custom_type_used || self.tracker.echo_used {\n            self.register_prelude_usage(&mut imports, \"CustomType\", Some(\"$CustomType\"));\n        };\n\n        if self.tracker.make_error_used {\n            self.register_prelude_usage(&mut imports, \"makeError\", None);\n        };\n\n        if self.tracker.int_remainder_used {\n            self.register_prelude_usage(&mut imports, \"remainderInt\", None);\n        };\n\n        if self.tracker.float_division_used {\n            self.register_prelude_usage(&mut imports, \"divideFloat\", None);\n        };\n\n        if self.tracker.int_division_used {\n            self.register_prelude_usage(&mut imports, \"divideInt\", None);\n        };\n\n        if self.tracker.object_equality_used {\n            self.register_prelude_usage(&mut imports, \"isEqual\", None);\n        };\n\n        if self.tracker.bit_array_literal_used {\n            self.register_prelude_usage(&mut imports, \"toBitArray\", None);\n        }\n\n        if self.tracker.bit_array_slice_used || self.tracker.echo_used {\n            self.register_prelude_usage(&mut imports, \"bitArraySlice\", None);\n        }\n\n        if self.tracker.bit_array_slice_to_float_used {\n            self.register_prelude_usage(&mut imports, \"bitArraySliceToFloat\", None);\n        }\n\n        if self.tracker.bit_array_slice_to_int_used || self.tracker.echo_used {\n            self.register_prelude_usage(&mut imports, \"bitArraySliceToInt\", None);\n        }\n\n        if self.tracker.sized_integer_segment_used {\n            self.register_prelude_usage(&mut imports, \"sizedInt\", None);\n        }\n\n        if self.tracker.string_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"stringBits\", None);\n        }\n\n        if self.tracker.string_utf16_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"stringToUtf16\", None);\n        }\n\n        if self.tracker.string_utf32_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"stringToUtf32\", None);\n        }\n\n        if self.tracker.codepoint_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"codepointBits\", None);\n        }\n\n        if self.tracker.codepoint_utf16_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"codepointToUtf16\", None);\n        }\n\n        if self.tracker.codepoint_utf32_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"codepointToUtf32\", None);\n        }\n\n        if self.tracker.float_bit_array_segment_used {\n            self.register_prelude_usage(&mut imports, \"sizedFloat\", None);\n        }\n\n        let echo_definition = self.echo_definition(&mut imports);\n        let type_reference = self.type_reference();\n        let filepath_definition = self.filepath_definition();\n\n        // Put it all together\n\n        if imports.is_empty() && statements.is_empty() {\n            docvec![\n                type_reference,\n                filepath_definition,\n                \"export {}\",\n                line(),\n                echo_definition\n            ]\n        } else if imports.is_empty() {\n            statements.push(line());\n            docvec![\n                type_reference,\n                filepath_definition,\n                statements,\n                echo_definition\n            ]\n        } else if statements.is_empty() {\n            docvec![\n                type_reference,\n                imports.into_doc(JavaScriptCodegenTarget::JavaScript),\n                filepath_definition,\n                echo_definition,\n            ]\n        } else {\n            docvec![\n                type_reference,\n                imports.into_doc(JavaScriptCodegenTarget::JavaScript),\n                line(),\n                filepath_definition,\n                statements,\n                line(),\n                echo_definition\n            ]\n        }\n    }\n\n    fn echo_definition(&mut self, imports: &mut Imports<'a>) -> Document<'a> {\n        if !self.tracker.echo_used {\n            return nil();\n        }\n\n        if StdlibPackage::Present == self.stdlib_package {\n            let value = Some((\n                AssignName::Variable(\"stdlib$dict\".into()),\n                SrcSpan::default(),\n            ));\n\n            self.register_import(imports, \"gleam_stdlib\", \"gleam/dict\", &value, &[]);\n        }\n        self.register_prelude_usage(imports, \"BitArray\", Some(\"$BitArray\"));\n        self.register_prelude_usage(imports, \"List\", Some(\"$List\"));\n        self.register_prelude_usage(imports, \"UtfCodepoint\", Some(\"$UtfCodepoint\"));\n        docvec![line(), std::include_str!(\"../templates/echo.mjs\"), line()]\n    }\n\n    fn register_prelude_usage(\n        &self,\n        imports: &mut Imports<'a>,\n        name: &'static str,\n        alias: Option<&'static str>,\n    ) {\n        let path = self.import_path(&self.module.type_info.package, PRELUDE_MODULE_NAME);\n        let member = Member {\n            name: name.to_doc(),\n            alias: alias.map(|a| a.to_doc()),\n        };\n        imports.register_module(path, [], [member]);\n    }\n\n    fn custom_type_definition(\n        &mut self,\n        custom_type: &'a TypedCustomType,\n    ) -> Option<Vec<Document<'a>>> {\n        if self\n            .module\n            .unused_definition_positions\n            .contains(&custom_type.location.start)\n        {\n            return None;\n        }\n\n        let TypedCustomType {\n            name,\n            publicity,\n            constructors,\n            opaque,\n            ..\n        } = custom_type;\n\n        // If there's no constructors then there's nothing to do here.\n        if constructors.is_empty() {\n            return Some(vec![]);\n        }\n\n        self.tracker.custom_type_used = true;\n\n        let constructor_publicity = if *opaque || publicity.is_private() {\n            Publicity::Private\n        } else {\n            Publicity::Public\n        };\n\n        let mut definitions = constructors\n            .iter()\n            .map(|constructor| self.variant_definition(constructor, name, constructor_publicity))\n            .collect_vec();\n\n        // Generate getters for fields shared between variants\n        if let Some(accessors_map) = self.module.type_info.accessors.get(name)\n            && !accessors_map.shared_accessors.is_empty()\n            // Don't bother generating shared getters when there's only one variant,\n            // since the specific accessors can always be uses instead.\n            && constructors.len() != 1\n            // Only generate accessors for the API if the constructors are public\n            && constructor_publicity.is_public()\n        {\n            definitions.push(self.shared_custom_type_fields(name, &accessors_map.shared_accessors));\n        }\n\n        Some(definitions)\n    }\n\n    fn variant_definition(\n        &self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n        publicity: Publicity,\n    ) -> Document<'a> {\n        let class_definition = self.variant_class_definition(constructor, publicity);\n\n        // If the custom type is private or opaque, we don't need to generate API\n        // functions for it.\n        if publicity.is_private() {\n            return class_definition;\n        }\n\n        let constructor_definition = self.variant_constructor_definition(constructor, type_name);\n        let variant_check_definition = self.variant_check_definition(constructor, type_name);\n        let fields_definition = self.variant_fields_definition(constructor, type_name);\n\n        docvec![\n            class_definition,\n            line(),\n            constructor_definition,\n            line(),\n            variant_check_definition,\n            fields_definition,\n        ]\n    }\n\n    fn variant_constructor_definition(\n        &self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n    ) -> Document<'a> {\n        let mut arguments = Vec::new();\n\n        for (index, parameter) in constructor.arguments.iter().enumerate() {\n            if let Some((_, label)) = &parameter.label {\n                arguments.push(maybe_escape_identifier(label).to_doc());\n            } else {\n                arguments.push(eco_format!(\"${index}\").to_doc());\n            }\n        }\n\n        let construction = docvec![\n            break_(\"\", \" \"),\n            \"new \",\n            constructor.name.as_str(),\n            \"(\",\n            join(arguments.clone(), break_(\",\", \", \")).group(),\n            \");\"\n        ]\n        .group();\n\n        docvec![\n            \"export const \",\n            type_name,\n            \"$\",\n            constructor.name.as_str(),\n            \" = (\",\n            join(arguments, break_(\",\", \", \")),\n            \") =>\",\n            construction.nest(INDENT),\n        ]\n    }\n\n    fn variant_check_definition(\n        &self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n    ) -> Document<'a> {\n        let construction = docvec![\n            break_(\"\", \" \"),\n            \"value instanceof \",\n            constructor.name.as_str(),\n            \";\"\n        ]\n        .group();\n\n        docvec![\n            \"export const \",\n            type_name,\n            \"$is\",\n            constructor.name.as_str(),\n            \" = (value) =>\",\n            construction.nest(INDENT),\n        ]\n    }\n\n    fn variant_fields_definition(\n        &self,\n        constructor: &'a TypedRecordConstructor,\n        type_name: &'a str,\n    ) -> Document<'a> {\n        let mut functions = Vec::new();\n\n        for (index, argument) in constructor.arguments.iter().enumerate() {\n            // Always generate the accessor for the value at this index. Although\n            // this is not necessary when a label is present, we want to make sure\n            // that adding a label to a record isn't a breaking change. For this\n            // reason, we need to generate an index getter even when a label is\n            // present to ensure consistent behaviour between labelled and unlabelled\n            // field access.\n            let function_name = eco_format!(\n                \"{type_name}${record_name}${index}\",\n                record_name = constructor.name,\n            );\n\n            let contents;\n\n            // If the argument is labelled, also generate a getter for the labelled\n            // argument.\n            if let Some((_, label)) = &argument.label {\n                let function_name = eco_format!(\n                    \"{type_name}${record_name}${label}\",\n                    record_name = constructor.name,\n                );\n\n                contents =\n                    docvec![break_(\"\", \" \"), \"value.\", maybe_escape_property(label), \";\"].group();\n\n                functions.push(docvec![\n                    line(),\n                    \"export const \",\n                    function_name,\n                    \" = (value) =>\",\n                    contents.clone().nest(INDENT),\n                ]);\n            } else {\n                contents = docvec![break_(\"\", \" \"), \"value[\", index, \"];\"].group()\n            }\n\n            functions.push(docvec![\n                line(),\n                \"export const \",\n                function_name,\n                \" = (value) =>\",\n                contents.nest(INDENT),\n            ]);\n        }\n\n        concat(functions)\n    }\n\n    fn shared_custom_type_fields(\n        &self,\n        type_name: &'a str,\n        shared_accessors: &HashMap<EcoString, RecordAccessor>,\n    ) -> Document<'a> {\n        let accessors = shared_accessors.keys().sorted().map(|field| {\n            let function_name = eco_format!(\"{type_name}${field}\");\n\n            let contents =\n                docvec![break_(\"\", \" \"), \"value.\", maybe_escape_property(field), \";\"].group();\n\n            docvec![\n                \"export const \",\n                function_name,\n                \" = (value) =>\",\n                contents.nest(INDENT),\n            ]\n        });\n        concat(Itertools::intersperse(accessors, line()))\n    }\n\n    fn variant_class_definition(\n        &self,\n        constructor: &'a TypedRecordConstructor,\n        publicity: Publicity,\n    ) -> Document<'a> {\n        fn parameter((i, arg): (usize, &TypedRecordConstructorArg)) -> Document<'_> {\n            arg.label\n                .as_ref()\n                .map(|(_, s)| maybe_escape_identifier(s))\n                .unwrap_or_else(|| eco_format!(\"${i}\"))\n                .to_doc()\n        }\n\n        let doc = if let Some((_, documentation)) = &constructor.documentation {\n            jsdoc_comment(documentation, publicity).append(line())\n        } else {\n            nil()\n        };\n\n        let head = if publicity.is_public() {\n            \"export class \"\n        } else {\n            \"class \"\n        };\n        let head = docvec![head, &constructor.name, \" extends $CustomType {\"];\n\n        if constructor.arguments.is_empty() {\n            return head.append(\"}\");\n        };\n\n        let parameters = join(\n            constructor.arguments.iter().enumerate().map(parameter),\n            break_(\",\", \", \"),\n        );\n\n        let constructor_body = join(\n            constructor.arguments.iter().enumerate().map(|(i, arg)| {\n                let var = parameter((i, arg));\n                match &arg.label {\n                    None => docvec![\"this[\", i, \"] = \", var, \";\"],\n                    Some((_, name)) => {\n                        docvec![\"this.\", maybe_escape_property(name), \" = \", var, \";\"]\n                    }\n                }\n            }),\n            line(),\n        );\n\n        let class_body = docvec![\n            line(),\n            \"constructor(\",\n            parameters,\n            \") {\",\n            docvec![line(), \"super();\", line(), constructor_body].nest(INDENT),\n            line(),\n            \"}\",\n        ]\n        .nest(INDENT);\n\n        docvec![doc, head, class_body, line(), \"}\"]\n    }\n\n    fn definitions(&mut self) -> Vec<Document<'a>> {\n        let mut definitions = vec![];\n\n        for custom_type in &self.module.definitions.custom_types {\n            if let Some(mut new_definitions) = self.custom_type_definition(custom_type) {\n                definitions.append(&mut new_definitions)\n            }\n        }\n\n        for constant in &self.module.definitions.constants {\n            if let Some(definition) = self.module_constant(constant) {\n                definitions.push(definition)\n            }\n        }\n\n        for function in &self.module.definitions.functions {\n            if let Some(definition) = self.module_function(function) {\n                definitions.push(definition)\n            }\n        }\n\n        definitions\n    }\n\n    fn collect_imports(&mut self) -> Imports<'a> {\n        let mut imports = Imports::new();\n\n        for Import {\n            module,\n            as_name,\n            unqualified_values,\n            package,\n            ..\n        } in &self.module.definitions.imports\n        {\n            self.register_import(&mut imports, package, module, as_name, unqualified_values);\n        }\n\n        for function in &self.module.definitions.functions {\n            if let Some((_, name)) = &function.name\n                && let Some((module, external_function, _)) = &function.external_javascript\n            {\n                self.register_external_function(\n                    &mut imports,\n                    function.publicity,\n                    name,\n                    module,\n                    external_function,\n                )\n            }\n        }\n\n        imports\n    }\n\n    fn import_path(&self, package: &'a str, module: &'a str) -> EcoString {\n        // TODO: strip shared prefixed between current module and imported\n        // module to avoid descending and climbing back out again\n        if package == self.module.type_info.package || package.is_empty() {\n            // Same package\n            match self.current_module_name_segments_count {\n                1 => eco_format!(\"./{module}.mjs\"),\n                _ => {\n                    let prefix = \"../\".repeat(self.current_module_name_segments_count - 1);\n                    eco_format!(\"{prefix}{module}.mjs\")\n                }\n            }\n        } else {\n            // Different package\n            let prefix = \"../\".repeat(self.current_module_name_segments_count);\n            eco_format!(\"{prefix}{package}/{module}.mjs\")\n        }\n    }\n\n    fn register_import(\n        &mut self,\n        imports: &mut Imports<'a>,\n        package: &'a str,\n        module: &'a str,\n        as_name: &Option<(AssignName, SrcSpan)>,\n        unqualified: &[UnqualifiedImport],\n    ) {\n        let get_name = |module: &'a str| {\n            module\n                .split('/')\n                .next_back()\n                .expect(\"JavaScript generator could not identify imported module name.\")\n        };\n\n        let (discarded, module_name) = match as_name {\n            None => (false, get_name(module)),\n            Some((AssignName::Discard(_), _)) => (true, get_name(module)),\n            Some((AssignName::Variable(name), _)) => (false, name.as_str()),\n        };\n\n        let module_name = eco_format!(\"${module_name}\");\n        let path = self.import_path(package, module);\n        let unqualified_imports = unqualified.iter().map(|i| {\n            let alias = i.as_name.as_ref().map(|n| {\n                self.register_in_scope(n);\n                maybe_escape_identifier(n).to_doc()\n            });\n            let name = maybe_escape_identifier(&i.name).to_doc();\n            Member { name, alias }\n        });\n\n        let aliases = if discarded { vec![] } else { vec![module_name] };\n        imports.register_module(path, aliases, unqualified_imports);\n    }\n\n    fn register_external_function(\n        &mut self,\n        imports: &mut Imports<'a>,\n        publicity: Publicity,\n        name: &'a str,\n        module: &'a str,\n        fun: &'a str,\n    ) {\n        let needs_escaping = !is_usable_js_identifier(name);\n        let member = Member {\n            name: fun.to_doc(),\n            alias: if name == fun && !needs_escaping {\n                None\n            } else if needs_escaping {\n                Some(escape_identifier(name).to_doc())\n            } else {\n                Some(name.to_doc())\n            },\n        };\n        if publicity.is_importable() {\n            imports.register_export(maybe_escape_identifier_string(name))\n        }\n        imports.register_module(EcoString::from(module), [], [member]);\n    }\n\n    fn module_constant(&mut self, constant: &'a TypedModuleConstant) -> Option<Document<'a>> {\n        let TypedModuleConstant {\n            documentation,\n            location,\n            publicity,\n            name,\n            value,\n            ..\n        } = constant;\n\n        // We don't generate any code for unused constants.\n        if self\n            .module\n            .unused_definition_positions\n            .contains(&location.start)\n        {\n            return None;\n        }\n\n        let head = if publicity.is_private() {\n            \"const \"\n        } else {\n            \"export const \"\n        };\n\n        let mut generator = expression::Generator::new(\n            self.module.name.clone(),\n            self.src_path.clone(),\n            self.line_numbers,\n            \"\".into(),\n            vec![],\n            &mut self.tracker,\n            self.module_scope.clone(),\n        );\n\n        let document = generator.constant_expression(Context::Constant, value);\n\n        let jsdoc = if let Some((_, documentation)) = documentation {\n            jsdoc_comment(documentation, *publicity).append(line())\n        } else {\n            nil()\n        };\n\n        Some(docvec![\n            jsdoc,\n            head,\n            maybe_escape_identifier(name),\n            \" = \",\n            document,\n            \";\",\n        ])\n    }\n\n    fn register_in_scope(&mut self, name: &str) {\n        let _ = self.module_scope.insert(name.into(), 0);\n    }\n\n    fn module_function(&mut self, function: &'a TypedFunction) -> Option<Document<'a>> {\n        // We don't generate any code for unused functions.\n        if self\n            .module\n            .unused_definition_positions\n            .contains(&function.location.start)\n        {\n            return None;\n        }\n\n        // If there's an external JavaScript implementation then it will be imported,\n        // so we don't need to generate a function definition.\n        if function.external_javascript.is_some() {\n            return None;\n        }\n\n        // If the function does not support JavaScript then we don't need to generate\n        // a function definition.\n        if !function.implementations.supports(Target::JavaScript) {\n            return None;\n        }\n\n        let (_, name) = function\n            .name\n            .as_ref()\n            .expect(\"A module's function must be named\");\n        let argument_names = function\n            .arguments\n            .iter()\n            .map(|arg| arg.names.get_variable_name())\n            .collect();\n        let mut generator = expression::Generator::new(\n            self.module.name.clone(),\n            self.src_path.clone(),\n            self.line_numbers,\n            name.clone(),\n            argument_names,\n            &mut self.tracker,\n            self.module_scope.clone(),\n        );\n\n        let function_doc = match &function.documentation {\n            None => nil(),\n            Some((_, documentation)) => {\n                jsdoc_comment(documentation, function.publicity).append(line())\n            }\n        };\n\n        let head = if function.publicity.is_private() {\n            \"function \"\n        } else {\n            \"export function \"\n        };\n\n        let body = generator.function_body(function.body.as_slice(), function.arguments.as_slice());\n\n        Some(docvec![\n            function_doc,\n            head,\n            maybe_escape_identifier(name.as_str()),\n            fun_arguments(function.arguments.as_slice(), generator.tail_recursion_used),\n            \" {\",\n            docvec![line(), body].nest(INDENT).group(),\n            line(),\n            \"}\",\n        ])\n    }\n\n    fn register_module_definitions_in_scope(&mut self) {\n        for constant in &self.module.definitions.constants {\n            self.register_in_scope(&constant.name)\n        }\n\n        for function in &self.module.definitions.functions {\n            if let Some((_, name)) = &function.name {\n                self.register_in_scope(name);\n            }\n        }\n\n        for import in &self.module.definitions.imports {\n            for unqualified_value in &import.unqualified_values {\n                self.register_in_scope(unqualified_value.used_name())\n            }\n        }\n    }\n\n    fn filepath_definition(&self) -> Document<'a> {\n        if !self.tracker.make_error_used {\n            return nil();\n        }\n\n        docvec![\"const FILEPATH = \", self.src_path.clone(), ';', lines(2)]\n    }\n}\n\nfn jsdoc_comment(documentation: &EcoString, publicity: Publicity) -> Document<'_> {\n    let doc_lines = documentation\n        .trim_end()\n        .split('\\n')\n        .map(|line| eco_format!(\" *{line}\", line = line.replace(\"*/\", \"*\\\\/\")).to_doc())\n        .collect_vec();\n\n    // We start with the documentation of the function\n    let doc_body = join(doc_lines, line());\n    let mut doc = docvec![\"/**\", line(), doc_body, line()];\n    if !publicity.is_public() {\n        // If the function is not public we hide the documentation using\n        // the `@ignore` tag: https://jsdoc.app/tags-ignore\n        doc = docvec![doc, \" * \", line(), \" * @ignore\", line()];\n    }\n    // And finally we close the doc comment\n    docvec![doc, \" */\"]\n}\n\n#[derive(Debug)]\npub struct ModuleConfig<'a> {\n    pub module: &'a TypedModule,\n    pub line_numbers: &'a LineNumbers,\n    pub src: &'a EcoString,\n    pub typescript: TypeScriptDeclarations,\n    pub stdlib_package: StdlibPackage,\n    pub path: &'a Utf8Path,\n    pub project_root: &'a Utf8Path,\n}\n\npub fn module(config: ModuleConfig<'_>) -> String {\n    let document = Generator::new(config).compile();\n    document.to_pretty_string(80)\n}\n\npub fn ts_declaration(module: &TypedModule) -> String {\n    let document = typescript::TypeScriptGenerator::new(module).compile();\n    document.to_pretty_string(80)\n}\n\nfn fun_arguments(arguments: &'_ [TypedArg], tail_recursion_used: bool) -> Document<'_> {\n    let mut discards = 0;\n    wrap_arguments(\n        arguments\n            .iter()\n            .map(|argument| match argument.get_variable_name() {\n                None => {\n                    let doc = if discards == 0 {\n                        \"_\".to_doc()\n                    } else {\n                        eco_format!(\"_{discards}\").to_doc()\n                    };\n                    discards += 1;\n                    doc\n                }\n                Some(name) if tail_recursion_used => eco_format!(\"loop${name}\").to_doc(),\n                Some(name) => maybe_escape_identifier(name).to_doc(),\n            }),\n    )\n}\n\nfn wrap_arguments<'a, I>(arguments: I) -> Document<'a>\nwhere\n    I: IntoIterator<Item = Document<'a>>,\n{\n    break_(\"\", \"\")\n        .append(join(arguments, break_(\",\", \", \")))\n        .nest(INDENT)\n        .append(break_(\"\", \"\"))\n        .surround(\"(\", \")\")\n        .group()\n}\n\nfn wrap_object<'a>(\n    items: impl IntoIterator<Item = (Document<'a>, Option<Document<'a>>)>,\n) -> Document<'a> {\n    let mut empty = true;\n    let fields = items.into_iter().map(|(key, value)| {\n        empty = false;\n        match value {\n            Some(value) => docvec![key, \": \", value],\n            None => key.to_doc(),\n        }\n    });\n    let fields = join(fields, break_(\",\", \", \"));\n\n    if empty {\n        \"{}\".to_doc()\n    } else {\n        docvec![\n            docvec![\"{\", break_(\"\", \" \"), fields]\n                .nest(INDENT)\n                .append(break_(\"\", \" \"))\n                .group(),\n            \"}\"\n        ]\n    }\n}\n\nfn is_usable_js_identifier(word: &str) -> bool {\n    !matches!(\n        word,\n        // Keywords and reserved words\n        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar\n        \"await\"\n            | \"arguments\"\n            | \"break\"\n            | \"case\"\n            | \"catch\"\n            | \"class\"\n            | \"const\"\n            | \"continue\"\n            | \"debugger\"\n            | \"default\"\n            | \"delete\"\n            | \"do\"\n            | \"else\"\n            | \"enum\"\n            | \"export\"\n            | \"extends\"\n            | \"eval\"\n            | \"false\"\n            | \"finally\"\n            | \"for\"\n            | \"function\"\n            | \"if\"\n            | \"implements\"\n            | \"import\"\n            | \"in\"\n            | \"instanceof\"\n            | \"interface\"\n            | \"let\"\n            | \"new\"\n            | \"null\"\n            | \"package\"\n            | \"private\"\n            | \"protected\"\n            | \"public\"\n            | \"return\"\n            | \"static\"\n            | \"super\"\n            | \"switch\"\n            | \"this\"\n            | \"throw\"\n            | \"true\"\n            | \"try\"\n            | \"typeof\"\n            | \"var\"\n            | \"void\"\n            | \"while\"\n            | \"with\"\n            | \"yield\"\n            // `undefined` to avoid any unintentional overriding.\n            | \"undefined\"\n            // `then` to avoid a module that defines a `then` function being\n            // used as a `thenable` in JavaScript when the module is imported\n            // dynamically, which results in unexpected behaviour.\n            // It is rather unfortunate that we have to do this.\n            | \"then\"\n    )\n}\n\nfn is_usable_js_property(label: &str) -> bool {\n    match label {\n        // `then` to avoid a custom type that defines a `then` function being\n        // used as a `thenable` in Javascript.\n        \"then\"\n        // `constructor` to avoid unintentional overriding of the constructor of\n        // records, leading to potential runtime crashes while using `withFields`.\n        | \"constructor\"\n        // `prototype` and `__proto__` to avoid unintentionally overriding the\n        // prototype chain.\n        | \"prototype\" | \"__proto__\" => false,\n        _ => true\n    }\n}\n\nfn maybe_escape_identifier_string(word: &str) -> EcoString {\n    if is_usable_js_identifier(word) {\n        EcoString::from(word)\n    } else {\n        escape_identifier(word)\n    }\n}\n\nfn escape_identifier(word: &str) -> EcoString {\n    eco_format!(\"{word}$\")\n}\n\nfn maybe_escape_identifier(word: &str) -> EcoString {\n    if is_usable_js_identifier(word) {\n        EcoString::from(word)\n    } else {\n        escape_identifier(word)\n    }\n}\n\nfn maybe_escape_property(label: &str) -> EcoString {\n    if is_usable_js_property(label) {\n        EcoString::from(label)\n    } else {\n        escape_identifier(label)\n    }\n}\n\n#[derive(Debug, Default)]\npub(crate) struct UsageTracker {\n    pub ok_used: bool,\n    pub list_used: bool,\n    pub list_empty_class_used: bool,\n    pub list_non_empty_class_used: bool,\n    pub prepend_used: bool,\n    pub error_used: bool,\n    pub int_remainder_used: bool,\n    pub make_error_used: bool,\n    pub custom_type_used: bool,\n    pub int_division_used: bool,\n    pub float_division_used: bool,\n    pub object_equality_used: bool,\n    pub bit_array_literal_used: bool,\n    pub bit_array_slice_used: bool,\n    pub bit_array_slice_to_float_used: bool,\n    pub bit_array_slice_to_int_used: bool,\n    pub sized_integer_segment_used: bool,\n    pub string_bit_array_segment_used: bool,\n    pub string_utf16_bit_array_segment_used: bool,\n    pub string_utf32_bit_array_segment_used: bool,\n    pub codepoint_bit_array_segment_used: bool,\n    pub codepoint_utf16_bit_array_segment_used: bool,\n    pub codepoint_utf32_bit_array_segment_used: bool,\n    pub float_bit_array_segment_used: bool,\n    pub echo_used: bool,\n}\n\nfn bool(bool: bool) -> Document<'static> {\n    match bool {\n        true => \"true\".to_doc(),\n        false => \"false\".to_doc(),\n    }\n}\n\n/// Int segments <= 48 bits wide in bit arrays are within JavaScript's safe range and are evaluated\n/// at compile time when all inputs are known. This is done for both bit array expressions and\n/// pattern matching.\n///\n/// Int segments of any size could be evaluated at compile time, but currently aren't due to the\n/// potential for causing large generated JS for inputs such as `<<0:8192>>`.\n///\npub(crate) const SAFE_INT_SEGMENT_MAX_SIZE: usize = 48;\n\n/// Evaluates the value of an Int segment in a bit array into its corresponding bytes. This avoids\n/// needing to do the evaluation at runtime when all inputs are known at compile-time.\n///\npub(crate) fn bit_array_segment_int_value_to_bytes(\n    mut value: BigInt,\n    size: BigInt,\n    endianness: Endianness,\n) -> Vec<u8> {\n    // Clamp negative sizes to zero\n    let size = size.max(BigInt::ZERO);\n\n    // Convert size to u32. This is safe because this function isn't called with a size greater\n    // than `SAFE_INT_SEGMENT_MAX_SIZE`.\n    let size = size\n        .to_u32()\n        .expect(\"bit array segment size to be a valid u32\");\n\n    // Convert negative number to two's complement representation\n    if value < BigInt::ZERO {\n        let value_modulus = BigInt::from(2).pow(size);\n        value = &value_modulus + (value % &value_modulus);\n    }\n\n    // Convert value to the desired number of bytes\n    let mut bytes = vec![0u8; size as usize / 8];\n    for byte in bytes.iter_mut() {\n        *byte = (&value % BigInt::from(256))\n            .to_u8()\n            .expect(\"modulo result to be a valid u32\");\n        value /= BigInt::from(256);\n    }\n\n    if endianness.is_big() {\n        bytes.reverse();\n    }\n\n    bytes\n}\n"
  },
  {
    "path": "compiler-core/src/lib.rs",
    "content": "#![warn(\n    clippy::all,\n    clippy::dbg_macro,\n    clippy::todo,\n    clippy::mem_forget,\n    // TODO: enable once the false positive bug is solved\n    // clippy::use_self,\n    clippy::filter_map_next,\n    clippy::needless_continue,\n    clippy::needless_borrow,\n    clippy::match_wildcard_for_single_variants,\n    clippy::imprecise_flops,\n    clippy::suboptimal_flops,\n    clippy::lossy_float_literal,\n    clippy::rest_pat_in_fully_bound_structs,\n    clippy::fn_params_excessive_bools,\n    clippy::inefficient_to_string,\n    clippy::linkedlist,\n    clippy::macro_use_imports,\n    clippy::option_option,\n    clippy::verbose_file_reads,\n    clippy::unnested_or_patterns,\n    rust_2018_idioms,\n    missing_debug_implementations,\n    missing_copy_implementations,\n    trivial_casts,\n    trivial_numeric_casts,\n    nonstandard_style,\n    unexpected_cfgs,\n    unused_import_braces,\n    unused_qualifications,\n    clippy::wildcard_enum_match_arm\n)]\n#![deny(\n    clippy::await_holding_lock,\n    clippy::disallowed_methods,\n    clippy::if_let_mutex,\n    clippy::indexing_slicing,\n    clippy::mem_forget,\n    clippy::ok_expect,\n    clippy::unimplemented,\n    clippy::unwrap_used,\n    unsafe_code,\n    unstable_features,\n    unused_results\n)]\n#![allow(\n    clippy::assign_op_pattern,\n    clippy::to_string_trait_impl,\n    clippy::match_single_binding,\n    clippy::match_like_matches_macro,\n    clippy::inconsistent_struct_constructor,\n    clippy::len_without_is_empty,\n    // TODO: fix\n    clippy::arc_with_non_send_sync,\n)]\n\n#[cfg(test)]\n#[macro_use]\nextern crate pretty_assertions;\n\npub mod analyse;\npub mod ast;\npub mod bit_array;\npub mod build;\npub mod codegen;\npub mod config;\npub mod dependency;\npub mod diagnostic;\npub mod docs;\npub mod encryption;\npub mod erlang;\npub mod error;\npub mod fix;\npub mod format;\npub mod hex;\npub mod io;\npub mod javascript;\npub mod line_numbers;\npub mod manifest;\npub mod metadata;\npub mod package_interface;\npub mod parse;\npub mod paths;\npub mod pretty;\npub mod requirement;\npub mod strings;\npub mod type_;\npub mod uid;\npub mod version;\npub mod warning;\n\npub(crate) mod ast_folder;\nmod call_graph;\nmod dep_tree;\npub(crate) mod derivation_tree;\npub mod exhaustiveness;\npub(crate) mod graph;\npub(crate) mod inline;\npub mod reference;\n\npub use error::{Error, Result};\npub use warning::Warning;\n\nconst GLEAM_CORE_PACKAGE_NAME: &str = \"\";\npub const STDLIB_PACKAGE_NAME: &str = \"gleam_stdlib\";\n"
  },
  {
    "path": "compiler-core/src/line_numbers.rs",
    "content": "use crate::ast::SrcSpan;\nuse lsp_types::Position;\nuse std::collections::HashMap;\n\n/// A struct which contains information about line numbers of a source file,\n/// and can convert between byte offsets that are used in the compiler and\n/// line-column pairs used in LSP.\n#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]\npub struct LineNumbers {\n    /// The byte offsets of the start of each line of the source file\n    pub line_starts: Vec<u32>,\n    /// The total length of the source file\n    pub length: u32,\n    /// A mapping of byte offsets to character length information. This is used\n    /// when converting between byte indices and line-column numbers, because\n    /// LSP uses UTF-16, while Rust encodes strings as UTF-8.\n    ///\n    /// This only contains characters which are more than one byte in UTF-8,\n    /// because one byte UTF-8 characters are one UTF-16 segment also, so no\n    /// translation is needed.\n    ///\n    /// We could store the whole source file here instead, however that would\n    /// be quite wasteful. Most Gleam programs use only ASCII characters, meaning\n    /// UTF-8 offsets are the same as UTF-16 ones. With this representation, we\n    /// only need to store a few characters.\n    ///\n    /// In most programs this will be empty because they will only be using\n    /// ASCII characters.\n    pub mapping: HashMap<usize, Character>,\n}\n\n/// Information about how a character is encoded in UTF-8 and UTF-16.\n#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq)]\npub struct Character {\n    /// The number of bytes needed to encode this in UTF-8.\n    pub length_utf8: u8,\n    /// The number of 16-bit segments needed to encode this in UTF-16.\n    pub length_utf16: u8,\n}\n\nimpl LineNumbers {\n    pub fn new(src: &str) -> Self {\n        Self {\n            length: src.len() as u32,\n            line_starts: std::iter::once(0)\n                .chain(src.match_indices('\\n').map(|(i, _)| i as u32 + 1))\n                .collect(),\n            mapping: Self::mapping(src),\n        }\n    }\n\n    fn mapping(src: &str) -> HashMap<usize, Character> {\n        let mut map = HashMap::new();\n\n        for (i, char) in src.char_indices() {\n            let length = char.len_utf8();\n            if length != 1 {\n                _ = map.insert(\n                    i,\n                    Character {\n                        length_utf8: length as u8,\n                        length_utf16: char.len_utf16() as u8,\n                    },\n                );\n            }\n        }\n\n        map\n    }\n\n    /// Returns the 1-indexed line number of a given byte index\n    pub fn line_number(&self, byte_index: u32) -> u32 {\n        self.line_starts\n            .binary_search(&byte_index)\n            .unwrap_or_else(|next_line| next_line - 1) as u32\n            + 1\n    }\n\n    /// Returns the 1-indexed line and column number of a given byte index,\n    /// using a UTF-16 character offset.\n    pub fn line_and_column_number(&self, byte_index: u32) -> LineColumn {\n        let line = self.line_number(byte_index);\n        let line_start = self\n            .line_starts\n            .get(line as usize - 1)\n            .copied()\n            .unwrap_or_default();\n\n        let mut u8_offset = line_start;\n        let mut u16_offset = 0;\n\n        loop {\n            if u8_offset >= byte_index {\n                break;\n            }\n\n            if let Some(length) = self.mapping.get(&(u8_offset as usize)) {\n                u8_offset += length.length_utf8 as u32;\n                u16_offset += length.length_utf16 as u32;\n            } else {\n                u16_offset += 1;\n                u8_offset += 1;\n            }\n        }\n\n        LineColumn {\n            line,\n            column: u16_offset + 1,\n        }\n    }\n\n    /// Returns the byte index of the corresponding LSP line-column `Position`,\n    /// translating from a UTF-16 character index to a UTF-8 byte index.\n    pub fn byte_index(&self, position: Position) -> u32 {\n        let line_start = match self.line_starts.get(position.line as usize) {\n            Some(&line_start) => line_start,\n            None => return self.length,\n        };\n\n        let mut u8_offset = line_start;\n        let mut u16_offset = 0;\n\n        loop {\n            if u16_offset >= position.character {\n                break;\n            }\n\n            if let Some(length) = self.mapping.get(&(u8_offset as usize)) {\n                u8_offset += length.length_utf8 as u32;\n                u16_offset += length.length_utf16 as u32;\n            } else {\n                u16_offset += 1;\n                u8_offset += 1;\n            }\n        }\n\n        u8_offset\n    }\n\n    /// Checks if the given span spans an entire line (excluding the newline\n    /// character itself).\n    pub fn spans_entire_line(&self, span: &SrcSpan) -> bool {\n        self.line_starts.iter().any(|&line_start| {\n            line_start == span.start && self.line_starts.contains(&(span.end + 1))\n        })\n    }\n}\n\n#[test]\nfn byte_index() {\n    let src = r#\"import gleam/io\n\npub fn main() {\n  io.println(\"Hello, world!\")\n}\n\"#;\n    let line_numbers = LineNumbers::new(src);\n\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 0,\n            character: 0\n        }),\n        0\n    );\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 0,\n            character: 4\n        }),\n        4\n    );\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 100,\n            character: 0\n        }),\n        src.len() as u32\n    );\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 2,\n            character: 1\n        }),\n        18\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3628\n#[test]\nfn byte_index_with_multibyte_characters() {\n    let src = r#\"fn wibble(_a, _b, _c) {\n  todo\n}\n\npub fn main() {\n  wibble(\"क्षि\", 10, <<\"abc\">>)\n}\n\"#;\n    let line_numbers = LineNumbers::new(src);\n\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 1,\n            character: 6\n        }),\n        30\n    );\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 5,\n            character: 2\n        }),\n        52\n    );\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 5,\n            character: 17\n        }),\n        75\n    );\n    assert_eq!(\n        line_numbers.byte_index(Position {\n            line: 6,\n            character: 1\n        }),\n        91\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3628\n#[test]\nfn line_and_column_with_multibyte_characters() {\n    let src = r#\"fn wibble(_a, _b, _c) {\n  todo\n}\n\npub fn main() {\n  wibble(\"क्षि\", 10, <<\"abc\">>)\n}\n\"#;\n    let line_numbers = LineNumbers::new(src);\n\n    assert_eq!(\n        line_numbers.line_and_column_number(30),\n        LineColumn { line: 2, column: 7 }\n    );\n    assert_eq!(\n        line_numbers.line_and_column_number(52),\n        LineColumn { line: 6, column: 3 }\n    );\n    assert_eq!(\n        line_numbers.line_and_column_number(75),\n        LineColumn {\n            line: 6,\n            column: 18\n        }\n    );\n    assert_eq!(\n        line_numbers.line_and_column_number(91),\n        LineColumn { line: 7, column: 2 }\n    );\n}\n\n/// A 1-index line and column position\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct LineColumn {\n    pub line: u32,\n    pub column: u32,\n}\n"
  },
  {
    "path": "compiler-core/src/manifest.rs",
    "content": "use std::collections::HashMap;\nuse std::fmt;\n\nuse crate::Result;\nuse crate::io::{make_relative, ordered_map};\nuse crate::requirement::Requirement;\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse itertools::Itertools;\n\n#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]\npub struct Manifest {\n    #[serde(serialize_with = \"ordered_map\")]\n    pub requirements: HashMap<EcoString, Requirement>,\n    #[serde(serialize_with = \"sorted_vec\")]\n    pub packages: Vec<ManifestPackage>,\n}\n\nimpl Manifest {\n    // Rather than using the toml library to do serialization we implement it\n    // manually so that we can control the formatting.\n    // We want to keep entries on a single line each so that they are more\n    // resistant to merge conflicts and are easier to fix when it does happen.\n    pub fn to_toml(&self, root_path: &Utf8Path) -> String {\n        let mut buffer = String::new();\n        let Self {\n            requirements,\n            packages,\n        } = self;\n\n        buffer.push_str(\n            \"# This file was generated by Gleam\n# You typically do not need to edit this file\n\n\",\n        );\n\n        // Packages\n        buffer.push_str(\"packages = [\\n\");\n        for ManifestPackage {\n            name,\n            source,\n            version,\n            otp_app,\n            build_tools,\n            requirements,\n        } in packages.iter().sorted_by(|a, b| a.name.cmp(&b.name))\n        {\n            buffer.push_str(r#\"  {\"#);\n            buffer.push_str(r#\" name = \"\"#);\n            buffer.push_str(name);\n            buffer.push_str(r#\"\", version = \"\"#);\n            buffer.push_str(&version.to_string());\n            buffer.push_str(r#\"\", build_tools = [\"#);\n            for (i, tool) in build_tools.iter().enumerate() {\n                if i != 0 {\n                    buffer.push_str(\", \");\n                }\n                buffer.push('\"');\n                buffer.push_str(tool);\n                buffer.push('\"');\n            }\n\n            buffer.push_str(\"], requirements = [\");\n            for (i, package) in requirements.iter().sorted_by(|a, b| a.cmp(b)).enumerate() {\n                if i != 0 {\n                    buffer.push_str(\", \");\n                }\n                buffer.push('\"');\n                buffer.push_str(package);\n                buffer.push('\"');\n            }\n            buffer.push(']');\n\n            if let Some(app) = otp_app {\n                buffer.push_str(\", otp_app = \\\"\");\n                buffer.push_str(app);\n                buffer.push('\"');\n            }\n\n            match source {\n                ManifestPackageSource::Hex { outer_checksum } => {\n                    buffer.push_str(r#\", source = \"hex\", outer_checksum = \"\"#);\n                    buffer.push_str(&outer_checksum.to_string());\n                    buffer.push('\"');\n                }\n                ManifestPackageSource::Git { repo, commit } => {\n                    buffer.push_str(r#\", source = \"git\", repo = \"\"#);\n                    buffer.push_str(repo);\n                    buffer.push_str(r#\"\", commit = \"\"#);\n                    buffer.push_str(commit);\n                    buffer.push('\"');\n                }\n                ManifestPackageSource::Local { path } => {\n                    buffer.push_str(r#\", source = \"local\", path = \"\"#);\n                    buffer.push_str(&make_relative(root_path, path).as_str().replace('\\\\', \"/\"));\n                    buffer.push('\"');\n                }\n            };\n\n            buffer.push_str(\" },\\n\");\n        }\n        buffer.push_str(\"]\\n\\n\");\n\n        // Requirements\n        buffer.push_str(\"[requirements]\\n\");\n        for (name, requirement) in requirements.iter().sorted_by(|a, b| a.0.cmp(b.0)) {\n            buffer.push_str(name);\n            buffer.push_str(\" = \");\n            buffer.push_str(&requirement.to_toml(root_path));\n            buffer.push('\\n');\n        }\n\n        buffer\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub struct Base16Checksum(pub Vec<u8>);\n\nimpl ToString for Base16Checksum {\n    fn to_string(&self) -> String {\n        base16::encode_upper(&self.0)\n    }\n}\n\nimpl serde::Serialize for Base16Checksum {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_str(&base16::encode_upper(&self.0))\n    }\n}\n\nimpl<'de> serde::Deserialize<'de> for Base16Checksum {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        deserializer.deserialize_str(Base16ChecksumVisitor)\n    }\n}\n\nstruct Base16ChecksumVisitor;\n\nimpl<'de> serde::de::Visitor<'de> for Base16ChecksumVisitor {\n    type Value = Base16Checksum;\n\n    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {\n        formatter.write_str(\"a base 16 checksum\")\n    }\n\n    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n    where\n        E: serde::de::Error,\n    {\n        base16::decode(value)\n            .map(Base16Checksum)\n            .map_err(serde::de::Error::custom)\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]\npub struct ManifestPackage {\n    pub name: EcoString,\n    pub version: Version,\n    pub build_tools: Vec<EcoString>,\n    #[serde(default)]\n    pub otp_app: Option<EcoString>,\n    #[serde(serialize_with = \"sorted_vec\")]\n    pub requirements: Vec<EcoString>,\n    #[serde(flatten)]\n    pub source: ManifestPackageSource,\n}\n\nimpl ManifestPackage {\n    pub fn with_build_tools(mut self, build_tools: &'static [&'static str]) -> Self {\n        self.build_tools = build_tools.iter().map(|s| (*s).into()).collect();\n        self\n    }\n\n    pub fn application_name(&self) -> &EcoString {\n        match self.otp_app {\n            Some(ref app) => app,\n            None => &self.name,\n        }\n    }\n\n    #[inline]\n    pub fn is_hex(&self) -> bool {\n        matches!(self.source, ManifestPackageSource::Hex { .. })\n    }\n\n    #[inline]\n    pub fn is_local(&self) -> bool {\n        matches!(self.source, ManifestPackageSource::Local { .. })\n    }\n\n    #[inline]\n    pub fn is_git(&self) -> bool {\n        matches!(self.source, ManifestPackageSource::Git { .. })\n    }\n}\n\n#[cfg(test)]\nimpl Default for ManifestPackage {\n    fn default() -> Self {\n        Self {\n            name: Default::default(),\n            build_tools: Default::default(),\n            otp_app: Default::default(),\n            requirements: Default::default(),\n            version: Version::new(1, 0, 0),\n            source: ManifestPackageSource::Hex {\n                outer_checksum: Base16Checksum(vec![]),\n            },\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]\n#[serde(tag = \"source\")]\npub enum ManifestPackageSource {\n    #[serde(rename = \"hex\")]\n    Hex { outer_checksum: Base16Checksum },\n    #[serde(rename = \"git\")]\n    Git { repo: EcoString, commit: EcoString },\n    #[serde(rename = \"local\")]\n    Local { path: Utf8PathBuf }, // should be the canonical path\n}\n\nimpl ManifestPackageSource {\n    pub fn kind(&self) -> ManifestPackageSourceKind {\n        match self {\n            ManifestPackageSource::Hex { .. } => ManifestPackageSourceKind::Hex,\n            ManifestPackageSource::Git { .. } => ManifestPackageSourceKind::Git,\n            ManifestPackageSource::Local { .. } => ManifestPackageSourceKind::Local,\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum ManifestPackageSourceKind {\n    Hex,\n    Git,\n    Local,\n}\n\nfn sorted_vec<S, T>(value: &[T], serializer: S) -> Result<S::Ok, S::Error>\nwhere\n    S: serde::Serializer,\n    T: serde::Serialize + Ord,\n{\n    use serde::Serialize;\n    let mut value: Vec<&T> = value.iter().collect();\n    value.sort();\n    value.serialize(serializer)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[cfg(windows)]\n    const HOME: &'static str = \"C:\\\\home\\\\louis\\\\packages\\\\some_folder\";\n\n    #[cfg(windows)]\n    const PACKAGE: &'static str = \"C:\\\\home\\\\louis\\\\packages\\\\path\\\\to\\\\package\";\n\n    #[cfg(windows)]\n    const PACKAGE_WITH_UNC: &'static str = \"\\\\\\\\?\\\\C:\\\\home\\\\louis\\\\packages\\\\path\\\\to\\\\package\";\n\n    #[cfg(not(windows))]\n    const HOME: &str = \"/home/louis/packages/some_folder\";\n\n    #[cfg(not(windows))]\n    const PACKAGE: &str = \"/home/louis/packages/path/to/package\";\n\n    #[test]\n    fn manifest_toml_format() {\n        let manifest = Manifest {\n            requirements: [\n                (\"zzz\".into(), Requirement::hex(\"> 0.0.0\").unwrap()),\n                (\"aaa\".into(), Requirement::hex(\"> 0.0.0\").unwrap()),\n                (\n                    \"awsome_local2\".into(),\n                    Requirement::git(\"https://github.com/gleam-lang/gleam.git\", \"bd9fe02f\"),\n                ),\n                (\n                    \"awsome_local1\".into(),\n                    Requirement::path(\"../path/to/package\"),\n                ),\n                (\"gleam_stdlib\".into(), Requirement::hex(\"~> 0.17\").unwrap()),\n                (\"gleeunit\".into(), Requirement::hex(\"~> 0.1\").unwrap()),\n            ]\n            .into(),\n            packages: vec![\n                ManifestPackage {\n                    name: \"gleam_stdlib\".into(),\n                    version: Version::new(0, 17, 1),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![1, 22]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"aaa\".into(),\n                    version: Version::new(0, 4, 0),\n                    build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                    otp_app: Some(\"aaa_app\".into()),\n                    requirements: vec![\"zzz\".into(), \"gleam_stdlib\".into()],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![3, 22]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"zzz\".into(),\n                    version: Version::new(0, 4, 0),\n                    build_tools: [\"mix\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![3, 22]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"awsome_local2\".into(),\n                    version: Version::new(1, 2, 3),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Git {\n                        repo: \"https://github.com/gleam-lang/gleam.git\".into(),\n                        commit: \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\".into(),\n                    },\n                },\n                ManifestPackage {\n                    name: \"awsome_local1\".into(),\n                    version: Version::new(1, 2, 3),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Local {\n                        path: PACKAGE.into(),\n                    },\n                },\n                ManifestPackage {\n                    name: \"gleeunit\".into(),\n                    version: Version::new(0, 4, 0),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![\"gleam_stdlib\".into()],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![3, 46]),\n                    },\n                },\n            ],\n        };\n\n        let buffer = manifest.to_toml(HOME.into());\n        assert_eq!(\n            buffer,\n            r#\"# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"aaa\", version = \"0.4.0\", build_tools = [\"rebar3\", \"make\"], requirements = [\"gleam_stdlib\", \"zzz\"], otp_app = \"aaa_app\", source = \"hex\", outer_checksum = \"0316\" },\n  { name = \"awsome_local1\", version = \"1.2.3\", build_tools = [\"gleam\"], requirements = [], source = \"local\", path = \"../path/to/package\" },\n  { name = \"awsome_local2\", version = \"1.2.3\", build_tools = [\"gleam\"], requirements = [], source = \"git\", repo = \"https://github.com/gleam-lang/gleam.git\", commit = \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\" },\n  { name = \"gleam_stdlib\", version = \"0.17.1\", build_tools = [\"gleam\"], requirements = [], source = \"hex\", outer_checksum = \"0116\" },\n  { name = \"gleeunit\", version = \"0.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], source = \"hex\", outer_checksum = \"032E\" },\n  { name = \"zzz\", version = \"0.4.0\", build_tools = [\"mix\"], requirements = [], source = \"hex\", outer_checksum = \"0316\" },\n]\n\n[requirements]\naaa = { version = \"> 0.0.0\" }\nawsome_local1 = { path = \"../path/to/package\" }\nawsome_local2 = { git = \"https://github.com/gleam-lang/gleam.git\", ref = \"bd9fe02f\" }\ngleam_stdlib = { version = \"~> 0.17\" }\ngleeunit = { version = \"~> 0.1\" }\nzzz = { version = \"> 0.0.0\" }\n\"#\n        );\n    }\n\n    #[cfg(windows)]\n    #[test]\n    fn manifest_toml_format_with_unc() {\n        let manifest = Manifest {\n            requirements: [\n                (\"zzz\".into(), Requirement::hex(\"> 0.0.0\").unwrap()),\n                (\"aaa\".into(), Requirement::hex(\"> 0.0.0\").unwrap()),\n                (\n                    \"awsome_local2\".into(),\n                    Requirement::git(\"https://github.com/gleam-lang/gleam.git\", \"main\"),\n                ),\n                (\n                    \"awsome_local1\".into(),\n                    Requirement::path(\"../path/to/package\"),\n                ),\n                (\"gleam_stdlib\".into(), Requirement::hex(\"~> 0.17\").unwrap()),\n                (\"gleeunit\".into(), Requirement::hex(\"~> 0.1\").unwrap()),\n            ]\n            .into(),\n            packages: vec![\n                ManifestPackage {\n                    name: \"gleam_stdlib\".into(),\n                    version: Version::new(0, 17, 1),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![1, 22]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"aaa\".into(),\n                    version: Version::new(0, 4, 0),\n                    build_tools: [\"rebar3\".into(), \"make\".into()].into(),\n                    otp_app: Some(\"aaa_app\".into()),\n                    requirements: vec![\"zzz\".into(), \"gleam_stdlib\".into()],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![3, 22]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"zzz\".into(),\n                    version: Version::new(0, 4, 0),\n                    build_tools: [\"mix\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![3, 22]),\n                    },\n                },\n                ManifestPackage {\n                    name: \"awsome_local2\".into(),\n                    version: Version::new(1, 2, 3),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Git {\n                        repo: \"https://github.com/gleam-lang/gleam.git\".into(),\n                        commit: \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\".into(),\n                    },\n                },\n                ManifestPackage {\n                    name: \"awsome_local1\".into(),\n                    version: Version::new(1, 2, 3),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![],\n                    source: ManifestPackageSource::Local {\n                        path: PACKAGE_WITH_UNC.into(),\n                    },\n                },\n                ManifestPackage {\n                    name: \"gleeunit\".into(),\n                    version: Version::new(0, 4, 0),\n                    build_tools: [\"gleam\".into()].into(),\n                    otp_app: None,\n                    requirements: vec![\"gleam_stdlib\".into()],\n                    source: ManifestPackageSource::Hex {\n                        outer_checksum: Base16Checksum(vec![3, 46]),\n                    },\n                },\n            ],\n        };\n\n        let buffer = manifest.to_toml(HOME.into());\n        assert_eq!(\n            buffer,\n            r#\"# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"aaa\", version = \"0.4.0\", build_tools = [\"rebar3\", \"make\"], requirements = [\"gleam_stdlib\", \"zzz\"], otp_app = \"aaa_app\", source = \"hex\", outer_checksum = \"0316\" },\n  { name = \"awsome_local1\", version = \"1.2.3\", build_tools = [\"gleam\"], requirements = [], source = \"local\", path = \"../path/to/package\" },\n  { name = \"awsome_local2\", version = \"1.2.3\", build_tools = [\"gleam\"], requirements = [], source = \"git\", repo = \"https://github.com/gleam-lang/gleam.git\", commit = \"bd9fe02f72250e6a136967917bcb1bdccaffa3c8\" },\n  { name = \"gleam_stdlib\", version = \"0.17.1\", build_tools = [\"gleam\"], requirements = [], source = \"hex\", outer_checksum = \"0116\" },\n  { name = \"gleeunit\", version = \"0.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], source = \"hex\", outer_checksum = \"032E\" },\n  { name = \"zzz\", version = \"0.4.0\", build_tools = [\"mix\"], requirements = [], source = \"hex\", outer_checksum = \"0316\" },\n]\n\n[requirements]\naaa = { version = \"> 0.0.0\" }\nawsome_local1 = { path = \"../path/to/package\" }\nawsome_local2 = { git = \"https://github.com/gleam-lang/gleam.git\", ref = \"main\" }\ngleam_stdlib = { version = \"~> 0.17\" }\ngleeunit = { version = \"~> 0.1\" }\nzzz = { version = \"> 0.0.0\" }\n\"#\n        );\n    }\n}\n\n#[derive(Debug)]\npub struct Resolved {\n    pub manifest: Manifest,\n    pub package_changes: PackageChanges,\n    pub requirements_changed: bool,\n}\n\n#[derive(Debug)]\npub struct PackageChanges {\n    pub added: Vec<(EcoString, Version)>,\n    pub changed: Vec<Changed>,\n    /// When updating git dependencies, it is possible to update to a newer commit\n    /// without updating the version of the package (which is specified in\n    /// `gleam.toml`). In this case, we still want to record the change, but it\n    /// must be stored differently.\n    pub changed_git: Vec<ChangedGit>,\n    pub removed: Vec<EcoString>,\n}\n\n#[derive(Debug, PartialEq)]\npub struct Changed {\n    pub name: EcoString,\n    pub old: Version,\n    pub new: Version,\n}\n\n#[derive(Debug, PartialEq)]\npub struct ChangedGit {\n    pub name: EcoString,\n    pub old_hash: EcoString,\n    pub new_hash: EcoString,\n}\n\nimpl Resolved {\n    pub fn any_changes(&self) -> bool {\n        self.requirements_changed || self.package_changes.any_changes()\n    }\n\n    pub fn all_added(manifest: Manifest) -> Resolved {\n        let added = manifest\n            .packages\n            .iter()\n            .map(|package| (package.name.clone(), package.version.clone()))\n            .collect();\n        Self {\n            manifest,\n            requirements_changed: true,\n            package_changes: PackageChanges {\n                added,\n                changed: vec![],\n                changed_git: vec![],\n                removed: vec![],\n            },\n        }\n    }\n\n    pub fn no_change(manifest: Manifest) -> Self {\n        Self {\n            manifest,\n            requirements_changed: false,\n            package_changes: PackageChanges {\n                added: vec![],\n                changed: vec![],\n                changed_git: vec![],\n                removed: vec![],\n            },\n        }\n    }\n}\n\nimpl PackageChanges {\n    pub fn any_changes(&self) -> bool {\n        !self.added.is_empty()\n            || !self.changed.is_empty()\n            || !self.changed_git.is_empty()\n            || !self.removed.is_empty()\n    }\n\n    /// Compare the old and new versions of the manifest and determine the package changes\n    pub fn between_manifests(old: &Manifest, new: &Manifest) -> Self {\n        let mut added = vec![];\n        let mut changed = vec![];\n        let mut changed_git = vec![];\n        let mut removed = vec![];\n        let mut old: HashMap<_, _> = old\n            .packages\n            .iter()\n            .map(|package| (&package.name, package))\n            .collect();\n\n        for new in &new.packages {\n            match old.remove(&new.name) {\n                // If the kind of source changed, the packages bear essentially no connection\n                Some(old) if new.source.kind() != old.source.kind() => {\n                    removed.push(old.name.clone());\n                    added.push((new.name.clone(), new.version.clone()));\n                }\n                Some(old) if old.version == new.version => match (&old.source, &new.source) {\n                    (\n                        ManifestPackageSource::Git {\n                            commit: old_hash, ..\n                        },\n                        ManifestPackageSource::Git {\n                            commit: new_hash, ..\n                        },\n                    ) if old_hash != new_hash => changed_git.push(ChangedGit {\n                        name: new.name.clone(),\n                        old_hash: old_hash.clone(),\n                        new_hash: new_hash.clone(),\n                    }),\n                    (\n                        ManifestPackageSource::Hex { .. }\n                        | ManifestPackageSource::Local { .. }\n                        | ManifestPackageSource::Git { .. },\n                        _,\n                    ) => {}\n                },\n                Some(old) => {\n                    changed.push(Changed {\n                        name: new.name.clone(),\n                        old: old.version.clone(),\n                        new: new.version.clone(),\n                    });\n                }\n                None => {\n                    added.push((new.name.clone(), new.version.clone()));\n                }\n            }\n        }\n\n        removed.extend(old.into_keys().cloned());\n\n        Self {\n            added,\n            changed,\n            changed_git,\n            removed,\n        }\n    }\n}\n\n#[cfg(test)]\nmod manifest_update_tests {\n    use std::collections::HashMap;\n\n    use ecow::EcoString;\n    use hexpm::version::Version;\n\n    use crate::manifest::{Base16Checksum, ManifestPackage, ManifestPackageSource, PackageChanges};\n    use crate::manifest::{Changed, Manifest};\n\n    #[test]\n    fn resolved_with_updated() {\n        let package = |name: &str, version| ManifestPackage {\n            name: EcoString::from(name),\n            version,\n            build_tools: vec![],\n            otp_app: None,\n            requirements: vec![],\n            source: ManifestPackageSource::Hex {\n                outer_checksum: Base16Checksum(vec![]),\n            },\n        };\n\n        let old = Manifest {\n            requirements: HashMap::new(),\n            packages: vec![\n                package(\"unchanged1\", Version::new(3, 0, 0)),\n                package(\"unchanged2\", Version::new(0, 1, 0)),\n                package(\"changed1\", Version::new(3, 0, 0)),\n                package(\"changed2\", Version::new(0, 1, 0)),\n                package(\"removed1\", Version::new(10, 0, 0)),\n                package(\"removed2\", Version::new(20, 1, 0)),\n            ],\n        };\n\n        let new = Manifest {\n            requirements: HashMap::new(),\n            packages: vec![\n                package(\"new1\", Version::new(1, 0, 0)),\n                package(\"new2\", Version::new(2, 1, 0)),\n                package(\"unchanged1\", Version::new(3, 0, 0)),\n                package(\"unchanged2\", Version::new(0, 1, 0)),\n                package(\"changed1\", Version::new(5, 0, 0)),\n                package(\"changed2\", Version::new(3, 0, 0)),\n            ],\n        };\n\n        let mut changes = PackageChanges::between_manifests(&old, &new);\n        changes.added.sort();\n        changes.changed.sort_by(|a, b| a.name.cmp(&b.name));\n        changes.removed.sort();\n\n        assert_eq!(\n            changes.added,\n            vec![\n                (\"new1\".into(), Version::new(1, 0, 0)),\n                (\"new2\".into(), Version::new(2, 1, 0)),\n            ]\n        );\n\n        assert_eq!(\n            changes.changed,\n            vec![\n                Changed {\n                    name: \"changed1\".into(),\n                    old: Version::new(3, 0, 0),\n                    new: Version::new(5, 0, 0)\n                },\n                Changed {\n                    name: \"changed2\".into(),\n                    old: Version::new(0, 1, 0),\n                    new: Version::new(3, 0, 0)\n                },\n            ]\n        );\n\n        assert_eq!(\n            changes.removed,\n            vec![EcoString::from(\"removed1\"), EcoString::from(\"removed2\")]\n        );\n    }\n\n    #[test]\n    fn resolved_with_source_type_change() {\n        let name = EcoString::from(\"wibble\");\n        let version = Version::new(1, 0, 0);\n        let package = |source| ManifestPackage {\n            name: name.clone(),\n            version: version.clone(),\n            build_tools: vec![],\n            otp_app: None,\n            requirements: vec![],\n            source,\n        };\n\n        let old = Manifest {\n            requirements: HashMap::new(),\n            packages: vec![package(ManifestPackageSource::Local {\n                path: \"wibble\".into(),\n            })],\n        };\n\n        let new = Manifest {\n            requirements: HashMap::new(),\n            packages: vec![package(ManifestPackageSource::Hex {\n                outer_checksum: Base16Checksum(vec![]),\n            })],\n        };\n\n        let changes = PackageChanges::between_manifests(&old, &new);\n        assert!(changes.changed.is_empty());\n        assert_eq!(changes.removed, vec![name.clone()]);\n        assert_eq!(changes.added, vec![(name.clone(), version.clone())]);\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/metadata/tests.rs",
    "content": "use hexpm::version::Version;\nuse rand::Rng;\nuse type_::{AccessorsMap, FieldMap, RecordAccessor};\n\nuse super::*;\nuse crate::{\n    analyse::Inferred,\n    ast::{\n        BitArrayOption, BitArraySegment, CallArg, Constant, Publicity, SrcSpan, TypedConstant,\n        TypedConstantBitArraySegmentOption,\n    },\n    build::Origin,\n    line_numbers::LineNumbers,\n    parse::LiteralFloatValue,\n    reference::{Reference, ReferenceKind},\n    type_::{\n        self, Deprecation, ModuleInterface, Opaque, References, Type, TypeAliasConstructor,\n        TypeConstructor, TypeValueConstructor, TypeValueConstructorField, TypeVariantConstructors,\n        ValueConstructor, ValueConstructorVariant,\n        expression::{Implementations, Purity},\n        prelude,\n    },\n    uid::UniqueIdGenerator,\n};\nuse std::{collections::HashMap, sync::Arc};\n\nuse pretty_assertions::assert_eq;\n\nfn roundtrip(input: &ModuleInterface) -> ModuleInterface {\n    let buffer = encode(input).unwrap();\n    let ids = UniqueIdGenerator::new();\n    decode(buffer.as_slice(), ids).unwrap()\n}\n\nfn constant_module(constant: TypedConstant) -> ModuleInterface {\n    ModuleInterface {\n        warnings: vec![],\n        is_internal: true,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleConstant {\n                    documentation: Some(\"Some documentation\".into()),\n                    literal: constant,\n                    location: SrcSpan::default(),\n                    module: \"one/two\".into(),\n                    implementations: Implementations {\n                        gleam: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    name: \"one\".into(),\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    }\n}\n\nfn bit_array_segment_option_module(option: TypedConstantBitArraySegmentOption) -> ModuleInterface {\n    constant_module(Constant::BitArray {\n        location: Default::default(),\n        segments: vec![BitArraySegment {\n            location: Default::default(),\n            value: Box::new(Constant::Int {\n                location: Default::default(),\n                value: \"1\".into(),\n                int_value: 1.into(),\n            }),\n            options: vec![option],\n            type_: type_::int(),\n        }],\n    })\n}\n\n#[test]\nfn empty_module() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: true,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"one/two\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn with_line_numbers() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"one/two\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\n            \"const a = 1\n        const b = 2\n        const c = 3\",\n        ),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_private_type() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b\".into(),\n        types: [(\n            \"ListIntType\".into(),\n            TypeConstructor {\n                type_: type_::list(type_::int()),\n                publicity: Publicity::Private,\n                origin: Default::default(),\n                module: \"the/module\".into(),\n                parameters: vec![],\n                deprecation: Deprecation::NotDeprecated,\n                documentation: None,\n            },\n        )]\n        .into(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_app_type() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b\".into(),\n        types: [(\n            \"ListIntType\".into(),\n            TypeConstructor {\n                type_: type_::list(type_::int()),\n                publicity: Publicity::Public,\n                origin: Default::default(),\n                module: \"the/module\".into(),\n                parameters: vec![],\n                deprecation: Deprecation::NotDeprecated,\n                documentation: None,\n            },\n        )]\n        .into(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_fn_type() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b\".into(),\n        types: [(\n            \"FnType\".into(),\n            TypeConstructor {\n                type_: type_::fn_(vec![type_::nil(), type_::float()], type_::int()),\n                publicity: Publicity::Public,\n                origin: Default::default(),\n                module: \"the/module\".into(),\n                parameters: vec![],\n                deprecation: Deprecation::NotDeprecated,\n                documentation: None,\n            },\n        )]\n        .into(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_tuple_type() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b\".into(),\n        types: [(\n            \"TupleType\".into(),\n            TypeConstructor {\n                type_: type_::tuple(vec![type_::nil(), type_::float(), type_::int()]),\n                publicity: Publicity::Public,\n                origin: Default::default(),\n                module: \"the/module\".into(),\n                parameters: vec![],\n                deprecation: Deprecation::NotDeprecated,\n                documentation: None,\n            },\n        )]\n        .into(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_generic_type() {\n    let t0 = type_::generic_var(0);\n    let t1 = type_::generic_var(1);\n    let t7 = type_::generic_var(7);\n    let t8 = type_::generic_var(8);\n\n    fn make(t1: Arc<Type>, t2: Arc<Type>) -> ModuleInterface {\n        ModuleInterface {\n            warnings: vec![],\n            is_internal: false,\n            package: \"some_package\".into(),\n            origin: Origin::Src,\n            name: \"a/b\".into(),\n            types: [(\n                \"TupleType\".into(),\n                TypeConstructor {\n                    type_: type_::tuple(vec![t1.clone(), t1.clone(), t2.clone()]),\n                    publicity: Publicity::Public,\n                    origin: Default::default(),\n                    module: \"the/module\".into(),\n                    parameters: vec![t1, t2],\n                    deprecation: Deprecation::NotDeprecated,\n                    documentation: None,\n                },\n            )]\n            .into(),\n            types_value_constructors: HashMap::new(),\n            values: HashMap::new(),\n            accessors: HashMap::new(),\n            line_numbers: LineNumbers::new(\"\"),\n            src_path: \"some_path\".into(),\n            minimum_required_version: Version::new(0, 1, 0),\n            type_aliases: HashMap::new(),\n            documentation: Vec::new(),\n            contains_echo: false,\n            references: References::default(),\n            inline_functions: HashMap::new(),\n        }\n    }\n\n    assert_eq!(roundtrip(&make(t7, t8)), make(t0, t1));\n}\n\n#[test]\nfn module_with_type_links() {\n    let linked_type = type_::link(type_::int());\n    let type_ = type_::int();\n\n    fn make(type_: Arc<Type>) -> ModuleInterface {\n        ModuleInterface {\n            warnings: vec![],\n            is_internal: false,\n            package: \"some_package\".into(),\n            origin: Origin::Src,\n            name: \"a\".into(),\n            types: [(\n                \"SomeType\".into(),\n                TypeConstructor {\n                    type_,\n                    publicity: Publicity::Public,\n                    origin: Default::default(),\n                    module: \"a\".into(),\n                    parameters: vec![],\n                    deprecation: Deprecation::NotDeprecated,\n                    documentation: None,\n                },\n            )]\n            .into(),\n            types_value_constructors: HashMap::new(),\n            values: HashMap::new(),\n            accessors: HashMap::new(),\n            line_numbers: LineNumbers::new(\"\"),\n            src_path: \"some_path\".into(),\n            minimum_required_version: Version::new(0, 1, 0),\n            type_aliases: HashMap::new(),\n            documentation: Vec::new(),\n            contains_echo: false,\n            references: References::default(),\n            inline_functions: HashMap::new(),\n        }\n    }\n\n    assert_eq!(roundtrip(&make(linked_type)), make(type_));\n}\n\n#[test]\nfn module_with_type_constructor_documentation() {\n    let linked_type = type_::link(type_::int());\n    let type_ = type_::int();\n\n    fn make(type_: Arc<Type>) -> ModuleInterface {\n        ModuleInterface {\n            warnings: vec![],\n            is_internal: false,\n            package: \"some_package\".into(),\n            origin: Origin::Src,\n            name: \"a\".into(),\n            types: [(\n                \"SomeType\".into(),\n                TypeConstructor {\n                    type_,\n                    publicity: Publicity::Public,\n                    origin: Default::default(),\n                    module: \"a\".into(),\n                    parameters: vec![],\n                    deprecation: Deprecation::NotDeprecated,\n                    documentation: Some(\"type documentation\".into()),\n                },\n            )]\n            .into(),\n            types_value_constructors: HashMap::new(),\n            values: HashMap::new(),\n            accessors: HashMap::new(),\n            line_numbers: LineNumbers::new(\"\"),\n            src_path: \"some_path\".into(),\n            minimum_required_version: Version::new(0, 1, 0),\n            type_aliases: HashMap::new(),\n            documentation: Vec::new(),\n            contains_echo: false,\n            references: References::default(),\n            inline_functions: HashMap::new(),\n        }\n    }\n\n    assert_eq!(roundtrip(&make(linked_type)), make(type_));\n}\n\n#[test]\nfn module_with_type_constructor_origin() {\n    let linked_type = type_::link(type_::int());\n    let type_ = type_::int();\n\n    fn make(type_: Arc<Type>) -> ModuleInterface {\n        ModuleInterface {\n            warnings: vec![],\n            is_internal: false,\n            package: \"some_package\".into(),\n            origin: Origin::Src,\n            name: \"a\".into(),\n            types: [(\n                \"SomeType\".into(),\n                TypeConstructor {\n                    type_,\n                    publicity: Publicity::Public,\n                    origin: SrcSpan {\n                        start: 535,\n                        end: 543,\n                    },\n                    module: \"a\".into(),\n                    parameters: vec![],\n                    deprecation: Deprecation::NotDeprecated,\n                    documentation: None,\n                },\n            )]\n            .into(),\n            types_value_constructors: HashMap::new(),\n            values: HashMap::new(),\n            accessors: HashMap::new(),\n            line_numbers: LineNumbers::new(\"\"),\n            src_path: \"some_path\".into(),\n            minimum_required_version: Version::new(0, 1, 0),\n            type_aliases: HashMap::new(),\n            documentation: Vec::new(),\n            contains_echo: false,\n            references: References::default(),\n            inline_functions: HashMap::new(),\n        }\n    }\n\n    assert_eq!(roundtrip(&make(linked_type)), make(type_));\n}\n\n#[test]\nfn module_type_to_constructors_mapping() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: [(\n            \"SomeType\".into(),\n            TypeVariantConstructors {\n                type_parameters_ids: vec![0, 1, 2],\n                variants: vec![TypeValueConstructor {\n                    name: \"One\".into(),\n                    parameters: vec![],\n                    documentation: Some(\"Some documentation\".into()),\n                }],\n                opaque: Opaque::NotOpaque,\n            },\n        )]\n        .into(),\n        accessors: HashMap::new(),\n        values: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_fn_value() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wobble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 535,\n                        end: 1100,\n                    },\n                    external_erlang: None,\n                    external_javascript: None,\n                    implementations: Implementations {\n                        gleam: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Pure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn deprecated_module_fn_value() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::Deprecated {\n                    message: \"wibble wobble\".into(),\n                },\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wobble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 535,\n                        end: 1100,\n                    },\n                    external_erlang: None,\n                    external_javascript: None,\n                    implementations: Implementations {\n                        gleam: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Pure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn private_module_fn_value() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Private,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wobble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 535,\n                        end: 1100,\n                    },\n                    external_erlang: None,\n                    external_javascript: None,\n                    implementations: Implementations {\n                        gleam: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Pure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n// https://github.com/gleam-lang/gleam/commit/c8f3bd0ddbf61c27ea35f37297058ecca7515f6c\n#[test]\nfn module_fn_value_regression() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b/c\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wabble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 52,\n                        end: 1100,\n                    },\n                    external_erlang: None,\n                    external_javascript: None,\n                    implementations: Implementations {\n                        gleam: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::TrustedPure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_fn_value_with_field_map() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wubble!\".into()),\n                    name: \"one\".into(),\n                    field_map: Some(FieldMap {\n                        arity: 20,\n                        fields: [(\"ok\".into(), 5), (\"ko\".into(), 7)].into(),\n                    }),\n                    external_erlang: None,\n                    external_javascript: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan { start: 2, end: 11 },\n                    implementations: Implementations {\n                        gleam: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Pure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn record_value() {\n    let mut random = rand::rng();\n\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::Record {\n                    documentation: Some(\"webble!\".into()),\n                    name: \"one\".into(),\n                    module: \"themodule\".into(),\n                    field_map: None,\n                    arity: random.random(),\n                    variants_count: random.random(),\n                    location: SrcSpan {\n                        start: random.random(),\n                        end: random.random(),\n                    },\n                    variant_index: random.random(),\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn record_value_with_field_map() {\n    let mut random = rand::rng();\n\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::Record {\n                    documentation: Some(\"wybble!\".into()),\n                    module: \"themodule\".into(),\n                    name: \"one\".into(),\n                    field_map: Some(FieldMap {\n                        arity: random.random(),\n                        fields: [\n                            (\"ok\".into(), random.random()),\n                            (\"ko\".into(), random.random()),\n                        ]\n                        .into(),\n                    }),\n                    arity: random.random(),\n                    variants_count: random.random(),\n                    variant_index: random.random(),\n                    location: SrcSpan {\n                        start: random.random(),\n                        end: random.random(),\n                    },\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn accessors() {\n    let accessors1 = [\n        (\n            \"a\".into(),\n            RecordAccessor {\n                index: 6,\n                label: \"siiixxx\".into(),\n                type_: type_::nil(),\n                documentation: Some(\"Here is some documentation\".into()),\n            },\n        ),\n        (\n            \"a\".into(),\n            RecordAccessor {\n                index: 5,\n                label: \"fiveee\".into(),\n                type_: type_::float(),\n                documentation: None,\n            },\n        ),\n    ];\n\n    let accessors2 = [(\n        \"a\".into(),\n        RecordAccessor {\n            index: 1,\n            label: \"ok\".into(),\n            type_: type_::float(),\n            documentation: Some(\"Documentation for the ok field\".into()),\n        },\n    )];\n\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: [\n            (\n                \"one\".into(),\n                AccessorsMap {\n                    publicity: Publicity::Public,\n                    type_: type_::int(),\n                    shared_accessors: accessors1.clone().into(),\n                    variant_specific_accessors: vec![accessors1.into()],\n                    variant_positional_accessors: vec![vec![type_::int(), type_::float()]],\n                },\n            ),\n            (\n                \"two\".into(),\n                AccessorsMap {\n                    publicity: Publicity::Public,\n                    type_: type_::int(),\n                    shared_accessors: accessors2.clone().into(),\n                    variant_specific_accessors: vec![accessors2.into()],\n                    variant_positional_accessors: vec![vec![]],\n                },\n            ),\n        ]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn private_accessors() {\n    let accessors1 = [\n        (\n            \"a\".into(),\n            RecordAccessor {\n                index: 6,\n                label: \"siiixxx\".into(),\n                type_: type_::nil(),\n                documentation: None,\n            },\n        ),\n        (\n            \"a\".into(),\n            RecordAccessor {\n                index: 5,\n                label: \"fiveee\".into(),\n                type_: type_::float(),\n                documentation: None,\n            },\n        ),\n    ];\n\n    let accessors2 = [(\n        \"a\".into(),\n        RecordAccessor {\n            index: 1,\n            label: \"ok\".into(),\n            type_: type_::float(),\n            documentation: None,\n        },\n    )];\n\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        contains_echo: false,\n        values: HashMap::new(),\n        accessors: [\n            (\n                \"one\".into(),\n                AccessorsMap {\n                    publicity: Publicity::Private,\n                    type_: type_::int(),\n                    shared_accessors: accessors1.clone().into(),\n                    variant_specific_accessors: vec![accessors1.into()],\n                    variant_positional_accessors: vec![vec![type_::int(), type_::float()]],\n                },\n            ),\n            (\n                \"two\".into(),\n                AccessorsMap {\n                    publicity: Publicity::Public,\n                    type_: type_::int(),\n                    shared_accessors: accessors2.clone().into(),\n                    variant_specific_accessors: vec![accessors2.into()],\n                    variant_positional_accessors: vec![vec![]],\n                },\n            ),\n        ]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_int() {\n    let module = constant_module(Constant::Int {\n        location: Default::default(),\n        value: \"100\".into(),\n        int_value: 100.into(),\n    });\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_float() {\n    let module = constant_module(Constant::Float {\n        location: Default::default(),\n        value: \"1.0\".into(),\n        float_value: LiteralFloatValue::ONE,\n    });\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_string() {\n    let module = constant_module(Constant::String {\n        location: Default::default(),\n        value: \"hello\".into(),\n    });\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_tuple() {\n    let int_float_tuple_type = type_::tuple(vec![type_::int(), type_::float()]);\n    let module = constant_module(Constant::Tuple {\n        location: Default::default(),\n        type_: type_::tuple(vec![\n            type_::int(),\n            type_::float(),\n            int_float_tuple_type.clone(),\n        ]),\n        elements: vec![\n            Constant::Int {\n                location: Default::default(),\n                value: \"1\".into(),\n                int_value: 1.into(),\n            },\n            Constant::Float {\n                location: Default::default(),\n                value: \"1.0\".into(),\n                float_value: LiteralFloatValue::ONE,\n            },\n            Constant::Tuple {\n                location: Default::default(),\n                type_: int_float_tuple_type,\n                elements: vec![\n                    Constant::Int {\n                        location: Default::default(),\n                        value: \"1\".into(),\n                        int_value: 1.into(),\n                    },\n                    Constant::Float {\n                        location: Default::default(),\n                        value: \"1.0\".into(),\n                        float_value: LiteralFloatValue::ONE,\n                    },\n                ],\n            },\n        ],\n    });\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_list() {\n    let module = constant_module(Constant::List {\n        location: Default::default(),\n        type_: type_::int(),\n        elements: vec![\n            Constant::Int {\n                location: Default::default(),\n                value: \"1\".into(),\n                int_value: 1.into(),\n            },\n            Constant::Int {\n                location: Default::default(),\n                value: \"2\".into(),\n                int_value: 2.into(),\n            },\n            Constant::Int {\n                location: Default::default(),\n                value: \"3\".into(),\n                int_value: 3.into(),\n            },\n        ],\n        tail: Some(Box::new(Constant::List {\n            location: Default::default(),\n            type_: type_::list(type_::int()),\n            elements: vec![\n                Constant::Int {\n                    location: Default::default(),\n                    value: \"4\".into(),\n                    int_value: 4.into(),\n                },\n                Constant::Int {\n                    location: Default::default(),\n                    value: \"5\".into(),\n                    int_value: 5.into(),\n                },\n            ],\n            tail: None,\n        })),\n    });\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_record() {\n    let module = constant_module(Constant::Record {\n        location: Default::default(),\n        module: None,\n        name: \"\".into(),\n        arguments: vec![\n            CallArg {\n                implicit: None,\n                label: None,\n                location: Default::default(),\n                value: Constant::Float {\n                    location: Default::default(),\n                    value: \"0.0\".into(),\n                    float_value: LiteralFloatValue::ZERO,\n                },\n            },\n            CallArg {\n                implicit: None,\n                label: None,\n                location: Default::default(),\n                value: Constant::Int {\n                    location: Default::default(),\n                    value: \"1\".into(),\n                    int_value: 1.into(),\n                },\n            },\n        ],\n        tag: \"thetag\".into(),\n        type_: type_::int(),\n        field_map: Inferred::Unknown,\n        record_constructor: None,\n    });\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_var() {\n    let one_original = Constant::Int {\n        location: Default::default(),\n        value: \"1\".into(),\n        int_value: 1.into(),\n    };\n\n    let one = Constant::Var {\n        location: Default::default(),\n        module: None,\n        name: \"one_original\".into(),\n        type_: type_::int(),\n        constructor: Some(Box::from(ValueConstructor {\n            publicity: Publicity::Public,\n            deprecation: Deprecation::NotDeprecated,\n            type_: type_::int(),\n            variant: ValueConstructorVariant::ModuleConstant {\n                documentation: Some(\"some doc\".into()),\n                literal: one_original.clone(),\n                location: SrcSpan::default(),\n                module: \"one/two\".into(),\n                implementations: Implementations {\n                    gleam: true,\n                    uses_erlang_externals: false,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                },\n                name: \"one_original\".into(),\n            },\n        })),\n    };\n\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [\n            (\n                \"one\".into(),\n                ValueConstructor {\n                    publicity: Publicity::Public,\n                    deprecation: Deprecation::NotDeprecated,\n                    type_: type_::int(),\n                    variant: ValueConstructorVariant::ModuleConstant {\n                        documentation: Some(\"some doc!!!!!!!!!\".into()),\n                        literal: one,\n                        location: SrcSpan::default(),\n                        module: \"one/two\".into(),\n                        implementations: Implementations {\n                            gleam: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                        },\n                        name: \"one\".into(),\n                    },\n                },\n            ),\n            (\n                \"one_original\".into(),\n                ValueConstructor {\n                    publicity: Publicity::Public,\n                    deprecation: Deprecation::NotDeprecated,\n                    type_: type_::int(),\n                    variant: ValueConstructorVariant::ModuleConstant {\n                        documentation: Some(\"some doc yeah\".into()),\n                        literal: one_original,\n                        location: SrcSpan::default(),\n                        module: \"one/two\".into(),\n                        implementations: Implementations {\n                            gleam: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                        },\n                        name: \"one_original\".into(),\n                    },\n                },\n            ),\n        ]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array() {\n    let module = constant_module(Constant::BitArray {\n        location: Default::default(),\n        segments: vec![],\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_unit() {\n    let module = bit_array_segment_option_module(BitArrayOption::Unit {\n        location: Default::default(),\n        value: 234,\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_float() {\n    let module = bit_array_segment_option_module(BitArrayOption::Float {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_int() {\n    let module = bit_array_segment_option_module(BitArrayOption::Int {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_size() {\n    let module = bit_array_segment_option_module(BitArrayOption::Size {\n        location: Default::default(),\n        value: Box::new(Constant::Int {\n            location: Default::default(),\n            value: \"1\".into(),\n            int_value: 1.into(),\n        }),\n        short_form: false,\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_size_short_form() {\n    let module = bit_array_segment_option_module(BitArrayOption::Size {\n        location: Default::default(),\n        value: Box::new(Constant::Int {\n            location: Default::default(),\n            value: \"1\".into(),\n            int_value: 1.into(),\n        }),\n        short_form: true,\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_bit_arry() {\n    let module = bit_array_segment_option_module(BitArrayOption::Bits {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_utf8() {\n    let module = bit_array_segment_option_module(BitArrayOption::Utf8 {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_utf16() {\n    let module = bit_array_segment_option_module(BitArrayOption::Utf16 {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_utf32() {\n    let module = bit_array_segment_option_module(BitArrayOption::Utf32 {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_utf8codepoint() {\n    let module = bit_array_segment_option_module(BitArrayOption::Utf8Codepoint {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_utf16codepoint() {\n    let module = bit_array_segment_option_module(BitArrayOption::Utf16Codepoint {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_utf32codepoint() {\n    let module = bit_array_segment_option_module(BitArrayOption::Utf32Codepoint {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_signed() {\n    let module = bit_array_segment_option_module(BitArrayOption::Signed {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_unsigned() {\n    let module = bit_array_segment_option_module(BitArrayOption::Unsigned {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_big() {\n    let module = bit_array_segment_option_module(BitArrayOption::Big {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_little() {\n    let module = bit_array_segment_option_module(BitArrayOption::Little {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn constant_bit_array_native() {\n    let module = bit_array_segment_option_module(BitArrayOption::Native {\n        location: Default::default(),\n    });\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn deprecated_type() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b\".into(),\n        types: [(\n            \"ListIntType\".into(),\n            TypeConstructor {\n                type_: type_::list(type_::int()),\n                publicity: Publicity::Public,\n                origin: Default::default(),\n                module: \"the/module\".into(),\n                parameters: vec![],\n                deprecation: Deprecation::Deprecated {\n                    message: \"oh no\".into(),\n                },\n                documentation: None,\n            },\n        )]\n        .into(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_fn_value_with_external_implementations() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b/c\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Public,\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wabble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 52,\n                        end: 1100,\n                    },\n                    external_erlang: Some((\"wibble\".into(), \"wobble\".into())),\n                    external_javascript: Some((\"wobble\".into(), \"wibble\".into())),\n                    implementations: Implementations {\n                        gleam: false,\n                        uses_erlang_externals: true,\n                        uses_javascript_externals: true,\n                        can_run_on_erlang: false,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Impure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_containing_echo() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b/c\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [].into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: true,\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn internal_module_fn() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b/c\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Internal {\n                    attribute_location: None,\n                },\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wabble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 52,\n                        end: 1100,\n                    },\n                    external_erlang: Some((\"wibble\".into(), \"wobble\".into())),\n                    external_javascript: Some((\"wobble\".into(), \"wibble\".into())),\n                    implementations: Implementations {\n                        gleam: false,\n                        uses_erlang_externals: true,\n                        uses_javascript_externals: true,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Unknown,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn internal_annotated_module_fn() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b/c\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: [(\n            \"one\".into(),\n            ValueConstructor {\n                publicity: Publicity::Internal {\n                    attribute_location: Some(SrcSpan {\n                        start: 11,\n                        end: 111,\n                    }),\n                },\n                deprecation: Deprecation::NotDeprecated,\n                type_: type_::int(),\n                variant: ValueConstructorVariant::ModuleFn {\n                    documentation: Some(\"wabble!\".into()),\n                    name: \"one\".into(),\n                    field_map: None,\n                    module: \"a\".into(),\n                    arity: 5,\n                    location: SrcSpan {\n                        start: 52,\n                        end: 1100,\n                    },\n                    external_erlang: Some((\"wibble\".into(), \"wobble\".into())),\n                    external_javascript: Some((\"wobble\".into(), \"wibble\".into())),\n                    implementations: Implementations {\n                        gleam: false,\n                        uses_erlang_externals: true,\n                        uses_javascript_externals: true,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                    },\n                    purity: Purity::Impure,\n                },\n            },\n        )]\n        .into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n// https://github.com/gleam-lang/gleam/issues/2599\n#[test]\nfn type_variable_ids_in_constructors_are_shared() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a/b/c\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::from([(\n            \"SomeType\".into(),\n            TypeVariantConstructors {\n                type_parameters_ids: vec![4, 5, 6],\n                variants: vec![TypeValueConstructor {\n                    name: \"One\".into(),\n                    parameters: vec![\n                        TypeValueConstructorField {\n                            type_: type_::generic_var(6),\n                            label: None,\n                            documentation: Some(\"Here's some documentation\".into()),\n                        },\n                        TypeValueConstructorField {\n                            type_: type_::int(),\n                            label: None,\n                            documentation: None,\n                        },\n                        TypeValueConstructorField {\n                            type_: type_::tuple(vec![type_::generic_var(4), type_::generic_var(5)]),\n                            label: None,\n                            documentation: None,\n                        },\n                    ],\n                    documentation: None,\n                }],\n                opaque: Opaque::NotOpaque,\n            },\n        )]),\n        accessors: HashMap::new(),\n        values: [].into(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    let expected = HashMap::from([(\n        \"SomeType\".into(),\n        TypeVariantConstructors {\n            type_parameters_ids: vec![0, 1, 2],\n            variants: vec![TypeValueConstructor {\n                name: \"One\".into(),\n                parameters: vec![\n                    TypeValueConstructorField {\n                        type_: type_::generic_var(2),\n                        label: None,\n                        documentation: Some(\"Here's some documentation\".into()),\n                    },\n                    TypeValueConstructorField {\n                        type_: type_::int(),\n                        label: None,\n                        documentation: None,\n                    },\n                    TypeValueConstructorField {\n                        type_: type_::tuple(vec![type_::generic_var(0), type_::generic_var(1)]),\n                        label: None,\n                        documentation: None,\n                    },\n                ],\n                documentation: None,\n            }],\n            opaque: Opaque::NotOpaque,\n        },\n    )]);\n\n    assert_eq!(roundtrip(&module).types_value_constructors, expected);\n}\n\n#[test]\nfn type_with_inferred_variant() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        contains_echo: false,\n        origin: Origin::Src,\n        name: \"a/b\".into(),\n        types: [(\n            \"Wibble\".into(),\n            TypeConstructor {\n                type_: Arc::new(Type::Named {\n                    publicity: Publicity::Internal {\n                        attribute_location: None,\n                    },\n                    package: \"some_package\".into(),\n                    module: \"the/module\".into(),\n                    name: \"Wibble\".into(),\n                    arguments: Vec::new(),\n                    inferred_variant: Some(1),\n                }),\n                publicity: Publicity::Internal {\n                    attribute_location: Some(SrcSpan::new(0, 10)),\n                },\n                origin: Default::default(),\n                module: \"the/module\".into(),\n                parameters: vec![],\n                deprecation: Deprecation::NotDeprecated,\n                documentation: None,\n            },\n        )]\n        .into(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_type_aliases() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"some_module\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: [(\n            \"MyAlias\".into(),\n            TypeAliasConstructor {\n                publicity: Publicity::Public,\n                module: \"some_module\".into(),\n                type_: prelude::int(),\n                arity: 1,\n                deprecation: Deprecation::NotDeprecated,\n                documentation: Some(\"Some documentation\".into()),\n                origin: Default::default(),\n                parameters: vec![type_::generic_var(0)],\n            },\n        )]\n        .into(),\n        documentation: Vec::new(),\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_documentation() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"some_module\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: vec![\n            \"This is a line of documentation\".into(),\n            \"And here is another\".into(),\n            \"And finally, a third\".into(),\n        ],\n        contains_echo: false,\n\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_opaque_type() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: [(\n            \"SomeType\".into(),\n            TypeVariantConstructors {\n                type_parameters_ids: vec![0, 1, 2],\n                variants: vec![TypeValueConstructor {\n                    name: \"One\".into(),\n                    parameters: vec![],\n                    documentation: Some(\"Some documentation\".into()),\n                }],\n                opaque: Opaque::Opaque,\n            },\n        )]\n        .into(),\n        accessors: HashMap::new(),\n        values: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n\n#[test]\nfn module_with_references() {\n    let module = ModuleInterface {\n        warnings: vec![],\n        is_internal: false,\n        package: \"some_package\".into(),\n        origin: Origin::Src,\n        name: \"a\".into(),\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        accessors: HashMap::new(),\n        values: HashMap::new(),\n        line_numbers: LineNumbers::new(\"\"),\n        src_path: \"some_path\".into(),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n        references: References {\n            imported_modules: [\"some_module\".into(), \"some_other_module\".into()].into(),\n            value_references: [\n                (\n                    (\"some_module\".into(), \"some_function\".into()),\n                    vec![\n                        Reference {\n                            location: SrcSpan::new(1, 6),\n                            kind: ReferenceKind::Definition,\n                        },\n                        Reference {\n                            location: SrcSpan::new(7, 11),\n                            kind: ReferenceKind::Unqualified,\n                        },\n                    ],\n                ),\n                (\n                    (\"some_other_module\".into(), \"some_constant\".into()),\n                    vec![\n                        Reference {\n                            location: SrcSpan::new(6, 9),\n                            kind: ReferenceKind::Import,\n                        },\n                        Reference {\n                            location: SrcSpan::new(90, 108),\n                            kind: ReferenceKind::Unqualified,\n                        },\n                    ],\n                ),\n                (\n                    (\"some_other_module\".into(), \"SomeTypeVariant\".into()),\n                    vec![\n                        Reference {\n                            location: SrcSpan::new(26, 35),\n                            kind: ReferenceKind::Qualified,\n                        },\n                        Reference {\n                            location: SrcSpan::new(152, 204),\n                            kind: ReferenceKind::Qualified,\n                        },\n                        Reference {\n                            location: SrcSpan::new(0, 8),\n                            kind: ReferenceKind::Qualified,\n                        },\n                    ],\n                ),\n            ]\n            .into(),\n            type_references: [(\n                (\"some_other_module\".into(), \"TypeVariant\".into()),\n                vec![\n                    Reference {\n                        location: SrcSpan::new(26, 35),\n                        kind: ReferenceKind::Qualified,\n                    },\n                    Reference {\n                        location: SrcSpan::new(152, 204),\n                        kind: ReferenceKind::Unqualified,\n                    },\n                    Reference {\n                        location: SrcSpan::new(0, 8),\n                        kind: ReferenceKind::Definition,\n                    },\n                ],\n            )]\n            .into(),\n        },\n        inline_functions: HashMap::new(),\n    };\n\n    assert_eq!(roundtrip(&module), module);\n}\n"
  },
  {
    "path": "compiler-core/src/metadata.rs",
    "content": "//! Seriaisation and deserialisation of Gleam compiler metadata into binary files\n//! using serde.\n\n#[cfg(test)]\nmod tests;\n\nuse std::{collections::HashMap, sync::Arc};\n\nuse crate::{\n    ast::{\n        BitArrayOption, BitArraySegment, CallArg, Constant, RecordBeingUpdated, RecordUpdateArg,\n        TypedConstant,\n    },\n    type_::{\n        self, AccessorsMap, ModuleInterface, RecordAccessor, Type, TypeAliasConstructor,\n        TypeConstructor, TypeValueConstructor, TypeValueConstructorField, TypeVar,\n        TypeVariantConstructors, ValueConstructor, ValueConstructorVariant,\n    },\n    uid::UniqueIdGenerator,\n};\n\npub fn encode(module: &ModuleInterface) -> Result<Vec<u8>, bincode::error::EncodeError> {\n    bincode::serde::encode_to_vec(module, bincode::config::legacy())\n}\n\npub fn decode(\n    bytes: &[u8],\n    ids: UniqueIdGenerator,\n) -> Result<ModuleInterface, bincode::error::DecodeError> {\n    bincode::serde::decode_from_slice(bytes, bincode::config::legacy())\n        .map(|(module, _)| remap_type_variable_ids(module, ids))\n}\n\nfn remap_type_variable_ids(module: ModuleInterface, ids: UniqueIdGenerator) -> ModuleInterface {\n    RemapIds::new(ids).module(module)\n}\n\nstruct RemapIds {\n    ids: UniqueIdGenerator,\n    remapped_variable_ids: HashMap<u64, u64>,\n}\n\nimpl RemapIds {\n    fn new(ids: UniqueIdGenerator) -> Self {\n        Self {\n            ids,\n            remapped_variable_ids: HashMap::new(),\n        }\n    }\n\n    fn module(&mut self, module: ModuleInterface) -> ModuleInterface {\n        let ModuleInterface {\n            name,\n            origin,\n            package,\n            types,\n            types_value_constructors,\n            values,\n            accessors,\n            line_numbers,\n            src_path,\n            is_internal,\n            warnings,\n            minimum_required_version,\n            type_aliases,\n            documentation,\n            contains_echo,\n            references,\n            inline_functions,\n        } = module;\n\n        let types = types\n            .into_iter()\n            .map(|(name, type_)| (name, self.type_constructor(type_)))\n            .collect();\n        let types_value_constructors = types_value_constructors\n            .into_iter()\n            .map(|(name, type_)| (name, self.type_variant_constructors(type_)))\n            .collect();\n        let values = values\n            .into_iter()\n            .map(|(name, value)| (name, self.value_constructor(value)))\n            .collect();\n        let accessors = accessors\n            .into_iter()\n            .map(|(name, accessors)| (name, self.accessors_map(accessors)))\n            .collect();\n        let type_aliases = type_aliases\n            .into_iter()\n            .map(|(name, type_)| (name, self.type_alias(type_)))\n            .collect();\n\n        ModuleInterface {\n            name,\n            origin,\n            package,\n            types,\n            types_value_constructors,\n            values,\n            accessors,\n            line_numbers,\n            src_path,\n            is_internal,\n            warnings,\n            minimum_required_version,\n            type_aliases,\n            documentation,\n            contains_echo,\n            references,\n            inline_functions,\n        }\n    }\n\n    fn type_constructor(&mut self, type_: TypeConstructor) -> TypeConstructor {\n        let TypeConstructor {\n            publicity,\n            origin,\n            module,\n            parameters,\n            type_,\n            deprecation,\n            documentation,\n        } = type_;\n\n        let parameters = parameters\n            .into_iter()\n            .map(|parameter| self.type_(parameter))\n            .collect();\n        let type_ = self.type_(type_);\n\n        TypeConstructor {\n            publicity,\n            origin,\n            module,\n            parameters,\n            type_,\n            deprecation,\n            documentation,\n        }\n    }\n\n    fn type_variant_constructors(\n        &mut self,\n        type_: TypeVariantConstructors,\n    ) -> TypeVariantConstructors {\n        let TypeVariantConstructors {\n            type_parameters_ids,\n            opaque,\n            variants,\n        } = type_;\n\n        let type_parameters_ids = type_parameters_ids\n            .into_iter()\n            .map(|id| self.id(id))\n            .collect();\n\n        let variants = variants\n            .into_iter()\n            .map(|variant| self.type_value_constructor(variant))\n            .collect();\n\n        TypeVariantConstructors {\n            type_parameters_ids,\n            opaque,\n            variants,\n        }\n    }\n\n    fn type_value_constructor(&mut self, variant: TypeValueConstructor) -> TypeValueConstructor {\n        let TypeValueConstructor {\n            name,\n            parameters,\n            documentation,\n        } = variant;\n\n        let parameters = parameters\n            .into_iter()\n            .map(\n                |TypeValueConstructorField {\n                     type_,\n                     label,\n                     documentation,\n                 }| TypeValueConstructorField {\n                    type_: self.type_(type_),\n                    label,\n                    documentation,\n                },\n            )\n            .collect();\n\n        TypeValueConstructor {\n            name,\n            parameters,\n            documentation,\n        }\n    }\n\n    fn value_constructor(&mut self, value: ValueConstructor) -> ValueConstructor {\n        let ValueConstructor {\n            publicity,\n            deprecation,\n            variant,\n            type_,\n        } = value;\n\n        let variant = self.value_constructor_variant(variant);\n\n        let type_ = self.type_(type_);\n\n        ValueConstructor {\n            publicity,\n            deprecation,\n            variant,\n            type_,\n        }\n    }\n\n    fn value_constructor_variant(\n        &mut self,\n        variant: ValueConstructorVariant,\n    ) -> ValueConstructorVariant {\n        match variant {\n            ValueConstructorVariant::LocalVariable { location, origin } => {\n                ValueConstructorVariant::LocalVariable { location, origin }\n            }\n            ValueConstructorVariant::ModuleConstant {\n                documentation,\n                location,\n                module,\n                name,\n                literal,\n                implementations,\n            } => ValueConstructorVariant::ModuleConstant {\n                documentation,\n                location,\n                module,\n                name,\n                literal: self.constant(literal),\n                implementations,\n            },\n            ValueConstructorVariant::ModuleFn {\n                name,\n                field_map,\n                module,\n                arity,\n                location,\n                documentation,\n                implementations,\n                external_erlang,\n                external_javascript,\n                purity,\n            } => ValueConstructorVariant::ModuleFn {\n                name,\n                field_map,\n                module,\n                arity,\n                location,\n                documentation,\n                implementations,\n                external_erlang,\n                external_javascript,\n                purity,\n            },\n            ValueConstructorVariant::Record {\n                name,\n                arity,\n                field_map,\n                location,\n                module,\n                variants_count,\n                variant_index,\n                documentation,\n            } => ValueConstructorVariant::Record {\n                name,\n                arity,\n                field_map,\n                location,\n                module,\n                variants_count,\n                variant_index,\n                documentation,\n            },\n        }\n    }\n\n    fn constant(&mut self, constant: TypedConstant) -> TypedConstant {\n        match constant {\n            Constant::Int {\n                location,\n                value,\n                int_value,\n            } => Constant::Int {\n                location,\n                value,\n                int_value,\n            },\n            Constant::Float {\n                location,\n                value,\n                float_value,\n            } => Constant::Float {\n                location,\n                value,\n                float_value,\n            },\n            Constant::String { location, value } => Constant::String { location, value },\n            Constant::Tuple {\n                location,\n                elements,\n                type_,\n            } => Constant::Tuple {\n                location,\n                elements: elements\n                    .into_iter()\n                    .map(|element| self.constant(element))\n                    .collect(),\n                type_: self.type_(type_),\n            },\n            Constant::List {\n                location,\n                elements,\n                type_,\n                tail,\n            } => Constant::List {\n                location,\n                elements: elements\n                    .into_iter()\n                    .map(|element| self.constant(element))\n                    .collect(),\n                type_: self.type_(type_),\n                tail: tail.map(|tail| Box::new(self.constant(*tail))),\n            },\n            Constant::Record {\n                location,\n                module,\n                name,\n                arguments,\n                tag,\n                type_,\n                field_map,\n                record_constructor,\n            } => Constant::Record {\n                location,\n                module,\n                name,\n                arguments: arguments\n                    .into_iter()\n                    .map(\n                        |CallArg {\n                             label,\n                             location,\n                             value,\n                             implicit,\n                         }| CallArg {\n                            label,\n                            location,\n                            value: self.constant(value),\n                            implicit,\n                        },\n                    )\n                    .collect(),\n                tag,\n                type_: self.type_(type_),\n                field_map,\n                record_constructor: record_constructor\n                    .map(|constructor| Box::new(self.value_constructor(*constructor))),\n            },\n            Constant::RecordUpdate {\n                location,\n                constructor_location,\n                module,\n                name,\n                record:\n                    RecordBeingUpdated {\n                        base: record,\n                        location: record_location,\n                    },\n                arguments,\n                tag,\n                type_,\n                field_map,\n            } => Constant::RecordUpdate {\n                location,\n                constructor_location,\n                module,\n                name,\n                record: RecordBeingUpdated {\n                    base: Box::new(self.constant(*record)),\n                    location: record_location,\n                },\n                arguments: arguments\n                    .into_iter()\n                    .map(\n                        |RecordUpdateArg {\n                             label,\n                             location,\n                             value,\n                         }| RecordUpdateArg {\n                            label,\n                            location,\n                            value: self.constant(value),\n                        },\n                    )\n                    .collect(),\n                tag,\n                type_: self.type_(type_),\n                field_map,\n            },\n            Constant::BitArray { location, segments } => Constant::BitArray {\n                location,\n                segments: segments\n                    .into_iter()\n                    .map(|segment| self.bit_array_segment(segment))\n                    .collect(),\n            },\n            Constant::Var {\n                location,\n                module,\n                name,\n                constructor,\n                type_,\n            } => Constant::Var {\n                location,\n                module,\n                name,\n                constructor: constructor\n                    .map(|constructor| Box::new(self.value_constructor(*constructor))),\n                type_: self.type_(type_),\n            },\n            Constant::StringConcatenation {\n                location,\n                left,\n                right,\n            } => Constant::StringConcatenation {\n                location,\n                left: Box::new(self.constant(*left)),\n                right: Box::new(self.constant(*right)),\n            },\n            Constant::Invalid {\n                location,\n                type_,\n                extra_information,\n            } => Constant::Invalid {\n                location,\n                type_: self.type_(type_),\n                extra_information,\n            },\n        }\n    }\n\n    fn bit_array_segment(\n        &mut self,\n        segment: BitArraySegment<TypedConstant, Arc<Type>>,\n    ) -> BitArraySegment<TypedConstant, Arc<Type>> {\n        let BitArraySegment {\n            location,\n            value,\n            options,\n            type_,\n        } = segment;\n\n        let value = Box::new(self.constant(*value));\n        let options = options\n            .into_iter()\n            .map(|option| self.bit_array_option(option))\n            .collect();\n        let type_ = self.type_(type_);\n\n        BitArraySegment {\n            location,\n            value,\n            options,\n            type_,\n        }\n    }\n\n    fn bit_array_option(\n        &mut self,\n        option: BitArrayOption<TypedConstant>,\n    ) -> BitArrayOption<TypedConstant> {\n        match option {\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => option,\n            BitArrayOption::Size {\n                location,\n                value,\n                short_form,\n            } => BitArrayOption::Size {\n                location,\n                value: Box::new(self.constant(*value)),\n                short_form,\n            },\n        }\n    }\n\n    fn accessors_map(&mut self, accessors: AccessorsMap) -> AccessorsMap {\n        let AccessorsMap {\n            publicity,\n            type_,\n            shared_accessors,\n            variant_specific_accessors,\n            variant_positional_accessors,\n        } = accessors;\n\n        let type_ = self.type_(type_);\n        let shared_accessors = shared_accessors\n            .into_iter()\n            .map(|(label, accessor)| (label, self.record_accessor(accessor)))\n            .collect();\n        let variant_specific_accessors = variant_specific_accessors\n            .into_iter()\n            .map(|variant_accessors| {\n                variant_accessors\n                    .into_iter()\n                    .map(|(label, accessor)| (label, self.record_accessor(accessor)))\n                    .collect()\n            })\n            .collect();\n\n        let variant_positional_accessors = variant_positional_accessors\n            .into_iter()\n            .map(|variant_accessors| {\n                variant_accessors\n                    .into_iter()\n                    .map(|type_| self.type_(type_))\n                    .collect()\n            })\n            .collect();\n\n        AccessorsMap {\n            publicity,\n            type_,\n            shared_accessors,\n            variant_specific_accessors,\n            variant_positional_accessors,\n        }\n    }\n\n    fn record_accessor(&mut self, accessor: RecordAccessor) -> RecordAccessor {\n        let RecordAccessor {\n            index,\n            label,\n            type_,\n            documentation,\n        } = accessor;\n        RecordAccessor {\n            index,\n            label,\n            type_: self.type_(type_),\n            documentation,\n        }\n    }\n\n    fn type_alias(&mut self, type_: TypeAliasConstructor) -> TypeAliasConstructor {\n        let TypeAliasConstructor {\n            publicity,\n            module,\n            type_,\n            arity,\n            deprecation,\n            documentation,\n            origin,\n            parameters,\n        } = type_;\n\n        let type_ = self.type_(type_);\n        let parameters = parameters\n            .into_iter()\n            .map(|parameter| self.type_(parameter))\n            .collect();\n\n        TypeAliasConstructor {\n            publicity,\n            module,\n            type_,\n            arity,\n            deprecation,\n            documentation,\n            origin,\n            parameters,\n        }\n    }\n\n    fn type_(&mut self, type_: Arc<Type>) -> Arc<Type> {\n        let type_ = match Arc::unwrap_or_clone(type_) {\n            Type::Named {\n                publicity,\n                package,\n                module,\n                name,\n                arguments,\n                inferred_variant,\n            } => Type::Named {\n                publicity,\n                package,\n                module,\n                name,\n                arguments: arguments\n                    .into_iter()\n                    .map(|argument| self.type_(argument))\n                    .collect(),\n                inferred_variant,\n            },\n            Type::Fn { arguments, return_ } => Type::Fn {\n                arguments: arguments\n                    .into_iter()\n                    .map(|argument| self.type_(argument))\n                    .collect(),\n                return_: self.type_(return_),\n            },\n            Type::Var { type_ } => return self.type_var(&type_.borrow()),\n\n            Type::Tuple { elements } => Type::Tuple {\n                elements: elements\n                    .into_iter()\n                    .map(|element| self.type_(element))\n                    .collect(),\n            },\n        };\n        Arc::new(type_)\n    }\n\n    fn type_var(&mut self, variable: &TypeVar) -> Arc<Type> {\n        match variable {\n            TypeVar::Link { type_ } => self.type_(type_.clone()),\n            TypeVar::Unbound { id } => type_::prelude::unbound_var(self.id(*id)),\n            TypeVar::Generic { id } => type_::prelude::generic_var(self.id(*id)),\n        }\n    }\n\n    fn id(&mut self, id: u64) -> u64 {\n        match self.remapped_variable_ids.get(&id) {\n            Some(new_id) => *new_id,\n            None => {\n                let new_id = self.ids.next();\n                _ = self.remapped_variable_ids.insert(id, new_id);\n                new_id\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__constructors_with_documentation.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\npub type Wibble {\\n  /// This is the Wibble variant. It contains some example data.\\n  Wibble(Int)\\n  /// This is the Wobble variant. It is a recursive type.\\n  Wobble(Wibble)\\n}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {\n        \"Wibble\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"parameters\": 0,\n          \"constructors\": [\n            {\n              \"documentation\": \" This is the Wibble variant. It contains some example data.\\n\",\n              \"name\": \"Wibble\",\n              \"parameters\": [\n                {\n                  \"label\": null,\n                  \"type\": {\n                    \"kind\": \"named\",\n                    \"name\": \"Int\",\n                    \"package\": \"\",\n                    \"module\": \"gleam\",\n                    \"parameters\": []\n                  }\n                }\n              ]\n            },\n            {\n              \"documentation\": \" This is the Wobble variant. It is a recursive type.\\n\",\n              \"name\": \"Wobble\",\n              \"parameters\": [\n                {\n                  \"label\": null,\n                  \"type\": {\n                    \"kind\": \"named\",\n                    \"name\": \"Wibble\",\n                    \"package\": \"my_package\",\n                    \"module\": \"my/module\",\n                    \"parameters\": []\n                  }\n                }\n              ]\n            }\n          ]\n        }\n      },\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__generic_function.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\npub type Wob(a) { Wob }\\n@deprecated(\\\"deprecation message\\\")\\npub fn main() { Wob }\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {\n        \"Wob\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"parameters\": 1,\n          \"constructors\": [\n            {\n              \"documentation\": null,\n              \"name\": \"Wob\",\n              \"parameters\": []\n            }\n          ]\n        }\n      },\n      \"constants\": {},\n      \"functions\": {\n        \"main\": {\n          \"documentation\": null,\n          \"deprecation\": {\n            \"message\": \"deprecation message\"\n          },\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"parameters\": [],\n          \"return\": {\n            \"kind\": \"named\",\n            \"name\": \"Wob\",\n            \"package\": \"my_package\",\n            \"module\": \"my/module\",\n            \"parameters\": [\n              {\n                \"kind\": \"variable\",\n                \"id\": 0\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__imported_aliased_type_keeps_original_name.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\nimport other_module.{type Element as Alias} as module_alias\\npub fn main() -> Alias(module_alias.Element(a)) {}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {\n        \"main\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"parameters\": [],\n          \"return\": {\n            \"kind\": \"named\",\n            \"name\": \"Element\",\n            \"package\": \"other_package\",\n            \"module\": \"other_module\",\n            \"parameters\": [\n              {\n                \"kind\": \"named\",\n                \"name\": \"Element\",\n                \"package\": \"other_package\",\n                \"module\": \"other_module\",\n                \"parameters\": [\n                  {\n                    \"kind\": \"variable\",\n                    \"id\": 0\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__imported_type.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\nimport other_module.{type Element}\\npub fn main() -> Element(Int) {}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {\n        \"main\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"parameters\": [],\n          \"return\": {\n            \"kind\": \"named\",\n            \"name\": \"Element\",\n            \"package\": \"other_package\",\n            \"module\": \"other_module\",\n            \"parameters\": [\n              {\n                \"kind\": \"named\",\n                \"name\": \"Int\",\n                \"package\": \"\",\n                \"module\": \"gleam\",\n                \"parameters\": []\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__internal_definitions_are_not_included.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\n@internal pub const float = 1.1\\n@internal pub fn main() {}\\n@internal pub type Wibble\\n@internal pub type Wobble = Int\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__internal_modules_are_not_exported.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"pub fn main() { 1 }\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {}\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__labelled_function_parameters.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\npub fn fold(list: List(a), from acc: b, with f: fn(a, b) -> b) -> b {\\n  todo\\n}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {\n        \"fold\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"parameters\": [\n            {\n              \"label\": null,\n              \"type\": {\n                \"kind\": \"named\",\n                \"name\": \"List\",\n                \"package\": \"\",\n                \"module\": \"gleam\",\n                \"parameters\": [\n                  {\n                    \"kind\": \"variable\",\n                    \"id\": 0\n                  }\n                ]\n              }\n            },\n            {\n              \"label\": \"from\",\n              \"type\": {\n                \"kind\": \"variable\",\n                \"id\": 1\n              }\n            },\n            {\n              \"label\": \"with\",\n              \"type\": {\n                \"kind\": \"fn\",\n                \"parameters\": [\n                  {\n                    \"kind\": \"variable\",\n                    \"id\": 0\n                  },\n                  {\n                    \"kind\": \"variable\",\n                    \"id\": 1\n                  }\n                ],\n                \"return\": {\n                  \"kind\": \"variable\",\n                  \"id\": 1\n                }\n              }\n            }\n          ],\n          \"return\": {\n            \"kind\": \"variable\",\n            \"id\": 1\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__multiple_type_variables.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\npub type Box(a, b)\\npub fn some_type_variables(a: a, b: b, c: Box(c, d)) -> Box(a, d) {}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {\n        \"Box\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"parameters\": 2,\n          \"constructors\": []\n        }\n      },\n      \"constants\": {},\n      \"functions\": {\n        \"some_type_variables\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"parameters\": [\n            {\n              \"label\": null,\n              \"type\": {\n                \"kind\": \"variable\",\n                \"id\": 0\n              }\n            },\n            {\n              \"label\": null,\n              \"type\": {\n                \"kind\": \"variable\",\n                \"id\": 1\n              }\n            },\n            {\n              \"label\": null,\n              \"type\": {\n                \"kind\": \"named\",\n                \"name\": \"Box\",\n                \"package\": \"my_package\",\n                \"module\": \"my/module\",\n                \"parameters\": [\n                  {\n                    \"kind\": \"variable\",\n                    \"id\": 2\n                  },\n                  {\n                    \"kind\": \"variable\",\n                    \"id\": 3\n                  }\n                ]\n              }\n            }\n          ],\n          \"return\": {\n            \"kind\": \"named\",\n            \"name\": \"Box\",\n            \"package\": \"my_package\",\n            \"module\": \"my/module\",\n            \"parameters\": [\n              {\n                \"kind\": \"variable\",\n                \"id\": 0\n              },\n              {\n                \"kind\": \"variable\",\n                \"id\": 3\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__opaque_constructors_are_not_exposed.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"pub opaque type Wibble { Wob }\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {\n        \"Wibble\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"parameters\": 0,\n          \"constructors\": []\n        }\n      },\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__package_documentation_is_included.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\n//// Some package\\n//// documentation!\\n\\npub fn main() { 1 }\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [\n        \" Some package\",\n        \" documentation!\"\n      ],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {\n        \"main\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"parameters\": [],\n          \"return\": {\n            \"kind\": \"named\",\n            \"name\": \"Int\",\n            \"package\": \"\",\n            \"module\": \"gleam\",\n            \"parameters\": []\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__prelude_types.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\npub const float = 1.1\\npub const string = \\\"\\\"\\npub const int = 1\\npub const bool = True\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {\n        \"bool\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"type\": {\n            \"kind\": \"named\",\n            \"name\": \"Bool\",\n            \"package\": \"\",\n            \"module\": \"gleam\",\n            \"parameters\": []\n          }\n        },\n        \"float\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"type\": {\n            \"kind\": \"named\",\n            \"name\": \"Float\",\n            \"package\": \"\",\n            \"module\": \"gleam\",\n            \"parameters\": []\n          }\n        },\n        \"int\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"type\": {\n            \"kind\": \"named\",\n            \"name\": \"Int\",\n            \"package\": \"\",\n            \"module\": \"gleam\",\n            \"parameters\": []\n          }\n        },\n        \"string\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"implementations\": {\n            \"gleam\": true,\n            \"uses-erlang-externals\": false,\n            \"uses-javascript-externals\": false,\n            \"can-run-on-erlang\": true,\n            \"can-run-on-javascript\": true\n          },\n          \"type\": {\n            \"kind\": \"named\",\n            \"name\": \"String\",\n            \"package\": \"\",\n            \"module\": \"gleam\",\n            \"parameters\": []\n          }\n        }\n      },\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__private_definitions_are_not_included.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\nconst float = 1.1\\nfn main() {}\\ntype Wibble\\ntype Wob = Int\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__type_aliases.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: pub type Wibble(a) = List(a)\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {\n        \"Wibble\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"parameters\": 1,\n          \"alias\": {\n            \"kind\": \"named\",\n            \"name\": \"List\",\n            \"package\": \"\",\n            \"module\": \"gleam\",\n            \"parameters\": [\n              {\n                \"kind\": \"variable\",\n                \"id\": 0\n              }\n            ]\n          }\n        }\n      },\n      \"types\": {},\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__type_constructors.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\npub type Box(a, b) {\\n  Box(b, Int)\\n  OtherBox(message: String, a: a)\\n}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {\n        \"Box\": {\n          \"documentation\": null,\n          \"deprecation\": null,\n          \"parameters\": 2,\n          \"constructors\": [\n            {\n              \"documentation\": null,\n              \"name\": \"Box\",\n              \"parameters\": [\n                {\n                  \"label\": null,\n                  \"type\": {\n                    \"kind\": \"variable\",\n                    \"id\": 1\n                  }\n                },\n                {\n                  \"label\": null,\n                  \"type\": {\n                    \"kind\": \"named\",\n                    \"name\": \"Int\",\n                    \"package\": \"\",\n                    \"module\": \"gleam\",\n                    \"parameters\": []\n                  }\n                }\n              ]\n            },\n            {\n              \"documentation\": null,\n              \"name\": \"OtherBox\",\n              \"parameters\": [\n                {\n                  \"label\": \"message\",\n                  \"type\": {\n                    \"kind\": \"named\",\n                    \"name\": \"String\",\n                    \"package\": \"\",\n                    \"module\": \"gleam\",\n                    \"parameters\": []\n                  }\n                },\n                {\n                  \"label\": \"a\",\n                  \"type\": {\n                    \"kind\": \"variable\",\n                    \"id\": 0\n                  }\n                }\n              ]\n            }\n          ]\n        }\n      },\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/snapshots/gleam_core__package_interface__tests__type_definition.snap",
    "content": "---\nsource: compiler-core/src/package_interface/tests.rs\nexpression: \"\\n/// Wibble's documentation\\npub type Wibble(a, b) {\\n  Wibble\\n  Wobble\\n}\\n\"\n---\n{\n  \"name\": \"my_package\",\n  \"version\": \"11.10.9-1.wibble+build\",\n  \"gleam-version-constraint\": \"1.0.0\",\n  \"modules\": {\n    \"my/module\": {\n      \"documentation\": [],\n      \"type-aliases\": {},\n      \"types\": {\n        \"Wibble\": {\n          \"documentation\": \" Wibble's documentation\\n\",\n          \"deprecation\": null,\n          \"parameters\": 2,\n          \"constructors\": [\n            {\n              \"documentation\": null,\n              \"name\": \"Wibble\",\n              \"parameters\": []\n            },\n            {\n              \"documentation\": null,\n              \"name\": \"Wobble\",\n              \"parameters\": []\n            }\n          ]\n        }\n      },\n      \"constants\": {},\n      \"functions\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface/tests.rs",
    "content": "use std::time::SystemTime;\n\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\nuse globset::GlobBuilder;\nuse hexpm::version::Identifier;\n\nuse crate::{\n    analyse::TargetSupport,\n    build::{Module, Origin, Package, Target},\n    config::{Docs, ErlangConfig, GleamVersion, JavaScriptConfig, PackageConfig},\n    line_numbers::LineNumbers,\n    type_::PRELUDE_MODULE_NAME,\n    uid::UniqueIdGenerator,\n    warning::{TypeWarningEmitter, WarningEmitter},\n};\n\nuse super::PackageInterface;\n\n#[macro_export]\nmacro_rules! assert_package_interface_with_name {\n    ($module_name:expr, $src:expr) => {\n        let output =\n            $crate::package_interface::tests::compile_package(Some($module_name), $src, None);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_package_interface {\n    (($dep_package:expr, $dep_name:expr, $dep_src:expr), $src:expr $(,)?) => {{\n        let output = $crate::package_interface::tests::compile_package(\n            None,\n            $src,\n            Some(($dep_package, $dep_name, $dep_src)),\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    (($dep_package:expr, $dep_name:expr, $dep_src:expr), $src:expr $(,)?) => {{\n        let output = $crate::package_interface::tests::compile_package(\n            None,\n            $src,\n            Some(($dep_package, $dep_name, $dep_src)),\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n\n    ($src:expr) => {{\n        let output = $crate::package_interface::tests::compile_package(None, $src, None);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    }};\n}\n\npub fn compile_package(\n    module_name: Option<&str>,\n    src: &str,\n    dep: Option<(&str, &str, &str)>,\n) -> String {\n    let mut modules = im::HashMap::new();\n    let ids = UniqueIdGenerator::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(\n        PRELUDE_MODULE_NAME.into(),\n        crate::type_::build_prelude(&ids),\n    );\n    let mut direct_dependencies = std::collections::HashMap::from_iter(vec![]);\n    if let Some((dep_package, dep_name, dep_src)) = dep {\n        let parsed = crate::parse::parse_module(\n            Utf8PathBuf::from(\"test/path\"),\n            dep_src,\n            &WarningEmitter::null(),\n        )\n        .expect(\"dep syntax error\");\n        let mut ast = parsed.module;\n        ast.name = dep_name.into();\n        let line_numbers = LineNumbers::new(dep_src);\n        let mut config = PackageConfig::default();\n        config.name = dep_package.into();\n\n        let dep = crate::analyse::ModuleAnalyzerConstructor::<()> {\n            target: Target::Erlang,\n            ids: &ids,\n            origin: Origin::Src,\n            importable_modules: &modules,\n            warnings: &TypeWarningEmitter::null(),\n            direct_dependencies: &std::collections::HashMap::new(),\n            dev_dependencies: &std::collections::HashSet::new(),\n            target_support: TargetSupport::Enforced,\n            package_config: &config,\n        }\n        .infer_module(ast, line_numbers, \"\".into())\n        .expect(\"should successfully infer\");\n        let _ = modules.insert(dep_name.into(), dep.type_info);\n        let _ = direct_dependencies.insert(dep_package.into(), ());\n    }\n    let parsed =\n        crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &WarningEmitter::null())\n            .expect(\"syntax error\");\n\n    let mut ast = parsed.module;\n    let module_name = module_name\n        .map(EcoString::from)\n        .unwrap_or(\"my/module\".into());\n\n    ast.name = module_name.clone();\n    let mut config = PackageConfig::default();\n    config.name = \"my_package\".into();\n    let ast = crate::analyse::ModuleAnalyzerConstructor {\n        target: Target::Erlang,\n        ids: &ids,\n        origin: Origin::Src,\n        importable_modules: &modules,\n        warnings: &TypeWarningEmitter::null(),\n        direct_dependencies: &direct_dependencies,\n        dev_dependencies: &std::collections::HashSet::new(),\n        target_support: TargetSupport::Enforced,\n        package_config: &config,\n    }\n    .infer_module(ast, LineNumbers::new(src), \"\".into())\n    .expect(\"should successfully infer\");\n\n    // TODO: all the bits above are basically copy pasted from the javascript\n    // and erlang test helpers. A refactor might be due here.\n    let mut module = Module {\n        name: module_name,\n        code: src.into(),\n        mtime: SystemTime::UNIX_EPOCH,\n        input_path: \"wibble\".into(),\n        origin: Origin::Src,\n        ast,\n        extra: parsed.extra,\n        dependencies: vec![],\n    };\n    module.attach_doc_and_module_comments();\n    let package: Package = package_from_module(module);\n    serde_json::to_string_pretty(&PackageInterface::from_package(\n        &package,\n        &Default::default(),\n    ))\n    .expect(\"to json\")\n}\n\nfn package_from_module(module: Module) -> Package {\n    Package {\n        config: PackageConfig {\n            name: \"my_package\".into(),\n            version: hexpm::version::Version {\n                major: 11,\n                minor: 10,\n                patch: 9,\n                pre: vec![\n                    Identifier::Numeric(1),\n                    Identifier::AlphaNumeric(\"wibble\".into()),\n                ],\n                build: Some(\"build\".into()),\n            },\n            gleam_version: Some(GleamVersion::new(\"1.0.0\".to_string()).unwrap()),\n            licences: vec![],\n            description: \"description\".into(),\n            documentation: Docs { pages: vec![] },\n            dependencies: std::collections::HashMap::new(),\n            dev_dependencies: std::collections::HashMap::new(),\n            repository: None,\n            links: vec![],\n            erlang: ErlangConfig::default(),\n            javascript: JavaScriptConfig::default(),\n            target: Target::Erlang,\n            internal_modules: Some(vec![\n                GlobBuilder::new(\"internals/*\")\n                    .build()\n                    .expect(\"internals glob\"),\n            ]),\n        },\n        cached_module_names: Vec::new(),\n        modules: vec![module],\n    }\n}\n\n#[test]\npub fn package_documentation_is_included() {\n    assert_package_interface!(\n        \"\n//// Some package\n//// documentation!\n\npub fn main() { 1 }\n\"\n    );\n}\n\n#[test]\npub fn private_definitions_are_not_included() {\n    assert_package_interface!(\n        \"\nconst float = 1.1\nfn main() {}\ntype Wibble\ntype Wob = Int\n\"\n    );\n}\n\n#[test]\npub fn internal_definitions_are_not_included() {\n    assert_package_interface!(\n        \"\n@internal pub const float = 1.1\n@internal pub fn main() {}\n@internal pub type Wibble\n@internal pub type Wobble = Int\n\"\n    );\n}\n\n#[test]\npub fn opaque_constructors_are_not_exposed() {\n    assert_package_interface!(\"pub opaque type Wibble { Wob }\")\n}\n\n#[test]\npub fn type_aliases() {\n    assert_package_interface!(\"pub type Wibble(a) = List(a)\")\n}\n\n#[test]\npub fn type_definition() {\n    assert_package_interface!(\n        \"\n/// Wibble's documentation\npub type Wibble(a, b) {\n  Wibble\n  Wobble\n}\n\"\n    )\n}\n\n#[test]\npub fn prelude_types() {\n    assert_package_interface!(\n        r#\"\npub const float = 1.1\npub const string = \"\"\npub const int = 1\npub const bool = True\n\"#\n    );\n}\n\n#[test]\npub fn generic_function() {\n    assert_package_interface!(\n        r#\"\npub type Wob(a) { Wob }\n@deprecated(\"deprecation message\")\npub fn main() { Wob }\n\"#\n    );\n}\n\n#[test]\npub fn imported_type() {\n    assert_package_interface!(\n        (\"other_package\", \"other_module\", \"pub type Element(a)\"),\n        r#\"\nimport other_module.{type Element}\npub fn main() -> Element(Int) {}\n\"#\n    );\n}\n\n#[test]\npub fn imported_aliased_type_keeps_original_name() {\n    assert_package_interface!(\n        (\"other_package\", \"other_module\", \"pub type Element(a)\"),\n        r#\"\nimport other_module.{type Element as Alias} as module_alias\npub fn main() -> Alias(module_alias.Element(a)) {}\n\"#\n    );\n}\n\n#[test]\npub fn multiple_type_variables() {\n    assert_package_interface!(\n        r#\"\npub type Box(a, b)\npub fn some_type_variables(a: a, b: b, c: Box(c, d)) -> Box(a, d) {}\n\"#\n    );\n}\n\n#[test]\npub fn type_constructors() {\n    assert_package_interface!(\n        r#\"\npub type Box(a, b) {\n  Box(b, Int)\n  OtherBox(message: String, a: a)\n}\n\"#\n    );\n}\n\n#[test]\npub fn internal_modules_are_not_exported() {\n    assert_package_interface_with_name!(\"internals/internal_module\", \"pub fn main() { 1 }\");\n}\n\n#[test]\npub fn labelled_function_parameters() {\n    assert_package_interface!(\n        r#\"\npub fn fold(list: List(a), from acc: b, with f: fn(a, b) -> b) -> b {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\npub fn constructors_with_documentation() {\n    assert_package_interface!(\n        r#\"\npub type Wibble {\n  /// This is the Wibble variant. It contains some example data.\n  Wibble(Int)\n  /// This is the Wobble variant. It is a recursive type.\n  Wobble(Wibble)\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/package_interface.rs",
    "content": "use std::{collections::HashMap, ops::Deref};\n\nuse ecow::EcoString;\nuse serde::Serialize;\n\n#[cfg(test)]\nmod tests;\n\nuse crate::{\n    io::ordered_map,\n    type_::{\n        self, Deprecation, Opaque, Type, TypeConstructor, TypeVar, TypeVariantConstructors,\n        ValueConstructorVariant, expression::Implementations,\n    },\n};\n\nuse crate::build::Package;\n\n/// The public interface of a package that gets serialised as a json object.\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct PackageInterface {\n    name: EcoString,\n    version: EcoString,\n    /// The Gleam version constraint that the package specifies in its `gleam.toml`.\n    gleam_version_constraint: Option<EcoString>,\n    /// A map from module name to its interface.\n    #[serde(serialize_with = \"ordered_map\")]\n    modules: HashMap<EcoString, ModuleInterface>,\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct ModuleInterface {\n    /// A vector with the lines composing the module's documentation (that is\n    /// every line preceded by a `////`).\n    documentation: Vec<EcoString>,\n    /// A map from type alias name to its interface.\n    #[serde(serialize_with = \"ordered_map\")]\n    type_aliases: HashMap<EcoString, TypeAliasInterface>,\n    /// A map from type name to its interface.\n    #[serde(serialize_with = \"ordered_map\")]\n    types: HashMap<EcoString, TypeDefinitionInterface>,\n    /// A map from constant name to its interface.\n    #[serde(serialize_with = \"ordered_map\")]\n    constants: HashMap<EcoString, ConstantInterface>,\n    /// A map from function name to its interface.\n    #[serde(serialize_with = \"ordered_map\")]\n    functions: HashMap<EcoString, FunctionInterface>,\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct TypeDefinitionInterface {\n    /// The definition's documentation comment (that is every line preceded by\n    /// `///`).\n    documentation: Option<EcoString>,\n    /// If the definition has a deprecation annotation `@deprecated(\"...\")`\n    /// this field will hold the reason of the deprecation.\n    deprecation: Option<DeprecationInterface>,\n    /// The number of type variables in the type definition.\n    /// ```gleam\n    /// /// This type has 2 type variables.\n    /// type Result(a, b) {\n    ///   Ok(a)\n    ///   Error(b)\n    /// }\n    /// ```\n    parameters: usize,\n    /// A list of the type constructors. If the type is marked as opaque it\n    /// won't have any visible constructors.\n    constructors: Vec<TypeConstructorInterface>,\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct TypeConstructorInterface {\n    /// The constructor's documentation comment (that is every line preceded by\n    /// `///`).\n    documentation: Option<EcoString>,\n    /// The name of the type constructor.\n    /// ```gleam\n    /// pub type Box(a) {\n    ///   MyBox(value: a)\n    /// //^^^^^ This is the constructor's name\n    /// }\n    /// ```\n    name: EcoString,\n    /// A list of the parameters needed by the constructor.\n    /// ```gleam\n    /// pub type Box(a) {\n    ///   MyBox(value: a)\n    /// //      ^^^^^^^^ This is the constructor's parameter.\n    /// }\n    /// ```\n    parameters: Vec<ParameterInterface>,\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct TypeAliasInterface {\n    /// The constructor's documentation comment (that is every line preceded by\n    /// `///`).\n    documentation: Option<EcoString>,\n    /// If the alias has a deprecation annotation `@deprecated(\"...\")`\n    /// this field will hold the reason of the deprecation.\n    deprecation: Option<DeprecationInterface>,\n    /// The number of type variables in the type alias definition.\n    /// ```gleam\n    /// /// This type alias has 2 type variables.\n    /// type Results(a, b) = List(Restul(a, b))\n    /// ```\n    parameters: usize,\n    /// The aliased type.\n    /// ```gleam\n    /// type Ints = List(Int)\n    /// //          ^^^^^^^^^ This is the aliased type in a type alias.\n    /// ```\n    alias: TypeInterface,\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct ConstantInterface {\n    /// The constant's documentation comment (that is every line preceded by\n    /// `///`).\n    documentation: Option<EcoString>,\n    /// If the constant has a deprecation annotation `@deprecated(\"...\")`\n    /// this field will hold the reason of the deprecation.\n    deprecation: Option<DeprecationInterface>,\n    implementations: ImplementationsInterface,\n    /// The constant's type.\n    #[serde(rename = \"type\")]\n    type_: TypeInterface,\n}\n\n/// A module's function. This differs from a simple `Fn` type as its arguments\n/// can be labelled.\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct FunctionInterface {\n    /// The function's documentation comment (that is every line preceded by\n    /// `///`).\n    documentation: Option<EcoString>,\n    /// If the constant has a deprecation annotation `@deprecated(\"...\")`\n    /// this field will hold the reason of the deprecation.\n    deprecation: Option<DeprecationInterface>,\n    implementations: ImplementationsInterface,\n    parameters: Vec<ParameterInterface>,\n    #[serde(rename = \"return\")]\n    return_: TypeInterface,\n}\n\n/// Informations about how a value is implemented.\n#[derive(Debug, Serialize, Copy, Clone)]\n#[serde(rename_all = \"kebab-case\")]\npub struct ImplementationsInterface {\n    /// Set to `true` if the const/function has a pure Gleam implementation\n    /// (that is, it never uses external code).\n    /// Being pure Gleam means that the function will support all Gleam\n    /// targets, even future ones that are not present to this day.\n    ///\n    /// Consider the following function:\n    ///\n    /// ```gleam\n    /// @external(erlang, \"wibble\", \"wobble\")\n    /// pub fn a_random_number() -> Int {\n    ///   4\n    ///   // This is a default implementation.\n    /// }\n    /// ```\n    ///\n    /// The implementations for this function will look like this:\n    ///\n    /// ```json\n    /// {\n    ///   gleam: true,\n    ///   can_run_on_erlang: true,\n    ///   can_run_on_javascript: true,\n    ///   uses_erlang_externals: true,\n    ///   uses_javascript_externals: false,\n    /// }\n    /// ```\n    ///\n    /// - `gleam: true` means that the function has a pure Gleam implementation\n    ///   and thus it can be used on all Gleam targets with no problems.\n    /// - `can_run_on_erlang: false` the function can be called on the Erlang\n    ///   target.\n    /// - `can_run_on_javascript: true` the function can be called on the JavaScript\n    ///   target.\n    /// - `uses_erlang_externals: true` means that the function will use Erlang\n    ///   external code when compiled to the Erlang target.\n    /// - `uses_javascript_externals: false` means that the function won't use\n    ///   JavaScript external code when compiled to JavaScript. The function can\n    ///   still be used on the JavaScript target since it has a pure Gleam\n    ///   implementation.\n    gleam: bool,\n    /// Set to `true` if the const/function is defined using Erlang external\n    /// code. That means that the function will use Erlang code through FFI when\n    /// compiled for the Erlang target.\n    uses_erlang_externals: bool,\n    /// Set to `true` if the const/function is defined using JavaScript external\n    /// code. That means that the function will use JavaScript code through FFI\n    /// when compiled for the JavaScript target.\n    ///\n    /// Let's have a look at an example:\n    ///\n    /// ```gleam\n    /// @external(javascript, \"wibble\", \"wobble\")\n    /// pub fn javascript_only() -> Int\n    /// ```\n    ///\n    /// It's implementations field will look like this:\n    ///\n    /// ```json\n    /// {\n    ///   gleam: false,\n    ///   can_run_on_erlang: false,\n    ///   can_run_on_javascript: true,\n    ///   uses_erlang_externals: false,\n    ///   uses_javascript_externals: true,\n    /// }\n    /// ```\n    ///\n    /// - `gleam: false` means that the function doesn't have a pure Gleam\n    ///   implementations. This means that the function is only defined using\n    ///   externals and can only be used on some targets.\n    /// - `can_run_on_erlang: false` the function cannot be called on the Erlang\n    ///   target.\n    /// - `can_run_on_javascript: true` the function can be called on the JavaScript\n    ///   target.\n    /// - `uses_erlang_externals: false` the function is not using external\n    ///   Erlang code.\n    /// - `uses_javascript_externals: true` the function is using JavaScript\n    ///   external code.\n    uses_javascript_externals: bool,\n    /// Whether the function can be called on the Erlang target, either due to a\n    /// pure Gleam implementation or an implementation that uses some Erlang\n    /// externals.\n    can_run_on_erlang: bool,\n    /// Whether the function can be called on the JavaScript target, either due\n    /// to a pure Gleam implementation or an implementation that uses some\n    /// JavaScript externals.\n    can_run_on_javascript: bool,\n}\n\nimpl ImplementationsInterface {\n    fn from_implementations(implementations: &Implementations) -> ImplementationsInterface {\n        // It might look a bit silly to just recreate an identical structure with\n        // a different name. However, this way we won't inadvertently cause breaking\n        // changes if we were to change the names used by the `Implementations` struct\n        // that is used by the target tracking algorithm.\n        // By doing this we can change the target tracking and package interface\n        // separately!\n        //\n        // This pattern matching makes sure we will remember to handle any change\n        // in the `Implementations` struct.\n        let Implementations {\n            gleam,\n            uses_erlang_externals,\n            uses_javascript_externals,\n\n            can_run_on_erlang,\n            can_run_on_javascript,\n        } = implementations;\n\n        ImplementationsInterface {\n            gleam: *gleam,\n            uses_erlang_externals: *uses_erlang_externals,\n            uses_javascript_externals: *uses_javascript_externals,\n            can_run_on_erlang: *can_run_on_erlang,\n            can_run_on_javascript: *can_run_on_javascript,\n        }\n    }\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct DeprecationInterface {\n    /// The reason for the deprecation.\n    message: EcoString,\n}\n\nimpl DeprecationInterface {\n    fn from_deprecation(deprecation: &Deprecation) -> Option<DeprecationInterface> {\n        match deprecation {\n            Deprecation::NotDeprecated => None,\n            Deprecation::Deprecated { message } => Some(DeprecationInterface {\n                message: message.clone(),\n            }),\n        }\n    }\n}\n\n#[derive(Serialize, Debug)]\n#[serde(tag = \"kind\")]\n#[serde(rename_all = \"kebab-case\")]\npub enum TypeInterface {\n    /// A tuple type like `#(Int, Float)`.\n    Tuple {\n        /// The types composing the tuple.\n        elements: Vec<TypeInterface>,\n    },\n    /// A function type like `fn(Int, String) -> String`.\n    Fn {\n        parameters: Vec<TypeInterface>,\n        #[serde(rename = \"return\")]\n        return_: Box<TypeInterface>,\n    },\n    /// A type variable.\n    /// ```gleam\n    /// pub fn wibble(value: a) -> a {}\n    /// //                   ^ This is a type variable.\n    /// ```\n    Variable { id: u64 },\n    /// A custom named type.\n    /// ```gleam\n    /// let value: Bool = True\n    ///            ^^^^ This is a named type.\n    /// ```\n    ///\n    /// All prelude types - like Bool, String, etc. - are named types as well.\n    /// In that case their package is an empty string `\"\"` and their module\n    /// name is the string `\"gleam\"`.\n    ///\n    Named {\n        name: EcoString,\n        /// The package the type is defined in.\n        package: EcoString,\n        /// The module the type is defined in.\n        module: EcoString,\n        /// The type parameters that might be needed to define a named type.\n        /// ```gleam\n        /// let result: Result(Int, e) = Ok(1)\n        /// //                 ^^^^^^ The `Result` named type has 2 parameters.\n        /// //                        In this case it's the Int type and a type\n        /// //                        variable.\n        /// ```\n        parameters: Vec<TypeInterface>,\n    },\n}\n\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"kebab-case\")]\npub struct ParameterInterface {\n    /// If the parameter is labelled this will hold the label's name.\n    /// ```gleam\n    /// pub fn repeat(times n: Int) -> List(Int)\n    /// //            ^^^^^ This is the parameter's label.\n    /// ```\n    label: Option<EcoString>,\n    /// The parameter's type.\n    /// ```gleam\n    /// pub fn repeat(times n: Int) -> List(Int)\n    /// //                     ^^^ This is the parameter's type.\n    /// ```\n    #[serde(rename = \"type\")]\n    type_: TypeInterface,\n}\n\nimpl PackageInterface {\n    pub fn from_package(\n        package: &Package,\n        cached_modules: &im::HashMap<EcoString, type_::ModuleInterface>,\n    ) -> PackageInterface {\n        PackageInterface {\n            name: package.config.name.clone(),\n            version: package.config.version.to_string().into(),\n            gleam_version_constraint: package\n                .config\n                .gleam_version\n                .clone()\n                .map(|version| EcoString::from(version.hex().to_string())),\n            modules: package\n                .modules\n                .iter()\n                .map(|module| &module.ast.type_info)\n                .chain(\n                    package\n                        .cached_module_names\n                        .iter()\n                        .filter_map(|name| cached_modules.get(name)),\n                )\n                .filter(|module| !package.config.is_internal_module(module.name.as_str()))\n                .map(|module| (module.name.clone(), ModuleInterface::from_interface(module)))\n                .collect(),\n        }\n    }\n}\n\nimpl ModuleInterface {\n    fn from_interface(interface: &type_::ModuleInterface) -> ModuleInterface {\n        let mut types = HashMap::new();\n        let mut type_aliases = HashMap::new();\n        let mut constants = HashMap::new();\n        let mut functions = HashMap::new();\n        for (name, constructor) in interface.types.iter().filter(|(name, c)| {\n            // Aliases are stored separately\n            c.publicity.is_public() && !interface.type_aliases.contains_key(*name)\n        }) {\n            let mut id_map = IdMap::new();\n\n            let TypeConstructor {\n                deprecation,\n                documentation,\n                ..\n            } = constructor;\n\n            for typed_parameter in &constructor.parameters {\n                id_map.add_type_variable_id(typed_parameter.as_ref());\n            }\n\n            let _ = types.insert(\n                name.clone(),\n                TypeDefinitionInterface {\n                    documentation: documentation.clone(),\n                    deprecation: DeprecationInterface::from_deprecation(deprecation),\n                    parameters: interface\n                        .types\n                        .get(&name.clone())\n                        .map_or(vec![], |t| t.parameters.clone())\n                        .len(),\n                    constructors: match interface.types_value_constructors.get(&name.clone()) {\n                        Some(TypeVariantConstructors {\n                            variants,\n                            opaque: Opaque::NotOpaque,\n                            ..\n                        }) => variants\n                            .iter()\n                            .map(|constructor| TypeConstructorInterface {\n                                documentation: constructor.documentation.clone(),\n                                name: constructor.name.clone(),\n                                parameters: constructor\n                                    .parameters\n                                    .iter()\n                                    .map(|arg| ParameterInterface {\n                                        label: arg.label.clone(),\n                                        // We share the same id_map between each step so that the\n                                        // incremental ids assigned are consisten with each other\n                                        type_: from_type_helper(arg.type_.as_ref(), &mut id_map),\n                                    })\n                                    .collect(),\n                            })\n                            .collect(),\n                        Some(_) | None => Vec::new(),\n                    },\n                },\n            );\n        }\n\n        for (name, alias) in interface\n            .type_aliases\n            .iter()\n            .filter(|(_, v)| v.publicity.is_public())\n        {\n            let _ = type_aliases.insert(\n                name.clone(),\n                TypeAliasInterface {\n                    documentation: alias.documentation.clone(),\n                    deprecation: DeprecationInterface::from_deprecation(&alias.deprecation),\n                    parameters: alias.arity,\n                    alias: TypeInterface::from_type(&alias.type_),\n                },\n            );\n        }\n\n        for (name, value) in interface\n            .values\n            .iter()\n            .filter(|(_, v)| v.publicity.is_public())\n        {\n            match (value.type_.as_ref(), value.variant.clone()) {\n                (\n                    Type::Fn {\n                        arguments,\n                        return_: return_type,\n                    },\n                    ValueConstructorVariant::ModuleFn {\n                        documentation,\n                        implementations,\n                        field_map,\n                        ..\n                    },\n                ) => {\n                    let mut id_map = IdMap::new();\n\n                    let reverse_field_map = field_map\n                        .as_ref()\n                        .map(|field_map| field_map.indices_to_labels())\n                        .unwrap_or_default();\n\n                    let _ = functions.insert(\n                        name.clone(),\n                        FunctionInterface {\n                            implementations: ImplementationsInterface::from_implementations(\n                                &implementations,\n                            ),\n                            deprecation: DeprecationInterface::from_deprecation(&value.deprecation),\n                            documentation,\n                            parameters: arguments\n                                .iter()\n                                .enumerate()\n                                .map(|(index, type_)| ParameterInterface {\n                                    label: reverse_field_map\n                                        .get(&(index as u32))\n                                        .map(|label| (*label).clone()),\n                                    type_: from_type_helper(type_, &mut id_map),\n                                })\n                                .collect(),\n                            return_: from_type_helper(return_type, &mut id_map),\n                        },\n                    );\n                }\n\n                (\n                    type_,\n                    ValueConstructorVariant::ModuleConstant {\n                        documentation,\n                        implementations,\n                        ..\n                    },\n                ) => {\n                    let _ = constants.insert(\n                        name.clone(),\n                        ConstantInterface {\n                            implementations: ImplementationsInterface::from_implementations(\n                                &implementations,\n                            ),\n                            type_: TypeInterface::from_type(type_),\n                            deprecation: DeprecationInterface::from_deprecation(&value.deprecation),\n                            documentation,\n                        },\n                    );\n                }\n\n                _ => {}\n            }\n        }\n\n        ModuleInterface {\n            documentation: interface.documentation.clone(),\n            types,\n            type_aliases,\n            constants,\n            functions,\n        }\n    }\n}\n\nimpl TypeInterface {\n    fn from_type(type_: &Type) -> TypeInterface {\n        from_type_helper(type_, &mut IdMap::new())\n    }\n}\n\n/// Turns a type into its interface, an `IdMap` is needed to make sure that all\n/// the type variables' ids that appear in the type are mapped to an incremental\n/// number and consistent with each other (that is, two types variables that\n/// have the same id will also have the same incremental number in the end).\nfn from_type_helper(type_: &Type, id_map: &mut IdMap) -> TypeInterface {\n    match type_ {\n        Type::Fn { arguments, return_ } => TypeInterface::Fn {\n            parameters: arguments\n                .iter()\n                .map(|argument| from_type_helper(argument.as_ref(), id_map))\n                .collect(),\n            return_: Box::new(from_type_helper(return_, id_map)),\n        },\n\n        Type::Tuple { elements } => TypeInterface::Tuple {\n            elements: elements\n                .iter()\n                .map(|element| from_type_helper(element.as_ref(), id_map))\n                .collect(),\n        },\n\n        Type::Var { type_ } => match type_\n            .as_ref()\n            .try_borrow()\n            .expect(\"borrow type after inference\")\n            .deref()\n        {\n            TypeVar::Link { type_ } => from_type_helper(type_, id_map),\n            // Since package serialisation happens after inference there\n            // should be no unbound type variables.\n            // TODO: This branch should be `unreachable!()` but because of\n            //       https://github.com/gleam-lang/gleam/issues/2533\n            //       we sometimes end up with those in top level\n            //       definitions.\n            //       However, `Unbound` and `Generic` ids are generated\n            //       using the same generator so we have no problem treating\n            //       unbound variables as generic ones since ids will never\n            //       overlap.\n            //       Once #2533 is closed this branch can be turned back to\n            //       be unreachable!().\n            TypeVar::Unbound { id } | TypeVar::Generic { id } => TypeInterface::Variable {\n                id: id_map.map_id(*id),\n            },\n        },\n\n        Type::Named {\n            name,\n            module,\n            arguments,\n            package,\n            ..\n        } => TypeInterface::Named {\n            name: name.clone(),\n            package: package.clone(),\n            module: module.clone(),\n            parameters: arguments\n                .iter()\n                .map(|argument| from_type_helper(argument.as_ref(), id_map))\n                .collect(),\n        },\n    }\n}\n\n/// This is a map that is used to map type variable id's to progressive numbers\n/// starting from 0.\n/// After type inference the ids associated with type variables can be quite\n/// high and are not the best to produce a human/machine readable output.\n///\n/// Imagine a function like this one: `pub fn wibble(item: a, rest: b) -> c`\n/// What we want here is for type variables to have increasing ids starting from\n/// 0: `a` with id `0`, `b` with id `1` and `c` with id `2`.\n///\n/// This map allows us to keep track of the ids we've run into and map those to\n/// their incremental counterpart starting from 0.\nstruct IdMap {\n    next_id: u64,\n    ids: HashMap<u64, u64>,\n}\n\nimpl IdMap {\n    /// Create a new map that will assign id numbers starting from 0.\n    fn new() -> IdMap {\n        IdMap {\n            next_id: 0,\n            ids: HashMap::new(),\n        }\n    }\n\n    /// Map an id to its mapped counterpart starting from 0. If an id has never\n    /// been seen before it will be assigned a new incremental number.\n    fn map_id(&mut self, id: u64) -> u64 {\n        match self.ids.get(&id) {\n            Some(mapped_id) => *mapped_id,\n            None => {\n                let mapped_id = self.next_id;\n                let _ = self.ids.insert(id, mapped_id);\n                self.next_id += 1;\n                mapped_id\n            }\n        }\n    }\n\n    /// If the type is a type variable, and has not been seen before, it will\n    /// be assigned to a new incremental number.\n    fn add_type_variable_id(&mut self, type_: &Type) {\n        match type_ {\n            // These types have no id to add to the map.\n            Type::Named { .. } | Type::Fn { .. } | Type::Tuple { .. } => (),\n            // If the type is actually a type variable whose id needs to be mapped.\n            Type::Var { type_ } => match type_\n                .as_ref()\n                .try_borrow()\n                .expect(\"borrow type after inference\")\n                .deref()\n            {\n                TypeVar::Link { .. } => (),\n                TypeVar::Unbound { id } | TypeVar::Generic { id } => {\n                    let _ = self.map_id(*id);\n                }\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/parse/error.rs",
    "content": "use crate::ast::{SrcSpan, TypeAst};\nuse crate::diagnostic::{ExtraLabel, Label};\nuse crate::error::wrap;\nuse crate::parse::Token;\nuse ecow::EcoString;\nuse itertools::Itertools;\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct LexicalError {\n    pub error: LexicalErrorType,\n    pub location: SrcSpan,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum InvalidUnicodeEscapeError {\n    MissingOpeningBrace,          // Expected '{'\n    ExpectedHexDigitOrCloseBrace, // Expected hex digit or '}'\n    InvalidNumberOfHexDigits,     // Expected between 1 and 6 hex digits\n    InvalidCodepoint,             // Invalid Unicode codepoint\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum LexicalErrorType {\n    BadStringEscape,                                 // string contains an unescaped slash\n    InvalidUnicodeEscape(InvalidUnicodeEscapeError), // \\u{...} escape sequence is invalid\n    DigitOutOfRadix,                                 // 0x012 , 2 is out of radix\n    NumTrailingUnderscore,                           // 1_000_ is not allowed\n    RadixIntNoValue,                                 // 0x, 0b, 0o without a value\n    MissingExponent,     // 1.0e, for example, where there is no exponent\n    UnexpectedStringEnd, // Unterminated string literal\n    UnrecognizedToken { tok: char },\n    InvalidTripleEqual,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ParseError {\n    pub error: ParseErrorType,\n    pub location: SrcSpan,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum ParseErrorType {\n    ExpectedEqual,              // expect \"=\"\n    ExpectedExpr,               // after \"->\" in a case clause\n    ExpectedName,               // any token used when a Name was expected\n    ExpectedPattern,            // after ':' where a pattern is expected\n    ExpectedType,               // after ':' or '->' where a type annotation is expected\n    ExpectedUpName,             // any token used when a UpName was expected\n    ExpectedValue,              // no value after \"=\"\n    ExpectedDefinition,         // after attributes\n    ExpectedDeprecationMessage, // after \"deprecated\"\n    ExpectedFunctionDefinition, // after function-only attributes\n    ExpectedTargetName,         // after \"@target(\"\n    ExprLparStart,              // it seems \"(\" was used to start an expression\n    ExtraSeparator,             // #(1,,) <- the 2nd comma is an extra separator\n    IncorrectName,              // UpName or DiscardName used when Name was expected\n    IncorrectUpName,            // Name or DiscardName used when UpName was expected\n    InvalidBitArraySegment,     // <<7:hello>> `hello` is an invalid BitArray segment\n    InvalidBitArrayUnit,        // in <<1:unit(x)>> x must be 1 <= x <= 256\n    InvalidTailPattern,         // only name and _name are allowed after \"..\" in list pattern\n    InvalidTupleAccess,         // only positive int literals for tuple access\n    LexError {\n        error: LexicalError,\n    },\n    NestedBitArrayPattern,        // <<<<1>>, 2>>, <<1>> is not allowed in there\n    NoLetBinding, // Bindings and rebinds always require let and must always bind to a value.\n    NoValueAfterEqual, // = <something other than a value>\n    NotConstType, // :fn(), name, _  are not valid const types\n    OpNakedRight, // Operator with no value to the right\n    OpaqueTypeAlias, // Type aliases cannot be opaque\n    TooManyArgHoles, // a function call can have at most 1 arg hole\n    DuplicateAttribute, // an attribute was used more than once\n    UnknownAttribute, // an attribute was used that is not known\n    UnknownTarget, // an unknown target was used\n    ListSpreadWithoutElements, // Pointless spread: `[..xs]`\n    ListSpreadFollowedByElements, // trying to append something after the spread: `[..xs, x]`\n    ListSpreadWithAnotherSpread {\n        first_spread_location: SrcSpan,\n    }, // trying to use multiple spreads: `[..xs, ..ys]`\n    UnexpectedLabel, // argument labels were provided, but are not supported in this context\n    UnexpectedEof,\n    UnexpectedReservedWord, // reserved word used when a name was expected\n    UnexpectedToken {\n        token: Token,\n        expected: Vec<EcoString>,\n        hint: Option<EcoString>,\n    },\n    UnexpectedFunction, // a function was used called outside of another function\n    // A variable was assigned or discarded on the left hand side of a <> pattern\n    ConcatPatternVariableLeftHandSide,\n    ListSpreadWithoutTail,               // let x = [1, ..]\n    ExpectedFunctionBody,                // let x = fn()\n    RedundantInternalAttribute,          // for a private definition marked as internal\n    InvalidModuleTypePattern,            // for patterns that have a dot like: `name.thing`\n    ListPatternSpreadFollowedByElements, // When there is a pattern after a spread [..rest, pattern]\n    ExpectedRecordConstructor {\n        name: EcoString,\n        public: bool,\n        opaque: bool,\n        field: EcoString,\n        field_type: Option<Box<TypeAst>>,\n    },\n    CallInClauseGuard, // case x { _ if f() -> 1 }\n    IfExpression,\n    ConstantRecordConstructorNoArguments, // const x = Record()\n    TypeDefinitionNoArguments,            // pub type Wibble() { ... }\n    UnknownAttributeRecordVariant, // an attribute was used that is not know for a custom type variant\n    // a Python-like import was written, such as `import gleam.io`, instead of `import gleam/io`\n    IncorrectImportModuleSeparator {\n        module: EcoString,\n        item: EcoString,\n    },\n    /// This can happen when there's an empty block in a case clause guard.\n    /// For example: `_ if a == {}`\n    EmptyGuardBlock,\n    // When the use tries to define a constant inside a function\n    ConstantInsideFunction,\n    FunctionDefinitionAngleGenerics, // fn something<T>() { ... }\n    // let a: List<String> = []\n    TypeUsageAngleGenerics {\n        module: Option<EcoString>,\n        name: EcoString,\n        arguments: Vec<TypeAst>,\n    },\n    // type Something<T> {\n    TypeDefinitionAngleGenerics {\n        name: EcoString,\n        arguments: Vec<EcoString>,\n    },\n}\n\npub(crate) struct ParseErrorDetails {\n    pub text: String,\n    pub label_text: EcoString,\n    pub extra_labels: Vec<ExtraLabel>,\n    pub hint: Option<String>,\n}\n\nimpl ParseErrorType {\n    pub(crate) fn details(&self) -> ParseErrorDetails {\n        match self {\n            ParseErrorType::ExpectedEqual => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a '=' after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedExpr => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting an expression after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedName => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a name here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedPattern => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a pattern after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedType => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/basics/assignments/\".into(),\n                hint: None,\n                label_text: \"I was expecting a type after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedUpName => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a type name here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedValue => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a value after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedDefinition => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a definition after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedDeprecationMessage => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"A deprecation attribute must have a string message.\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedFunctionDefinition => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting a function definition after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedTargetName => ParseErrorDetails {\n                text: \"Try `erlang`, `javascript`.\".into(),\n                hint: None,\n                label_text: \"I was expecting a target name after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExtraSeparator => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\"Try removing it?\".into()),\n                label_text: \"This is an extra delimiter\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExprLparStart => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\n                    \"To group expressions in Gleam, use \\\"{\\\" and \\\"}\\\"; \\\ntuples are created with `#(` and `)`.\"\n                        .into(),\n                ),\n                label_text: \"This parenthesis cannot be understood here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::IncorrectName => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(wrap(\n                    \"Variable and module names start with a lowercase letter, \\\nand can contain a-z, 0-9, or _.\",\n                )),\n                label_text: \"I'm expecting a lowercase name here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::IncorrectUpName => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(wrap(\n                    \"Type names start with a uppercase letter, and can \\\ncontain a-z, A-Z, or 0-9.\",\n                )),\n                label_text: \"I'm expecting a type name here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::InvalidBitArraySegment => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/data-types/bit-arrays/\".into(),\n                hint: Some(format!(\n                    \"Valid BitArray segment options are:\\n{}\",\n                    wrap(\n                        \"bits, bytes, int, float, utf8, utf16, utf32, utf8_codepoint, \\\nutf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, unit.\",\n                    )\n                )),\n                label_text: \"This is not a valid BitArray segment option\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::InvalidBitArrayUnit => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/data-types/bit-arrays/\".into(),\n                hint: Some(\"Unit must be an integer literal >= 1 and <= 256.\".into()),\n                label_text: \"This is not a valid BitArray unit value\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::InvalidTailPattern => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"This part of a list pattern can only be a name or a discard\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::InvalidTupleAccess => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\n                    \"Only non negative integer literals like 0, or 1_000 can be used.\".into(),\n                ),\n                label_text: \"This integer is not valid for tuple access\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::LexError { error: lex_err } => {\n                let (label_text, text_lines) = lex_err.to_parse_error_info();\n                let text = text_lines.join(\"\\n\");\n                ParseErrorDetails {\n                    text,\n                    hint: None,\n                    label_text: label_text.into(),\n                    extra_labels: vec![],\n                }\n            }\n\n            ParseErrorType::NestedBitArrayPattern => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"BitArray patterns cannot be nested\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::NotConstType => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/basics/constants/\".into(),\n                hint: None,\n                label_text: \"This type is not allowed in module constants\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::NoLetBinding => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/basics/assignments/\".into(),\n                hint: Some(\"Use let for binding.\".into()),\n                label_text: \"There must be a 'let' to bind variable to value\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::NoValueAfterEqual => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"I was expecting to see a value after this equals sign\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::OpaqueTypeAlias => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/basics/type-aliases/\".into(),\n                hint: None,\n                label_text: \"Type Aliases cannot be opaque\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::OpNakedRight => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\"Remove it or put a value after it.\".into()),\n                label_text: \"This operator has no value on its right side\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::TooManyArgHoles => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/functions/functions/\".into(),\n                hint: Some(\"Function calls can have at most one argument hole.\".into()),\n                label_text: \"There is more than 1 argument hole in this function call\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnexpectedEof => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"The module ended unexpectedly\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ListSpreadWithoutElements => ParseErrorDetails {\n                text: \"See: https://tour.gleam.run/basics/lists/\".into(),\n                hint: Some(\"Try prepending some elements [1, 2, ..list].\".into()),\n                label_text: \"This spread does nothing\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ListSpreadWithAnotherSpread {\n                first_spread_location,\n            } => ParseErrorDetails {\n                text: [\n                    \"Lists are immutable and singly-linked, so to join two or more lists\",\n                    \"all the elements of the lists would need to be copied into a new list.\",\n                    \"This would be slow, so there is no built-in syntax for it.\",\n                ]\n                .join(\"\\n\"),\n                hint: None,\n                label_text: \"I wasn't expecting a second list here\".into(),\n                extra_labels: vec![ExtraLabel {\n                    src_info: None,\n                    label: Label {\n                        text: Some(\"You're using a list here\".into()),\n                        span: *first_spread_location,\n                    },\n                }],\n            },\n\n            ParseErrorType::ListSpreadFollowedByElements => ParseErrorDetails {\n                text: [\n                    \"Lists are immutable and singly-linked, so to append items to them\",\n                    \"all the elements of a list would need to be copied into a new list.\",\n                    \"This would be slow, so there is no built-in syntax for it.\",\n                    \"\",\n                ]\n                .join(\"\\n\"),\n                hint: Some(\n                    \"Prepend items to the list and then reverse it once you are done.\".into(),\n                ),\n                label_text: \"I wasn't expecting elements after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ListPatternSpreadFollowedByElements => ParseErrorDetails {\n                text: [\n                    \"Lists are immutable and singly-linked, so to match on the end\",\n                    \"of a list would require the whole list to be traversed. This\",\n                    \"would be slow, so there is no built-in syntax for it. Pattern\",\n                    \"match on the start of the list instead.\",\n                ]\n                .join(\"\\n\"),\n                hint: None,\n                label_text: \"I wasn't expecting elements after this\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnexpectedReservedWord => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\"I was expecting to see a name here.\".into()),\n                label_text: \"This is a reserved word\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnexpectedLabel => ParseErrorDetails {\n                text: \"Please remove the argument label.\".into(),\n                hint: None,\n                label_text: \"Argument labels are not allowed for anonymous functions\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnexpectedToken {\n                token,\n                expected,\n                hint,\n            } => {\n                let found = match token {\n                    Token::Int { .. } => \"an Int\".to_string(),\n                    Token::Float { .. } => \"a Float\".to_string(),\n                    Token::String { .. } => \"a String\".to_string(),\n                    Token::CommentDoc { .. } => \"a comment\".to_string(),\n                    Token::DiscardName { .. } => \"a discard name\".to_string(),\n                    Token::Name { .. } | Token::UpName { .. } => \"a name\".to_string(),\n                    _ if token.is_reserved_word() => format!(\"the keyword {token}\"),\n                    Token::LeftParen\n                    | Token::RightParen\n                    | Token::LeftSquare\n                    | Token::RightSquare\n                    | Token::LeftBrace\n                    | Token::RightBrace\n                    | Token::Plus\n                    | Token::Minus\n                    | Token::Star\n                    | Token::Slash\n                    | Token::Less\n                    | Token::Greater\n                    | Token::LessEqual\n                    | Token::GreaterEqual\n                    | Token::Percent\n                    | Token::PlusDot\n                    | Token::MinusDot\n                    | Token::StarDot\n                    | Token::SlashDot\n                    | Token::LessDot\n                    | Token::GreaterDot\n                    | Token::LessEqualDot\n                    | Token::GreaterEqualDot\n                    | Token::Concatenate\n                    | Token::Colon\n                    | Token::Comma\n                    | Token::Hash\n                    | Token::Bang\n                    | Token::Equal\n                    | Token::EqualEqual\n                    | Token::NotEqual\n                    | Token::Vbar\n                    | Token::VbarVbar\n                    | Token::AmperAmper\n                    | Token::LtLt\n                    | Token::GtGt\n                    | Token::Pipe\n                    | Token::Dot\n                    | Token::RArrow\n                    | Token::LArrow\n                    | Token::DotDot\n                    | Token::At\n                    | Token::EndOfFile\n                    | Token::CommentNormal\n                    | Token::CommentModule\n                    | Token::NewLine\n                    | Token::As\n                    | Token::Assert\n                    | Token::Auto\n                    | Token::Case\n                    | Token::Const\n                    | Token::Delegate\n                    | Token::Derive\n                    | Token::Echo\n                    | Token::Else\n                    | Token::Fn\n                    | Token::If\n                    | Token::Implement\n                    | Token::Import\n                    | Token::Let\n                    | Token::Macro\n                    | Token::Opaque\n                    | Token::Panic\n                    | Token::Pub\n                    | Token::Test\n                    | Token::Todo\n                    | Token::Type\n                    | Token::Use => token.to_string(),\n                };\n\n                let messages = std::iter::once(format!(\"Found {found}, expected one of: \"))\n                    .chain(expected.iter().map(|s| format!(\"- {s}\")));\n\n                let messages = match hint {\n                    Some(hint_text) => messages\n                        .chain(std::iter::once(format!(\"Hint: {hint_text}\")))\n                        .collect_vec(),\n                    _ => messages.collect(),\n                };\n\n                ParseErrorDetails {\n                    text: messages.join(\"\\n\"),\n                    hint: None,\n                    label_text: \"I was not expecting this\".into(),\n                    extra_labels: vec![],\n                }\n            }\n\n            ParseErrorType::ConcatPatternVariableLeftHandSide => ParseErrorDetails {\n                text: [\n                    \"We can't tell what size this prefix should be so we don't know\",\n                    \"how to handle this pattern.\",\n                    \"\",\n                    \"If you want to match one character consider using `pop_grapheme`\",\n                    \"from the stdlib's `gleam/string` module.\",\n                ]\n                .join(\"\\n\"),\n                hint: None,\n                label_text: \"This must be a string literal\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnexpectedFunction => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"Functions can only be called within other functions\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ListSpreadWithoutTail => ParseErrorDetails {\n                text: \"If a list expression has a spread then a tail must also be given.\".into(),\n                hint: None,\n                label_text: \"I was expecting a value after this spread\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnknownAttribute => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\"Try `deprecated`, `external` or `internal` instead.\".into()),\n                label_text: \"I don't recognise this attribute\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::DuplicateAttribute => ParseErrorDetails {\n                text: \"This attribute has already been given.\".into(),\n                hint: None,\n                label_text: \"Duplicate attribute\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnknownTarget => ParseErrorDetails {\n                text: \"Try `erlang`, `javascript`.\".into(),\n                hint: None,\n                label_text: \"I don't recognise this target\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedFunctionBody => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"This function does not have a body\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::RedundantInternalAttribute => ParseErrorDetails {\n                text: \"Only a public definition can be annotated as internal.\".into(),\n                hint: Some(\"Remove the `@internal` annotation.\".into()),\n                label_text: \"Redundant internal attribute\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::InvalidModuleTypePattern => ParseErrorDetails {\n                text: [\n                    \"I'm expecting a pattern here\",\n                    \"Hint: A pattern can be a constructor name, a literal value\",\n                    \"or a variable to bind a value to, etc.\",\n                    \"See: https://tour.gleam.run/flow-control/case-expressions/\",\n                ]\n                .join(\"\\n\"),\n                hint: None,\n                label_text: \"Invalid pattern\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ExpectedRecordConstructor {\n                name,\n                public,\n                opaque,\n                field,\n                field_type,\n            } => {\n                let (accessor, opaque) = match *public {\n                    true if *opaque => (\"pub \", \"opaque \"),\n                    true => (\"pub \", \"\"),\n                    false => (\"\", \"\"),\n                };\n\n                let mut annotation = EcoString::new();\n                match field_type {\n                    Some(t) => t.print(&mut annotation),\n                    None => annotation.push_str(\"Type\"),\n                };\n\n                ParseErrorDetails {\n                    text: [\n                        \"Each custom type variant must have a constructor:\\n\".into(),\n                        format!(\"{accessor}{opaque}type {name} {{\"),\n                        format!(\"  {name}(\"),\n                        format!(\"    {field}: {annotation},\"),\n                        \"  )\".into(),\n                        \"}\".into(),\n                    ]\n                    .join(\"\\n\"),\n                    hint: None,\n                    label_text: \"I was not expecting this\".into(),\n                    extra_labels: vec![],\n                }\n            }\n\n            ParseErrorType::CallInClauseGuard => ParseErrorDetails {\n                text: \"Functions cannot be called in clause guards.\".into(),\n                hint: None,\n                label_text: \"Unsupported expression\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::IfExpression => ParseErrorDetails {\n                text: [\n                    \"If you want to write a conditional expression you can use a `case`:\",\n                    \"\",\n                    \"    case condition {\",\n                    \"      True -> todo\",\n                    \"      False -> todo\",\n                    \"    }\",\n                    \"\",\n                    \"See: https://tour.gleam.run/flow-control/case-expressions/\",\n                ]\n                .join(\"\\n\"),\n                hint: None,\n                label_text: \"Gleam doesn't have if expressions\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ConstantRecordConstructorNoArguments => ParseErrorDetails {\n                text: \"A record must be passed arguments when constructed.\".into(),\n                hint: None,\n                label_text: \"I was expecting arguments here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::TypeDefinitionNoArguments => ParseErrorDetails {\n                text: \"A generic type must have at least a generic parameter.\".into(),\n                hint: Some(\"If a type is not generic you should omit the `()`.\".into()),\n                label_text: \"I was expecting generic parameters here\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::UnknownAttributeRecordVariant => ParseErrorDetails {\n                text: \"\".into(),\n                hint: Some(\"Did you mean `@deprecated`?\".into()),\n                label_text: \"This attribute cannot be used on a variant.\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::IncorrectImportModuleSeparator { module, item } => ParseErrorDetails {\n                text: [\n                    \"Perhaps you meant one of:\".into(),\n                    \"\".into(),\n                    format!(\"    import {module}/{item}\"),\n                    format!(\"    import {module}.{{item}}\"),\n                ]\n                .join(\"\\n\"),\n                hint: None,\n                label_text: \"I was expecting either `/` or `.{` here.\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::EmptyGuardBlock => ParseErrorDetails {\n                text: \"\".into(),\n                hint: None,\n                label_text: \"A clause guard block cannot be empty\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::ConstantInsideFunction => ParseErrorDetails {\n                text: wrap(\n                    \"All variables are immutable in Gleam, so constants inside \\\nfunctions are not necessary.\",\n                ),\n                hint: Some(\n                    \"Either move this into the global scope or use `let` binding instead.\".into(),\n                ),\n                label_text: \"Constants are not allowed inside functions\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::FunctionDefinitionAngleGenerics => ParseErrorDetails {\n                text: \"\\\nGeneric function type variables do not need to be predeclared like they\nwould be in some other languages, instead they are written with lowercase\nnames.\n\n    fn example(argument: generic) -> generic\n\nSee: https://tour.gleam.run/functions/generic-functions/\"\n                    .into(),\n                hint: None,\n                label_text: \"I was expecting `(` here.\".into(),\n                extra_labels: vec![],\n            },\n\n            ParseErrorType::TypeUsageAngleGenerics {\n                module,\n                name,\n                arguments,\n            } => {\n                let type_arguments = arguments\n                    .iter()\n                    .map(|argument| {\n                        let mut argument_string = EcoString::new();\n                        argument.print(&mut argument_string);\n                        argument_string\n                    })\n                    .join(\", \");\n                let replacement_type = match module {\n                    Some(module) => format!(\"{module}.{name}({type_arguments})\"),\n                    None => format!(\"{name}({type_arguments})\"),\n                };\n\n                ParseErrorDetails {\n                    text: format!(\n                        \"\\\nType parameters use lowercase names and are surrounded by parentheses.\n\n    {replacement_type}\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\"\n                    ),\n                    hint: None,\n                    label_text: \"I was expecting `(` here.\".into(),\n                    extra_labels: vec![],\n                }\n            }\n\n            ParseErrorType::TypeDefinitionAngleGenerics { name, arguments } => {\n                let comma_separated_arguments = arguments.join(\", \");\n\n                ParseErrorDetails {\n                    text: format!(\n                        \"\\\nType parameters use lowercase names and are surrounded by parentheses.\n\n    type {name}({comma_separated_arguments}) {{\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\"\n                    ),\n                    hint: None,\n                    label_text: \"I was expecting `(` here.\".into(),\n                    extra_labels: vec![],\n                }\n            }\n        }\n    }\n}\n\nimpl LexicalError {\n    pub fn to_parse_error_info(&self) -> (&'static str, Vec<String>) {\n        match &self.error {\n            LexicalErrorType::BadStringEscape => (\n                \"I don't understand this escape code\",\n                vec![\n                    \"Hint: Add another backslash before it.\".into(),\n                    \"See: https://tour.gleam.run/basics/strings\".into(),\n                ],\n            ),\n            LexicalErrorType::DigitOutOfRadix => {\n                (\"This digit is too big for the specified radix\", vec![])\n            }\n            LexicalErrorType::NumTrailingUnderscore => (\n                \"Numbers cannot have a trailing underscore\",\n                vec![\"Hint: remove it.\".into()],\n            ),\n            LexicalErrorType::RadixIntNoValue => (\"This integer has no value\", vec![]),\n            LexicalErrorType::MissingExponent => (\n                \"This float is missing an exponent\",\n                vec![\"Hint: Add an exponent or remove the trailing `e`\".into()],\n            ),\n            LexicalErrorType::UnexpectedStringEnd => {\n                (\"The string starting here was left open\", vec![])\n            }\n            LexicalErrorType::UnrecognizedToken { tok } if *tok == ';' => (\n                \"Remove this semicolon\",\n                vec![\n                    \"Hint: Semicolons used to be whitespace and did nothing.\".into(),\n                    \"You can safely remove them without your program changing.\".into(),\n                ],\n            ),\n            LexicalErrorType::UnrecognizedToken { tok } if *tok == '\\'' => (\n                \"Unexpected single quote\",\n                vec![\"Hint: Strings are written with double quotes.\".into()],\n            ),\n            LexicalErrorType::UnrecognizedToken { .. } => (\n                \"I can't figure out what to do with this character\",\n                vec![\"Hint: Is it a typo?\".into()],\n            ),\n            LexicalErrorType::InvalidUnicodeEscape(\n                InvalidUnicodeEscapeError::MissingOpeningBrace,\n            ) => (\n                \"Expected '{' in Unicode escape sequence\",\n                vec![\"Hint: Add it.\".into()],\n            ),\n            LexicalErrorType::InvalidUnicodeEscape(\n                InvalidUnicodeEscapeError::ExpectedHexDigitOrCloseBrace,\n            ) => (\n                \"Expected hex digit or '}' in Unicode escape sequence\",\n                vec![\n                    \"Hint: Hex digits are digits from 0 to 9 and letters from a to f or A to F.\"\n                        .into(),\n                ],\n            ),\n            LexicalErrorType::InvalidUnicodeEscape(\n                InvalidUnicodeEscapeError::InvalidNumberOfHexDigits,\n            ) => (\n                \"Expected between 1 and 6 hex digits in Unicode escape sequence\",\n                vec![],\n            ),\n            LexicalErrorType::InvalidUnicodeEscape(InvalidUnicodeEscapeError::InvalidCodepoint) => {\n                (\"Invalid Unicode codepoint\", vec![])\n            }\n            LexicalErrorType::InvalidTripleEqual => (\n                \"Did you mean `==`?\",\n                vec![\n                    \"Gleam uses `==` to check for equality between two values.\".into(),\n                    \"See: https://tour.gleam.run/basics/equality\".into(),\n                ],\n            ),\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/parse/extra.rs",
    "content": "use std::cmp::Ordering;\n\nuse ecow::EcoString;\n\nuse crate::ast::SrcSpan;\n\n#[derive(Debug, PartialEq, Eq, Default)]\npub struct ModuleExtra {\n    pub module_comments: Vec<SrcSpan>,\n    pub doc_comments: Vec<SrcSpan>,\n    pub comments: Vec<SrcSpan>,\n    pub empty_lines: Vec<u32>,\n    pub new_lines: Vec<u32>,\n    pub trailing_commas: Vec<u32>,\n}\n\nimpl ModuleExtra {\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    /// Detects if a byte index is in a comment context\n    pub fn is_within_comment(&self, byte_index: u32) -> bool {\n        let cmp = |span: &SrcSpan| {\n            if byte_index < span.start {\n                Ordering::Greater\n            } else if byte_index > span.end {\n                Ordering::Less\n            } else {\n                Ordering::Equal\n            }\n        };\n\n        self.comments.binary_search_by(cmp).is_ok()\n            || self.doc_comments.binary_search_by(cmp).is_ok()\n            || self.module_comments.binary_search_by(cmp).is_ok()\n    }\n\n    pub(crate) fn has_comment_between(&self, start: u32, end: u32) -> bool {\n        self.first_comment_between(start, end).is_some()\n    }\n\n    pub fn first_comment_between(&self, start: u32, end: u32) -> Option<SrcSpan> {\n        self.comments\n            .binary_search_by(|comment| {\n                if comment.end < start {\n                    Ordering::Less\n                } else if comment.start > end {\n                    Ordering::Greater\n                } else {\n                    Ordering::Equal\n                }\n            })\n            .ok()\n            .and_then(|index| self.comments.get(index).copied())\n    }\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub struct Comment<'a> {\n    pub start: u32,\n    pub content: &'a str,\n}\n\nimpl<'a> From<(&SrcSpan, &'a EcoString)> for Comment<'a> {\n    fn from(value: (&SrcSpan, &'a EcoString)) -> Self {\n        Self::from((value.0, value.1.as_str()))\n    }\n}\n\nimpl<'a> From<(&SrcSpan, &'a str)> for Comment<'a> {\n    fn from(src: (&SrcSpan, &'a str)) -> Comment<'a> {\n        let start = src.0.start;\n        let end = src.0.end as usize;\n        Comment {\n            start,\n            content: src\n                .1\n                .get(start as usize..end)\n                .expect(\"From span to comment\"),\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/parse/lexer.rs",
    "content": "use ecow::EcoString;\n\nuse crate::ast::SrcSpan;\nuse crate::parse::LiteralFloatValue;\nuse crate::parse::error::{LexicalError, LexicalErrorType};\nuse crate::parse::token::Token;\nuse std::char;\n\nuse super::error::InvalidUnicodeEscapeError;\n\n#[derive(Debug)]\npub struct Lexer<T: Iterator<Item = (u32, char)>> {\n    chars: T,\n    pending: Vec<Spanned>,\n    chr0: Option<char>,\n    chr1: Option<char>,\n    loc0: u32,\n    loc1: u32,\n}\npub type Spanned = (u32, Token, u32);\npub type LexResult = Result<Spanned, LexicalError>;\n\npub fn str_to_keyword(word: &str) -> Option<Token> {\n    // Alphabetical keywords:\n    match word {\n        \"as\" => Some(Token::As),\n        \"assert\" => Some(Token::Assert),\n        \"auto\" => Some(Token::Auto),\n        \"case\" => Some(Token::Case),\n        \"const\" => Some(Token::Const),\n        \"delegate\" => Some(Token::Delegate),\n        \"derive\" => Some(Token::Derive),\n        \"echo\" => Some(Token::Echo),\n        \"else\" => Some(Token::Else),\n        \"fn\" => Some(Token::Fn),\n        \"if\" => Some(Token::If),\n        \"implement\" => Some(Token::Implement),\n        \"import\" => Some(Token::Import),\n        \"let\" => Some(Token::Let),\n        \"macro\" => Some(Token::Macro),\n        \"opaque\" => Some(Token::Opaque),\n        \"panic\" => Some(Token::Panic),\n        \"pub\" => Some(Token::Pub),\n        \"test\" => Some(Token::Test),\n        \"todo\" => Some(Token::Todo),\n        \"type\" => Some(Token::Type),\n        \"use\" => Some(Token::Use),\n        _ => None,\n    }\n}\n\npub fn make_tokenizer(source: &str) -> impl Iterator<Item = LexResult> + '_ {\n    let chars = source.char_indices().map(|(i, c)| (i as u32, c));\n    let nlh = NewlineHandler::new(chars);\n    Lexer::new(nlh)\n}\n\n// The newline handler is an iterator which collapses different newline\n// types into \\n always.\n#[derive(Debug)]\npub struct NewlineHandler<T: Iterator<Item = (u32, char)>> {\n    source: T,\n    chr0: Option<(u32, char)>,\n    chr1: Option<(u32, char)>,\n}\n\nimpl<T> NewlineHandler<T>\nwhere\n    T: Iterator<Item = (u32, char)>,\n{\n    pub fn new(source: T) -> Self {\n        let mut nlh = NewlineHandler {\n            source,\n            chr0: None,\n            chr1: None,\n        };\n        let _ = nlh.shift();\n        let _ = nlh.shift();\n        nlh\n    }\n\n    fn shift(&mut self) -> Option<(u32, char)> {\n        let result = self.chr0;\n        self.chr0 = self.chr1;\n        self.chr1 = self.source.next();\n        result\n    }\n}\n\nimpl<T> Iterator for NewlineHandler<T>\nwhere\n    T: Iterator<Item = (u32, char)>,\n{\n    type Item = (u32, char);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        // Collapse \\r\\n into \\n\n        if let Some((i, '\\r')) = self.chr0 {\n            if let Some((_, '\\n')) = self.chr1 {\n                // Transform windows EOL into \\n\n                let _ = self.shift();\n                // using the position from the \\r\n                self.chr0 = Some((i, '\\n'))\n            } else {\n                // Transform MAC EOL into \\n\n                self.chr0 = Some((i, '\\n'))\n            }\n        }\n\n        self.shift()\n    }\n}\n\nimpl<T> Lexer<T>\nwhere\n    T: Iterator<Item = (u32, char)>,\n{\n    pub fn new(input: T) -> Self {\n        let mut lxr = Lexer {\n            chars: input,\n            pending: Vec::new(),\n            chr0: None,\n            chr1: None,\n            loc0: 0,\n            loc1: 0,\n        };\n        let _ = lxr.next_char();\n        let _ = lxr.next_char();\n\n        // Check whether the first character is a UTF-8 byte order mark, and if so, consume it.\n        if lxr.chr0 == Some('\\u{feff}') {\n            let _ = lxr.next_char();\n        }\n\n        lxr\n    }\n\n    // This is the main entry point. Call this function to retrieve the next token.\n    // This function is used by the iterator implementation.\n    fn inner_next(&mut self) -> LexResult {\n        // top loop, keep on processing, until we have something pending.\n        while self.pending.is_empty() {\n            self.consume_normal()?;\n        }\n\n        Ok(self.pending.remove(0))\n    }\n\n    // Take a look at the next character, if any, and decide upon the next steps.\n    fn consume_normal(&mut self) -> Result<(), LexicalError> {\n        // Check if we have some character:\n        if let Some(c) = self.chr0 {\n            let mut check_for_minus = false;\n            if self.is_upname_start(c) {\n                let name = self.lex_upname()?;\n                self.emit(name)\n            } else if self.is_name_start(c) {\n                check_for_minus = true;\n                let name = self.lex_name()?;\n                self.emit(name);\n            } else if self.is_number_start(c, self.chr1) {\n                check_for_minus = true;\n                let num = self.lex_number()?;\n                self.emit(num);\n            } else {\n                self.consume_character(c)?;\n            }\n            if check_for_minus {\n                // We want to lex `1-1` and `x-1` as `1 - 1` and `x - 1`\n                if Some('-') == self.chr0 && self.is_number_start('-', self.chr1) {\n                    self.eat_single_char(Token::Minus);\n                }\n            }\n        } else {\n            // We reached end of file.\n            let tok_pos = self.get_pos();\n            self.emit((tok_pos, Token::EndOfFile, tok_pos));\n        }\n\n        Ok(())\n    }\n\n    fn consume_character(&mut self, c: char) -> Result<(), LexicalError> {\n        match c {\n            '@' => {\n                self.eat_single_char(Token::At);\n            }\n            '\"' => {\n                let string = self.lex_string()?;\n                self.emit(string);\n            }\n            '=' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                match self.chr0 {\n                    Some('=') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        if let Some('=') = self.chr0 {\n                            return Err(LexicalError {\n                                error: LexicalErrorType::InvalidTripleEqual,\n                                location: SrcSpan {\n                                    start: tok_start,\n                                    end: tok_end + 1,\n                                },\n                            });\n                        };\n                        self.emit((tok_start, Token::EqualEqual, tok_end));\n                    }\n                    _ => {\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Equal, tok_end));\n                    }\n                }\n            }\n            '+' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                if let Some('.') = self.chr0 {\n                    let _ = self.next_char();\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::PlusDot, tok_end));\n                } else {\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::Plus, tok_end));\n                }\n            }\n            '*' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                match self.chr0 {\n                    Some('.') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::StarDot, tok_end));\n                    }\n                    _ => {\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Star, tok_end));\n                    }\n                }\n            }\n            '/' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                match self.chr0 {\n                    Some('.') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::SlashDot, tok_end));\n                    }\n                    Some('/') => {\n                        let _ = self.next_char();\n                        let comment = self.lex_comment();\n                        self.emit(comment);\n                    }\n                    _ => {\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Slash, tok_end));\n                    }\n                }\n            }\n            '%' => {\n                self.eat_single_char(Token::Percent);\n            }\n            '|' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                if let Some('|') = self.chr0 {\n                    let _ = self.next_char();\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::VbarVbar, tok_end));\n                } else if let Some('>') = self.chr0 {\n                    let _ = self.next_char();\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::Pipe, tok_end));\n                } else {\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::Vbar, tok_end));\n                }\n            }\n            '&' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                if let Some('&') = self.chr0 {\n                    let _ = self.next_char();\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::AmperAmper, tok_end));\n                } else {\n                    return Err(LexicalError {\n                        error: LexicalErrorType::UnrecognizedToken { tok: '&' },\n                        location: SrcSpan {\n                            start: tok_start,\n                            end: tok_start,\n                        },\n                    });\n                }\n            }\n            '-' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                match self.chr0 {\n                    Some('.') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::MinusDot, tok_end));\n                    }\n                    Some('>') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::RArrow, tok_end));\n                    }\n                    _ => {\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Minus, tok_end));\n                    }\n                }\n            }\n            '!' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                if let Some('=') = self.chr0 {\n                    let _ = self.next_char();\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::NotEqual, tok_end));\n                } else {\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::Bang, tok_end));\n                }\n            }\n            '(' => {\n                self.eat_single_char(Token::LeftParen);\n            }\n            ')' => {\n                self.eat_single_char(Token::RightParen);\n            }\n            '[' => {\n                self.eat_single_char(Token::LeftSquare);\n            }\n            ']' => {\n                self.eat_single_char(Token::RightSquare);\n            }\n            '{' => {\n                self.eat_single_char(Token::LeftBrace);\n            }\n            '}' => {\n                self.eat_single_char(Token::RightBrace);\n            }\n            ':' => {\n                self.eat_single_char(Token::Colon);\n            }\n            '<' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                match self.chr0 {\n                    Some('>') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Concatenate, tok_end));\n                    }\n                    Some('<') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::LtLt, tok_end));\n                    }\n                    Some('.') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::LessDot, tok_end));\n                    }\n                    Some('-') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::LArrow, tok_end));\n                    }\n                    Some('=') => {\n                        let _ = self.next_char();\n                        match self.chr0 {\n                            Some('.') => {\n                                let _ = self.next_char();\n                                let tok_end = self.get_pos();\n                                self.emit((tok_start, Token::LessEqualDot, tok_end));\n                            }\n                            _ => {\n                                let tok_end = self.get_pos();\n                                self.emit((tok_start, Token::LessEqual, tok_end));\n                            }\n                        }\n                    }\n                    _ => {\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Less, tok_end));\n                    }\n                }\n            }\n            '>' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                match self.chr0 {\n                    Some('>') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::GtGt, tok_end));\n                    }\n                    Some('.') => {\n                        let _ = self.next_char();\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::GreaterDot, tok_end));\n                    }\n                    Some('=') => {\n                        let _ = self.next_char();\n                        match self.chr0 {\n                            Some('.') => {\n                                let _ = self.next_char();\n                                let tok_end = self.get_pos();\n                                self.emit((tok_start, Token::GreaterEqualDot, tok_end));\n                            }\n                            _ => {\n                                let tok_end = self.get_pos();\n                                self.emit((tok_start, Token::GreaterEqual, tok_end));\n                            }\n                        }\n                    }\n                    _ => {\n                        let tok_end = self.get_pos();\n                        self.emit((tok_start, Token::Greater, tok_end));\n                    }\n                }\n            }\n            ',' => {\n                self.eat_single_char(Token::Comma);\n            }\n            '.' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                if let Some('.') = &self.chr0 {\n                    let _ = self.next_char();\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::DotDot, tok_end));\n                } else {\n                    let tok_end = self.get_pos();\n                    self.emit((tok_start, Token::Dot, tok_end));\n                    self.maybe_lex_dot_access()?;\n                }\n            }\n            '#' => {\n                self.eat_single_char(Token::Hash);\n            }\n            '\\n' | ' ' | '\\t' | '\\x0C' => {\n                let tok_start = self.get_pos();\n                let _ = self.next_char();\n                let tok_end = self.get_pos();\n                if c == '\\n' {\n                    self.emit((tok_start, Token::NewLine, tok_end));\n                }\n            }\n            c => {\n                let location = self.get_pos();\n                return Err(LexicalError {\n                    error: LexicalErrorType::UnrecognizedToken { tok: c },\n                    location: SrcSpan {\n                        start: location,\n                        end: location,\n                    },\n                });\n            }\n        }\n\n        Ok(())\n    }\n\n    // Lexer helper functions:\n    // this can be either a reserved word, or a name\n    fn lex_name(&mut self) -> LexResult {\n        let mut name = String::new();\n        let start_pos = self.get_pos();\n\n        while self.is_name_continuation() {\n            name.push(self.next_char().expect(\"lex_name continue\"))\n        }\n\n        let end_pos = self.get_pos();\n\n        match str_to_keyword(&name) {\n            Some(tok) => Ok((start_pos, tok, end_pos)),\n            _ => {\n                if name.starts_with('_') {\n                    Ok((start_pos, Token::DiscardName { name: name.into() }, end_pos))\n                } else {\n                    Ok((start_pos, Token::Name { name: name.into() }, end_pos))\n                }\n            }\n        }\n    }\n    // A type name or constructor\n    fn lex_upname(&mut self) -> LexResult {\n        let mut name = String::new();\n        let start_pos = self.get_pos();\n\n        while self.is_name_continuation() {\n            name.push(self.next_char().expect(\"lex_upname upname\"));\n        }\n\n        let end_pos = self.get_pos();\n\n        match str_to_keyword(&name) {\n            Some(tok) => Ok((start_pos, tok, end_pos)),\n            _ => Ok((start_pos, Token::UpName { name: name.into() }, end_pos)),\n        }\n    }\n\n    fn lex_number(&mut self) -> LexResult {\n        let start_pos = self.get_pos();\n        let num = if self.chr0 == Some('0') {\n            if self.chr1 == Some('x') || self.chr1 == Some('X') {\n                // Hex!\n                let _ = self.next_char();\n                let _ = self.next_char();\n                self.lex_number_radix(start_pos, 16, \"0x\")?\n            } else if self.chr1 == Some('o') || self.chr1 == Some('O') {\n                // Octal!\n                let _ = self.next_char();\n                let _ = self.next_char();\n                self.lex_number_radix(start_pos, 8, \"0o\")?\n            } else if self.chr1 == Some('b') || self.chr1 == Some('B') {\n                // Binary!\n                let _ = self.next_char();\n                let _ = self.next_char();\n                self.lex_number_radix(start_pos, 2, \"0b\")?\n            } else {\n                self.lex_decimal_number()?\n            }\n        } else {\n            self.lex_decimal_number()?\n        };\n\n        if Some('_') == self.chr0 {\n            let location = self.get_pos();\n            Err(LexicalError {\n                error: LexicalErrorType::NumTrailingUnderscore,\n                location: SrcSpan {\n                    start: location,\n                    end: location,\n                },\n            })\n        } else {\n            Ok(num)\n        }\n    }\n\n    // Lex a hex/octal/decimal/binary number without a decimal point.\n    fn lex_number_radix(&mut self, start_pos: u32, radix: u32, prefix: &str) -> LexResult {\n        let num = self.radix_run(radix);\n        if num.is_empty() {\n            let location = self.get_pos() - 1;\n            Err(LexicalError {\n                error: LexicalErrorType::RadixIntNoValue,\n                location: SrcSpan {\n                    start: location,\n                    end: location,\n                },\n            })\n        } else if radix < 16 && Lexer::<T>::is_digit_of_radix(self.chr0, 16) {\n            let location = self.get_pos();\n            Err(LexicalError {\n                error: LexicalErrorType::DigitOutOfRadix,\n                location: SrcSpan {\n                    start: location,\n                    end: location,\n                },\n            })\n        } else {\n            let value = format!(\"{prefix}{num}\");\n            let int_value = super::parse_int_value(&value).expect(\"int value to parse as bigint\");\n            let end_pos = self.get_pos();\n            Ok((\n                start_pos,\n                Token::Int {\n                    value: value.into(),\n                    int_value,\n                },\n                end_pos,\n            ))\n        }\n    }\n\n    // Lex a normal number, that is, no octal, hex or binary number.\n    // This function cannot be reached without the head of the stream being either 0-9 or '-', 0-9\n    fn lex_decimal_number(&mut self) -> LexResult {\n        self.lex_decimal_or_int_number(true)\n    }\n\n    fn lex_int_number(&mut self) -> LexResult {\n        self.lex_decimal_or_int_number(false)\n    }\n\n    fn lex_decimal_or_int_number(&mut self, can_lex_decimal: bool) -> LexResult {\n        let start_pos = self.get_pos();\n        let mut value = String::new();\n        // consume negative sign\n        if self.chr0 == Some('-') {\n            value.push(self.next_char().expect(\"lex_normal_number negative\"));\n        }\n        // consume first run of digits\n        value.push_str(&self.radix_run(10));\n\n        // If float:\n        if can_lex_decimal && self.chr0 == Some('.') {\n            value.push(self.next_char().expect(\"lex_normal_number float\"));\n            value.push_str(&self.radix_run(10));\n\n            // If scientific:\n            if self.chr0 == Some('e') {\n                value.push(self.next_char().expect(\"lex_normal_number scientific\"));\n                if self.chr0 == Some('-') {\n                    value.push(\n                        self.next_char()\n                            .expect(\"lex_normal_number scientific negative\"),\n                    );\n                }\n                let exponent_run = self.radix_run(10);\n                if exponent_run.is_empty() {\n                    return Err(LexicalError {\n                        error: LexicalErrorType::MissingExponent,\n                        location: SrcSpan::new(start_pos, self.get_pos()),\n                    });\n                }\n                value.push_str(&exponent_run);\n            }\n            let end_pos = self.get_pos();\n            let float_value =\n                LiteralFloatValue::parse(&value).expect(\"float value to parse as non-NaN f64\");\n            Ok((\n                start_pos,\n                Token::Float {\n                    value: value.into(),\n                    float_value,\n                },\n                end_pos,\n            ))\n        } else {\n            let int_value = super::parse_int_value(&value).expect(\"int value to parse as bigint\");\n            let end_pos = self.get_pos();\n            Ok((\n                start_pos,\n                Token::Int {\n                    value: value.into(),\n                    int_value,\n                },\n                end_pos,\n            ))\n        }\n    }\n\n    // Maybe lex dot access that comes after name token.\n    fn maybe_lex_dot_access(&mut self) -> Result<(), LexicalError> {\n        // It can be nested like: `tuple.1.2.3.4`\n        loop {\n            if matches!(self.chr0, Some('0'..='9')) {\n                let number = self.lex_int_number()?;\n                self.emit(number);\n            } else {\n                break;\n            }\n        }\n        Ok(())\n    }\n\n    // Consume a sequence of numbers with the given radix,\n    // the digits can be decorated with underscores\n    // like this: '1_2_3_4' == '1234'\n    fn radix_run(&mut self, radix: u32) -> String {\n        let mut value_text = String::new();\n\n        loop {\n            if let Some(c) = self.take_number(radix) {\n                value_text.push(c);\n            } else if self.chr0 == Some('_') && Lexer::<T>::is_digit_of_radix(self.chr1, radix) {\n                value_text.push('_');\n                let _ = self.next_char();\n            } else {\n                break;\n            }\n        }\n        value_text\n    }\n\n    // Consume a single character with the given radix.\n    fn take_number(&mut self, radix: u32) -> Option<char> {\n        let take_char = Lexer::<T>::is_digit_of_radix(self.chr0, radix);\n\n        if take_char {\n            Some(self.next_char().expect(\"take_number next char\"))\n        } else {\n            None\n        }\n    }\n\n    // Test if a digit is of a certain radix.\n    fn is_digit_of_radix(c: Option<char>, radix: u32) -> bool {\n        match radix {\n            2 | 8 | 10 | 16 => c.filter(|c| c.is_digit(radix)).is_some(),\n            other => panic!(\"Radix not implemented: {other}\"),\n        }\n    }\n\n    // There are 3 kinds of comments\n    // 2 slash, normal\n    // 3 slash, document\n    // 4 slash, module\n    // this function is entered after 2 slashes\n    fn lex_comment(&mut self) -> Spanned {\n        enum Kind {\n            Comment,\n            Doc,\n            ModuleDoc,\n        }\n        let kind = match (self.chr0, self.chr1) {\n            (Some('/'), Some('/')) => {\n                let _ = self.next_char();\n                let _ = self.next_char();\n                Kind::ModuleDoc\n            }\n            (Some('/'), _) => {\n                let _ = self.next_char();\n                Kind::Doc\n            }\n            _ => Kind::Comment,\n        };\n        let mut content = EcoString::new();\n        let start_pos = self.get_pos();\n        while Some('\\n') != self.chr0 {\n            match self.chr0 {\n                Some(c) => content.push(c),\n                None => break,\n            }\n            let _ = self.next_char();\n        }\n        let end_pos = self.get_pos();\n        let token = match kind {\n            Kind::Comment => Token::CommentNormal,\n            Kind::Doc => Token::CommentDoc { content },\n            Kind::ModuleDoc => Token::CommentModule,\n        };\n        (start_pos, token, end_pos)\n    }\n\n    fn lex_string(&mut self) -> LexResult {\n        let start_pos = self.get_pos();\n        // advance past the first quote\n        let _ = self.next_char();\n        let mut string_content = String::new();\n\n        loop {\n            match self.next_char() {\n                Some('\\\\') => {\n                    let slash_pos = self.get_pos() - 1;\n                    if let Some(c) = self.chr0 {\n                        match c {\n                            'f' | 'n' | 'r' | 't' | '\"' | '\\\\' => {\n                                let _ = self.next_char();\n                                string_content.push('\\\\');\n                                string_content.push(c);\n                            }\n                            'u' => {\n                                let _ = self.next_char();\n\n                                if self.chr0 != Some('{') {\n                                    return Err(LexicalError {\n                                        error: LexicalErrorType::InvalidUnicodeEscape(\n                                            InvalidUnicodeEscapeError::MissingOpeningBrace,\n                                        ),\n                                        location: SrcSpan {\n                                            start: self.get_pos() - 1,\n                                            end: self.get_pos(),\n                                        },\n                                    });\n                                }\n\n                                // All digits inside \\u{...}.\n                                let mut hex_digits = String::new();\n\n                                loop {\n                                    let _ = self.next_char();\n\n                                    let Some(chr) = self.chr0 else {\n                                        break;\n                                    };\n\n                                    // Don't break early when we've reached 6 digits to ensure a\n                                    // useful error message\n                                    if chr == '}' {\n                                        break;\n                                    }\n\n                                    hex_digits.push(chr);\n\n                                    if !chr.is_ascii_hexdigit() {\n                                        return Err(LexicalError {\n                                            error: LexicalErrorType::InvalidUnicodeEscape(\n                                                InvalidUnicodeEscapeError::ExpectedHexDigitOrCloseBrace,\n                                            ),\n                                            location: SrcSpan {\n                                                start: self.get_pos(),\n                                                end: self.get_pos() + 1,\n                                            },\n                                        });\n                                    }\n                                }\n\n                                if self.chr0 != Some('}') {\n                                    return Err(LexicalError {\n                                        error: LexicalErrorType::InvalidUnicodeEscape(\n                                            InvalidUnicodeEscapeError::ExpectedHexDigitOrCloseBrace,\n                                        ),\n                                        location: SrcSpan {\n                                            start: self.get_pos() - 1,\n                                            end: self.get_pos(),\n                                        },\n                                    });\n                                }\n\n                                let _ = self.next_char();\n\n                                if !(1..=6).contains(&hex_digits.len()) {\n                                    return Err(LexicalError {\n                                        error: LexicalErrorType::InvalidUnicodeEscape(\n                                            InvalidUnicodeEscapeError::InvalidNumberOfHexDigits,\n                                        ),\n                                        location: SrcSpan {\n                                            start: slash_pos,\n                                            end: self.get_pos(),\n                                        },\n                                    });\n                                }\n\n                                // Checks for i >= 0x110000 || (i >= 0xD800 && i < 0xE000),\n                                // where i is the unicode codepoint.\n                                if char::from_u32(u32::from_str_radix(&hex_digits, 16).expect(\n                                    \"Cannot parse codepoint number in Unicode escape sequence\",\n                                ))\n                                .is_none()\n                                {\n                                    return Err(LexicalError {\n                                        error: LexicalErrorType::InvalidUnicodeEscape(\n                                            InvalidUnicodeEscapeError::InvalidCodepoint,\n                                        ),\n                                        location: SrcSpan {\n                                            start: slash_pos,\n                                            end: self.get_pos(),\n                                        },\n                                    });\n                                }\n\n                                string_content.push_str(\"\\\\u{\");\n                                string_content.push_str(&hex_digits);\n                                string_content.push('}');\n                            }\n                            _ => {\n                                return Err(LexicalError {\n                                    error: LexicalErrorType::BadStringEscape,\n                                    location: SrcSpan {\n                                        start: slash_pos,\n                                        end: slash_pos + 1,\n                                    },\n                                });\n                            }\n                        }\n                    } else {\n                        return Err(LexicalError {\n                            error: LexicalErrorType::BadStringEscape,\n                            location: SrcSpan {\n                                start: slash_pos,\n                                end: slash_pos,\n                            },\n                        });\n                    }\n                }\n                Some('\"') => break,\n                Some(c) => string_content.push(c),\n                None => {\n                    return Err(LexicalError {\n                        error: LexicalErrorType::UnexpectedStringEnd,\n                        location: SrcSpan {\n                            start: start_pos,\n                            end: start_pos,\n                        },\n                    });\n                }\n            }\n        }\n        let end_pos = self.get_pos();\n\n        let tok = Token::String {\n            value: string_content.into(),\n        };\n\n        Ok((start_pos, tok, end_pos))\n    }\n\n    fn is_name_start(&self, c: char) -> bool {\n        matches!(c, '_' | 'a'..='z')\n    }\n    fn is_upname_start(&self, c: char) -> bool {\n        c.is_ascii_uppercase()\n    }\n    fn is_number_start(&self, c: char, c1: Option<char>) -> bool {\n        match c {\n            '0'..='9' => true,\n            '-' => matches!(c1, Some('0'..='9')),\n            _ => false,\n        }\n    }\n\n    fn is_name_continuation(&self) -> bool {\n        self.chr0\n            .map(|c| matches!(c, '_' | '0'..='9' | 'a'..='z' | 'A'..='Z'))\n            .unwrap_or(false)\n    }\n\n    // advance the stream and emit a token\n    fn eat_single_char(&mut self, ty: Token) {\n        let tok_start = self.get_pos();\n        let _ = self.next_char().expect(\"eat_single_char\");\n        let tok_end = self.get_pos();\n        self.emit((tok_start, ty, tok_end));\n    }\n\n    // Helper function to go to the next character coming up.\n    fn next_char(&mut self) -> Option<char> {\n        let c = self.chr0;\n        let nxt = match self.chars.next() {\n            Some((loc, c)) => {\n                self.loc0 = self.loc1;\n                self.loc1 = loc;\n                Some(c)\n            }\n            None => {\n                // EOF needs a single advance\n                self.loc0 = self.loc1;\n                self.loc1 += 1;\n                None\n            }\n        };\n        self.chr0 = self.chr1;\n        self.chr1 = nxt;\n        c\n    }\n\n    // Helper function to retrieve the current position.\n    fn get_pos(&self) -> u32 {\n        self.loc0\n    }\n\n    // Helper function to emit a lexed token to the queue of tokens.\n    fn emit(&mut self, spanned: Spanned) {\n        self.pending.push(spanned);\n    }\n}\n\nimpl<T> Iterator for Lexer<T>\nwhere\n    T: Iterator<Item = (u32, char)>,\n{\n    type Item = LexResult;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let token = self.inner_next();\n\n        match token {\n            Ok((_, Token::EndOfFile, _)) => None,\n            r => Some(r),\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__append_to_const_list.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst wibble = [2, 3]\\nconst wobble = [..wibble, 4, 5]\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [2, 3]\nconst wobble = [..wibble, 4, 5]\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:17\n  │\n3 │ const wobble = [..wibble, 4, 5]\n  │                 ^^^^^^^^ I wasn't expecting elements after this\n\nLists are immutable and singly-linked, so to append items to them\nall the elements of a list would need to be copied into a new list.\nThis would be slow, so there is no built-in syntax for it.\n\nHint: Prepend items to the list and then reverse it once you are done.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__argument_scope.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n1 + let a = 5\\na\\n\"\n---\n----- SOURCE CODE\n\n1 + let a = 5\na\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:3\n  │\n2 │ 1 + let a = 5\n  │   ^ This operator has no value on its right side\n\nHint: Remove it or put a value after it.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__arithmetic_in_guards.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ncase 2, 3 {\\n    x, y if x + y == 1 -> True\\n}\"\n---\n[\n    Expression(\n        Case {\n            location: SrcSpan {\n                start: 1,\n                end: 45,\n            },\n            subjects: [\n                Int {\n                    location: SrcSpan {\n                        start: 6,\n                        end: 7,\n                    },\n                    value: \"2\",\n                    int_value: 2,\n                },\n                Int {\n                    location: SrcSpan {\n                        start: 9,\n                        end: 10,\n                    },\n                    value: \"3\",\n                    int_value: 3,\n                },\n            ],\n            clauses: Some(\n                [\n                    Clause {\n                        location: SrcSpan {\n                            start: 17,\n                            end: 43,\n                        },\n                        pattern: [\n                            Variable {\n                                location: SrcSpan {\n                                    start: 17,\n                                    end: 18,\n                                },\n                                name: \"x\",\n                                type_: (),\n                                origin: VariableOrigin {\n                                    syntax: Variable(\n                                        \"x\",\n                                    ),\n                                    declaration: ClausePattern,\n                                },\n                            },\n                            Variable {\n                                location: SrcSpan {\n                                    start: 20,\n                                    end: 21,\n                                },\n                                name: \"y\",\n                                type_: (),\n                                origin: VariableOrigin {\n                                    syntax: Variable(\n                                        \"y\",\n                                    ),\n                                    declaration: ClausePattern,\n                                },\n                            },\n                        ],\n                        alternative_patterns: [],\n                        guard: Some(\n                            BinaryOperator {\n                                location: SrcSpan {\n                                    start: 25,\n                                    end: 35,\n                                },\n                                operator: Eq,\n                                left: BinaryOperator {\n                                    location: SrcSpan {\n                                        start: 25,\n                                        end: 30,\n                                    },\n                                    operator: AddInt,\n                                    left: Var {\n                                        location: SrcSpan {\n                                            start: 25,\n                                            end: 26,\n                                        },\n                                        type_: (),\n                                        name: \"x\",\n                                        definition_location: SrcSpan {\n                                            start: 0,\n                                            end: 0,\n                                        },\n                                        origin: VariableOrigin {\n                                            syntax: Generated,\n                                            declaration: Generated,\n                                        },\n                                    },\n                                    right: Var {\n                                        location: SrcSpan {\n                                            start: 29,\n                                            end: 30,\n                                        },\n                                        type_: (),\n                                        name: \"y\",\n                                        definition_location: SrcSpan {\n                                            start: 0,\n                                            end: 0,\n                                        },\n                                        origin: VariableOrigin {\n                                            syntax: Generated,\n                                            declaration: Generated,\n                                        },\n                                    },\n                                },\n                                right: Constant(\n                                    Int {\n                                        location: SrcSpan {\n                                            start: 34,\n                                            end: 35,\n                                        },\n                                        value: \"1\",\n                                        int_value: 1,\n                                    },\n                                ),\n                            },\n                        ),\n                        then: Var {\n                            location: SrcSpan {\n                                start: 39,\n                                end: 43,\n                            },\n                            name: \"True\",\n                        },\n                    },\n                ],\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assert_statement.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert 10 != 11\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 15,\n            },\n            value: BinOp {\n                location: SrcSpan {\n                    start: 7,\n                    end: 15,\n                },\n                name: NotEq,\n                name_location: SrcSpan {\n                    start: 10,\n                    end: 12,\n                },\n                left: Int {\n                    location: SrcSpan {\n                        start: 7,\n                        end: 9,\n                    },\n                    value: \"10\",\n                    int_value: 10,\n                },\n                right: Int {\n                    location: SrcSpan {\n                        start: 13,\n                        end: 15,\n                    },\n                    value: \"11\",\n                    int_value: 11,\n                },\n            },\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assert_statement_followed_by_statement.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert let a = 10\n---\n----- SOURCE CODE\nassert let a = 10\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:8\n  │\n1 │ assert let a = 10\n  │        ^^^ I was not expecting this\n\nFound the keyword `let`, expected one of: \n- An expression\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assert_statement_with_message.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"assert False as \\\"Uh oh\\\"\"\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 23,\n            },\n            value: Var {\n                location: SrcSpan {\n                    start: 7,\n                    end: 12,\n                },\n                name: \"False\",\n            },\n            message: Some(\n                String {\n                    location: SrcSpan {\n                        start: 16,\n                        end: 23,\n                    },\n                    value: \"Uh oh\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assert_statement_without_expression.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert\n---\n----- SOURCE CODE\nassert\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:6\n  │\n1 │ assert\n  │      ^ The module ended unexpectedly\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assign_left_hand_side_of_concat_pattern.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n        case \\\"\\\" {\\n          first <> rest -> rest\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        case \"\" {\n          first <> rest -> rest\n        }\n        \n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:11\n  │\n3 │           first <> rest -> rest\n  │           ^^^^^ This must be a string literal\n\nWe can't tell what size this prefix should be so we don't know\nhow to handle this pattern.\n\nIf you want to match one character consider using `pop_grapheme`\nfrom the stdlib's `gleam/string` module.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assignment_pattern_invalid_bit_segment.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    let <<b1, pub>> = <<24, 3>>\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    let <<b1, pub>> = <<24, 3>>\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:15\n  │\n3 │     let <<b1, pub>> = <<24, 3>>\n  │               ^^^ I was not expecting this\n\nFound the keyword `pub`, expected one of: \n- `>>`\n- a bit array segment pattern\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__assignment_pattern_invalid_tuple.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    let #(a, case, c) = #(1, 2, 3)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    let #(a, case, c) = #(1, 2, 3)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:14\n  │\n3 │     let #(a, case, c) = #(1, 2, 3)\n  │              ^^^^ I was not expecting this\n\nFound the keyword `case`, expected one of: \n- `)`\n- a pattern\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__attributes_with_improper_definition.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@deprecated(\\\"1\\\")\\n@external(erlang, \\\"module\\\", \\\"fun\\\")\\n\"\n---\n----- SOURCE CODE\n\n@deprecated(\"1\")\n@external(erlang, \"module\", \"fun\")\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │  \n2 │ ╭ @deprecated(\"1\")\n3 │ │ @external(erlang, \"module\", \"fun\")\n  │ ╰──────────────────────────────────^ I was expecting a function definition after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__attributes_with_no_definition.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@deprecated(\\\"1\\\")\\n@target(erlang)\\n\"\n---\n----- SOURCE CODE\n\n@deprecated(\"1\")\n@target(erlang)\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │  \n2 │ ╭ @deprecated(\"1\")\n3 │ │ @target(erlang)\n  │ ╰───────────────^ I was expecting a definition after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__bare_expression.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"1\"\n---\n[\n    Expression(\n        Int {\n            location: SrcSpan {\n                start: 0,\n                end: 1,\n            },\n            value: \"1\",\n            int_value: 1,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__bit_array_invalid_segment.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    <<72, 101, 108, 108, 111, 44, 32, 74, 111, 101, const>>\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    <<72, 101, 108, 108, 111, 44, 32, 74, 111, 101, const>>\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:53\n  │\n3 │     <<72, 101, 108, 108, 111, 44, 32, 74, 111, 101, const>>\n  │                                                     ^^^^^ I was not expecting this\n\nFound the keyword `const`, expected one of: \n- `>>`\n- a bit array segment\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__block_of_one.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"{ 1 }\"\n---\n[\n    Expression(\n        Block {\n            location: SrcSpan {\n                start: 0,\n                end: 5,\n            },\n            statements: [\n                Expression(\n                    Int {\n                        location: SrcSpan {\n                            start: 2,\n                            end: 3,\n                        },\n                        value: \"1\",\n                        int_value: 1,\n                    },\n                ),\n            ],\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__block_of_two.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"{ 1 2 }\"\n---\n[\n    Expression(\n        Block {\n            location: SrcSpan {\n                start: 0,\n                end: 7,\n            },\n            statements: [\n                Expression(\n                    Int {\n                        location: SrcSpan {\n                            start: 2,\n                            end: 3,\n                        },\n                        value: \"1\",\n                        int_value: 1,\n                    },\n                ),\n                Expression(\n                    Int {\n                        location: SrcSpan {\n                            start: 4,\n                            end: 5,\n                        },\n                        value: \"2\",\n                        int_value: 2,\n                    },\n                ),\n            ],\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__byte_order_mark.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: ﻿todo\n---\n[\n    Expression(\n        Todo {\n            kind: Keyword,\n            location: SrcSpan {\n                start: 3,\n                end: 7,\n            },\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__byte_order_mark_module.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nassertion_line: 2103\nexpression: \"﻿\\nconst local_const = other.Record(..other.base, field: value)\\n\"\nsnapshot_kind: text\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 4,\n                            end: 21,\n                        },\n                        publicity: Private,\n                        name: \"local_const\",\n                        name_location: SrcSpan {\n                            start: 10,\n                            end: 21,\n                        },\n                        annotation: None,\n                        value: RecordUpdate {\n                            location: SrcSpan {\n                                start: 24,\n                                end: 64,\n                            },\n                            constructor_location: SrcSpan {\n                                start: 24,\n                                end: 36,\n                            },\n                            module: Some(\n                                (\n                                    \"other\",\n                                    SrcSpan {\n                                        start: 24,\n                                        end: 29,\n                                    },\n                                ),\n                            ),\n                            name: \"Record\",\n                            record: RecordBeingUpdated {\n                                base: Var {\n                                    location: SrcSpan {\n                                        start: 39,\n                                        end: 49,\n                                    },\n                                    module: Some(\n                                        (\n                                            \"other\",\n                                            SrcSpan {\n                                                start: 39,\n                                                end: 44,\n                                            },\n                                        ),\n                                    ),\n                                    name: \"base\",\n                                    constructor: None,\n                                    type_: (),\n                                },\n                                location: SrcSpan {\n                                    start: 39,\n                                    end: 49,\n                                },\n                            },\n                            arguments: [\n                                RecordUpdateArg {\n                                    label: \"field\",\n                                    location: SrcSpan {\n                                        start: 51,\n                                        end: 63,\n                                    },\n                                    value: Var {\n                                        location: SrcSpan {\n                                            start: 58,\n                                            end: 63,\n                                        },\n                                        module: None,\n                                        name: \"value\",\n                                        constructor: None,\n                                        type_: (),\n                                    },\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [\n            3,\n            64,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__capture_with_name.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  add(_name, 1)\\n}\\n\\nfn add(x, y) {\\n  x + y\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  add(_name, 1)\n}\n\nfn add(x, y) {\n  x + y\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:7\n  │\n3 │   add(_name, 1)\n  │       ^^^^^ I was not expecting this\n\nFound a name, expected one of: \n- An expression\n- An underscore\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_alternative_clause_no_subject.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    case 1 {\\n      1 | -> 1\\n      _ -> 1\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    case 1 {\n      1 | -> 1\n      _ -> 1\n    }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:9\n  │\n4 │       1 | -> 1\n  │         ^ I was expecting a pattern after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_clause_no_subject.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    case 1 {\\n      -> 1\\n      _ -> 2\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    case 1 {\n      -> 1\n      _ -> 2\n    }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:7\n  │\n4 │       -> 1\n  │       ^^ I was not expecting this\n\nFound `->`, expected one of: \n- `}`\n- a case clause\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_expression_without_body.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: case a\n---\n[\n    Expression(\n        Case {\n            location: SrcSpan {\n                start: 0,\n                end: 6,\n            },\n            subjects: [\n                Var {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 6,\n                    },\n                    name: \"a\",\n                },\n            ],\n            clauses: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_guard_with_empty_block.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"case 1 {\\n  _ if a || {}  -> 1\\n}\"\n---\n----- SOURCE CODE\ncase 1 {\n  _ if a || {}  -> 1\n}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:13\n  │\n2 │   _ if a || {}  -> 1\n  │             ^^ A clause guard block cannot be empty\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_guard_with_nested_blocks.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"case 1 {\\n  _ if { 1 || { 1 || 1 } } || 1  -> 1\\n}\"\n---\n[\n    Expression(\n        Case {\n            location: SrcSpan {\n                start: 0,\n                end: 48,\n            },\n            subjects: [\n                Int {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 6,\n                    },\n                    value: \"1\",\n                    int_value: 1,\n                },\n            ],\n            clauses: Some(\n                [\n                    Clause {\n                        location: SrcSpan {\n                            start: 11,\n                            end: 46,\n                        },\n                        pattern: [\n                            Discard {\n                                name: \"_\",\n                                location: SrcSpan {\n                                    start: 11,\n                                    end: 12,\n                                },\n                                type_: (),\n                            },\n                        ],\n                        alternative_patterns: [],\n                        guard: Some(\n                            BinaryOperator {\n                                location: SrcSpan {\n                                    start: 16,\n                                    end: 40,\n                                },\n                                operator: Or,\n                                left: Block {\n                                    location: SrcSpan {\n                                        start: 16,\n                                        end: 35,\n                                    },\n                                    value: BinaryOperator {\n                                        location: SrcSpan {\n                                            start: 18,\n                                            end: 33,\n                                        },\n                                        operator: Or,\n                                        left: Constant(\n                                            Int {\n                                                location: SrcSpan {\n                                                    start: 18,\n                                                    end: 19,\n                                                },\n                                                value: \"1\",\n                                                int_value: 1,\n                                            },\n                                        ),\n                                        right: Block {\n                                            location: SrcSpan {\n                                                start: 23,\n                                                end: 33,\n                                            },\n                                            value: BinaryOperator {\n                                                location: SrcSpan {\n                                                    start: 25,\n                                                    end: 31,\n                                                },\n                                                operator: Or,\n                                                left: Constant(\n                                                    Int {\n                                                        location: SrcSpan {\n                                                            start: 25,\n                                                            end: 26,\n                                                        },\n                                                        value: \"1\",\n                                                        int_value: 1,\n                                                    },\n                                                ),\n                                                right: Constant(\n                                                    Int {\n                                                        location: SrcSpan {\n                                                            start: 30,\n                                                            end: 31,\n                                                        },\n                                                        value: \"1\",\n                                                        int_value: 1,\n                                                    },\n                                                ),\n                                            },\n                                        },\n                                    },\n                                },\n                                right: Constant(\n                                    Int {\n                                        location: SrcSpan {\n                                            start: 39,\n                                            end: 40,\n                                        },\n                                        value: \"1\",\n                                        int_value: 1,\n                                    },\n                                ),\n                            },\n                        ),\n                        then: Int {\n                            location: SrcSpan {\n                                start: 45,\n                                end: 46,\n                            },\n                            value: \"1\",\n                            int_value: 1,\n                        },\n                    },\n                ],\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_invalid_case_pattern.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    case 1 {\\n        -> -> 0\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    case 1 {\n        -> -> 0\n    }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:9\n  │\n4 │         -> -> 0\n  │         ^^ I was not expecting this\n\nFound `->`, expected one of: \n- `}`\n- a case clause\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_invalid_expression.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    case 1, type {\\n        _, _ -> 0\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    case 1, type {\n        _, _ -> 0\n    }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:13\n  │\n3 │     case 1, type {\n  │             ^^^^ I was not expecting this\n\nFound the keyword `type`, expected one of: \n- `}`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_list_pattern_after_spread.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    case somelist {\\n        [..rest, last] -> 1\\n        _ -> 2\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    case somelist {\n        [..rest, last] -> 1\n        _ -> 2\n    }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:10\n  │\n4 │         [..rest, last] -> 1\n  │          ^^^^^^ I wasn't expecting elements after this\n\nLists are immutable and singly-linked, so to match on the end\nof a list would require the whole list to be traversed. This\nwould be slow, so there is no built-in syntax for it. Pattern\nmatch on the start of the list instead.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_invalid_bit_array_segment.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst a = <<1, 2, <->>\\n\"\n---\n----- SOURCE CODE\n\nconst a = <<1, 2, <->>\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:19\n  │\n2 │ const a = <<1, 2, <->>\n  │                   ^^ I was not expecting this\n\nFound `<-`, expected one of: \n- `>>`\n- a bit array segment\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_invalid_list.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst a = [1, 2, <-]\\n\"\n---\n----- SOURCE CODE\n\nconst a = [1, 2, <-]\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:18\n  │\n2 │ const a = [1, 2, <-]\n  │                  ^^ I was not expecting this\n\nFound `<-`, expected one of: \n- `]`\n- a constant value\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_invalid_record_constructor.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype A {\\n    A(String, Int)\\n}\\nconst a = A(\\\"a\\\", let)\\n\"\n---\n----- SOURCE CODE\n\ntype A {\n    A(String, Int)\n}\nconst a = A(\"a\", let)\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:5:18\n  │\n5 │ const a = A(\"a\", let)\n  │                  ^^^ I was not expecting this\n\nFound the keyword `let`, expected one of: \n- `)`\n- a constant record argument\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_invalid_tuple.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst a = #(1, 2, <-)\\n\"\n---\n----- SOURCE CODE\n\nconst a = #(1, 2, <-)\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:19\n  │\n2 │ const a = #(1, 2, <-)\n  │                   ^^ I was not expecting this\n\nFound `<-`, expected one of: \n- `)`\n- a constant value\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_record_update_all_fields.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Person {\\n  Person(name: String, age: Int, city: String)\\n}\\n\\nconst base = Person(\\\"Alice\\\", 30, \\\"London\\\")\\nconst updated = Person(..base, name: \\\"Bob\\\", age: 25, city: \\\"Paris\\\")\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 1,\n                            end: 12,\n                        },\n                        end_position: 63,\n                        name: \"Person\",\n                        name_location: SrcSpan {\n                            start: 6,\n                            end: 12,\n                        },\n                        publicity: Private,\n                        constructors: [\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 17,\n                                    end: 61,\n                                },\n                                name_location: SrcSpan {\n                                    start: 17,\n                                    end: 23,\n                                },\n                                name: \"Person\",\n                                arguments: [\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 24,\n                                                    end: 28,\n                                                },\n                                                \"name\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 30,\n                                                    end: 36,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 30,\n                                                    end: 36,\n                                                },\n                                                module: None,\n                                                name: \"String\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 24,\n                                            end: 36,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 38,\n                                                    end: 41,\n                                                },\n                                                \"age\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 43,\n                                                    end: 46,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 43,\n                                                    end: 46,\n                                                },\n                                                module: None,\n                                                name: \"Int\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 38,\n                                            end: 46,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 48,\n                                                    end: 52,\n                                                },\n                                                \"city\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 54,\n                                                    end: 60,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 54,\n                                                    end: 60,\n                                                },\n                                                module: None,\n                                                name: \"String\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 48,\n                                            end: 60,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                ],\n                                documentation: None,\n                                deprecation: NotDeprecated,\n                            },\n                        ],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: false,\n                        parameters: [],\n                        typed_parameters: [],\n                        external_erlang: None,\n                        external_javascript: None,\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 65,\n                            end: 75,\n                        },\n                        publicity: Private,\n                        name: \"base\",\n                        name_location: SrcSpan {\n                            start: 71,\n                            end: 75,\n                        },\n                        annotation: None,\n                        value: Record {\n                            location: SrcSpan {\n                                start: 78,\n                                end: 107,\n                            },\n                            module: None,\n                            name: \"Person\",\n                            arguments: [\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 85,\n                                        end: 92,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 85,\n                                            end: 92,\n                                        },\n                                        value: \"Alice\",\n                                    },\n                                    implicit: None,\n                                },\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 94,\n                                        end: 96,\n                                    },\n                                    value: Int {\n                                        location: SrcSpan {\n                                            start: 94,\n                                            end: 96,\n                                        },\n                                        value: \"30\",\n                                        int_value: 30,\n                                    },\n                                    implicit: None,\n                                },\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 98,\n                                        end: 106,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 98,\n                                            end: 106,\n                                        },\n                                        value: \"London\",\n                                    },\n                                    implicit: None,\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                            record_constructor: None,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 108,\n                            end: 121,\n                        },\n                        publicity: Private,\n                        name: \"updated\",\n                        name_location: SrcSpan {\n                            start: 114,\n                            end: 121,\n                        },\n                        annotation: None,\n                        value: RecordUpdate {\n                            location: SrcSpan {\n                                start: 124,\n                                end: 175,\n                            },\n                            constructor_location: SrcSpan {\n                                start: 124,\n                                end: 130,\n                            },\n                            module: None,\n                            name: \"Person\",\n                            record: RecordBeingUpdated {\n                                base: Var {\n                                    location: SrcSpan {\n                                        start: 133,\n                                        end: 137,\n                                    },\n                                    module: None,\n                                    name: \"base\",\n                                    constructor: None,\n                                    type_: (),\n                                },\n                                location: SrcSpan {\n                                    start: 133,\n                                    end: 137,\n                                },\n                            },\n                            arguments: [\n                                RecordUpdateArg {\n                                    label: \"name\",\n                                    location: SrcSpan {\n                                        start: 139,\n                                        end: 150,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 145,\n                                            end: 150,\n                                        },\n                                        value: \"Bob\",\n                                    },\n                                },\n                                RecordUpdateArg {\n                                    label: \"age\",\n                                    location: SrcSpan {\n                                        start: 152,\n                                        end: 159,\n                                    },\n                                    value: Int {\n                                        location: SrcSpan {\n                                            start: 157,\n                                            end: 159,\n                                        },\n                                        value: \"25\",\n                                        int_value: 25,\n                                    },\n                                },\n                                RecordUpdateArg {\n                                    label: \"city\",\n                                    location: SrcSpan {\n                                        start: 161,\n                                        end: 174,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 167,\n                                            end: 174,\n                                        },\n                                        value: \"Paris\",\n                                    },\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [\n            64,\n        ],\n        new_lines: [\n            0,\n            14,\n            61,\n            63,\n            64,\n            107,\n            175,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_record_update_basic.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Person {\\n  Person(name: String, age: Int)\\n}\\n\\nconst alice = Person(\\\"Alice\\\", 30)\\nconst bob = Person(..alice, name: \\\"Bob\\\")\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 1,\n                            end: 12,\n                        },\n                        end_position: 49,\n                        name: \"Person\",\n                        name_location: SrcSpan {\n                            start: 6,\n                            end: 12,\n                        },\n                        publicity: Private,\n                        constructors: [\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 17,\n                                    end: 47,\n                                },\n                                name_location: SrcSpan {\n                                    start: 17,\n                                    end: 23,\n                                },\n                                name: \"Person\",\n                                arguments: [\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 24,\n                                                    end: 28,\n                                                },\n                                                \"name\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 30,\n                                                    end: 36,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 30,\n                                                    end: 36,\n                                                },\n                                                module: None,\n                                                name: \"String\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 24,\n                                            end: 36,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 38,\n                                                    end: 41,\n                                                },\n                                                \"age\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 43,\n                                                    end: 46,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 43,\n                                                    end: 46,\n                                                },\n                                                module: None,\n                                                name: \"Int\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 38,\n                                            end: 46,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                ],\n                                documentation: None,\n                                deprecation: NotDeprecated,\n                            },\n                        ],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: false,\n                        parameters: [],\n                        typed_parameters: [],\n                        external_erlang: None,\n                        external_javascript: None,\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 51,\n                            end: 62,\n                        },\n                        publicity: Private,\n                        name: \"alice\",\n                        name_location: SrcSpan {\n                            start: 57,\n                            end: 62,\n                        },\n                        annotation: None,\n                        value: Record {\n                            location: SrcSpan {\n                                start: 65,\n                                end: 84,\n                            },\n                            module: None,\n                            name: \"Person\",\n                            arguments: [\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 72,\n                                        end: 79,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 72,\n                                            end: 79,\n                                        },\n                                        value: \"Alice\",\n                                    },\n                                    implicit: None,\n                                },\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 81,\n                                        end: 83,\n                                    },\n                                    value: Int {\n                                        location: SrcSpan {\n                                            start: 81,\n                                            end: 83,\n                                        },\n                                        value: \"30\",\n                                        int_value: 30,\n                                    },\n                                    implicit: None,\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                            record_constructor: None,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 85,\n                            end: 94,\n                        },\n                        publicity: Private,\n                        name: \"bob\",\n                        name_location: SrcSpan {\n                            start: 91,\n                            end: 94,\n                        },\n                        annotation: None,\n                        value: RecordUpdate {\n                            location: SrcSpan {\n                                start: 97,\n                                end: 125,\n                            },\n                            constructor_location: SrcSpan {\n                                start: 97,\n                                end: 103,\n                            },\n                            module: None,\n                            name: \"Person\",\n                            record: RecordBeingUpdated {\n                                base: Var {\n                                    location: SrcSpan {\n                                        start: 106,\n                                        end: 111,\n                                    },\n                                    module: None,\n                                    name: \"alice\",\n                                    constructor: None,\n                                    type_: (),\n                                },\n                                location: SrcSpan {\n                                    start: 106,\n                                    end: 111,\n                                },\n                            },\n                            arguments: [\n                                RecordUpdateArg {\n                                    label: \"name\",\n                                    location: SrcSpan {\n                                        start: 113,\n                                        end: 124,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 119,\n                                            end: 124,\n                                        },\n                                        value: \"Bob\",\n                                    },\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [\n            50,\n        ],\n        new_lines: [\n            0,\n            14,\n            47,\n            49,\n            50,\n            84,\n            125,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_record_update_only.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Person {\\n  Person(name: String, age: Int)\\n}\\n\\nconst alice = Person(\\\"Alice\\\", 30)\\nconst bob = Person(..alice)\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 1,\n                            end: 12,\n                        },\n                        end_position: 49,\n                        name: \"Person\",\n                        name_location: SrcSpan {\n                            start: 6,\n                            end: 12,\n                        },\n                        publicity: Private,\n                        constructors: [\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 17,\n                                    end: 47,\n                                },\n                                name_location: SrcSpan {\n                                    start: 17,\n                                    end: 23,\n                                },\n                                name: \"Person\",\n                                arguments: [\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 24,\n                                                    end: 28,\n                                                },\n                                                \"name\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 30,\n                                                    end: 36,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 30,\n                                                    end: 36,\n                                                },\n                                                module: None,\n                                                name: \"String\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 24,\n                                            end: 36,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 38,\n                                                    end: 41,\n                                                },\n                                                \"age\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 43,\n                                                    end: 46,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 43,\n                                                    end: 46,\n                                                },\n                                                module: None,\n                                                name: \"Int\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 38,\n                                            end: 46,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                ],\n                                documentation: None,\n                                deprecation: NotDeprecated,\n                            },\n                        ],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: false,\n                        parameters: [],\n                        typed_parameters: [],\n                        external_erlang: None,\n                        external_javascript: None,\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 51,\n                            end: 62,\n                        },\n                        publicity: Private,\n                        name: \"alice\",\n                        name_location: SrcSpan {\n                            start: 57,\n                            end: 62,\n                        },\n                        annotation: None,\n                        value: Record {\n                            location: SrcSpan {\n                                start: 65,\n                                end: 84,\n                            },\n                            module: None,\n                            name: \"Person\",\n                            arguments: [\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 72,\n                                        end: 79,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 72,\n                                            end: 79,\n                                        },\n                                        value: \"Alice\",\n                                    },\n                                    implicit: None,\n                                },\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 81,\n                                        end: 83,\n                                    },\n                                    value: Int {\n                                        location: SrcSpan {\n                                            start: 81,\n                                            end: 83,\n                                        },\n                                        value: \"30\",\n                                        int_value: 30,\n                                    },\n                                    implicit: None,\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                            record_constructor: None,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 85,\n                            end: 94,\n                        },\n                        publicity: Private,\n                        name: \"bob\",\n                        name_location: SrcSpan {\n                            start: 91,\n                            end: 94,\n                        },\n                        annotation: None,\n                        value: RecordUpdate {\n                            location: SrcSpan {\n                                start: 97,\n                                end: 112,\n                            },\n                            constructor_location: SrcSpan {\n                                start: 97,\n                                end: 103,\n                            },\n                            module: None,\n                            name: \"Person\",\n                            record: RecordBeingUpdated {\n                                base: Var {\n                                    location: SrcSpan {\n                                        start: 106,\n                                        end: 111,\n                                    },\n                                    module: None,\n                                    name: \"alice\",\n                                    constructor: None,\n                                    type_: (),\n                                },\n                                location: SrcSpan {\n                                    start: 106,\n                                    end: 111,\n                                },\n                            },\n                            arguments: [],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [\n            50,\n        ],\n        new_lines: [\n            0,\n            14,\n            47,\n            49,\n            50,\n            84,\n            112,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_record_update_with_module.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst local_const = other.Record(..other.base, field: value)\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 1,\n                            end: 18,\n                        },\n                        publicity: Private,\n                        name: \"local_const\",\n                        name_location: SrcSpan {\n                            start: 7,\n                            end: 18,\n                        },\n                        annotation: None,\n                        value: RecordUpdate {\n                            location: SrcSpan {\n                                start: 21,\n                                end: 61,\n                            },\n                            constructor_location: SrcSpan {\n                                start: 21,\n                                end: 33,\n                            },\n                            module: Some(\n                                (\n                                    \"other\",\n                                    SrcSpan {\n                                        start: 21,\n                                        end: 26,\n                                    },\n                                ),\n                            ),\n                            name: \"Record\",\n                            record: RecordBeingUpdated {\n                                base: Var {\n                                    location: SrcSpan {\n                                        start: 36,\n                                        end: 46,\n                                    },\n                                    module: Some(\n                                        (\n                                            \"other\",\n                                            SrcSpan {\n                                                start: 36,\n                                                end: 41,\n                                            },\n                                        ),\n                                    ),\n                                    name: \"base\",\n                                    constructor: None,\n                                    type_: (),\n                                },\n                                location: SrcSpan {\n                                    start: 36,\n                                    end: 46,\n                                },\n                            },\n                            arguments: [\n                                RecordUpdateArg {\n                                    label: \"field\",\n                                    location: SrcSpan {\n                                        start: 48,\n                                        end: 60,\n                                    },\n                                    value: Var {\n                                        location: SrcSpan {\n                                            start: 55,\n                                            end: 60,\n                                        },\n                                        module: None,\n                                        name: \"value\",\n                                        constructor: None,\n                                        type_: (),\n                                    },\n                                },\n                            ],\n                            tag: (),\n                            type_: (),\n                            field_map: Unknown,\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [\n            0,\n            61,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_string_concat.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst cute = \\\"cute\\\"\\nconst cute_bee = cute <> \\\"bee\\\"\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 1,\n                            end: 11,\n                        },\n                        publicity: Private,\n                        name: \"cute\",\n                        name_location: SrcSpan {\n                            start: 7,\n                            end: 11,\n                        },\n                        annotation: None,\n                        value: String {\n                            location: SrcSpan {\n                                start: 14,\n                                end: 20,\n                            },\n                            value: \"cute\",\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: ModuleConstant(\n                    ModuleConstant {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 21,\n                            end: 35,\n                        },\n                        publicity: Private,\n                        name: \"cute_bee\",\n                        name_location: SrcSpan {\n                            start: 27,\n                            end: 35,\n                        },\n                        annotation: None,\n                        value: StringConcatenation {\n                            location: SrcSpan {\n                                start: 38,\n                                end: 51,\n                            },\n                            left: Var {\n                                location: SrcSpan {\n                                    start: 38,\n                                    end: 42,\n                                },\n                                module: None,\n                                name: \"cute\",\n                                constructor: None,\n                                type_: (),\n                            },\n                            right: String {\n                                location: SrcSpan {\n                                    start: 46,\n                                    end: 51,\n                                },\n                                value: \"bee\",\n                            },\n                        },\n                        type_: (),\n                        deprecation: NotDeprecated,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [\n            0,\n            20,\n            51,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_string_concat_naked_right.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst no_cute_bee = \\\"cute\\\" <>\\n\"\n---\n----- SOURCE CODE\n\nconst no_cute_bee = \"cute\" <>\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:28\n  │\n2 │ const no_cute_bee = \"cute\" <>\n  │                            ^^ This operator has no value on its right side\n\nHint: Remove it or put a value after it.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_with_function_call.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn wibble() { 123 }\\nconst wib: Int = wibble()\\n\"\n---\n----- SOURCE CODE\n\npub fn wibble() { 123 }\nconst wib: Int = wibble()\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:18\n  │\n3 │ const wib: Int = wibble()\n  │                  ^^^^^^^ Functions can only be called within other functions\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__const_with_function_call_with_args.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn wibble() { 123 }\\nconst wib: Int = wibble(1, \\\"wobble\\\")\\n\"\n---\n----- SOURCE CODE\n\npub fn wibble() { 123 }\nconst wib: Int = wibble(1, \"wobble\")\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:18\n  │\n3 │ const wib: Int = wibble(1, \"wobble\")\n  │                  ^^^^^^^ Functions can only be called within other functions\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__constant_inside_function.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  const x = 10\\n  x\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  const x = 10\n  x\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:3\n  │\n3 │   const x = 10\n  │   ^^^^^ Constants are not allowed inside functions\n\nAll variables are immutable in Gleam, so constants inside functions are not\nnecessary.\nHint: Either move this into the global scope or use `let` binding instead.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__correct_precedence_in_pattern_size.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let assert <<size, payload:size(size + 2 * 8)>> = <<>>\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 0,\n                end: 54,\n            },\n            value: BitArray {\n                location: SrcSpan {\n                    start: 50,\n                    end: 54,\n                },\n                segments: [],\n            },\n            pattern: BitArray {\n                location: SrcSpan {\n                    start: 11,\n                    end: 47,\n                },\n                segments: [\n                    BitArraySegment {\n                        location: SrcSpan {\n                            start: 13,\n                            end: 17,\n                        },\n                        value: Variable {\n                            location: SrcSpan {\n                                start: 13,\n                                end: 17,\n                            },\n                            name: \"size\",\n                            type_: (),\n                            origin: VariableOrigin {\n                                syntax: Variable(\n                                    \"size\",\n                                ),\n                                declaration: LetPattern,\n                            },\n                        },\n                        options: [],\n                        type_: (),\n                    },\n                    BitArraySegment {\n                        location: SrcSpan {\n                            start: 19,\n                            end: 45,\n                        },\n                        value: Variable {\n                            location: SrcSpan {\n                                start: 19,\n                                end: 26,\n                            },\n                            name: \"payload\",\n                            type_: (),\n                            origin: VariableOrigin {\n                                syntax: Variable(\n                                    \"payload\",\n                                ),\n                                declaration: LetPattern,\n                            },\n                        },\n                        options: [\n                            Size {\n                                location: SrcSpan {\n                                    start: 27,\n                                    end: 45,\n                                },\n                                value: BitArraySize(\n                                    BinaryOperator {\n                                        location: SrcSpan {\n                                            start: 32,\n                                            end: 44,\n                                        },\n                                        operator: Add,\n                                        left: Variable {\n                                            location: SrcSpan {\n                                                start: 32,\n                                                end: 36,\n                                            },\n                                            name: \"size\",\n                                            constructor: None,\n                                            type_: (),\n                                        },\n                                        right: BinaryOperator {\n                                            location: SrcSpan {\n                                                start: 39,\n                                                end: 44,\n                                            },\n                                            operator: Multiply,\n                                            left: Int {\n                                                location: SrcSpan {\n                                                    start: 39,\n                                                    end: 40,\n                                                },\n                                                value: \"2\",\n                                                int_value: 2,\n                                            },\n                                            right: Int {\n                                                location: SrcSpan {\n                                                    start: 43,\n                                                    end: 44,\n                                                },\n                                                value: \"8\",\n                                                int_value: 8,\n                                            },\n                                        },\n                                    },\n                                ),\n                                short_form: false,\n                            },\n                        ],\n                        type_: (),\n                    },\n                ],\n            },\n            kind: Assert {\n                location: SrcSpan {\n                    start: 0,\n                    end: 10,\n                },\n                assert_keyword_start: 4,\n                message: None,\n            },\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__deeply_nested_tuples.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet tup = #(#(#(#(4))))\\n{{{tup.0}.0}.0}.0\\n\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 1,\n                end: 24,\n            },\n            value: Tuple {\n                location: SrcSpan {\n                    start: 11,\n                    end: 24,\n                },\n                elements: [\n                    Tuple {\n                        location: SrcSpan {\n                            start: 13,\n                            end: 23,\n                        },\n                        elements: [\n                            Tuple {\n                                location: SrcSpan {\n                                    start: 15,\n                                    end: 22,\n                                },\n                                elements: [\n                                    Tuple {\n                                        location: SrcSpan {\n                                            start: 17,\n                                            end: 21,\n                                        },\n                                        elements: [\n                                            Int {\n                                                location: SrcSpan {\n                                                    start: 19,\n                                                    end: 20,\n                                                },\n                                                value: \"4\",\n                                                int_value: 4,\n                                            },\n                                        ],\n                                    },\n                                ],\n                            },\n                        ],\n                    },\n                ],\n            },\n            pattern: Variable {\n                location: SrcSpan {\n                    start: 5,\n                    end: 8,\n                },\n                name: \"tup\",\n                type_: (),\n                origin: VariableOrigin {\n                    syntax: Variable(\n                        \"tup\",\n                    ),\n                    declaration: LetPattern,\n                },\n            },\n            kind: Let,\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n    Expression(\n        TupleIndex {\n            location: SrcSpan {\n                start: 25,\n                end: 42,\n            },\n            index: 0,\n            tuple: Block {\n                location: SrcSpan {\n                    start: 25,\n                    end: 40,\n                },\n                statements: [\n                    Expression(\n                        TupleIndex {\n                            location: SrcSpan {\n                                start: 26,\n                                end: 39,\n                            },\n                            index: 0,\n                            tuple: Block {\n                                location: SrcSpan {\n                                    start: 26,\n                                    end: 37,\n                                },\n                                statements: [\n                                    Expression(\n                                        TupleIndex {\n                                            location: SrcSpan {\n                                                start: 27,\n                                                end: 36,\n                                            },\n                                            index: 0,\n                                            tuple: Block {\n                                                location: SrcSpan {\n                                                    start: 27,\n                                                    end: 34,\n                                                },\n                                                statements: [\n                                                    Expression(\n                                                        TupleIndex {\n                                                            location: SrcSpan {\n                                                                start: 28,\n                                                                end: 33,\n                                                            },\n                                                            index: 0,\n                                                            tuple: Var {\n                                                                location: SrcSpan {\n                                                                    start: 28,\n                                                                    end: 31,\n                                                                },\n                                                                name: \"tup\",\n                                                            },\n                                                        },\n                                                    ),\n                                                ],\n                                            },\n                                        },\n                                    ),\n                                ],\n                            },\n                        },\n                    ),\n                ],\n            },\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__deeply_nested_tuples_no_block.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet tup = #(#(#(#(4))))\\ntup.0.0.0.0\\n\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 1,\n                end: 24,\n            },\n            value: Tuple {\n                location: SrcSpan {\n                    start: 11,\n                    end: 24,\n                },\n                elements: [\n                    Tuple {\n                        location: SrcSpan {\n                            start: 13,\n                            end: 23,\n                        },\n                        elements: [\n                            Tuple {\n                                location: SrcSpan {\n                                    start: 15,\n                                    end: 22,\n                                },\n                                elements: [\n                                    Tuple {\n                                        location: SrcSpan {\n                                            start: 17,\n                                            end: 21,\n                                        },\n                                        elements: [\n                                            Int {\n                                                location: SrcSpan {\n                                                    start: 19,\n                                                    end: 20,\n                                                },\n                                                value: \"4\",\n                                                int_value: 4,\n                                            },\n                                        ],\n                                    },\n                                ],\n                            },\n                        ],\n                    },\n                ],\n            },\n            pattern: Variable {\n                location: SrcSpan {\n                    start: 5,\n                    end: 8,\n                },\n                name: \"tup\",\n                type_: (),\n                origin: VariableOrigin {\n                    syntax: Variable(\n                        \"tup\",\n                    ),\n                    declaration: LetPattern,\n                },\n            },\n            kind: Let,\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n    Expression(\n        TupleIndex {\n            location: SrcSpan {\n                start: 25,\n                end: 36,\n            },\n            index: 0,\n            tuple: TupleIndex {\n                location: SrcSpan {\n                    start: 25,\n                    end: 34,\n                },\n                index: 0,\n                tuple: TupleIndex {\n                    location: SrcSpan {\n                        start: 25,\n                        end: 32,\n                    },\n                    index: 0,\n                    tuple: TupleIndex {\n                        location: SrcSpan {\n                            start: 25,\n                            end: 30,\n                        },\n                        index: 0,\n                        tuple: Var {\n                            location: SrcSpan {\n                                start: 25,\n                                end: 28,\n                            },\n                            name: \"tup\",\n                        },\n                    },\n                },\n            },\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    @deprecated(\\\"1\\\")\\n    Wibble1\\n    Wibble2\\n}\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 1,\n                            end: 12,\n                        },\n                        end_position: 61,\n                        name: \"Wibble\",\n                        name_location: SrcSpan {\n                            start: 6,\n                            end: 12,\n                        },\n                        publicity: Private,\n                        constructors: [\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 40,\n                                    end: 47,\n                                },\n                                name_location: SrcSpan {\n                                    start: 40,\n                                    end: 47,\n                                },\n                                name: \"Wibble1\",\n                                arguments: [],\n                                documentation: None,\n                                deprecation: Deprecated {\n                                    message: \"1\",\n                                },\n                            },\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 52,\n                                    end: 59,\n                                },\n                                name_location: SrcSpan {\n                                    start: 52,\n                                    end: 59,\n                                },\n                                name: \"Wibble2\",\n                                arguments: [],\n                                documentation: None,\n                                deprecation: NotDeprecated,\n                            },\n                        ],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: false,\n                        parameters: [],\n                        typed_parameters: [],\n                        external_erlang: None,\n                        external_javascript: None,\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [\n            0,\n            14,\n            35,\n            47,\n            59,\n            61,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_without_message.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@deprecated()\\npub fn main() -> Nil {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\n@deprecated()\npub fn main() -> Nil {\n  Nil\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @deprecated()\n  │ ^^^^^^^^^^^ A deprecation attribute must have a string message.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__discard_left_hand_side_of_concat_pattern.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n        case \\\"\\\" {\\n          _ <> rest -> rest\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        case \"\" {\n          _ <> rest -> rest\n        }\n        \n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:11\n  │\n3 │           _ <> rest -> rest\n  │           ^ This must be a string literal\n\nWe can't tell what size this prefix should be so we don't know\nhow to handle this pattern.\n\nIf you want to match one character consider using `pop_grapheme`\nfrom the stdlib's `gleam/string` module.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__doesnt_issue_special_error_for_pythonic_import_if_slash.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: import one/two.three\n---\n----- SOURCE CODE\nimport one/two.three\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:16\n  │\n1 │ import one/two.three\n  │                ^^^^^ I was not expecting this\n\nFound a name, expected one of: \n- `{`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__dot_access_function_call_in_case_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet my_string = \\\"hello\\\"\\ncase my_string {\\n    _ if string.length(my_string) > 2 -> io.debug(\\\"doesn't work')\\n}\"\n---\n----- SOURCE CODE\n\nlet my_string = \"hello\"\ncase my_string {\n    _ if string.length(my_string) > 2 -> io.debug(\"doesn't work')\n}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:10\n  │\n4 │     _ if string.length(my_string) > 2 -> io.debug(\"doesn't work')\n  │          ^^^^^^^^^^^^^^^^^^^^^^^^ Unsupported expression\n\nFunctions cannot be called in clause guards.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_at_start_of_pipeline_wraps_the_whole_thing.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo 1 |> wibble |> wobble\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 26,\n            },\n            keyword_end: 4,\n            expression: Some(\n                PipeLine {\n                    expressions: [\n                        Int {\n                            location: SrcSpan {\n                                start: 5,\n                                end: 6,\n                            },\n                            value: \"1\",\n                            int_value: 1,\n                        },\n                        Var {\n                            location: SrcSpan {\n                                start: 10,\n                                end: 16,\n                            },\n                            name: \"wibble\",\n                        },\n                        Var {\n                            location: SrcSpan {\n                                start: 20,\n                                end: 26,\n                            },\n                            name: \"wobble\",\n                        },\n                    ],\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_cannot_have_an_expression_in_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"[] |> echo fun |> wibble\"\n---\n[\n    Expression(\n        PipeLine {\n            expressions: [\n                List {\n                    location: SrcSpan {\n                        start: 0,\n                        end: 2,\n                    },\n                    elements: [],\n                    tail: None,\n                },\n                Echo {\n                    location: SrcSpan {\n                        start: 6,\n                        end: 10,\n                    },\n                    keyword_end: 10,\n                    expression: None,\n                    message: None,\n                },\n            ],\n        },\n    ),\n    Expression(\n        PipeLine {\n            expressions: [\n                Var {\n                    location: SrcSpan {\n                        start: 11,\n                        end: 14,\n                    },\n                    name: \"fun\",\n                },\n                Var {\n                    location: SrcSpan {\n                        start: 18,\n                        end: 24,\n                    },\n                    name: \"wibble\",\n                },\n            ],\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_followed_by_expression_ends_where_expression_ends.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo wibble\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 11,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 11,\n                    },\n                    name: \"wibble\",\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_has_lower_precedence_than_binop.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo 1 + 1\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 10,\n            },\n            keyword_end: 4,\n            expression: Some(\n                BinOp {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 10,\n                    },\n                    name: AddInt,\n                    name_location: SrcSpan {\n                        start: 7,\n                        end: 8,\n                    },\n                    left: Int {\n                        location: SrcSpan {\n                            start: 5,\n                            end: 6,\n                        },\n                        value: \"1\",\n                        int_value: 1,\n                    },\n                    right: Int {\n                        location: SrcSpan {\n                            start: 9,\n                            end: 10,\n                        },\n                        value: \"1\",\n                        int_value: 1,\n                    },\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_has_lower_precedence_than_pipeline.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo wibble |> wobble |> woo\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 28,\n            },\n            keyword_end: 4,\n            expression: Some(\n                PipeLine {\n                    expressions: [\n                        Var {\n                            location: SrcSpan {\n                                start: 5,\n                                end: 11,\n                            },\n                            name: \"wibble\",\n                        },\n                        Var {\n                            location: SrcSpan {\n                                start: 15,\n                                end: 21,\n                            },\n                            name: \"wobble\",\n                        },\n                        Var {\n                            location: SrcSpan {\n                                start: 25,\n                                end: 28,\n                            },\n                            name: \"woo\",\n                        },\n                    ],\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_in_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"[] |> echo |> wibble\"\n---\n[\n    Expression(\n        PipeLine {\n            expressions: [\n                List {\n                    location: SrcSpan {\n                        start: 0,\n                        end: 2,\n                    },\n                    elements: [],\n                    tail: None,\n                },\n                Echo {\n                    location: SrcSpan {\n                        start: 6,\n                        end: 10,\n                    },\n                    keyword_end: 10,\n                    expression: None,\n                    message: None,\n                },\n                Var {\n                    location: SrcSpan {\n                        start: 14,\n                        end: 20,\n                    },\n                    name: \"wibble\",\n                },\n            ],\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_assert_and_message_1.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert 1 == echo 2 as this_belongs_to_echo\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 42,\n            },\n            value: BinOp {\n                location: SrcSpan {\n                    start: 7,\n                    end: 42,\n                },\n                name: Eq,\n                name_location: SrcSpan {\n                    start: 9,\n                    end: 11,\n                },\n                left: Int {\n                    location: SrcSpan {\n                        start: 7,\n                        end: 8,\n                    },\n                    value: \"1\",\n                    int_value: 1,\n                },\n                right: Echo {\n                    location: SrcSpan {\n                        start: 12,\n                        end: 42,\n                    },\n                    keyword_end: 16,\n                    expression: Some(\n                        Int {\n                            location: SrcSpan {\n                                start: 17,\n                                end: 18,\n                            },\n                            value: \"2\",\n                            int_value: 2,\n                        },\n                    ),\n                    message: Some(\n                        Var {\n                            location: SrcSpan {\n                                start: 22,\n                                end: 42,\n                            },\n                            name: \"this_belongs_to_echo\",\n                        },\n                    ),\n                },\n            },\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_assert_and_message_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert echo True as this_belongs_to_echo\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 40,\n            },\n            value: Echo {\n                location: SrcSpan {\n                    start: 7,\n                    end: 40,\n                },\n                keyword_end: 11,\n                expression: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 12,\n                            end: 16,\n                        },\n                        name: \"True\",\n                    },\n                ),\n                message: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 20,\n                            end: 40,\n                        },\n                        name: \"this_belongs_to_echo\",\n                    },\n                ),\n            },\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_assert_and_messages_1.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert 1 == echo 2 as this_belongs_to_echo as this_belongs_to_assert\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 68,\n            },\n            value: BinOp {\n                location: SrcSpan {\n                    start: 7,\n                    end: 42,\n                },\n                name: Eq,\n                name_location: SrcSpan {\n                    start: 9,\n                    end: 11,\n                },\n                left: Int {\n                    location: SrcSpan {\n                        start: 7,\n                        end: 8,\n                    },\n                    value: \"1\",\n                    int_value: 1,\n                },\n                right: Echo {\n                    location: SrcSpan {\n                        start: 12,\n                        end: 42,\n                    },\n                    keyword_end: 16,\n                    expression: Some(\n                        Int {\n                            location: SrcSpan {\n                                start: 17,\n                                end: 18,\n                            },\n                            value: \"2\",\n                            int_value: 2,\n                        },\n                    ),\n                    message: Some(\n                        Var {\n                            location: SrcSpan {\n                                start: 22,\n                                end: 42,\n                            },\n                            name: \"this_belongs_to_echo\",\n                        },\n                    ),\n                },\n            },\n            message: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 46,\n                        end: 68,\n                    },\n                    name: \"this_belongs_to_assert\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_assert_and_messages_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert echo True as this_belongs_to_echo as this_belongs_to_assert\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 66,\n            },\n            value: Echo {\n                location: SrcSpan {\n                    start: 7,\n                    end: 40,\n                },\n                keyword_end: 11,\n                expression: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 12,\n                            end: 16,\n                        },\n                        name: \"True\",\n                    },\n                ),\n                message: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 20,\n                            end: 40,\n                        },\n                        name: \"this_belongs_to_echo\",\n                    },\n                ),\n            },\n            message: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 44,\n                        end: 66,\n                    },\n                    name: \"this_belongs_to_assert\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_assert_and_messages_3.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: assert echo 1 == 2 as this_belongs_to_echo as this_belongs_to_assert\n---\n[\n    Assert(\n        Assert {\n            location: SrcSpan {\n                start: 0,\n                end: 68,\n            },\n            value: Echo {\n                location: SrcSpan {\n                    start: 7,\n                    end: 42,\n                },\n                keyword_end: 11,\n                expression: Some(\n                    BinOp {\n                        location: SrcSpan {\n                            start: 12,\n                            end: 18,\n                        },\n                        name: Eq,\n                        name_location: SrcSpan {\n                            start: 14,\n                            end: 16,\n                        },\n                        left: Int {\n                            location: SrcSpan {\n                                start: 12,\n                                end: 13,\n                            },\n                            value: \"1\",\n                            int_value: 1,\n                        },\n                        right: Int {\n                            location: SrcSpan {\n                                start: 17,\n                                end: 18,\n                            },\n                            value: \"2\",\n                            int_value: 2,\n                        },\n                    },\n                ),\n                message: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 22,\n                            end: 42,\n                        },\n                        name: \"this_belongs_to_echo\",\n                    },\n                ),\n            },\n            message: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 46,\n                        end: 68,\n                    },\n                    name: \"this_belongs_to_assert\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_block.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"echo { 1 + 1 }\"\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 14,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Block {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 14,\n                    },\n                    statements: [\n                        Expression(\n                            BinOp {\n                                location: SrcSpan {\n                                    start: 7,\n                                    end: 12,\n                                },\n                                name: AddInt,\n                                name_location: SrcSpan {\n                                    start: 9,\n                                    end: 10,\n                                },\n                                left: Int {\n                                    location: SrcSpan {\n                                        start: 7,\n                                        end: 8,\n                                    },\n                                    value: \"1\",\n                                    int_value: 1,\n                                },\n                                right: Int {\n                                    location: SrcSpan {\n                                        start: 11,\n                                        end: 12,\n                                    },\n                                    value: \"1\",\n                                    int_value: 1,\n                                },\n                            },\n                        ),\n                    ],\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_complex_expression.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"echo wibble as { this <> complex }\"\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 34,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 11,\n                    },\n                    name: \"wibble\",\n                },\n            ),\n            message: Some(\n                Block {\n                    location: SrcSpan {\n                        start: 15,\n                        end: 34,\n                    },\n                    statements: [\n                        Expression(\n                            BinOp {\n                                location: SrcSpan {\n                                    start: 17,\n                                    end: 32,\n                                },\n                                name: Concatenate,\n                                name_location: SrcSpan {\n                                    start: 22,\n                                    end: 24,\n                                },\n                                left: Var {\n                                    location: SrcSpan {\n                                        start: 17,\n                                        end: 21,\n                                    },\n                                    name: \"this\",\n                                },\n                                right: Var {\n                                    location: SrcSpan {\n                                        start: 25,\n                                        end: 32,\n                                    },\n                                    name: \"complex\",\n                                },\n                            },\n                        ),\n                    ],\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_let_assert_and_message.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: let assert 1 = echo 2 as this_belongs_to_echo\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 0,\n                end: 45,\n            },\n            value: Echo {\n                location: SrcSpan {\n                    start: 15,\n                    end: 45,\n                },\n                keyword_end: 19,\n                expression: Some(\n                    Int {\n                        location: SrcSpan {\n                            start: 20,\n                            end: 21,\n                        },\n                        value: \"2\",\n                        int_value: 2,\n                    },\n                ),\n                message: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 25,\n                            end: 45,\n                        },\n                        name: \"this_belongs_to_echo\",\n                    },\n                ),\n            },\n            pattern: Int {\n                location: SrcSpan {\n                    start: 11,\n                    end: 12,\n                },\n                value: \"1\",\n                int_value: 1,\n            },\n            kind: Assert {\n                location: SrcSpan {\n                    start: 0,\n                    end: 10,\n                },\n                assert_keyword_start: 4,\n                message: None,\n            },\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_let_assert_and_messages.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: let assert 1 = echo 1 as this_belongs_to_echo as this_belongs_to_assert\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 0,\n                end: 71,\n            },\n            value: Echo {\n                location: SrcSpan {\n                    start: 15,\n                    end: 45,\n                },\n                keyword_end: 19,\n                expression: Some(\n                    Int {\n                        location: SrcSpan {\n                            start: 20,\n                            end: 21,\n                        },\n                        value: \"1\",\n                        int_value: 1,\n                    },\n                ),\n                message: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 25,\n                            end: 45,\n                        },\n                        name: \"this_belongs_to_echo\",\n                    },\n                ),\n            },\n            pattern: Int {\n                location: SrcSpan {\n                    start: 11,\n                    end: 12,\n                },\n                value: \"1\",\n                int_value: 1,\n            },\n            kind: Assert {\n                location: SrcSpan {\n                    start: 0,\n                    end: 10,\n                },\n                assert_keyword_start: 4,\n                message: Some(\n                    Var {\n                        location: SrcSpan {\n                            start: 49,\n                            end: 71,\n                        },\n                        name: \"this_belongs_to_assert\",\n                    },\n                ),\n            },\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_no_expressions_after_it.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 4,\n            },\n            keyword_end: 4,\n            expression: None,\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_no_expressions_after_it_but_a_message.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo as message\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 15,\n            },\n            keyword_end: 4,\n            expression: None,\n            message: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 8,\n                        end: 15,\n                    },\n                    name: \"message\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_panic.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"echo panic as \\\"a\\\"\"\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 17,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Panic {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 17,\n                    },\n                    message: Some(\n                        String {\n                            location: SrcSpan {\n                                start: 14,\n                                end: 17,\n                            },\n                            value: \"a\",\n                        },\n                    ),\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_panic_and_message.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"echo panic as \\\"a\\\"\"\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 17,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Panic {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 17,\n                    },\n                    message: Some(\n                        String {\n                            location: SrcSpan {\n                                start: 14,\n                                end: 17,\n                            },\n                            value: \"a\",\n                        },\n                    ),\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_panic_and_messages.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"echo panic as \\\"a\\\" as \\\"b\\\"\"\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 24,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Panic {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 17,\n                    },\n                    message: Some(\n                        String {\n                            location: SrcSpan {\n                                start: 14,\n                                end: 17,\n                            },\n                            value: \"a\",\n                        },\n                    ),\n                },\n            ),\n            message: Some(\n                String {\n                    location: SrcSpan {\n                        start: 21,\n                        end: 24,\n                    },\n                    value: \"b\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_simple_expression_1.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo wibble as message\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 22,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 11,\n                    },\n                    name: \"wibble\",\n                },\n            ),\n            message: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 15,\n                        end: 22,\n                    },\n                    name: \"message\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__echo_with_simple_expression_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"echo wibble as \\\"message\\\"\"\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 24,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Var {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 11,\n                    },\n                    name: \"wibble\",\n                },\n            ),\n            message: Some(\n                String {\n                    location: SrcSpan {\n                        start: 15,\n                        end: 24,\n                    },\n                    value: \"message\",\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__error_message_on_variable_starting_with_underscore.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n  pub fn main() {\\n    let val = _func_starting_with_underscore(1)\\n  }\"\n---\n----- SOURCE CODE\n\n  pub fn main() {\n    let val = _func_starting_with_underscore(1)\n  }\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:15\n  │\n3 │     let val = _func_starting_with_underscore(1)\n  │               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I'm expecting a lowercase name here\n\nHint: Variable and module names start with a lowercase letter, and can contain\na-z, 0-9, or _.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__error_message_on_variable_starting_with_underscore2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n  pub fn main() {\\n    case 1 {\\n      1 -> _with_underscore(1)\\n    }\\n  }\"\n---\n----- SOURCE CODE\n\n  pub fn main() {\n    case 1 {\n      1 -> _with_underscore(1)\n    }\n  }\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:12\n  │\n4 │       1 -> _with_underscore(1)\n  │            ^^^^^^^^^^^^^^^^ I'm expecting a lowercase name here\n\nHint: Variable and module names start with a lowercase letter, and can contain\na-z, 0-9, or _.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    @external(erlang, \\\"one\\\", \\\"two\\\")\\n    Wibble1\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    @external(erlang, \"one\", \"two\")\n    Wibble1\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │     @external(erlang, \"one\", \"two\")\n  │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This attribute cannot be used on a variant.\n\nHint: Did you mean `@deprecated`?\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_with_custom_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@external(erlang, \\\"gleam_stdlib\\\", \\\"dict\\\")\\n@external(javascript, \\\"./gleam_stdlib.d.ts\\\", \\\"Dict\\\")\\npub type Dict(key, value)\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 96,\n                            end: 121,\n                        },\n                        end_position: 121,\n                        name: \"Dict\",\n                        name_location: SrcSpan {\n                            start: 105,\n                            end: 109,\n                        },\n                        publicity: Public,\n                        constructors: [],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: false,\n                        parameters: [\n                            (\n                                SrcSpan {\n                                    start: 110,\n                                    end: 113,\n                                },\n                                \"key\",\n                            ),\n                            (\n                                SrcSpan {\n                                    start: 115,\n                                    end: 120,\n                                },\n                                \"value\",\n                            ),\n                        ],\n                        typed_parameters: [],\n                        external_erlang: Some(\n                            (\n                                \"gleam_stdlib\",\n                                \"dict\",\n                                SrcSpan {\n                                    start: 1,\n                                    end: 42,\n                                },\n                            ),\n                        ),\n                        external_javascript: Some(\n                            (\n                                \"./gleam_stdlib.d.ts\",\n                                \"Dict\",\n                                SrcSpan {\n                                    start: 43,\n                                    end: 95,\n                                },\n                            ),\n                        ),\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [\n            0,\n            42,\n            95,\n            121,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_with_non_fn_definition.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@external(erlang, \\\"module\\\", \\\"fun\\\")\\npub type Fun = Fun\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"module\", \"fun\")\npub type Fun = Fun\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @external(erlang, \"module\", \"fun\")\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I was expecting a function definition after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__float_empty_exponent.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: 1.32e\n---\n----- SOURCE CODE\n1.32e\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:1\n  │\n1 │ 1.32e\n  │ ^^^^^ This float is missing an exponent\n\nHint: Add an exponent or remove the trailing `e`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__function_call_in_case_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet my_string = \\\"hello\\\"\\ncase my_string {\\n    _ if length(my_string) > 2 -> io.debug(\\\"doesn't work')\\n}\"\n---\n----- SOURCE CODE\n\nlet my_string = \"hello\"\ncase my_string {\n    _ if length(my_string) > 2 -> io.debug(\"doesn't work')\n}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:10\n  │\n4 │     _ if length(my_string) > 2 -> io.debug(\"doesn't work')\n  │          ^^^^^^^^^^^^^^^^^ Unsupported expression\n\nFunctions cannot be called in clause guards.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__function_definition_angle_generics_error.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"fn id<T>(x: T) { x }\"\n---\n----- SOURCE CODE\nfn id<T>(x: T) { x }\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:6\n  │\n1 │ fn id<T>(x: T) { x }\n  │      ^ I was expecting `(` here.\n\nGeneric function type variables do not need to be predeclared like they\nwould be in some other languages, instead they are written with lowercase\nnames.\n\n    fn example(argument: generic) -> generic\n\nSee: https://tour.gleam.run/functions/generic-functions/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__function_inside_a_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n  fn wobble() {}\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  fn wobble() {}\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:3\n  │\n3 │   fn wobble() {}\n  │   ^^ I was not expecting this\n\nFound the keyword `fn`, expected one of: \n- `}`\n- a record constructor\nHint: Gleam is not an object oriented programming language so\nfunctions are declared separately from types.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__function_invalid_signature.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn f(a, \\\"b\\\") -> String {\\n    a <> b\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn f(a, \"b\") -> String {\n    a <> b\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:9\n  │\n2 │ fn f(a, \"b\") -> String {\n  │         ^^^ I was not expecting this\n\nFound a String, expected one of: \n- `)`\n- a function parameter\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__function_type_invalid_param_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn f(g: fn(Int, 1) -> Int) -> Int {\\n  g(0, 1)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn f(g: fn(Int, 1) -> Int) -> Int {\n  g(0, 1)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:17\n  │\n2 │ fn f(g: fn(Int, 1) -> Int) -> Int {\n  │                 ^ I was not expecting this\n\nFound an Int, expected one of: \n- `)`\n- a type\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__if_like_expression.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  let a = if wibble {\\n    wobble\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = if wibble {\n    wobble\n  }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:11\n  │\n3 │   let a = if wibble {\n  │           ^^ Gleam doesn't have if expressions\n\nIf you want to write a conditional expression you can use a `case`:\n\n    case condition {\n      True -> todo\n      False -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/case-expressions/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__import_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"import wibble.{type Wobble, Wobble, type Wabble}\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: Import(\n                    Import {\n                        documentation: None,\n                        location: SrcSpan {\n                            start: 0,\n                            end: 48,\n                        },\n                        module_location: SrcSpan {\n                            start: 7,\n                            end: 13,\n                        },\n                        module: \"wibble\",\n                        as_name: None,\n                        unqualified_values: [\n                            UnqualifiedImport {\n                                location: SrcSpan {\n                                    start: 28,\n                                    end: 34,\n                                },\n                                imported_name_location: SrcSpan {\n                                    start: 28,\n                                    end: 34,\n                                },\n                                name: \"Wobble\",\n                                as_name: None,\n                            },\n                        ],\n                        unqualified_types: [\n                            UnqualifiedImport {\n                                location: SrcSpan {\n                                    start: 15,\n                                    end: 26,\n                                },\n                                imported_name_location: SrcSpan {\n                                    start: 20,\n                                    end: 26,\n                                },\n                                name: \"Wobble\",\n                                as_name: None,\n                            },\n                            UnqualifiedImport {\n                                location: SrcSpan {\n                                    start: 36,\n                                    end: 47,\n                                },\n                                imported_name_location: SrcSpan {\n                                    start: 41,\n                                    end: 47,\n                                },\n                                name: \"Wabble\",\n                                as_name: None,\n                            },\n                        ],\n                        package: (),\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__incomplete_function.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: fn()\n---\n----- SOURCE CODE\nfn()\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:1\n  │\n1 │ fn()\n  │ ^^^^ This function does not have a body\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__inner_single_quote_parses.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet a = \\\"inner 'quotes'\\\"\\n\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 1,\n                end: 25,\n            },\n            value: String {\n                location: SrcSpan {\n                    start: 9,\n                    end: 25,\n                },\n                value: \"inner 'quotes'\",\n            },\n            pattern: Variable {\n                location: SrcSpan {\n                    start: 5,\n                    end: 6,\n                },\n                name: \"a\",\n                type_: (),\n                origin: VariableOrigin {\n                    syntax: Variable(\n                        \"a\",\n                    ),\n                    declaration: LetPattern,\n                },\n            },\n            kind: Let,\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    @internal\\n    Wibble1\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    @internal\n    Wibble1\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │     @internal\n  │     ^^^^^^^^^ This attribute cannot be used on a variant.\n\nHint: Did you mean `@deprecated`?\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  wibble(:)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  wibble(:)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:10\n  │\n3 │   wibble(:)\n  │          ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_label_shorthand_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  wibble(:,)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  wibble(:,)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:10\n  │\n3 │   wibble(:,)\n  │          ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_label_shorthand_3.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  wibble(:arg)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  wibble(:arg)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:10\n  │\n3 │   wibble(:arg)\n  │          ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_label_shorthand_4.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  wibble(arg::)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  wibble(arg::)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:14\n  │\n3 │   wibble(arg::)\n  │              ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_label_shorthand_5.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  wibble(arg::arg)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  wibble(arg::arg)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:14\n  │\n3 │   wibble(arg::arg)\n  │              ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_left_paren_in_case_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet my_string = \\\"hello\\\"\\ncase my_string {\\n    _ if string.length( > 2 -> io.debug(\\\"doesn't work')\\n}\"\n---\n----- SOURCE CODE\n\nlet my_string = \"hello\"\ncase my_string {\n    _ if string.length( > 2 -> io.debug(\"doesn't work')\n}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:23\n  │\n4 │     _ if string.length( > 2 -> io.debug(\"doesn't work')\n  │                       ^ I was not expecting this\n\nFound `(`, expected one of: \n- `->`\nHint: Did you mean to wrap a multi line clause in curly braces?\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_pattern_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  let Wibble(:) = todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let Wibble(:) = todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:14\n  │\n3 │   let Wibble(:) = todo\n  │              ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_pattern_label_shorthand_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  let Wibble(:arg) = todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let Wibble(:arg) = todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:14\n  │\n3 │   let Wibble(:arg) = todo\n  │              ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_pattern_label_shorthand_3.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  let Wibble(arg::) = todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let Wibble(arg::) = todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:18\n  │\n3 │   let Wibble(arg::) = todo\n  │                  ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_pattern_label_shorthand_4.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  let Wibble(arg: arg:) = todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let Wibble(arg: arg:) = todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:22\n  │\n3 │   let Wibble(arg: arg:) = todo\n  │                      ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__invalid_pattern_label_shorthand_5.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  let Wibble(arg1: arg2:) = todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let Wibble(arg1: arg2:) = todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:24\n  │\n3 │   let Wibble(arg1: arg2:) = todo\n  │                        ^ I was not expecting this\n\nFound `:`, expected one of: \n- `)`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__list_spread_as_first_item_followed_by_other_items.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() -> Nil {\\n  let xs = [1, 2, 3]\\n  [..xs, 3 + 3, 4]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  [..xs, 3 + 3, 4]\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:4\n  │\n4 │   [..xs, 3 + 3, 4]\n  │    ^^^^ I wasn't expecting elements after this\n\nLists are immutable and singly-linked, so to append items to them\nall the elements of a list would need to be copied into a new list.\nThis would be slow, so there is no built-in syntax for it.\n\nHint: Prepend items to the list and then reverse it once you are done.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__list_spread_followed_by_extra_item_and_another_spread.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() -> Nil {\\n  let xs = [1, 2, 3]\\n  let ys = [5, 6, 7]\\n  [..xs, 4, ..ys]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  let ys = [5, 6, 7]\n  [..xs, 4, ..ys]\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:5:4\n  │\n5 │   [..xs, 4, ..ys]\n  │    ^^^^ I wasn't expecting elements after this\n\nLists are immutable and singly-linked, so to append items to them\nall the elements of a list would need to be copied into a new list.\nThis would be slow, so there is no built-in syntax for it.\n\nHint: Prepend items to the list and then reverse it once you are done.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__list_spread_followed_by_extra_items.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() -> Nil {\\n  let xs = [1, 2, 3]\\n  [1, 2, ..xs, 3 + 3, 4]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  [1, 2, ..xs, 3 + 3, 4]\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:10\n  │\n4 │   [1, 2, ..xs, 3 + 3, 4]\n  │          ^^^^ I wasn't expecting elements after this\n\nLists are immutable and singly-linked, so to append items to them\nall the elements of a list would need to be copied into a new list.\nThis would be slow, so there is no built-in syntax for it.\n\nHint: Prepend items to the list and then reverse it once you are done.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__list_spread_followed_by_other_spread.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nassertion_line: 959\nexpression: \"\\npub fn main() -> Nil {\\n  let xs = [1, 2, 3]\\n  let ys = [5, 6, 7]\\n  [1, ..xs, ..ys]\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  let ys = [5, 6, 7]\n  [1, ..xs, ..ys]\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:5:13\n  │\n5 │   [1, ..xs, ..ys]\n  │       --    ^^ I wasn't expecting a second list here\n  │       │      \n  │       You're using a list here\n\nLists are immutable and singly-linked, so to join two or more lists\nall the elements of the lists would need to be copied into a new list.\nThis would be slow, so there is no built-in syntax for it.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__list_spread_with_no_tail_in_the_middle_of_a_list.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() -> Nil {\\n  let xs = [1, 2, 3]\\n  [1, 2, .., 3 + 3, 4]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  [1, 2, .., 3 + 3, 4]\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:10\n  │\n4 │   [1, 2, .., 3 + 3, 4]\n  │          ^^ I was expecting a value after this spread\n\nIf a list expression has a spread then a tail must also be given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__missing_constructor_arguments.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub type A {\\n  A(Int)\\n}\\n\\nconst a = A()\\n\"\n---\n----- SOURCE CODE\n\npub type A {\n  A(Int)\n}\n\nconst a = A()\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:6:12\n  │\n6 │ const a = A()\n  │            ^^ I was expecting arguments here\n\nA record must be passed arguments when constructed.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__missing_target.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@target()\\npub fn one() {}\"\n---\n----- SOURCE CODE\n\n@target()\npub fn one() {}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:8\n  │\n2 │ @target()\n  │        ^ I was expecting a target name after this\n\nTry `erlang`, `javascript`.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__missing_target_and_bracket.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@target(\\npub fn one() {}\"\n---\n----- SOURCE CODE\n\n@target(\npub fn one() {}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:8\n  │\n2 │ @target(\n  │        ^ I was expecting a target name after this\n\nTry `erlang`, `javascript`.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__missing_type_constructor_arguments_in_type_definition.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub type A() {\\n  A(Int)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type A() {\n  A(Int)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:11\n  │\n2 │ pub type A() {\n  │           ^^ I was expecting generic parameters here\n\nA generic type must have at least a generic parameter.\nHint: If a type is not generic you should omit the `()`.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    @deprecated(\\\"1\\\")\\n    @deprecated(\\\"2\\\")\\n    Wibble1\\n    Wibble2\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    @deprecated(\"1\")\n    @deprecated(\"2\")\n    Wibble1\n    Wibble2\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:5\n  │\n4 │     @deprecated(\"2\")\n  │     ^^^^^^^^^^^ Duplicate attribute\n\nThis attribute has already been given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attributes.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@deprecated(\\\"1\\\")\\n@deprecated(\\\"2\\\")\\npub fn main() -> Nil {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\n@deprecated(\"1\")\n@deprecated(\"2\")\npub fn main() -> Nil {\n  Nil\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:1\n  │\n3 │ @deprecated(\"2\")\n  │ ^^^^^^^^^^^ Duplicate attribute\n\nThis attribute has already been given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_external_for_same_project_erlang.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@external(erlang, \\\"one\\\", \\\"two\\\")\\n@external(erlang, \\\"three\\\", \\\"four\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"one\", \"two\")\n@external(erlang, \"three\", \"four\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:1\n  │\n3 │ @external(erlang, \"three\", \"four\")\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Duplicate attribute\n\nThis attribute has already been given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_external_for_same_project_javascript.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@external(javascript, \\\"one\\\", \\\"two\\\")\\n@external(javascript, \\\"three\\\", \\\"four\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"one\", \"two\")\n@external(javascript, \"three\", \"four\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:1\n  │\n3 │ @external(javascript, \"three\", \"four\")\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Duplicate attribute\n\nThis attribute has already been given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_internal_attributes.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@internal\\n@internal\\npub fn main() -> Nil {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\n@internal\n@internal\npub fn main() -> Nil {\n  Nil\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:1\n  │\n3 │ @internal\n  │ ^^^^^^^^^ Duplicate attribute\n\nThis attribute has already been given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    @external(erlang, \\\"one\\\", \\\"two\\\")\\n    @target(erlang)\\n    @internal\\n    Wibble1\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    @external(erlang, \"one\", \"two\")\n    @target(erlang)\n    @internal\n    Wibble1\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │  \n3 │ ╭     @external(erlang, \"one\", \"two\")\n4 │ │     @target(erlang)\n5 │ │     @internal\n  │ ╰─────────────^ This attribute cannot be used on a variant.\n\nHint: Did you mean `@deprecated`?\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_block.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"{ 1 { 1.0 2.0 } 3 }\"\n---\n[\n    Expression(\n        Block {\n            location: SrcSpan {\n                start: 0,\n                end: 19,\n            },\n            statements: [\n                Expression(\n                    Int {\n                        location: SrcSpan {\n                            start: 2,\n                            end: 3,\n                        },\n                        value: \"1\",\n                        int_value: 1,\n                    },\n                ),\n                Expression(\n                    Block {\n                        location: SrcSpan {\n                            start: 4,\n                            end: 15,\n                        },\n                        statements: [\n                            Expression(\n                                Float {\n                                    location: SrcSpan {\n                                        start: 6,\n                                        end: 9,\n                                    },\n                                    value: \"1.0\",\n                                    float_value: LiteralFloatValue(\n                                        1.0,\n                                    ),\n                                },\n                            ),\n                            Expression(\n                                Float {\n                                    location: SrcSpan {\n                                        start: 10,\n                                        end: 13,\n                                    },\n                                    value: \"2.0\",\n                                    float_value: LiteralFloatValue(\n                                        2.0,\n                                    ),\n                                },\n                            ),\n                        ],\n                    },\n                ),\n                Expression(\n                    Int {\n                        location: SrcSpan {\n                            start: 16,\n                            end: 17,\n                        },\n                        value: \"3\",\n                        int_value: 3,\n                    },\n                ),\n            ],\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_tuple_access_after_function.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: tuple().0.1\n---\n[\n    Expression(\n        TupleIndex {\n            location: SrcSpan {\n                start: 0,\n                end: 11,\n            },\n            index: 1,\n            tuple: TupleIndex {\n                location: SrcSpan {\n                    start: 0,\n                    end: 9,\n                },\n                index: 0,\n                tuple: Call {\n                    location: SrcSpan {\n                        start: 0,\n                        end: 7,\n                    },\n                    fun: Var {\n                        location: SrcSpan {\n                            start: 0,\n                            end: 5,\n                        },\n                        name: \"tuple\",\n                    },\n                    arguments: [],\n                },\n            },\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_tuples.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet tup = #(#(5, 6))\\n{tup.0}.1\\n\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 1,\n                end: 21,\n            },\n            value: Tuple {\n                location: SrcSpan {\n                    start: 11,\n                    end: 21,\n                },\n                elements: [\n                    Tuple {\n                        location: SrcSpan {\n                            start: 13,\n                            end: 20,\n                        },\n                        elements: [\n                            Int {\n                                location: SrcSpan {\n                                    start: 15,\n                                    end: 16,\n                                },\n                                value: \"5\",\n                                int_value: 5,\n                            },\n                            Int {\n                                location: SrcSpan {\n                                    start: 18,\n                                    end: 19,\n                                },\n                                value: \"6\",\n                                int_value: 6,\n                            },\n                        ],\n                    },\n                ],\n            },\n            pattern: Variable {\n                location: SrcSpan {\n                    start: 5,\n                    end: 8,\n                },\n                name: \"tup\",\n                type_: (),\n                origin: VariableOrigin {\n                    syntax: Variable(\n                        \"tup\",\n                    ),\n                    declaration: LetPattern,\n                },\n            },\n            kind: Let,\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n    Expression(\n        TupleIndex {\n            location: SrcSpan {\n                start: 22,\n                end: 31,\n            },\n            index: 1,\n            tuple: Block {\n                location: SrcSpan {\n                    start: 22,\n                    end: 29,\n                },\n                statements: [\n                    Expression(\n                        TupleIndex {\n                            location: SrcSpan {\n                                start: 23,\n                                end: 28,\n                            },\n                            index: 0,\n                            tuple: Var {\n                                location: SrcSpan {\n                                    start: 23,\n                                    end: 26,\n                                },\n                                name: \"tup\",\n                            },\n                        },\n                    ),\n                ],\n            },\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_tuples_no_block.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet tup = #(#(5, 6))\\ntup.0.1\\n\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 1,\n                end: 21,\n            },\n            value: Tuple {\n                location: SrcSpan {\n                    start: 11,\n                    end: 21,\n                },\n                elements: [\n                    Tuple {\n                        location: SrcSpan {\n                            start: 13,\n                            end: 20,\n                        },\n                        elements: [\n                            Int {\n                                location: SrcSpan {\n                                    start: 15,\n                                    end: 16,\n                                },\n                                value: \"5\",\n                                int_value: 5,\n                            },\n                            Int {\n                                location: SrcSpan {\n                                    start: 18,\n                                    end: 19,\n                                },\n                                value: \"6\",\n                                int_value: 6,\n                            },\n                        ],\n                    },\n                ],\n            },\n            pattern: Variable {\n                location: SrcSpan {\n                    start: 5,\n                    end: 8,\n                },\n                name: \"tup\",\n                type_: (),\n                origin: VariableOrigin {\n                    syntax: Variable(\n                        \"tup\",\n                    ),\n                    declaration: LetPattern,\n                },\n            },\n            kind: Let,\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n    Expression(\n        TupleIndex {\n            location: SrcSpan {\n                start: 22,\n                end: 29,\n            },\n            index: 1,\n            tuple: TupleIndex {\n                location: SrcSpan {\n                    start: 22,\n                    end: 27,\n                },\n                index: 0,\n                tuple: Var {\n                    location: SrcSpan {\n                        start: 22,\n                        end: 25,\n                    },\n                    name: \"tup\",\n                },\n            },\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__no_eq_after_binding_snapshot_1.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: let wibble\n---\n----- SOURCE CODE\nlet wibble\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:5\n  │\n1 │ let wibble\n  │     ^^^^^^ I was expecting a '=' after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__no_eq_after_binding_snapshot_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let wibble\\n        wibble = 4\"\n---\n----- SOURCE CODE\nlet wibble\n        wibble = 4\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:5\n  │\n1 │ let wibble\n  │     ^^^^^^ I was expecting a '=' after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__no_let_binding_snapshot_1.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: wibble = 4\n---\n----- SOURCE CODE\nwibble = 4\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:8\n  │\n1 │ wibble = 4\n  │        ^ There must be a 'let' to bind variable to value\n\nSee: https://tour.gleam.run/basics/assignments/\nHint: Use let for binding.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__no_let_binding_snapshot_2.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"wibble:Int = 4\"\n---\n----- SOURCE CODE\nwibble:Int = 4\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ wibble:Int = 4\n  │       ^ There must be a 'let' to bind variable to value\n\nSee: https://tour.gleam.run/basics/assignments/\nHint: Use let for binding.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__no_let_binding_snapshot_3.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let wobble:Int = 32\\n        wobble = 42\"\n---\n----- SOURCE CODE\nlet wobble:Int = 32\n        wobble = 42\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:16\n  │\n2 │         wobble = 42\n  │                ^ There must be a 'let' to bind variable to value\n\nSee: https://tour.gleam.run/basics/assignments/\nHint: Use let for binding.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__non_module_level_function_with_a_name.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  fn my() { 1 }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  fn my() { 1 }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:6\n  │\n3 │   fn my() { 1 }\n  │      ^^ I was not expecting this\n\nFound a name, expected one of: \n- `(`\nHint: Only module-level functions can be named.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__non_module_level_function_with_not_a_name.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  fn @() { 1 }  // wrong token and not a name\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  fn @() { 1 }  // wrong token and not a name\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:6\n  │\n3 │   fn @() { 1 }  // wrong token and not a name\n  │      ^ I was not expecting this\n\nFound `@`, expected one of: \n- `(`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__operator_in_pattern_size.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let assert <<size, payload:size(size - 1)>> = <<>>\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 0,\n                end: 50,\n            },\n            value: BitArray {\n                location: SrcSpan {\n                    start: 46,\n                    end: 50,\n                },\n                segments: [],\n            },\n            pattern: BitArray {\n                location: SrcSpan {\n                    start: 11,\n                    end: 43,\n                },\n                segments: [\n                    BitArraySegment {\n                        location: SrcSpan {\n                            start: 13,\n                            end: 17,\n                        },\n                        value: Variable {\n                            location: SrcSpan {\n                                start: 13,\n                                end: 17,\n                            },\n                            name: \"size\",\n                            type_: (),\n                            origin: VariableOrigin {\n                                syntax: Variable(\n                                    \"size\",\n                                ),\n                                declaration: LetPattern,\n                            },\n                        },\n                        options: [],\n                        type_: (),\n                    },\n                    BitArraySegment {\n                        location: SrcSpan {\n                            start: 19,\n                            end: 41,\n                        },\n                        value: Variable {\n                            location: SrcSpan {\n                                start: 19,\n                                end: 26,\n                            },\n                            name: \"payload\",\n                            type_: (),\n                            origin: VariableOrigin {\n                                syntax: Variable(\n                                    \"payload\",\n                                ),\n                                declaration: LetPattern,\n                            },\n                        },\n                        options: [\n                            Size {\n                                location: SrcSpan {\n                                    start: 27,\n                                    end: 41,\n                                },\n                                value: BitArraySize(\n                                    BinaryOperator {\n                                        location: SrcSpan {\n                                            start: 32,\n                                            end: 40,\n                                        },\n                                        operator: Subtract,\n                                        left: Variable {\n                                            location: SrcSpan {\n                                                start: 32,\n                                                end: 36,\n                                            },\n                                            name: \"size\",\n                                            constructor: None,\n                                            type_: (),\n                                        },\n                                        right: Int {\n                                            location: SrcSpan {\n                                                start: 39,\n                                                end: 40,\n                                            },\n                                            value: \"1\",\n                                            int_value: 1,\n                                        },\n                                    },\n                                ),\n                                short_form: false,\n                            },\n                        ],\n                        type_: (),\n                    },\n                ],\n            },\n            kind: Assert {\n                location: SrcSpan {\n                    start: 0,\n                    end: 10,\n                },\n                assert_keyword_start: 4,\n                message: None,\n            },\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__panic_with_echo.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"panic as echo \\\"string\\\"\"\n---\n[\n    Expression(\n        Panic {\n            location: SrcSpan {\n                start: 0,\n                end: 22,\n            },\n            message: Some(\n                Echo {\n                    location: SrcSpan {\n                        start: 9,\n                        end: 22,\n                    },\n                    keyword_end: 13,\n                    expression: Some(\n                        String {\n                            location: SrcSpan {\n                                start: 14,\n                                end: 22,\n                            },\n                            value: \"string\",\n                        },\n                    ),\n                    message: None,\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__panic_with_echo_and_message.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: panic as echo wibble as message\n---\n[\n    Expression(\n        Panic {\n            location: SrcSpan {\n                start: 0,\n                end: 31,\n            },\n            message: Some(\n                Echo {\n                    location: SrcSpan {\n                        start: 9,\n                        end: 31,\n                    },\n                    keyword_end: 13,\n                    expression: Some(\n                        Var {\n                            location: SrcSpan {\n                                start: 14,\n                                end: 20,\n                            },\n                            name: \"wibble\",\n                        },\n                    ),\n                    message: Some(\n                        Var {\n                            location: SrcSpan {\n                                start: 24,\n                                end: 31,\n                            },\n                            name: \"message\",\n                        },\n                    ),\n                },\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__prepend_no_elements_to_const_list.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst wibble = [2, 3]\\nconst wobble = [..wibble]\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [2, 3]\nconst wobble = [..wibble]\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:16\n  │\n3 │ const wobble = [..wibble]\n  │                ^^^^^^^^^^ This spread does nothing\n\nSee: https://tour.gleam.run/basics/lists/\nHint: Try prepending some elements [1, 2, ..list].\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__prepend_to_const_list_with_multiple_spreads.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst wibble = [2, 3]\\nconst wobble = [0, 1]\\nconst wubble = [..wobble, ..wibble]\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [2, 3]\nconst wobble = [0, 1]\nconst wubble = [..wobble, ..wibble]\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:27\n  │\n4 │ const wubble = [..wobble, ..wibble]\n  │                 --        ^^ I wasn't expecting a second list here\n  │                 │          \n  │                 You're using a list here\n\nLists are immutable and singly-linked, so to join two or more lists\nall the elements of the lists would need to be copied into a new list.\nThis would be slow, so there is no built-in syntax for it.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__prepend_to_const_list_with_no_tail.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst wibble = [1, 2, ..]\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [1, 2, ..]\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:23\n  │\n2 │ const wibble = [1, 2, ..]\n  │                       ^^ I was expecting a value after this spread\n\nIf a list expression has a spread then a tail must also be given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__prepend_to_const_list_without_comma.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nconst wibble = [2, 3]\\nconst wobble = [1 ..wibble]\\n\"\n---\n----- SOURCE CODE\n\nconst wibble = [2, 3]\nconst wobble = [1 ..wibble]\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:19\n  │\n3 │ const wobble = [1 ..wibble]\n  │                   ^^ I was not expecting this\n\nFound `..`, expected one of: \n- `]`\n- a constant value\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__private_internal_const.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@internal\\nconst wibble = 1\\n\"\n---\n----- SOURCE CODE\n\n@internal\nconst wibble = 1\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ Redundant internal attribute\n\nOnly a public definition can be annotated as internal.\nHint: Remove the `@internal` annotation.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__private_internal_function.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@internal\\nfn wibble() { todo }\\n\"\n---\n----- SOURCE CODE\n\n@internal\nfn wibble() { todo }\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ Redundant internal attribute\n\nOnly a public definition can be annotated as internal.\nHint: Remove the `@internal` annotation.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__private_internal_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@internal\\ntype Wibble {\\n  Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\n@internal\ntype Wibble {\n  Wibble\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ Redundant internal attribute\n\nOnly a public definition can be annotated as internal.\nHint: Remove the `@internal` annotation.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__private_internal_type_alias.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@internal\\ntype Alias = Int\\n\"\n---\n----- SOURCE CODE\n\n@internal\ntype Alias = Int\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ Redundant internal attribute\n\nOnly a public definition can be annotated as internal.\nHint: Remove the `@internal` annotation.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__private_opaque_type_is_parsed.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"opaque type Wibble { Wobble }\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 0,\n                            end: 18,\n                        },\n                        end_position: 29,\n                        name: \"Wibble\",\n                        name_location: SrcSpan {\n                            start: 12,\n                            end: 18,\n                        },\n                        publicity: Private,\n                        constructors: [\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 21,\n                                    end: 27,\n                                },\n                                name_location: SrcSpan {\n                                    start: 21,\n                                    end: 27,\n                                },\n                                name: \"Wobble\",\n                                arguments: [],\n                                documentation: None,\n                                deprecation: NotDeprecated,\n                            },\n                        ],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: true,\n                        parameters: [],\n                        typed_parameters: [],\n                        external_erlang: None,\n                        external_javascript: None,\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [],\n        new_lines: [],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__pub_function_inside_a_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n  pub fn wobble() {}\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  pub fn wobble() {}\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:3\n  │\n3 │   pub fn wobble() {}\n  │   ^^^ I was not expecting this\n\nFound the keyword `pub`, expected one of: \n- `}`\n- a record constructor\nHint: Gleam is not an object oriented programming language so\nfunctions are declared separately from types.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(wibble: String)\\n}\\n\\nfn wobble() {\\n  Wibble(\\\"a\\\").\\n}\\n\"\n---\nParsed {\n    module: Module {\n        name: \"\",\n        documentation: [],\n        type_info: (),\n        definitions: [\n            TargetedDefinition {\n                definition: CustomType(\n                    CustomType {\n                        location: SrcSpan {\n                            start: 1,\n                            end: 12,\n                        },\n                        end_position: 43,\n                        name: \"Wibble\",\n                        name_location: SrcSpan {\n                            start: 6,\n                            end: 12,\n                        },\n                        publicity: Private,\n                        constructors: [\n                            RecordConstructor {\n                                location: SrcSpan {\n                                    start: 19,\n                                    end: 41,\n                                },\n                                name_location: SrcSpan {\n                                    start: 19,\n                                    end: 25,\n                                },\n                                name: \"Wibble\",\n                                arguments: [\n                                    RecordConstructorArg {\n                                        label: Some(\n                                            (\n                                                SrcSpan {\n                                                    start: 26,\n                                                    end: 32,\n                                                },\n                                                \"wibble\",\n                                            ),\n                                        ),\n                                        ast: Constructor(\n                                            TypeAstConstructor {\n                                                location: SrcSpan {\n                                                    start: 34,\n                                                    end: 40,\n                                                },\n                                                name_location: SrcSpan {\n                                                    start: 34,\n                                                    end: 40,\n                                                },\n                                                module: None,\n                                                name: \"String\",\n                                                arguments: [],\n                                                start_parentheses: None,\n                                            },\n                                        ),\n                                        location: SrcSpan {\n                                            start: 26,\n                                            end: 40,\n                                        },\n                                        type_: (),\n                                        doc: None,\n                                    },\n                                ],\n                                documentation: None,\n                                deprecation: NotDeprecated,\n                            },\n                        ],\n                        documentation: None,\n                        deprecation: NotDeprecated,\n                        opaque: false,\n                        parameters: [],\n                        typed_parameters: [],\n                        external_erlang: None,\n                        external_javascript: None,\n                    },\n                ),\n                target: None,\n            },\n            TargetedDefinition {\n                definition: Function(\n                    Function {\n                        location: SrcSpan {\n                            start: 45,\n                            end: 56,\n                        },\n                        body_start: Some(\n                            57,\n                        ),\n                        end_position: 75,\n                        name: Some(\n                            (\n                                SrcSpan {\n                                    start: 48,\n                                    end: 54,\n                                },\n                                \"wobble\",\n                            ),\n                        ),\n                        arguments: [],\n                        body: [\n                            Expression(\n                                FieldAccess {\n                                    location: SrcSpan {\n                                        start: 61,\n                                        end: 73,\n                                    },\n                                    label_location: SrcSpan {\n                                        start: 72,\n                                        end: 73,\n                                    },\n                                    label: \"\",\n                                    container: Call {\n                                        location: SrcSpan {\n                                            start: 61,\n                                            end: 72,\n                                        },\n                                        fun: Var {\n                                            location: SrcSpan {\n                                                start: 61,\n                                                end: 67,\n                                            },\n                                            name: \"Wibble\",\n                                        },\n                                        arguments: [\n                                            CallArg {\n                                                label: None,\n                                                location: SrcSpan {\n                                                    start: 68,\n                                                    end: 71,\n                                                },\n                                                value: String {\n                                                    location: SrcSpan {\n                                                        start: 68,\n                                                        end: 71,\n                                                    },\n                                                    value: \"a\",\n                                                },\n                                                implicit: None,\n                                            },\n                                        ],\n                                    },\n                                },\n                            ),\n                        ],\n                        publicity: Private,\n                        deprecation: NotDeprecated,\n                        return_annotation: None,\n                        return_type: (),\n                        documentation: None,\n                        external_erlang: None,\n                        external_javascript: None,\n                        implementations: Implementations {\n                            gleam: true,\n                            can_run_on_erlang: true,\n                            can_run_on_javascript: true,\n                            uses_erlang_externals: false,\n                            uses_javascript_externals: false,\n                        },\n                        purity: Pure,\n                    },\n                ),\n                target: None,\n            },\n        ],\n        names: Names {\n            local_types: {},\n            imported_modules: {},\n            type_variables: {},\n            local_value_constructors: {},\n            reexport_aliases: {},\n        },\n        unused_definition_positions: {},\n    },\n    extra: ModuleExtra {\n        module_comments: [],\n        doc_comments: [],\n        comments: [],\n        empty_lines: [\n            44,\n        ],\n        new_lines: [\n            0,\n            14,\n            41,\n            43,\n            44,\n            58,\n            73,\n            75,\n        ],\n        trailing_commas: [],\n    },\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__repeated_echos.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: echo echo echo 1\n---\n[\n    Expression(\n        Echo {\n            location: SrcSpan {\n                start: 0,\n                end: 16,\n            },\n            keyword_end: 4,\n            expression: Some(\n                Echo {\n                    location: SrcSpan {\n                        start: 5,\n                        end: 16,\n                    },\n                    keyword_end: 9,\n                    expression: Some(\n                        Echo {\n                            location: SrcSpan {\n                                start: 10,\n                                end: 16,\n                            },\n                            keyword_end: 14,\n                            expression: Some(\n                                Int {\n                                    location: SrcSpan {\n                                        start: 15,\n                                        end: 16,\n                                    },\n                                    value: \"1\",\n                                    int_value: 1,\n                                },\n                            ),\n                            message: None,\n                        },\n                    ),\n                    message: None,\n                },\n            ),\n            message: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_auto.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const auto = 1\n---\n----- SOURCE CODE\nconst auto = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const auto = 1\n  │       ^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_delegate.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const delegate = 1\n---\n----- SOURCE CODE\nconst delegate = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const delegate = 1\n  │       ^^^^^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_derive.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const derive = 1\n---\n----- SOURCE CODE\nconst derive = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const derive = 1\n  │       ^^^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_echo.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const echo = 1\n---\n----- SOURCE CODE\nconst echo = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const echo = 1\n  │       ^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_else.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const else = 1\n---\n----- SOURCE CODE\nconst else = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const else = 1\n  │       ^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_implement.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const implement = 1\n---\n----- SOURCE CODE\nconst implement = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const implement = 1\n  │       ^^^^^^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_macro.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const macro = 1\n---\n----- SOURCE CODE\nconst macro = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const macro = 1\n  │       ^^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__reserved_test.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: const test = 1\n---\n----- SOURCE CODE\nconst test = 1\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:7\n  │\n1 │ const test = 1\n  │       ^^^^ This is a reserved word\n\nHint: I was expecting to see a name here.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__semicolons.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"{ 2 + 3; - -5; }\"\n---\n----- SOURCE CODE\n{ 2 + 3; - -5; }\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:8\n  │\n1 │ { 2 + 3; - -5; }\n  │        ^ Remove this semicolon\n\nHint: Semicolons used to be whitespace and did nothing.\nYou can safely remove them without your program changing.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__special_error_for_pythonic_import.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: import gleam.io\n---\n----- SOURCE CODE\nimport gleam.io\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:13\n  │\n1 │ import gleam.io\n  │             ^ I was expecting either `/` or `.{` here.\n\nPerhaps you meant one of:\n\n    import gleam/io\n    import gleam.{item}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__special_error_for_pythonic_neste_import.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: import one.two.three\n---\n----- SOURCE CODE\nimport one.two.three\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:11\n  │\n1 │ import one.two.three\n  │           ^ I was expecting either `/` or `.{` here.\n\nPerhaps you meant one of:\n\n    import one/two\n    import one.{item}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__string_concatenation_in_case_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nlet my_string = \\\"hello \\\"\\ncase my_string {\\n    _ if my_string <> \\\"world\\\" == \\\"hello world\\\" -> io.debug(\\\"ok\\\")\\n}\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 1,\n                end: 25,\n            },\n            value: String {\n                location: SrcSpan {\n                    start: 17,\n                    end: 25,\n                },\n                value: \"hello \",\n            },\n            pattern: Variable {\n                location: SrcSpan {\n                    start: 5,\n                    end: 14,\n                },\n                name: \"my_string\",\n                type_: (),\n                origin: VariableOrigin {\n                    syntax: Variable(\n                        \"my_string\",\n                    ),\n                    declaration: LetPattern,\n                },\n            },\n            kind: Let,\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n    Expression(\n        Case {\n            location: SrcSpan {\n                start: 26,\n                end: 109,\n            },\n            subjects: [\n                Var {\n                    location: SrcSpan {\n                        start: 31,\n                        end: 40,\n                    },\n                    name: \"my_string\",\n                },\n            ],\n            clauses: Some(\n                [\n                    Clause {\n                        location: SrcSpan {\n                            start: 47,\n                            end: 107,\n                        },\n                        pattern: [\n                            Discard {\n                                name: \"_\",\n                                location: SrcSpan {\n                                    start: 47,\n                                    end: 48,\n                                },\n                                type_: (),\n                            },\n                        ],\n                        alternative_patterns: [],\n                        guard: Some(\n                            BinaryOperator {\n                                location: SrcSpan {\n                                    start: 52,\n                                    end: 89,\n                                },\n                                operator: Eq,\n                                left: BinaryOperator {\n                                    location: SrcSpan {\n                                        start: 52,\n                                        end: 72,\n                                    },\n                                    operator: Concatenate,\n                                    left: Var {\n                                        location: SrcSpan {\n                                            start: 52,\n                                            end: 61,\n                                        },\n                                        type_: (),\n                                        name: \"my_string\",\n                                        definition_location: SrcSpan {\n                                            start: 0,\n                                            end: 0,\n                                        },\n                                        origin: VariableOrigin {\n                                            syntax: Generated,\n                                            declaration: Generated,\n                                        },\n                                    },\n                                    right: Constant(\n                                        String {\n                                            location: SrcSpan {\n                                                start: 65,\n                                                end: 72,\n                                            },\n                                            value: \"world\",\n                                        },\n                                    ),\n                                },\n                                right: Constant(\n                                    String {\n                                        location: SrcSpan {\n                                            start: 76,\n                                            end: 89,\n                                        },\n                                        value: \"hello world\",\n                                    },\n                                ),\n                            },\n                        ),\n                        then: Call {\n                            location: SrcSpan {\n                                start: 93,\n                                end: 107,\n                            },\n                            fun: FieldAccess {\n                                location: SrcSpan {\n                                    start: 93,\n                                    end: 101,\n                                },\n                                label_location: SrcSpan {\n                                    start: 96,\n                                    end: 101,\n                                },\n                                label: \"debug\",\n                                container: Var {\n                                    location: SrcSpan {\n                                        start: 93,\n                                        end: 95,\n                                    },\n                                    name: \"io\",\n                                },\n                            },\n                            arguments: [\n                                CallArg {\n                                    label: None,\n                                    location: SrcSpan {\n                                        start: 102,\n                                        end: 106,\n                                    },\n                                    value: String {\n                                        location: SrcSpan {\n                                            start: 102,\n                                            end: 106,\n                                        },\n                                        value: \"ok\",\n                                    },\n                                    implicit: None,\n                                },\n                            ],\n                        },\n                    },\n                ],\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__string_single_char_suggestion.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n    pub fn main() {\\n        let a = 'example'\\n      }\\n    \"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        let a = 'example'\n      }\n    \n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:17\n  │\n3 │         let a = 'example'\n  │                 ^ Unexpected single quote\n\nHint: Strings are written with double quotes.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Wibble {\\n    @target(erlang)\\n    Wibble2\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    @target(erlang)\n    Wibble2\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │     @target(erlang)\n  │     ^^^^^^^^^^^^^^^ This attribute cannot be used on a variant.\n\nHint: Did you mean `@deprecated`?\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__tuple_invalid_expr.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    #(1, 2, const)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    #(1, 2, const)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:13\n  │\n3 │     #(1, 2, const)\n  │             ^^^^^ I was not expecting this\n\nFound the keyword `const`, expected one of: \n- `)`\n- an expression\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__tuple_without_hash.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n    let triple = (1, 2.2, \\\"three\\\")\\n    io.debug(triple)\\n    let (a, *, *) = triple\\n    io.debug(a)\\n    io.debug(triple.1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let triple = (1, 2.2, \"three\")\n    io.debug(triple)\n    let (a, *, *) = triple\n    io.debug(a)\n    io.debug(triple.1)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:18\n  │\n3 │     let triple = (1, 2.2, \"three\")\n  │                  ^ This parenthesis cannot be understood here\n\nHint: To group expressions in Gleam, use \"{\" and \"}\"; tuples are created with `#(` and `)`.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_angle_generics_definition_error.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Either<a, b> {\\n    This(a)\\n    That(b)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Either<a, b> {\n    This(a)\n    That(b)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:12\n  │\n2 │ type Either<a, b> {\n  │            ^ I was expecting `(` here.\n\nType parameters use lowercase names and are surrounded by parentheses.\n\n    type Either(a, b) {\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_angle_generics_definition_error_fallback.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Either<type A, type B> {\\n    This(A)\\n    That(B)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Either<type A, type B> {\n    This(A)\n    That(B)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:12\n  │\n2 │ type Either<type A, type B> {\n  │            ^ I was expecting `(` here.\n\nType parameters use lowercase names and are surrounded by parentheses.\n\n    type Either(value) {\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_angle_generics_definition_with_upname_error.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype Either<A, B> {\\n    This(A)\\n    That(B)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Either<A, B> {\n    This(A)\n    That(B)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:12\n  │\n2 │ type Either<A, B> {\n  │            ^ I was expecting `(` here.\n\nType parameters use lowercase names and are surrounded by parentheses.\n\n    type Either(a, b) {\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_angle_generics_usage_with_module_error.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let set: set.Set<Int> = set.new()\"\n---\n----- SOURCE CODE\nlet set: set.Set<Int> = set.new()\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:17\n  │\n1 │ let set: set.Set<Int> = set.new()\n  │                 ^ I was expecting `(` here.\n\nType parameters use lowercase names and are surrounded by parentheses.\n\n    set.Set(Int)\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_angle_generics_usage_without_module_error.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let list: List<Int, String> = []\"\n---\n----- SOURCE CODE\nlet list: List<Int, String> = []\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:15\n  │\n1 │ let list: List<Int, String> = []\n  │               ^ I was expecting `(` here.\n\nType parameters use lowercase names and are surrounded by parentheses.\n\n    List(Int, String)\n\nSee: https://tour.gleam.run/data-types/generic-custom-types/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_constructor.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype A {\\n    A(String)\\n    type\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype A {\n    A(String)\n    type\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:5\n  │\n4 │     type\n  │     ^^^^ I was not expecting this\n\nFound the keyword `type`, expected one of: \n- `}`\n- a record constructor\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_constructor_arg.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype A {\\n    A(type: String)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype A {\n    A(type: String)\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:7\n  │\n3 │     A(type: String)\n  │       ^^^^ I was not expecting this\n\nFound the keyword `type`, expected one of: \n- `)`\n- a constructor argument name\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_record.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype A {\\n    One\\n    Two\\n    3\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype A {\n    One\n    Two\n    3\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:5:5\n  │\n5 │     3\n  │     ^ I was not expecting this\n\nFound an Int, expected one of: \n- `}`\n- a record constructor\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_record_constructor.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub type User {\\n    name: String,\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type User {\n    name: String,\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │     name: String,\n  │     ^^^^ I was not expecting this\n\nEach custom type variant must have a constructor:\n\npub type User {\n  User(\n    name: String,\n  )\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_record_constructor_invalid_field_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype User {\\n    name: \\\"Test User\\\",\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype User {\n    name: \"Test User\",\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │     name: \"Test User\",\n  │     ^^^^ I was not expecting this\n\nEach custom type variant must have a constructor:\n\ntype User {\n  User(\n    name: Type,\n  )\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_record_constructor_without_field_type.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub opaque type User {\\n    name\\n}\\n\"\n---\n----- SOURCE CODE\n\npub opaque type User {\n    name\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │     name\n  │     ^^^^ I was not expecting this\n\nEach custom type variant must have a constructor:\n\npub opaque type User {\n  User(\n    name: Type,\n  )\n}\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__type_invalid_type_name.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\ntype A(a, type) {\\n    A\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype A(a, type) {\n    A\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:11\n  │\n2 │ type A(a, type) {\n  │           ^^^^ I was not expecting this\n\nFound the keyword `type`, expected one of: \n- `)`\n- a name\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__unknown_attribute.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"@go_faster()\\npub fn main() { 1 }\"\n---\n----- SOURCE CODE\n@go_faster()\npub fn main() { 1 }\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:1\n  │\n1 │ @go_faster()\n  │ ^^^^^^^^^^ I don't recognise this attribute\n\nHint: Try `deprecated`, `external` or `internal` instead.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__unknown_external_target.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@external(erl, \\\"one\\\", \\\"two\\\")\\npub fn one(x: Int) -> Int {\\n  todo\\n}\"\n---\n----- SOURCE CODE\n\n@external(erl, \"one\", \"two\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:1\n  │\n2 │ @external(erl, \"one\", \"two\")\n  │ ^^^^^^^^^ I don't recognise this target\n\nTry `erlang`, `javascript`.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__unknown_target.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\n@target(abc)\\npub fn one() {}\"\n---\n----- SOURCE CODE\n\n@target(abc)\npub fn one() {}\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:9\n  │\n2 │ @target(abc)\n  │         ^^^ I don't recognise this target\n\nTry `erlang`, `javascript`.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__use_invalid_assignments.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\nfn main() {\\n    use fn <- result.try(get_username())\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn main() {\n    use fn <- result.try(get_username())\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:9\n  │\n3 │     use fn <- result.try(get_username())\n  │         ^ I was expecting a pattern after this\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__valueless_list_spread_expression.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let x = [1, 2, 3, ..]\"\n---\n----- SOURCE CODE\nlet x = [1, 2, 3, ..]\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:1:19\n  │\n1 │ let x = [1, 2, 3, ..]\n  │                   ^^ I was expecting a value after this spread\n\nIf a list expression has a spread then a tail must also be given.\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__with_let_binding3.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let assert [x] = [2]\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 0,\n                end: 20,\n            },\n            value: List {\n                location: SrcSpan {\n                    start: 17,\n                    end: 20,\n                },\n                elements: [\n                    Int {\n                        location: SrcSpan {\n                            start: 18,\n                            end: 19,\n                        },\n                        value: \"2\",\n                        int_value: 2,\n                    },\n                ],\n                tail: None,\n            },\n            pattern: List {\n                location: SrcSpan {\n                    start: 11,\n                    end: 14,\n                },\n                elements: [\n                    Variable {\n                        location: SrcSpan {\n                            start: 12,\n                            end: 13,\n                        },\n                        name: \"x\",\n                        type_: (),\n                        origin: VariableOrigin {\n                            syntax: Variable(\n                                \"x\",\n                            ),\n                            declaration: LetPattern,\n                        },\n                    },\n                ],\n                tail: None,\n                type_: (),\n            },\n            kind: Assert {\n                location: SrcSpan {\n                    start: 0,\n                    end: 10,\n                },\n                assert_keyword_start: 4,\n                message: None,\n            },\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: None,\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__with_let_binding3_and_annotation.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"let assert [x]: List(Int) = [2]\"\n---\n[\n    Assignment(\n        Assignment {\n            location: SrcSpan {\n                start: 0,\n                end: 31,\n            },\n            value: List {\n                location: SrcSpan {\n                    start: 28,\n                    end: 31,\n                },\n                elements: [\n                    Int {\n                        location: SrcSpan {\n                            start: 29,\n                            end: 30,\n                        },\n                        value: \"2\",\n                        int_value: 2,\n                    },\n                ],\n                tail: None,\n            },\n            pattern: List {\n                location: SrcSpan {\n                    start: 11,\n                    end: 14,\n                },\n                elements: [\n                    Variable {\n                        location: SrcSpan {\n                            start: 12,\n                            end: 13,\n                        },\n                        name: \"x\",\n                        type_: (),\n                        origin: VariableOrigin {\n                            syntax: Variable(\n                                \"x\",\n                            ),\n                            declaration: LetPattern,\n                        },\n                    },\n                ],\n                tail: None,\n                type_: (),\n            },\n            kind: Assert {\n                location: SrcSpan {\n                    start: 0,\n                    end: 10,\n                },\n                assert_keyword_start: 4,\n                message: None,\n            },\n            compiled_case: CompiledCase {\n                tree: Fail,\n                subject_variables: [],\n            },\n            annotation: Some(\n                Constructor(\n                    TypeAstConstructor {\n                        location: SrcSpan {\n                            start: 16,\n                            end: 25,\n                        },\n                        name_location: SrcSpan {\n                            start: 16,\n                            end: 20,\n                        },\n                        module: None,\n                        name: \"List\",\n                        arguments: [\n                            Constructor(\n                                TypeAstConstructor {\n                                    location: SrcSpan {\n                                        start: 21,\n                                        end: 24,\n                                    },\n                                    name_location: SrcSpan {\n                                        start: 21,\n                                        end: 24,\n                                    },\n                                    module: None,\n                                    name: \"Int\",\n                                    arguments: [],\n                                    start_parentheses: None,\n                                },\n                            ),\n                        ],\n                        start_parentheses: Some(\n                            20,\n                        ),\n                    },\n                ),\n            ),\n        },\n    ),\n]\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nassertion_line: 2025\nexpression: \"\\npub fn main(): Nil {}\\n        \"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main(): Nil {}\n        \n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:2:14\n  │\n2 │ pub fn main(): Nil {}\n  │              ^ I was not expecting this\n\nFound `:`, expected one of: \n- `->`\nHint: Return type annotations are written using `->`, not `:`\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_record_access_pattern.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  case wibble {\\n    wibble.thing -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case wibble {\n    wibble.thing -> 1\n  }\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:4:5\n  │\n4 │     wibble.thing -> 1\n  │     ^^^^^^^^^^^^ Invalid pattern\n\nI'm expecting a pattern here\nHint: A pattern can be a constructor name, a literal value\nor a variable to bind a value to, etc.\nSee: https://tour.gleam.run/flow-control/case-expressions/\n"
  },
  {
    "path": "compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_type_of_comments_with_hash.snap",
    "content": "---\nsource: compiler-core/src/parse/tests.rs\nexpression: \"\\npub fn main() {\\n  # a python-style comment\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  # a python-style comment\n}\n\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/parse/error.gleam:3:5\n  │\n3 │   # a python-style comment\n  │     ^ I was not expecting this\n\nFound a name, expected one of: \n- `(`\nHint: Maybe you meant to create a comment?\nComments in Gleam start with `//`, not `#`\n"
  },
  {
    "path": "compiler-core/src/parse/tests.rs",
    "content": "use crate::ast::SrcSpan;\nuse crate::parse::error::{\n    InvalidUnicodeEscapeError, LexicalError, LexicalErrorType, ParseError, ParseErrorType,\n};\nuse crate::parse::lexer::make_tokenizer;\nuse crate::parse::token::Token;\nuse crate::warning::WarningEmitter;\nuse camino::Utf8PathBuf;\n\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse pretty_assertions::assert_eq;\n\nmacro_rules! assert_error {\n    ($src:expr, $error:expr $(,)?) => {\n        let result = crate::parse::parse_statement_sequence($src).expect_err(\"should not parse\");\n        assert_eq!(($src, $error), ($src, result),);\n    };\n    ($src:expr) => {\n        let error = $crate::parse::tests::expect_error($src);\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\", $src, error);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\nmacro_rules! assert_module_error {\n    ($src:expr) => {\n        let error = $crate::parse::tests::expect_module_error($src);\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\", $src, error);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\nmacro_rules! assert_parse_module {\n    ($src:expr) => {\n        let result = crate::parse::parse_module(\n            camino::Utf8PathBuf::from(\"test/path\"),\n            $src,\n            &crate::warning::WarningEmitter::null(),\n        )\n        .expect(\"should parse\");\n        insta::assert_snapshot!(insta::internals::AutoName, &format!(\"{:#?}\", result), $src);\n    };\n}\n\nmacro_rules! assert_parse {\n    ($src:expr) => {\n        let result = crate::parse::parse_statement_sequence($src).expect(\"should parse\");\n        insta::assert_snapshot!(insta::internals::AutoName, &format!(\"{:#?}\", result), $src);\n    };\n}\n\npub fn expect_module_error(src: &str) -> String {\n    let result =\n        crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &WarningEmitter::null())\n            .expect_err(\"should not parse\");\n    let error = crate::error::Error::Parse {\n        src: src.into(),\n        path: Utf8PathBuf::from(\"/src/parse/error.gleam\"),\n        error: Box::new(result),\n    };\n    error.pretty_string()\n}\n\npub fn expect_error(src: &str) -> String {\n    let result = crate::parse::parse_statement_sequence(src).expect_err(\"should not parse\");\n    let error = crate::error::Error::Parse {\n        src: src.into(),\n        path: Utf8PathBuf::from(\"/src/parse/error.gleam\"),\n        error: Box::new(result),\n    };\n    error.pretty_string()\n}\n\n#[test]\nfn int_tests() {\n    // bad binary digit\n    assert_error!(\n        \"0b012\",\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::DigitOutOfRadix,\n                    location: SrcSpan { start: 4, end: 4 },\n                }\n            },\n            location: SrcSpan { start: 4, end: 4 },\n        }\n    );\n    // bad octal digit\n    assert_error!(\n        \"0o12345678\",\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::DigitOutOfRadix,\n                    location: SrcSpan { start: 9, end: 9 },\n                }\n            },\n            location: SrcSpan { start: 9, end: 9 },\n        }\n    );\n    // no int value\n    assert_error!(\n        \"0x\",\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::RadixIntNoValue,\n                    location: SrcSpan { start: 1, end: 1 },\n                }\n            },\n            location: SrcSpan { start: 1, end: 1 },\n        }\n    );\n    // trailing underscore\n    assert_error!(\n        \"1_000_\",\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::NumTrailingUnderscore,\n                    location: SrcSpan { start: 5, end: 5 },\n                }\n            },\n            location: SrcSpan { start: 5, end: 5 },\n        }\n    );\n}\n\n#[test]\nfn string_bad_character_escape() {\n    assert_error!(\n        r#\"\"\\g\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::BadStringEscape,\n                    location: SrcSpan { start: 1, end: 2 },\n                }\n            },\n            location: SrcSpan { start: 1, end: 2 },\n        }\n    );\n}\n\n#[test]\nfn string_bad_character_escape_leading_backslash() {\n    assert_error!(\n        r#\"\"\\\\\\g\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::BadStringEscape,\n                    location: SrcSpan { start: 3, end: 4 },\n                }\n            },\n            location: SrcSpan { start: 3, end: 4 },\n        }\n    );\n}\n\n#[test]\nfn string_freestanding_unicode_escape_sequence() {\n    assert_error!(\n        r#\"\"\\u\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::MissingOpeningBrace,\n                    ),\n                    location: SrcSpan { start: 2, end: 3 },\n                }\n            },\n            location: SrcSpan { start: 2, end: 3 },\n        }\n    );\n}\n\n#[test]\nfn string_unicode_escape_sequence_no_braces() {\n    assert_error!(\n        r#\"\"\\u65\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::MissingOpeningBrace,\n                    ),\n                    location: SrcSpan { start: 2, end: 3 },\n                }\n            },\n            location: SrcSpan { start: 2, end: 3 },\n        }\n    );\n}\n\n#[test]\nfn string_unicode_escape_sequence_invalid_hex() {\n    assert_error!(\n        r#\"\"\\u{z}\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::ExpectedHexDigitOrCloseBrace,\n                    ),\n                    location: SrcSpan { start: 4, end: 5 },\n                }\n            },\n            location: SrcSpan { start: 4, end: 5 },\n        }\n    );\n}\n\n#[test]\nfn string_unclosed_unicode_escape_sequence() {\n    assert_error!(\n        r#\"\"\\u{039a\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::ExpectedHexDigitOrCloseBrace,\n                    ),\n                    location: SrcSpan { start: 8, end: 9 },\n                }\n            },\n            location: SrcSpan { start: 8, end: 9 },\n        }\n    );\n}\n\n#[test]\nfn string_empty_unicode_escape_sequence() {\n    assert_error!(\n        r#\"\"\\u{}\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::InvalidNumberOfHexDigits,\n                    ),\n                    location: SrcSpan { start: 1, end: 5 },\n                }\n            },\n            location: SrcSpan { start: 1, end: 5 },\n        }\n    );\n}\n\n#[test]\nfn string_overlong_unicode_escape_sequence() {\n    assert_error!(\n        r#\"\"\\u{0011f601}\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::InvalidNumberOfHexDigits,\n                    ),\n                    location: SrcSpan { start: 1, end: 13 },\n                }\n            },\n            location: SrcSpan { start: 1, end: 13 },\n        }\n    );\n}\n\n#[test]\nfn string_invalid_unicode_escape_sequence() {\n    assert_error!(\n        r#\"\"\\u{110000}\"\"#,\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidUnicodeEscape(\n                        InvalidUnicodeEscapeError::InvalidCodepoint,\n                    ),\n                    location: SrcSpan { start: 1, end: 11 },\n                }\n            },\n            location: SrcSpan { start: 1, end: 11 },\n        }\n    );\n}\n\n#[test]\nfn bit_array() {\n    // non int value in bit array unit option\n    assert_error!(\n        \"let x = <<1:unit(0)>> x\",\n        ParseError {\n            error: ParseErrorType::InvalidBitArrayUnit,\n            location: SrcSpan { start: 17, end: 18 }\n        }\n    );\n}\n\n#[test]\nfn bit_array1() {\n    assert_error!(\n        \"let x = <<1:unit(257)>> x\",\n        ParseError {\n            error: ParseErrorType::InvalidBitArrayUnit,\n            location: SrcSpan { start: 17, end: 20 }\n        }\n    );\n}\n\n#[test]\nfn bit_array2() {\n    // patterns cannot be nested\n    assert_error!(\n        \"case <<>> { <<<<1>>:bits>> -> 1 }\",\n        ParseError {\n            error: ParseErrorType::NestedBitArrayPattern,\n            location: SrcSpan { start: 14, end: 19 }\n        }\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3125\n#[test]\nfn triple_equals() {\n    assert_error!(\n        \"let wobble:Int = 32\n        wobble === 42\",\n        ParseError {\n            error: ParseErrorType::LexError {\n                error: LexicalError {\n                    error: LexicalErrorType::InvalidTripleEqual,\n                    location: SrcSpan { start: 35, end: 38 },\n                }\n            },\n            location: SrcSpan { start: 35, end: 38 },\n        }\n    );\n}\n\n#[test]\nfn triple_equals_with_whitespace() {\n    assert_error!(\n        \"let wobble:Int = 32\n        wobble ==     = 42\",\n        ParseError {\n            error: ParseErrorType::OpNakedRight,\n            location: SrcSpan { start: 35, end: 37 },\n        }\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1231\n#[test]\nfn pointless_spread() {\n    assert_error!(\n        \"let xs = [] [..xs]\",\n        ParseError {\n            error: ParseErrorType::ListSpreadWithoutElements,\n            location: SrcSpan { start: 12, end: 18 },\n        }\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1613\n#[test]\nfn anonymous_function_labeled_arguments() {\n    assert_error!(\n        \"let anon_subtract = fn (minuend a: Int, subtrahend b: Int) -> Int {\n  a - b\n}\",\n        ParseError {\n            location: SrcSpan { start: 24, end: 31 },\n            error: ParseErrorType::UnexpectedLabel\n        }\n    );\n}\n\n#[test]\nfn no_let_binding() {\n    assert_error!(\n        \"wibble = 32\",\n        ParseError {\n            location: SrcSpan { start: 7, end: 8 },\n            error: ParseErrorType::NoLetBinding\n        }\n    );\n}\n\n#[test]\nfn no_let_binding1() {\n    assert_error!(\n        \"wibble:Int = 32\",\n        ParseError {\n            location: SrcSpan { start: 6, end: 7 },\n            error: ParseErrorType::NoLetBinding\n        }\n    );\n}\n\n#[test]\nfn no_let_binding2() {\n    assert_error!(\n        \"let wobble:Int = 32\n        wobble = 42\",\n        ParseError {\n            location: SrcSpan { start: 35, end: 36 },\n            error: ParseErrorType::NoLetBinding\n        }\n    );\n}\n\n#[test]\nfn no_let_binding3() {\n    assert_error!(\n        \"[x] = [2]\",\n        ParseError {\n            location: SrcSpan { start: 4, end: 5 },\n            error: ParseErrorType::NoLetBinding\n        }\n    );\n}\n\n#[test]\nfn with_let_binding3() {\n    // The same with `let assert` must parse:\n    assert_parse!(\"let assert [x] = [2]\");\n}\n\n#[test]\nfn with_let_binding3_and_annotation() {\n    assert_parse!(\"let assert [x]: List(Int) = [2]\");\n}\n\n#[test]\nfn no_eq_after_binding() {\n    assert_error!(\n        \"let wibble\",\n        ParseError {\n            location: SrcSpan { start: 4, end: 10 },\n            error: ParseErrorType::ExpectedEqual\n        }\n    );\n}\n\n#[test]\nfn no_eq_after_binding1() {\n    assert_error!(\n        \"let wibble\n        wibble = 4\",\n        ParseError {\n            location: SrcSpan { start: 4, end: 10 },\n            error: ParseErrorType::ExpectedEqual\n        }\n    );\n}\n\n#[test]\nfn echo_followed_by_expression_ends_where_expression_ends() {\n    assert_parse!(\"echo wibble\");\n}\n\n#[test]\nfn echo_with_simple_expression_1() {\n    assert_parse!(\"echo wibble as message\");\n}\n\n#[test]\nfn echo_with_simple_expression_2() {\n    assert_parse!(\"echo wibble as \\\"message\\\"\");\n}\n\n#[test]\nfn echo_with_complex_expression() {\n    assert_parse!(\"echo wibble as { this <> complex }\");\n}\n\n#[test]\nfn echo_with_no_expressions_after_it() {\n    assert_parse!(\"echo\");\n}\n\n#[test]\nfn echo_with_no_expressions_after_it_but_a_message() {\n    assert_parse!(\"echo as message\");\n}\n\n#[test]\nfn echo_with_block() {\n    assert_parse!(\"echo { 1 + 1 }\");\n}\n\n#[test]\nfn echo_has_lower_precedence_than_binop() {\n    assert_parse!(\"echo 1 + 1\");\n}\n\n#[test]\nfn echo_in_a_pipeline() {\n    assert_parse!(\"[] |> echo |> wibble\");\n}\n\n#[test]\nfn echo_has_lower_precedence_than_pipeline() {\n    assert_parse!(\"echo wibble |> wobble |> woo\");\n}\n\n#[test]\nfn echo_cannot_have_an_expression_in_a_pipeline() {\n    // So this is actually two pipelines!\n    assert_parse!(\"[] |> echo fun |> wibble\");\n}\n\n#[test]\nfn panic_with_echo() {\n    assert_parse!(\"panic as echo \\\"string\\\"\");\n}\n\n#[test]\nfn panic_with_echo_and_message() {\n    assert_parse!(\"panic as echo wibble as message\");\n}\n\n#[test]\nfn echo_with_panic() {\n    assert_parse!(\"echo panic as \\\"a\\\"\");\n}\n\n#[test]\nfn echo_with_panic_and_message() {\n    assert_parse!(\"echo panic as \\\"a\\\"\");\n}\n\n#[test]\nfn echo_with_panic_and_messages() {\n    assert_parse!(\"echo panic as \\\"a\\\" as \\\"b\\\"\");\n}\n\n#[test]\nfn echo_with_assert_and_message_1() {\n    assert_parse!(\"assert 1 == echo 2 as this_belongs_to_echo\");\n}\n\n#[test]\nfn echo_with_assert_and_message_2() {\n    assert_parse!(\"assert echo True as this_belongs_to_echo\");\n}\n\n#[test]\nfn echo_with_assert_and_messages_1() {\n    assert_parse!(\"assert 1 == echo 2 as this_belongs_to_echo as this_belongs_to_assert\");\n}\n\n#[test]\nfn echo_with_assert_and_messages_2() {\n    assert_parse!(\"assert echo True as this_belongs_to_echo as this_belongs_to_assert\");\n}\n\n#[test]\nfn echo_with_assert_and_messages_3() {\n    assert_parse!(\"assert echo 1 == 2 as this_belongs_to_echo as this_belongs_to_assert\");\n}\n\n#[test]\nfn echo_with_let_assert_and_message() {\n    assert_parse!(\"let assert 1 = echo 2 as this_belongs_to_echo\");\n}\n\n#[test]\nfn echo_with_let_assert_and_messages() {\n    assert_parse!(\"let assert 1 = echo 1 as this_belongs_to_echo as this_belongs_to_assert\");\n}\n\n#[test]\nfn repeated_echos() {\n    assert_parse!(\"echo echo echo 1\");\n}\n\n#[test]\nfn echo_at_start_of_pipeline_wraps_the_whole_thing() {\n    assert_parse!(\"echo 1 |> wibble |> wobble\");\n}\n\n#[test]\nfn no_let_binding_snapshot_1() {\n    assert_error!(\"wibble = 4\");\n}\n\n#[test]\nfn no_let_binding_snapshot_2() {\n    assert_error!(\"wibble:Int = 4\");\n}\n\n#[test]\nfn no_let_binding_snapshot_3() {\n    assert_error!(\n        \"let wobble:Int = 32\n        wobble = 42\"\n    );\n}\n\n#[test]\nfn no_eq_after_binding_snapshot_1() {\n    assert_error!(\"let wibble\");\n}\n#[test]\nfn no_eq_after_binding_snapshot_2() {\n    assert_error!(\n        \"let wibble\n        wibble = 4\"\n    );\n}\n\n#[test]\nfn discard_left_hand_side_of_concat_pattern() {\n    assert_error!(\n        r#\"\n        case \"\" {\n          _ <> rest -> rest\n        }\n        \"#\n    );\n}\n\n#[test]\nfn assign_left_hand_side_of_concat_pattern() {\n    assert_error!(\n        r#\"\n        case \"\" {\n          first <> rest -> rest\n        }\n        \"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1890\n#[test]\nfn valueless_list_spread_expression() {\n    assert_error!(r#\"let x = [1, 2, 3, ..]\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/2035\n#[test]\nfn semicolons() {\n    assert_error!(r#\"{ 2 + 3; - -5; }\"#);\n}\n\n#[test]\nfn bare_expression() {\n    assert_parse!(r#\"1\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1991\n#[test]\nfn block_of_one() {\n    assert_parse!(r#\"{ 1 }\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1991\n#[test]\nfn block_of_two() {\n    assert_parse!(r#\"{ 1 2 }\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1991\n#[test]\nfn nested_block() {\n    assert_parse!(r#\"{ 1 { 1.0 2.0 } 3 }\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1831\n#[test]\nfn argument_scope() {\n    assert_error!(\n        \"\n1 + let a = 5\na\n\"\n    );\n}\n\n#[test]\nfn multiple_external_for_same_project_erlang() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"one\", \"two\")\n@external(erlang, \"three\", \"four\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_external_for_same_project_javascript() {\n    assert_module_error!(\n        r#\"\n@external(javascript, \"one\", \"two\")\n@external(javascript, \"three\", \"four\")\npub fn one(x: Int) -> Int {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn unknown_external_target() {\n    assert_module_error!(\n        r#\"\n@external(erl, \"one\", \"two\")\npub fn one(x: Int) -> Int {\n  todo\n}\"#\n    );\n}\n\n#[test]\nfn unknown_target() {\n    assert_module_error!(\n        r#\"\n@target(abc)\npub fn one() {}\"#\n    );\n}\n\n#[test]\nfn missing_target() {\n    assert_module_error!(\n        r#\"\n@target()\npub fn one() {}\"#\n    );\n}\n\n#[test]\nfn missing_target_and_bracket() {\n    assert_module_error!(\n        r#\"\n@target(\npub fn one() {}\"#\n    );\n}\n\n#[test]\nfn unknown_attribute() {\n    assert_module_error!(\n        r#\"@go_faster()\npub fn main() { 1 }\"#\n    );\n}\n\n#[test]\nfn incomplete_function() {\n    assert_error!(\"fn()\");\n}\n\n#[test]\nfn multiple_deprecation_attributes() {\n    assert_module_error!(\n        r#\"\n@deprecated(\"1\")\n@deprecated(\"2\")\npub fn main() -> Nil {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecation_without_message() {\n    assert_module_error!(\n        r#\"\n@deprecated()\npub fn main() -> Nil {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_internal_attributes() {\n    assert_module_error!(\n        r#\"\n@internal\n@internal\npub fn main() -> Nil {\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn attributes_with_no_definition() {\n    assert_module_error!(\n        r#\"\n@deprecated(\"1\")\n@target(erlang)\n\"#\n    );\n}\n\n#[test]\nfn external_attribute_with_custom_type() {\n    assert_parse_module!(\n        r#\"\n@external(erlang, \"gleam_stdlib\", \"dict\")\n@external(javascript, \"./gleam_stdlib.d.ts\", \"Dict\")\npub type Dict(key, value)\n\"#\n    );\n}\n\n#[test]\nfn external_attribute_with_non_fn_definition() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"module\", \"fun\")\npub type Fun = Fun\n\"#\n    );\n}\n\n#[test]\nfn attributes_with_improper_definition() {\n    assert_module_error!(\n        r#\"\n@deprecated(\"1\")\n@external(erlang, \"module\", \"fun\")\n\"#\n    );\n}\n\n#[test]\nfn const_with_function_call() {\n    assert_module_error!(\n        r#\"\npub fn wibble() { 123 }\nconst wib: Int = wibble()\n\"#\n    );\n}\n\n#[test]\nfn const_with_function_call_with_args() {\n    assert_module_error!(\n        r#\"\npub fn wibble() { 123 }\nconst wib: Int = wibble(1, \"wobble\")\n\"#\n    );\n}\n\n#[test]\nfn import_type() {\n    assert_parse_module!(r#\"import wibble.{type Wobble, Wobble, type Wabble}\"#);\n}\n\n#[test]\nfn reserved_auto() {\n    assert_module_error!(r#\"const auto = 1\"#);\n}\n\n#[test]\nfn reserved_delegate() {\n    assert_module_error!(r#\"const delegate = 1\"#);\n}\n\n#[test]\nfn reserved_derive() {\n    assert_module_error!(r#\"const derive = 1\"#);\n}\n\n#[test]\nfn reserved_else() {\n    assert_module_error!(r#\"const else = 1\"#);\n}\n\n#[test]\nfn reserved_implement() {\n    assert_module_error!(r#\"const implement = 1\"#);\n}\n\n#[test]\nfn reserved_macro() {\n    assert_module_error!(r#\"const macro = 1\"#);\n}\n\n#[test]\nfn reserved_test() {\n    assert_module_error!(r#\"const test = 1\"#);\n}\n\n#[test]\nfn reserved_echo() {\n    assert_module_error!(r#\"const echo = 1\"#);\n}\n\n#[test]\nfn capture_with_name() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  add(_name, 1)\n}\n\nfn add(x, y) {\n  x + y\n}\n\"#\n    );\n}\n\n#[test]\nfn list_spread_with_no_tail_in_the_middle_of_a_list() {\n    assert_module_error!(\n        r#\"\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  [1, 2, .., 3 + 3, 4]\n}\n\"#\n    );\n}\n\n#[test]\nfn list_spread_followed_by_extra_items() {\n    assert_module_error!(\n        r#\"\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  [1, 2, ..xs, 3 + 3, 4]\n}\n\"#\n    );\n}\n\n#[test]\nfn list_spread_followed_by_extra_item_and_another_spread() {\n    assert_module_error!(\n        r#\"\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  let ys = [5, 6, 7]\n  [..xs, 4, ..ys]\n}\n\"#\n    );\n}\n\n#[test]\nfn list_spread_followed_by_other_spread() {\n    assert_module_error!(\n        r#\"\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  let ys = [5, 6, 7]\n  [1, ..xs, ..ys]\n}\n\"#\n    );\n}\n\n#[test]\nfn list_spread_as_first_item_followed_by_other_items() {\n    assert_module_error!(\n        r#\"\npub fn main() -> Nil {\n  let xs = [1, 2, 3]\n  [..xs, 3 + 3, 4]\n}\n\"#\n    );\n}\n\n// Tests for nested tuples and structs in tuples\n// https://github.com/gleam-lang/gleam/issues/1980\n\n#[test]\nfn nested_tuples() {\n    assert_parse!(\n        r#\"\nlet tup = #(#(5, 6))\n{tup.0}.1\n\"#\n    );\n}\n\n#[test]\nfn nested_tuples_no_block() {\n    assert_parse!(\n        r#\"\nlet tup = #(#(5, 6))\ntup.0.1\n\"#\n    );\n}\n\n#[test]\nfn deeply_nested_tuples() {\n    assert_parse!(\n        r#\"\nlet tup = #(#(#(#(4))))\n{{{tup.0}.0}.0}.0\n\"#\n    );\n}\n\n#[test]\nfn deeply_nested_tuples_no_block() {\n    assert_parse!(\n        r#\"\nlet tup = #(#(#(#(4))))\ntup.0.0.0.0\n\"#\n    );\n}\n\n#[test]\nfn inner_single_quote_parses() {\n    assert_parse!(\n        r#\"\nlet a = \"inner 'quotes'\"\n\"#\n    );\n}\n\n#[test]\nfn string_single_char_suggestion() {\n    assert_module_error!(\n        \"\n    pub fn main() {\n        let a = 'example'\n      }\n    \"\n    );\n}\n\n#[test]\nfn private_internal_const() {\n    assert_module_error!(\n        \"\n@internal\nconst wibble = 1\n\"\n    );\n}\n\n#[test]\nfn private_internal_type_alias() {\n    assert_module_error!(\n        \"\n@internal\ntype Alias = Int\n\"\n    );\n}\n\n#[test]\nfn private_internal_function() {\n    assert_module_error!(\n        \"\n@internal\nfn wibble() { todo }\n\"\n    );\n}\n\n#[test]\nfn private_internal_type() {\n    assert_module_error!(\n        \"\n@internal\ntype Wibble {\n  Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn wrong_record_access_pattern() {\n    assert_module_error!(\n        \"\npub fn main() {\n  case wibble {\n    wibble.thing -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn tuple_invalid_expr() {\n    assert_module_error!(\n        \"\nfn main() {\n    #(1, 2, const)\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_invalid_segment() {\n    assert_module_error!(\n        \"\nfn main() {\n    <<72, 101, 108, 108, 111, 44, 32, 74, 111, 101, const>>\n}\n\"\n    );\n}\n\n#[test]\nfn case_invalid_expression() {\n    assert_module_error!(\n        \"\nfn main() {\n    case 1, type {\n        _, _ -> 0\n    }\n}\n\"\n    );\n}\n\n#[test]\nfn case_invalid_case_pattern() {\n    assert_module_error!(\n        \"\nfn main() {\n    case 1 {\n        -> -> 0\n    }\n}\n\"\n    );\n}\n\n#[test]\nfn case_clause_no_subject() {\n    assert_module_error!(\n        \"\nfn main() {\n    case 1 {\n      -> 1\n      _ -> 2\n    }\n}\n\"\n    );\n}\n\n#[test]\nfn case_alternative_clause_no_subject() {\n    assert_module_error!(\n        \"\nfn main() {\n    case 1 {\n      1 | -> 1\n      _ -> 1\n    }\n}\n\"\n    );\n}\n\n#[test]\nfn use_invalid_assignments() {\n    assert_module_error!(\n        \"\nfn main() {\n    use fn <- result.try(get_username())\n}\n\"\n    );\n}\n\n#[test]\nfn assignment_pattern_invalid_tuple() {\n    assert_module_error!(\n        \"\nfn main() {\n    let #(a, case, c) = #(1, 2, 3)\n}\n\"\n    );\n}\n\n#[test]\nfn assignment_pattern_invalid_bit_segment() {\n    assert_module_error!(\n        \"\nfn main() {\n    let <<b1, pub>> = <<24, 3>>\n}\n\"\n    );\n}\n\n#[test]\nfn case_list_pattern_after_spread() {\n    assert_module_error!(\n        \"\nfn main() {\n    case somelist {\n        [..rest, last] -> 1\n        _ -> 2\n    }\n}\n\"\n    );\n}\n\n#[test]\nfn type_invalid_constructor() {\n    assert_module_error!(\n        \"\ntype A {\n    A(String)\n    type\n}\n\"\n    );\n}\n\n// Tests whether diagnostic presents an example of how to formulate a proper\n// record constructor based off a common user error pattern.\n// https://github.com/gleam-lang/gleam/issues/3324\n\n#[test]\nfn type_invalid_record_constructor() {\n    assert_module_error!(\n        \"\npub type User {\n    name: String,\n}\n\"\n    );\n}\n\n#[test]\nfn type_invalid_record_constructor_without_field_type() {\n    assert_module_error!(\n        \"\npub opaque type User {\n    name\n}\n\"\n    );\n}\n\n#[test]\nfn type_invalid_record_constructor_invalid_field_type() {\n    assert_module_error!(\n        r#\"\ntype User {\n    name: \"Test User\",\n}\n\"#\n    );\n}\n\n#[test]\nfn type_invalid_type_name() {\n    assert_module_error!(\n        \"\ntype A(a, type) {\n    A\n}\n\"\n    );\n}\n\n#[test]\nfn type_invalid_constructor_arg() {\n    assert_module_error!(\n        \"\ntype A {\n    A(type: String)\n}\n\"\n    );\n}\n\n#[test]\nfn type_invalid_record() {\n    assert_module_error!(\n        \"\ntype A {\n    One\n    Two\n    3\n}\n\"\n    );\n}\n\n#[test]\nfn function_type_invalid_param_type() {\n    assert_module_error!(\n        \"\nfn f(g: fn(Int, 1) -> Int) -> Int {\n  g(0, 1)\n}\n\"\n    );\n}\n\n#[test]\nfn function_invalid_signature() {\n    assert_module_error!(\n        r#\"\nfn f(a, \"b\") -> String {\n    a <> b\n}\n\"#\n    );\n}\n\n#[test]\nfn const_invalid_tuple() {\n    assert_module_error!(\n        \"\nconst a = #(1, 2, <-)\n\"\n    );\n}\n\n#[test]\nfn const_invalid_list() {\n    assert_module_error!(\n        \"\nconst a = [1, 2, <-]\n\"\n    );\n}\n\n#[test]\nfn const_invalid_bit_array_segment() {\n    assert_module_error!(\n        \"\nconst a = <<1, 2, <->>\n\"\n    );\n}\n\n#[test]\nfn const_invalid_record_constructor() {\n    assert_module_error!(\n        \"\ntype A {\n    A(String, Int)\n}\nconst a = A(\\\"a\\\", let)\n\"\n    );\n}\n\n// record access should parse even if there is no label written\n#[test]\nfn record_access_no_label() {\n    assert_parse_module!(\n        \"\ntype Wibble {\n    Wibble(wibble: String)\n}\n\nfn wobble() {\n  Wibble(\\\"a\\\").\n}\n\"\n    );\n}\n\n#[test]\nfn newline_tokens() {\n    assert_eq!(\n        make_tokenizer(\"1\\n\\n2\\n\").collect_vec(),\n        [\n            Ok((\n                0,\n                Token::Int {\n                    value: \"1\".into(),\n                    int_value: 1.into()\n                },\n                1\n            )),\n            Ok((1, Token::NewLine, 2)),\n            Ok((2, Token::NewLine, 3)),\n            Ok((\n                3,\n                Token::Int {\n                    value: \"2\".into(),\n                    int_value: 2.into()\n                },\n                4\n            )),\n            Ok((4, Token::NewLine, 5))\n        ]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1756\n#[test]\nfn arithmetic_in_guards() {\n    assert_parse!(\n        \"\ncase 2, 3 {\n    x, y if x + y == 1 -> True\n}\"\n    );\n}\n\n#[test]\nfn const_string_concat() {\n    assert_parse_module!(\n        \"\nconst cute = \\\"cute\\\"\nconst cute_bee = cute <> \\\"bee\\\"\n\"\n    );\n}\n\n#[test]\nfn const_string_concat_naked_right() {\n    assert_module_error!(\n        \"\nconst no_cute_bee = \\\"cute\\\" <>\n\"\n    );\n}\n\n#[test]\nfn function_call_in_case_clause_guard() {\n    assert_error!(\n        r#\"\nlet my_string = \"hello\"\ncase my_string {\n    _ if length(my_string) > 2 -> io.debug(\"doesn't work')\n}\"#\n    );\n}\n\n#[test]\nfn dot_access_function_call_in_case_clause_guard() {\n    assert_error!(\n        r#\"\nlet my_string = \"hello\"\ncase my_string {\n    _ if string.length(my_string) > 2 -> io.debug(\"doesn't work')\n}\"#\n    );\n}\n\n#[test]\nfn invalid_left_paren_in_case_clause_guard() {\n    assert_error!(\n        r#\"\nlet my_string = \"hello\"\ncase my_string {\n    _ if string.length( > 2 -> io.debug(\"doesn't work')\n}\"#\n    );\n}\n\n#[test]\nfn string_concatenation_in_case_clause_guard() {\n    assert_parse!(\n        r#\"\nlet my_string = \"hello \"\ncase my_string {\n    _ if my_string <> \"world\" == \"hello world\" -> io.debug(\"ok\")\n}\"#\n    );\n}\n\n#[test]\nfn invalid_label_shorthand() {\n    assert_module_error!(\n        \"\npub fn main() {\n  wibble(:)\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_label_shorthand_2() {\n    assert_module_error!(\n        \"\npub fn main() {\n  wibble(:,)\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_label_shorthand_3() {\n    assert_module_error!(\n        \"\npub fn main() {\n  wibble(:arg)\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_label_shorthand_4() {\n    assert_module_error!(\n        \"\npub fn main() {\n  wibble(arg::)\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_label_shorthand_5() {\n    assert_module_error!(\n        \"\npub fn main() {\n  wibble(arg::arg)\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_pattern_label_shorthand() {\n    assert_module_error!(\n        \"\npub fn main() {\n  let Wibble(:) = todo\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_pattern_label_shorthand_2() {\n    assert_module_error!(\n        \"\npub fn main() {\n  let Wibble(:arg) = todo\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_pattern_label_shorthand_3() {\n    assert_module_error!(\n        \"\npub fn main() {\n  let Wibble(arg::) = todo\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_pattern_label_shorthand_4() {\n    assert_module_error!(\n        \"\npub fn main() {\n  let Wibble(arg: arg:) = todo\n}\n\"\n    );\n}\n\n#[test]\nfn invalid_pattern_label_shorthand_5() {\n    assert_module_error!(\n        \"\npub fn main() {\n  let Wibble(arg1: arg2:) = todo\n}\n\"\n    );\n}\n\nfn first_parsed_docstring(src: &str) -> EcoString {\n    let parsed =\n        crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &WarningEmitter::null())\n            .expect(\"should parse\");\n\n    parsed\n        .module\n        .definitions\n        .first()\n        .expect(\"parsed a definition\")\n        .definition\n        .get_doc()\n        .expect(\"definition without doc\")\n}\n\n#[test]\nfn doc_comment_before_comment_is_not_attached_to_following_function() {\n    assert_eq!(\n        first_parsed_docstring(\n            r#\"\n    /// Not included!\n    // pub fn call()\n\n    /// Doc!\n    pub fn wibble() {}\n\"#\n        ),\n        \" Doc!\\n\"\n    )\n}\n\n#[test]\nfn doc_comment_before_comment_is_not_attached_to_following_type() {\n    assert_eq!(\n        first_parsed_docstring(\n            r#\"\n    /// Not included!\n    // pub fn call()\n\n    /// Doc!\n    pub type Wibble\n\"#\n        ),\n        \" Doc!\\n\"\n    )\n}\n\n#[test]\nfn doc_comment_before_comment_is_not_attached_to_following_type_alias() {\n    assert_eq!(\n        first_parsed_docstring(\n            r#\"\n    /// Not included!\n    // pub fn call()\n\n    /// Doc!\n    pub type Wibble = Int\n\"#\n        ),\n        \" Doc!\\n\"\n    )\n}\n\n#[test]\nfn doc_comment_before_comment_is_not_attached_to_following_constant() {\n    assert_eq!(\n        first_parsed_docstring(\n            r#\"\n    /// Not included!\n    // pub fn call()\n\n    /// Doc!\n    pub const wibble = 1\n\"#\n        ),\n        \" Doc!\\n\"\n    );\n}\n\n#[test]\nfn non_module_level_function_with_a_name() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  fn my() { 1 }\n}\n\"#\n    );\n}\n\n#[test]\nfn error_message_on_variable_starting_with_underscore() {\n    // https://github.com/gleam-lang/gleam/issues/3504\n    assert_module_error!(\n        \"\n  pub fn main() {\n    let val = _func_starting_with_underscore(1)\n  }\"\n    );\n}\n\n#[test]\nfn non_module_level_function_with_not_a_name() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  fn @() { 1 }  // wrong token and not a name\n}\n\"#\n    );\n}\n\n#[test]\nfn error_message_on_variable_starting_with_underscore2() {\n    // https://github.com/gleam-lang/gleam/issues/3504\n    assert_module_error!(\n        \"\n  pub fn main() {\n    case 1 {\n      1 -> _with_underscore(1)\n    }\n  }\"\n    );\n}\n\n#[test]\nfn function_inside_a_type() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n  fn wobble() {}\n}\n\"#\n    );\n}\n\n#[test]\nfn pub_function_inside_a_type() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n  pub fn wobble() {}\n}\n\"#\n    );\n}\n\n#[test]\nfn if_like_expression() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let a = if wibble {\n    wobble\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3730\n#[test]\nfn missing_constructor_arguments() {\n    assert_module_error!(\n        \"\npub type A {\n  A(Int)\n}\n\nconst a = A()\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3796\n#[test]\nfn missing_type_constructor_arguments_in_type_definition() {\n    assert_module_error!(\n        \"\npub type A() {\n  A(Int)\n}\n\"\n    );\n}\n\n#[test]\nfn tuple_without_hash() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n    let triple = (1, 2.2, \"three\")\n    io.debug(triple)\n    let (a, *, *) = triple\n    io.debug(a)\n    io.debug(triple.1)\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecation_attribute_on_type_variant() {\n    assert_parse_module!(\n        r#\"\ntype Wibble {\n    @deprecated(\"1\")\n    Wibble1\n    Wibble2\n}\n\"#\n    );\n}\n\n#[test]\n\nfn float_empty_exponent() {\n    assert_error!(\"1.32e\");\n}\n\n#[test]\nfn multiple_deprecation_attribute_on_type_variant() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n    @deprecated(\"1\")\n    @deprecated(\"2\")\n    Wibble1\n    Wibble2\n}\n\"#\n    );\n}\n\n#[test]\nfn target_attribute_on_type_variant() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n    @target(erlang)\n    Wibble2\n}\n\"#\n    );\n}\n\n#[test]\nfn internal_attribute_on_type_variant() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n    @internal\n    Wibble1\n}\n\"#\n    );\n}\n\n#[test]\nfn external_attribute_on_type_variant() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n    @external(erlang, \"one\", \"two\")\n    Wibble1\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_unsupported_attributes_on_type_variant() {\n    assert_module_error!(\n        r#\"\ntype Wibble {\n    @external(erlang, \"one\", \"two\")\n    @target(erlang)\n    @internal\n    Wibble1\n}\n\"#\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3870\nfn nested_tuple_access_after_function() {\n    assert_parse!(\"tuple().0.1\");\n}\n\n#[test]\nfn case_expression_without_body() {\n    assert_parse!(\"case a\");\n}\n\n#[test]\nfn assert_statement() {\n    assert_parse!(\"assert 10 != 11\");\n}\n\n#[test]\nfn assert_statement_with_message() {\n    assert_parse!(r#\"assert False as \"Uh oh\"\"#);\n}\n\n#[test]\nfn assert_statement_without_expression() {\n    assert_error!(\"assert\");\n}\n\n#[test]\nfn assert_statement_followed_by_statement() {\n    assert_error!(\"assert let a = 10\");\n}\n\n#[test]\nfn special_error_for_pythonic_import() {\n    assert_module_error!(\"import gleam.io\");\n}\n\n#[test]\nfn special_error_for_pythonic_neste_import() {\n    assert_module_error!(\"import one.two.three\");\n}\n\n#[test]\nfn doesnt_issue_special_error_for_pythonic_import_if_slash() {\n    assert_module_error!(\"import one/two.three\");\n}\n\n#[test]\nfn operator_in_pattern_size() {\n    assert_parse!(\"let assert <<size, payload:size(size - 1)>> = <<>>\");\n}\n\n#[test]\nfn correct_precedence_in_pattern_size() {\n    assert_parse!(\"let assert <<size, payload:size(size + 2 * 8)>> = <<>>\");\n}\n\n#[test]\nfn private_opaque_type_is_parsed() {\n    assert_parse_module!(\"opaque type Wibble { Wobble }\");\n}\n\n#[test]\nfn case_guard_with_nested_blocks() {\n    assert_parse!(\n        \"case 1 {\n  _ if { 1 || { 1 || 1 } } || 1  -> 1\n}\"\n    );\n}\n\n#[test]\nfn case_guard_with_empty_block() {\n    assert_error!(\n        \"case 1 {\n  _ if a || {}  -> 1\n}\"\n    );\n}\n\n#[test]\nfn constant_inside_function() {\n    assert_module_error!(\n        \"\npub fn main() {\n  const x = 10\n  x\n}\n\"\n    );\n}\n\n#[test]\nfn function_definition_angle_generics_error() {\n    assert_module_error!(\"fn id<T>(x: T) { x }\");\n}\n\n#[test]\nfn type_angle_generics_usage_without_module_error() {\n    assert_error!(\"let list: List<Int, String> = []\");\n}\n\n#[test]\nfn type_angle_generics_usage_with_module_error() {\n    assert_error!(\"let set: set.Set<Int> = set.new()\");\n}\n\n#[test]\nfn type_angle_generics_definition_error() {\n    assert_module_error!(\n        r#\"\ntype Either<a, b> {\n    This(a)\n    That(b)\n}\n\"#\n    );\n}\n\n#[test]\nfn type_angle_generics_definition_with_upname_error() {\n    assert_module_error!(\n        r#\"\ntype Either<A, B> {\n    This(A)\n    That(B)\n}\n\"#\n    );\n}\n\n#[test]\nfn type_angle_generics_definition_error_fallback() {\n    // Example of a more incorrect syntax, where Gleam doesn't make a suggestion.\n    // In this case, an example type argument is used instead.\n    assert_module_error!(\n        r#\"\ntype Either<type A, type B> {\n    This(A)\n    That(B)\n}\n\"#\n    );\n}\n\n#[test]\nfn wrong_type_of_comments_with_hash() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  # a python-style comment\n}\n\"#\n    );\n}\n\n#[test]\nfn wrong_function_return_type_declaration_using_colon_instead_of_right_arrow() {\n    assert_module_error!(\n        r#\"\npub fn main(): Nil {}\n        \"#\n    );\n}\n\n#[test]\nfn const_record_update_basic() {\n    assert_parse_module!(\n        r#\"\ntype Person {\n  Person(name: String, age: Int)\n}\n\nconst alice = Person(\"Alice\", 30)\nconst bob = Person(..alice, name: \"Bob\")\n\"#\n    );\n}\n\n#[test]\nfn const_record_update_all_fields() {\n    assert_parse_module!(\n        r#\"\ntype Person {\n  Person(name: String, age: Int, city: String)\n}\n\nconst base = Person(\"Alice\", 30, \"London\")\nconst updated = Person(..base, name: \"Bob\", age: 25, city: \"Paris\")\n\"#\n    );\n}\n\n#[test]\nfn const_record_update_only() {\n    assert_parse_module!(\n        r#\"\ntype Person {\n  Person(name: String, age: Int)\n}\n\nconst alice = Person(\"Alice\", 30)\nconst bob = Person(..alice)\n\"#\n    );\n}\n\n#[test]\nfn const_record_update_with_module() {\n    assert_parse_module!(\n        r#\"\nconst local_const = other.Record(..other.base, field: value)\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5391\n#[test]\nfn byte_order_mark() {\n    assert_parse!(\"\\u{feff}todo\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/5391\n#[test]\nfn byte_order_mark_module() {\n    assert_parse_module!(\n        \"\\u{feff}\nconst local_const = other.Record(..other.base, field: value)\n\"\n    );\n}\n\n#[test]\nfn prepend_to_const_list_without_comma() {\n    // While this is valid (but deprecated) syntax for expressions, prepending to\n    // constant lists wasn't added until after the deprecation, so it was never\n    // valid in the first place.\n    assert_module_error!(\n        \"\nconst wibble = [2, 3]\nconst wobble = [1 ..wibble]\n\"\n    );\n}\n\n#[test]\nfn prepend_to_const_list_with_multiple_spreads() {\n    assert_module_error!(\n        \"\nconst wibble = [2, 3]\nconst wobble = [0, 1]\nconst wubble = [..wobble, ..wibble]\n\"\n    );\n}\n\n#[test]\nfn prepend_to_const_list_with_no_tail() {\n    assert_module_error!(\n        \"\nconst wibble = [1, 2, ..]\n\"\n    );\n}\n\n#[test]\nfn prepend_no_elements_to_const_list() {\n    assert_module_error!(\n        \"\nconst wibble = [2, 3]\nconst wobble = [..wibble]\n\"\n    );\n}\n\n#[test]\nfn append_to_const_list() {\n    assert_module_error!(\n        \"\nconst wibble = [2, 3]\nconst wobble = [..wibble, 4, 5]\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/parse/token.rs",
    "content": "use num_bigint::BigInt;\nuse std::fmt;\n\nuse ecow::EcoString;\n\nuse crate::parse::LiteralFloatValue;\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum Token {\n    Name {\n        name: EcoString,\n    },\n    UpName {\n        name: EcoString,\n    },\n    DiscardName {\n        name: EcoString,\n    },\n    Int {\n        value: EcoString,\n        int_value: BigInt,\n    },\n    Float {\n        value: EcoString,\n        float_value: LiteralFloatValue,\n    },\n    String {\n        value: EcoString,\n    },\n    CommentDoc {\n        content: EcoString,\n    },\n    // Groupings\n    LeftParen,   // (\n    RightParen,  // )\n    LeftSquare,  // [\n    RightSquare, // ]\n    LeftBrace,   // {\n    RightBrace,  // }\n    // Int Operators\n    Plus,\n    Minus,\n    Star,\n    Slash,\n    Less,\n    Greater,\n    LessEqual,\n    GreaterEqual,\n    Percent,\n    // Float Operators\n    PlusDot,         // '+.'\n    MinusDot,        // '-.'\n    StarDot,         // '*.'\n    SlashDot,        // '/.'\n    LessDot,         // '<.'\n    GreaterDot,      // '>.'\n    LessEqualDot,    // '<=.'\n    GreaterEqualDot, // '>=.'\n    // String Operators\n    Concatenate, // '<>'\n    // Other Punctuation\n    Colon,\n    Comma,\n    Hash, // '#'\n    Bang, // '!'\n    Equal,\n    EqualEqual, // '=='\n    NotEqual,   // '!='\n    Vbar,       // '|'\n    VbarVbar,   // '||'\n    AmperAmper, // '&&'\n    LtLt,       // '<<'\n    GtGt,       // '>>'\n    Pipe,       // '|>'\n    Dot,        // '.'\n    RArrow,     // '->'\n    LArrow,     // '<-'\n    DotDot,     // '..'\n    At,         // '@'\n    EndOfFile,\n    // Extra\n    CommentNormal,\n    CommentModule,\n    NewLine,\n    // Keywords (alphabetically):\n    As,\n    Assert,\n    Auto,\n    Case,\n    Const,\n    Delegate,\n    Derive,\n    Echo,\n    Else,\n    Fn,\n    If,\n    Implement,\n    Import,\n    Let,\n    Macro,\n    Opaque,\n    Panic,\n    Pub,\n    Test,\n    Todo,\n    Type,\n    Use,\n}\n\nimpl Token {\n    pub fn guard_precedence(&self) -> Option<u8> {\n        match self {\n            Self::VbarVbar => Some(1),\n\n            Self::AmperAmper => Some(2),\n\n            Self::EqualEqual | Self::NotEqual => Some(3),\n\n            Self::Less\n            | Self::LessEqual\n            | Self::LessDot\n            | Self::LessEqualDot\n            | Self::GreaterEqual\n            | Self::Greater\n            | Self::GreaterEqualDot\n            | Self::GreaterDot => Some(4),\n\n            Self::Concatenate => Some(5),\n\n            Self::Plus | Self::PlusDot | Self::Minus | Self::MinusDot => Some(6),\n\n            Self::Star | Self::StarDot | Self::Slash | Self::SlashDot | Self::Percent => Some(7),\n\n            Self::Name { .. }\n            | Self::UpName { .. }\n            | Self::DiscardName { .. }\n            | Self::Int { .. }\n            | Self::Float { .. }\n            | Self::String { .. }\n            | Self::CommentDoc { .. }\n            | Self::LeftParen\n            | Self::RightParen\n            | Self::LeftSquare\n            | Self::RightSquare\n            | Self::LeftBrace\n            | Self::RightBrace\n            | Self::Colon\n            | Self::Comma\n            | Self::Hash\n            | Self::Bang\n            | Self::Equal\n            | Self::Vbar\n            | Self::LtLt\n            | Self::GtGt\n            | Self::Pipe\n            | Self::Dot\n            | Self::RArrow\n            | Self::LArrow\n            | Self::DotDot\n            | Self::At\n            | Self::EndOfFile\n            | Self::CommentNormal\n            | Self::CommentModule\n            | Self::NewLine\n            | Self::As\n            | Self::Assert\n            | Self::Auto\n            | Self::Case\n            | Self::Const\n            | Self::Delegate\n            | Self::Derive\n            | Self::Echo\n            | Self::Else\n            | Self::Fn\n            | Self::If\n            | Self::Implement\n            | Self::Import\n            | Self::Let\n            | Self::Macro\n            | Self::Opaque\n            | Self::Panic\n            | Self::Pub\n            | Self::Test\n            | Self::Todo\n            | Self::Type\n            | Self::Use => None,\n        }\n    }\n\n    pub fn is_reserved_word(&self) -> bool {\n        match self {\n            Token::As\n            | Token::Assert\n            | Token::Case\n            | Token::Const\n            | Token::Fn\n            | Token::If\n            | Token::Import\n            | Token::Let\n            | Token::Opaque\n            | Token::Pub\n            | Token::Todo\n            | Token::Type\n            | Token::Use\n            | Token::Auto\n            | Token::Delegate\n            | Token::Derive\n            | Token::Echo\n            | Token::Else\n            | Token::Implement\n            | Token::Macro\n            | Token::Panic\n            | Token::Test => true,\n\n            Token::Name { .. }\n            | Token::UpName { .. }\n            | Token::DiscardName { .. }\n            | Token::Int { .. }\n            | Token::Float { .. }\n            | Token::String { .. }\n            | Token::CommentDoc { .. }\n            | Token::LeftParen\n            | Token::RightParen\n            | Token::LeftSquare\n            | Token::RightSquare\n            | Token::LeftBrace\n            | Token::RightBrace\n            | Token::Plus\n            | Token::Minus\n            | Token::Star\n            | Token::Slash\n            | Token::Less\n            | Token::Greater\n            | Token::LessEqual\n            | Token::GreaterEqual\n            | Token::Percent\n            | Token::PlusDot\n            | Token::MinusDot\n            | Token::StarDot\n            | Token::SlashDot\n            | Token::LessDot\n            | Token::GreaterDot\n            | Token::LessEqualDot\n            | Token::GreaterEqualDot\n            | Token::Concatenate\n            | Token::Colon\n            | Token::Comma\n            | Token::Hash\n            | Token::Bang\n            | Token::Equal\n            | Token::EqualEqual\n            | Token::NotEqual\n            | Token::Vbar\n            | Token::VbarVbar\n            | Token::AmperAmper\n            | Token::LtLt\n            | Token::GtGt\n            | Token::Pipe\n            | Token::Dot\n            | Token::RArrow\n            | Token::LArrow\n            | Token::DotDot\n            | Token::At\n            | Token::EndOfFile\n            | Token::CommentNormal\n            | Token::CommentModule\n            | Token::NewLine => false,\n        }\n    }\n}\n\nimpl fmt::Display for Token {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let s = match self {\n            Token::Name { name } | Token::UpName { name } | Token::DiscardName { name } => {\n                name.as_str()\n            }\n            Token::Int {\n                value,\n                int_value: _,\n            }\n            | Token::Float {\n                value,\n                float_value: _,\n            }\n            | Token::String { value } => value.as_str(),\n            Token::AmperAmper => \"&&\",\n            Token::As => \"as\",\n            Token::Assert => \"assert\",\n            Token::At => \"@\",\n            Token::Auto => \"auto\",\n            Token::Bang => \"!\",\n            Token::Case => \"case\",\n            Token::Colon => \":\",\n            Token::Comma => \",\",\n            Token::CommentDoc { .. } => \"///\",\n            Token::CommentModule => \"////\",\n            Token::CommentNormal => \"//\",\n            Token::Const => \"const\",\n            Token::Delegate => \"delegate\",\n            Token::Derive => \"derive\",\n            Token::Dot => \".\",\n            Token::DotDot => \"..\",\n            Token::Echo => \"echo\",\n            Token::Else => \"else\",\n            Token::NewLine => \"NEWLINE\",\n            Token::EndOfFile => \"EOF\",\n            Token::Equal => \"=\",\n            Token::EqualEqual => \"==\",\n            Token::Fn => \"fn\",\n            Token::Greater => \">\",\n            Token::GreaterDot => \">.\",\n            Token::GreaterEqual => \">=\",\n            Token::GreaterEqualDot => \">=.\",\n            Token::GtGt => \">>\",\n            Token::Hash => \"#\",\n            Token::If => \"if\",\n            Token::Implement => \"implement\",\n            Token::Import => \"import\",\n            Token::LArrow => \"<-\",\n            Token::LeftBrace => \"{\",\n            Token::LeftParen => \"(\",\n            Token::LeftSquare => \"[\",\n            Token::Less => \"<\",\n            Token::LessDot => \"<.\",\n            Token::LessEqual => \"<=\",\n            Token::LessEqualDot => \"<=.\",\n            Token::Let => \"let\",\n            Token::Concatenate => \"<>\",\n            Token::LtLt => \"<<\",\n            Token::Macro => \"macro\",\n            Token::Minus => \"-\",\n            Token::MinusDot => \"-.\",\n            Token::NotEqual => \"!=\",\n            Token::Opaque => \"opaque\",\n            Token::Panic => \"panic\",\n            Token::Percent => \"%\",\n            Token::Pipe => \"|>\",\n            Token::Plus => \"+\",\n            Token::PlusDot => \"+.\",\n            Token::Pub => \"pub\",\n            Token::RArrow => \"->\",\n            Token::RightBrace => \"}\",\n            Token::RightParen => \")\",\n            Token::RightSquare => \"]\",\n            Token::Slash => \"/\",\n            Token::SlashDot => \"/.\",\n            Token::Star => \"*\",\n            Token::StarDot => \"*.\",\n            Token::Test => \"test\",\n            Token::Todo => \"todo\",\n            Token::Type => \"type\",\n            Token::Use => \"use\",\n            Token::Vbar => \"|\",\n            Token::VbarVbar => \"||\",\n        };\n        write!(f, \"`{s}`\")\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/parse.rs",
    "content": "// Gleam Parser\n//\n// Terminology:\n//   Expression Unit:\n//     Essentially a thing that goes between operators.\n//     Int, Bool, function call, \"{\" expression-sequence \"}\", case x {}, ..etc\n//\n//   Expression:\n//     One or more Expression Units separated by an operator\n//\n//   Binding:\n//     (let|let assert|use) name (:TypeAnnotation)? = Expression\n//\n//   Expression Sequence:\n//     * One or more Expressions\n//     * A Binding followed by at least one more Expression Sequences\n//\n// Naming Conventions:\n//   parse_x\n//      Parse a specific part of the grammar, not erroring if it cannot.\n//      Generally returns `Result<Option<A>, ParseError>`, note the inner Option\n//\n//   expect_x\n//      Parse a generic or specific part of the grammar, erroring if it cannot.\n//      Generally returns `Result<A, ParseError>`, note no inner Option\n//\n//   maybe_x\n//      Parse a generic part of the grammar. Returning `None` if it cannot.\n//      Returns `Some(x)` and advances the token stream if it can.\n//\n// Operator Precedence Parsing:\n//   Needs to take place in expressions and in clause guards.\n//   It is accomplished using the Simple Precedence Parser algorithm.\n//   See: https://en.wikipedia.org/wiki/Simple_precedence_parser\n//\n//   It relies or the operator grammar being in the general form:\n//   e ::= expr op expr | expr\n//   Which just means that exprs and operators always alternate, starting with an expr\n//\n//   The gist of the algorithm is:\n//   Create 2 stacks, one to hold expressions, and one to hold un-reduced operators.\n//   While consuming the input stream, if an expression is encountered add it to the top\n//   of the expression stack. If an operator is encountered, compare its precedence to the\n//   top of the operator stack and perform the appropriate action, which is either using an\n//   operator to reduce 2 expressions on the top of the expression stack or put it on the top\n//   of the operator stack. When the end of the input is reached, attempt to reduce all of the\n//   expressions down to a single expression(or no expression) using the remaining operators\n//   on the operator stack. If there are any operators left, or more than 1 expression left\n//   this is a syntax error. But the implementation here shouldn't need to handle that case\n//   as the outer parser ensures the correct structure.\n//\npub mod error;\npub mod extra;\npub mod lexer;\nmod token;\n\nuse crate::Warning;\nuse crate::analyse::Inferred;\nuse crate::ast::{\n    Arg, ArgNames, Assert, AssignName, Assignment, AssignmentKind, BinOp, BitArrayOption,\n    BitArraySegment, BitArraySize, CAPTURE_VARIABLE, CallArg, Clause, ClauseGuard, Constant,\n    CustomType, Definition, Function, FunctionLiteralKind, HasLocation, Import, IntOperator,\n    Module, ModuleConstant, Pattern, Publicity, RecordBeingUpdated, RecordConstructor,\n    RecordConstructorArg, RecordUpdateArg, SrcSpan, Statement, TailPattern, TargetedDefinition,\n    TodoKind, TypeAlias, TypeAst, TypeAstConstructor, TypeAstFn, TypeAstHole, TypeAstTuple,\n    TypeAstVar, UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedConstant,\n    UntypedDefinition, UntypedExpr, UntypedModule, UntypedPattern, UntypedRecordUpdateArg,\n    UntypedStatement, UntypedUseAssignment, Use, UseAssignment,\n};\nuse crate::build::Target;\nuse crate::error::wrap;\nuse crate::exhaustiveness::CompiledCase;\nuse crate::parse::extra::ModuleExtra;\nuse crate::type_::Deprecation;\nuse crate::type_::error::{VariableDeclaration, VariableOrigin, VariableSyntax};\nuse crate::type_::expression::{Implementations, Purity};\nuse crate::warning::{DeprecatedSyntaxWarning, WarningEmitter};\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\nuse error::{LexicalError, ParseError, ParseErrorType};\nuse lexer::{LexResult, Spanned};\nuse num_bigint::BigInt;\nuse serde::{Deserialize, Serialize};\nuse std::cmp::Ordering;\nuse std::collections::VecDeque;\nuse std::hash::{Hash, Hasher};\nuse std::str::FromStr;\npub use token::Token;\nuse vec1::{Vec1, vec1};\n\n#[cfg(test)]\nmod tests;\n\n#[derive(Debug)]\npub struct Parsed {\n    pub module: UntypedModule,\n    pub extra: ModuleExtra,\n}\n\n/// We use this to keep track of the `@internal` annotation for top level\n/// definitions. Instead of using just a boolean we want to keep track of the\n/// source position of the annotation in case it is present. This way we can\n/// report a better error message highlighting the annotation in case it is\n/// used on a private definition (it doesn't make sense to mark something\n/// private as internal):\n///\n/// ```txt\n/// @internal\n/// ^^^^^^^^^ we first get to the annotation\n/// fn wibble() {}\n/// ^^ and only later discover it's applied on a private definition\n///    so we have to keep track of the attribute's position to highlight it\n///    in the resulting error message.\n/// ```\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]\nenum InternalAttribute {\n    #[default]\n    Missing,\n    Present(SrcSpan),\n}\n\n#[derive(Debug, Default)]\nstruct Attributes {\n    target: Option<Target>,\n    deprecated: Deprecation,\n    external_erlang: Option<(EcoString, EcoString, SrcSpan)>,\n    external_javascript: Option<(EcoString, EcoString, SrcSpan)>,\n    internal: InternalAttribute,\n}\n\nimpl Attributes {\n    fn has_function_only(&self) -> bool {\n        self.external_erlang.is_some() || self.external_javascript.is_some()\n    }\n\n    fn has_external_for(&self, target: Target) -> bool {\n        match target {\n            Target::Erlang => self.external_erlang.is_some(),\n            Target::JavaScript => self.external_javascript.is_some(),\n        }\n    }\n\n    fn set_external_for(&mut self, target: Target, ext: Option<(EcoString, EcoString, SrcSpan)>) {\n        match target {\n            Target::Erlang => self.external_erlang = ext,\n            Target::JavaScript => self.external_javascript = ext,\n        }\n    }\n}\n\n//\n// Public Interface\n//\n\npub type SpannedString = (SrcSpan, EcoString);\n\npub fn parse_module(\n    path: Utf8PathBuf,\n    src: &str,\n    warnings: &WarningEmitter,\n) -> Result<Parsed, ParseError> {\n    let lex = lexer::make_tokenizer(src);\n    let mut parser = Parser::new(lex);\n    let mut parsed = parser.parse_module()?;\n    parsed.extra = parser.extra;\n\n    let src = EcoString::from(src);\n    for warning in parser.warnings {\n        warnings.emit(Warning::DeprecatedSyntax {\n            path: path.clone(),\n            src: src.clone(),\n            warning,\n        });\n    }\n\n    for detached in parser.detached_doc_comments {\n        warnings.emit(Warning::DetachedDocComment {\n            path: path.clone(),\n            src: src.clone(),\n            location: detached,\n        });\n    }\n\n    Ok(parsed)\n}\n\n//\n// Test Interface\n//\n#[cfg(test)]\npub fn parse_statement_sequence(src: &str) -> Result<Vec1<UntypedStatement>, ParseError> {\n    let lex = lexer::make_tokenizer(src);\n    let mut parser = Parser::new(lex);\n    let expr = parser.parse_statement_seq();\n    let expr = parser.ensure_no_errors_or_remaining_input(expr)?;\n    match expr {\n        Some((e, _)) => Ok(e),\n        _ => parse_error(ParseErrorType::ExpectedExpr, SrcSpan { start: 0, end: 0 }),\n    }\n}\n\n//\n// Test Interface\n//\n#[cfg(test)]\npub fn parse_const_value(src: &str) -> Result<Constant<(), ()>, ParseError> {\n    let lex = lexer::make_tokenizer(src);\n    let mut parser = Parser::new(lex);\n    let expr = parser.parse_const_value();\n    let expr = parser.ensure_no_errors_or_remaining_input(expr)?;\n    match expr {\n        Some(e) => Ok(e),\n        _ => parse_error(ParseErrorType::ExpectedExpr, SrcSpan { start: 0, end: 0 }),\n    }\n}\n\n//\n// Parser\n//\n#[derive(Debug)]\npub struct Parser<T: Iterator<Item = LexResult>> {\n    tokens: T,\n    lex_errors: Vec<LexicalError>,\n    warnings: Vec<DeprecatedSyntaxWarning>,\n    tok0: Option<Spanned>,\n    tok1: Option<Spanned>,\n    extra: ModuleExtra,\n    doc_comments: VecDeque<(u32, EcoString)>,\n    detached_doc_comments: Vec<SrcSpan>,\n}\nimpl<T> Parser<T>\nwhere\n    T: Iterator<Item = LexResult>,\n{\n    pub fn new(input: T) -> Self {\n        let mut parser = Parser {\n            tokens: input,\n            lex_errors: vec![],\n            warnings: vec![],\n            tok0: None,\n            tok1: None,\n            extra: ModuleExtra::new(),\n            doc_comments: VecDeque::new(),\n            detached_doc_comments: Vec::new(),\n        };\n        parser.advance();\n        parser.advance();\n        parser\n    }\n\n    fn parse_module(&mut self) -> Result<Parsed, ParseError> {\n        let definitions = Parser::series_of(self, &Parser::parse_definition, None);\n        let definitions = self.ensure_no_errors_or_remaining_input(definitions)?;\n        let module = Module {\n            name: \"\".into(),\n            documentation: vec![],\n            type_info: (),\n            definitions,\n            names: Default::default(),\n            unused_definition_positions: Default::default(),\n        };\n        Ok(Parsed {\n            module,\n            extra: Default::default(),\n        })\n    }\n\n    // The way the parser is currently implemented, it cannot exit immediately while advancing\n    // the token stream upon seeing a LexError. That is to avoid having to put `?` all over the\n    // place and instead we collect LexErrors in `self.lex_errors` and attempt to continue parsing.\n    // Once parsing has returned we want to surface an error in the order:\n    // 1) LexError, 2) ParseError, 3) More Tokens Left\n    fn ensure_no_errors_or_remaining_input<A>(\n        &mut self,\n        parse_result: Result<A, ParseError>,\n    ) -> Result<A, ParseError> {\n        let parse_result = self.ensure_no_errors(parse_result)?;\n        if let Some((start, token, end)) = self.next_tok() {\n            // there are still more tokens\n            let expected = vec![\"An import, const, type, or function.\".into()];\n            return parse_error(\n                ParseErrorType::UnexpectedToken {\n                    token,\n                    expected,\n                    hint: None,\n                },\n                SrcSpan { start, end },\n            );\n        }\n        // no errors\n        Ok(parse_result)\n    }\n\n    // The way the parser is currently implemented, it cannot exit immediately\n    // while advancing the token stream upon seeing a LexError. That is to avoid\n    // having to put `?` all over the place and instead we collect LexErrors in\n    // `self.lex_errors` and attempt to continue parsing.\n    // Once parsing has returned we want to surface an error in the order:\n    // 1) LexError, 2) ParseError\n    fn ensure_no_errors<A>(\n        &mut self,\n        parse_result: Result<A, ParseError>,\n    ) -> Result<A, ParseError> {\n        if let Some(error) = self.lex_errors.first() {\n            // Lex errors first\n            let location = error.location;\n            let error = *error;\n            parse_error(ParseErrorType::LexError { error }, location)\n        } else {\n            // Return any existing parse error\n            parse_result\n        }\n    }\n\n    fn parse_definition(&mut self) -> Result<Option<TargetedDefinition>, ParseError> {\n        let mut attributes = Attributes::default();\n        let location = self.parse_attributes(&mut attributes)?;\n\n        let def = match (self.tok0.take(), self.tok1.as_ref()) {\n            // Imports\n            (Some((start, Token::Import, _)), _) => {\n                self.advance();\n                self.parse_import(start)\n            }\n            // Module Constants\n            (Some((start, Token::Const, _)), _) => {\n                self.advance();\n                self.parse_module_const(start, false, &attributes)\n            }\n            (Some((start, Token::Pub, _)), Some((_, Token::Const, _))) => {\n                self.advance();\n                self.advance();\n                self.parse_module_const(start, true, &attributes)\n            }\n\n            // Function\n            (Some((start, Token::Fn, _)), _) => {\n                self.advance();\n                self.parse_function(start, false, false, &mut attributes)\n            }\n            (Some((start, Token::Pub, _)), Some((_, Token::Fn, _))) => {\n                self.advance();\n                self.advance();\n                self.parse_function(start, true, false, &mut attributes)\n            }\n\n            // Custom Types, and Type Aliases\n            (Some((start, Token::Type, _)), _) => {\n                self.advance();\n                self.parse_custom_type(start, false, false, &mut attributes)\n            }\n            (Some((start, Token::Pub, _)), Some((_, Token::Opaque, _))) => {\n                self.advance();\n                self.advance();\n                let _ = self.expect_one(&Token::Type)?;\n                self.parse_custom_type(start, true, true, &mut attributes)\n            }\n            (Some((start, Token::Pub, _)), Some((_, Token::Type, _))) => {\n                self.advance();\n                self.advance();\n                self.parse_custom_type(start, true, false, &mut attributes)\n            }\n            (Some((start, Token::Opaque, _)), Some((_, Token::Type, _))) => {\n                // A private opaque type makes no sense! We still want to parse it\n                // and return an error later during the analysis phase.\n                self.advance();\n                self.advance();\n                self.parse_custom_type(start, false, true, &mut attributes)\n            }\n\n            (t0, _) => {\n                self.tok0 = t0;\n                Ok(None)\n            }\n        }?;\n\n        match (def, location) {\n            (Some(definition), _) if definition.is_function() || definition.is_custom_type() => {\n                Ok(Some(TargetedDefinition {\n                    definition,\n                    target: attributes.target,\n                }))\n            }\n\n            (Some(definition), None) => Ok(Some(TargetedDefinition {\n                definition,\n                target: attributes.target,\n            })),\n\n            (_, Some(location)) if attributes.has_function_only() => {\n                parse_error(ParseErrorType::ExpectedFunctionDefinition, location)\n            }\n\n            (Some(definition), _) => Ok(Some(TargetedDefinition {\n                definition,\n                target: attributes.target,\n            })),\n\n            (_, Some(location)) => parse_error(ParseErrorType::ExpectedDefinition, location),\n\n            (None, None) => Ok(None),\n        }\n    }\n\n    //\n    // Parse Expressions\n    //\n\n    // examples:\n    //   unit\n    //   unit op unit\n    //   unit op unit pipe unit(call)\n    //   unit op unit pipe unit(call) pipe unit(call)\n    fn parse_expression(&mut self) -> Result<Option<UntypedExpr>, ParseError> {\n        self.parse_expression_inner(false)\n    }\n\n    fn parse_expression_inner(\n        &mut self,\n        is_let_binding: bool,\n    ) -> Result<Option<UntypedExpr>, ParseError> {\n        // uses the simple operator parser algorithm\n        let mut opstack = vec![];\n        let mut estack = vec![];\n        let mut last_op_start = 0;\n        let mut last_op_end = 0;\n\n        // This is used to keep track if we've just ran into a `|>` operator in\n        // order to properly parse an echo based on its position: if it is in a\n        // pipeline then it isn't expected to be followed by an expression.\n        // Otherwise, it's expected to be followed by an expression.\n        let mut expression_unit_context = ExpressionUnitContext::Other;\n\n        loop {\n            match self.parse_expression_unit(expression_unit_context)? {\n                Some(unit) => {\n                    self.post_process_expression_unit(&unit, is_let_binding)?;\n                    estack.push(unit)\n                }\n                _ if estack.is_empty() => return Ok(None),\n                _ => {\n                    return parse_error(\n                        ParseErrorType::OpNakedRight,\n                        SrcSpan {\n                            start: last_op_start,\n                            end: last_op_end,\n                        },\n                    );\n                }\n            }\n\n            let Some((op_s, t, op_e)) = self.tok0.take() else {\n                break;\n            };\n\n            let Some(p) = precedence(&t) else {\n                self.tok0 = Some((op_s, t, op_e));\n                break;\n            };\n\n            expression_unit_context = if t == Token::Pipe {\n                ExpressionUnitContext::FollowingPipe\n            } else {\n                ExpressionUnitContext::Other\n            };\n\n            // Is Op\n            self.advance();\n            last_op_start = op_s;\n            last_op_end = op_e;\n            let _ = handle_op(\n                Some(((op_s, t, op_e), p)),\n                &mut opstack,\n                &mut estack,\n                &do_reduce_expression,\n            );\n        }\n\n        Ok(handle_op(\n            None,\n            &mut opstack,\n            &mut estack,\n            &do_reduce_expression,\n        ))\n    }\n\n    fn post_process_expression_unit(\n        &mut self,\n        unit: &UntypedExpr,\n        is_let_binding: bool,\n    ) -> Result<(), ParseError> {\n        // Produce better error message for `[x] = [1]` outside\n        // of `let` statement.\n        if !is_let_binding\n            && let UntypedExpr::List { .. } = unit\n            && let Some((start, Token::Equal, end)) = self.tok0\n        {\n            return parse_error(ParseErrorType::NoLetBinding, SrcSpan { start, end });\n        }\n        Ok(())\n    }\n\n    // examples:\n    //   1\n    //   \"one\"\n    //   True\n    //   fn() { \"hi\" }\n    //   unit().unit().unit()\n    //   A(a.., label: tuple(1))\n    //   { expression_sequence }\n    fn parse_expression_unit(\n        &mut self,\n        context: ExpressionUnitContext,\n    ) -> Result<Option<UntypedExpr>, ParseError> {\n        let mut expr = match self.tok0.take() {\n            Some((start, Token::String { value }, end)) => {\n                self.advance();\n                UntypedExpr::String {\n                    location: SrcSpan { start, end },\n                    value,\n                }\n            }\n            Some((start, Token::Int { value, int_value }, end)) => {\n                self.advance();\n                UntypedExpr::Int {\n                    location: SrcSpan { start, end },\n                    value,\n                    int_value,\n                }\n            }\n\n            Some((start, Token::Float { value, float_value }, end)) => {\n                self.advance();\n                UntypedExpr::Float {\n                    location: SrcSpan { start, end },\n                    value,\n                    float_value,\n                }\n            }\n\n            // var lower_name and UpName\n            Some((start, Token::Name { name } | Token::UpName { name }, end)) => {\n                self.advance();\n                UntypedExpr::Var {\n                    location: SrcSpan { start, end },\n                    name,\n                }\n            }\n\n            Some((start, Token::Todo, end)) => {\n                self.advance();\n                let message = self.maybe_parse_as_message()?;\n                let end = message.as_ref().map_or(end, |m| m.location().end);\n                UntypedExpr::Todo {\n                    location: SrcSpan { start, end },\n                    kind: TodoKind::Keyword,\n                    message,\n                }\n            }\n\n            Some((start, Token::Panic, end)) => {\n                self.advance();\n                let message = self.maybe_parse_as_message()?;\n                let end = message.as_ref().map_or(end, |m| m.location().end);\n                UntypedExpr::Panic {\n                    location: SrcSpan { start, end },\n                    message,\n                }\n            }\n\n            Some((start, Token::Echo, echo_end)) => {\n                self.advance();\n                if context == ExpressionUnitContext::FollowingPipe {\n                    // If an echo is used as a step in a pipeline (`|> echo`)\n                    // then it cannot be followed by an expression.\n                    let message = self.maybe_parse_as_message()?;\n                    let end = message.as_ref().map_or(echo_end, |m| m.location().end);\n                    UntypedExpr::Echo {\n                        location: SrcSpan { start, end },\n                        keyword_end: echo_end,\n                        expression: None,\n                        message,\n                    }\n                } else {\n                    // Otherwise it must be followed by an expression.\n                    // However, you might have noticed we're not erroring if the\n                    // expression is not there. Instead we move this error to\n                    // the analysis phase so that a wrong usage of echo won't\n                    // stop analysis from happening everywhere and be fault\n                    // tolerant like everything else.\n                    let expression = self.parse_expression()?;\n                    let end = expression.as_ref().map_or(echo_end, |e| e.location().end);\n\n                    let message = self.maybe_parse_as_message()?;\n                    let end = message.as_ref().map_or(end, |m| m.location().end);\n\n                    UntypedExpr::Echo {\n                        location: SrcSpan { start, end },\n                        keyword_end: echo_end,\n                        expression: expression.map(Box::new),\n                        message,\n                    }\n                }\n            }\n\n            Some((start, Token::Hash, _)) => {\n                self.advance();\n                let _ = self\n                    .expect_one(&Token::LeftParen)\n                    .map_err(|e| self.add_comment_style_hint(e))?;\n                let elements =\n                    Parser::series_of(self, &Parser::parse_expression, Some(&Token::Comma))?;\n                let (_, end) =\n                    self.expect_one_following_series(&Token::RightParen, \"an expression\")?;\n                UntypedExpr::Tuple {\n                    location: SrcSpan { start, end },\n                    elements,\n                }\n            }\n\n            // list\n            Some((start, Token::LeftSquare, _)) => {\n                self.advance();\n                let (elements, elements_end_with_comma) = self.series_of_has_trailing_separator(\n                    &Parser::parse_expression,\n                    Some(&Token::Comma),\n                )?;\n\n                // Parse an optional tail\n                let mut tail = None;\n                let mut elements_after_tail = None;\n                let mut dot_dot_location = None;\n\n                if let Some((start, end)) = self.maybe_one(&Token::DotDot) {\n                    dot_dot_location = Some((start, end));\n                    tail = self.parse_expression()?.map(Box::new);\n                    if self.maybe_one(&Token::Comma).is_some() {\n                        // See if there's a list of items after the tail,\n                        // like `[..wibble, wobble, wabble]`\n                        let elements =\n                            self.series_of(&Parser::parse_expression, Some(&Token::Comma));\n                        match elements {\n                            Err(_) => {}\n                            Ok(elements) => {\n                                elements_after_tail = Some(elements);\n                            }\n                        };\n                    };\n\n                    if tail.is_some() {\n                        if !elements_end_with_comma {\n                            self.warnings\n                                .push(DeprecatedSyntaxWarning::DeprecatedListPrepend {\n                                    location: SrcSpan { start, end },\n                                });\n                        }\n\n                        // Give a better error when there is two consecutive spreads\n                        // like `[..wibble, ..wabble, woo]`. However, if there's other\n                        // elements after the tail of the list\n                        if let Some((second_start, second_end)) = self.maybe_one(&Token::DotDot) {\n                            let _second_tail = self.parse_expression();\n\n                            if elements_after_tail.is_none()\n                                || elements_after_tail\n                                    .as_ref()\n                                    .is_some_and(|vec| vec.is_empty())\n                            {\n                                return parse_error(\n                                    ParseErrorType::ListSpreadWithAnotherSpread {\n                                        first_spread_location: SrcSpan { start, end },\n                                    },\n                                    SrcSpan {\n                                        start: second_start,\n                                        end: second_end,\n                                    },\n                                );\n                            }\n                        }\n                    }\n                }\n\n                let (_, end) = self.expect_one(&Token::RightSquare)?;\n\n                // Return errors for malformed lists\n                match dot_dot_location {\n                    Some((start, end)) if tail.is_none() => {\n                        return parse_error(\n                            ParseErrorType::ListSpreadWithoutTail,\n                            SrcSpan { start, end },\n                        );\n                    }\n                    _ => {}\n                }\n                if tail.is_some()\n                    && elements.is_empty()\n                    && elements_after_tail.as_ref().is_none_or(|e| e.is_empty())\n                {\n                    return parse_error(\n                        ParseErrorType::ListSpreadWithoutElements,\n                        SrcSpan { start, end },\n                    );\n                }\n\n                match elements_after_tail {\n                    Some(elements) if !elements.is_empty() => {\n                        let (start, end) = match (dot_dot_location, tail) {\n                            (Some((start, _)), Some(tail)) => (start, tail.location().end),\n                            (_, _) => (start, end),\n                        };\n                        return parse_error(\n                            ParseErrorType::ListSpreadFollowedByElements,\n                            SrcSpan { start, end },\n                        );\n                    }\n                    _ => {}\n                }\n\n                UntypedExpr::List {\n                    location: SrcSpan { start, end },\n                    elements,\n                    tail,\n                }\n            }\n\n            // BitArray\n            Some((start, Token::LtLt, _)) => {\n                self.advance();\n                let segments = Parser::series_of(\n                    self,\n                    &|s| {\n                        Parser::parse_bit_array_segment(\n                            s,\n                            &(|this| this.parse_expression_unit(ExpressionUnitContext::Other)),\n                            &Parser::expect_expression,\n                            &bit_array_expr_int,\n                        )\n                    },\n                    Some(&Token::Comma),\n                )?;\n                let (_, end) =\n                    self.expect_one_following_series(&Token::GtGt, \"a bit array segment\")?;\n                UntypedExpr::BitArray {\n                    location: SrcSpan { start, end },\n                    segments,\n                }\n            }\n            Some((start, Token::Fn, _)) => {\n                self.advance();\n                let mut attributes = Attributes::default();\n                match self.parse_function(start, false, true, &mut attributes)? {\n                    Some(Definition::Function(Function {\n                        location,\n                        arguments,\n                        body,\n                        return_annotation,\n                        end_position,\n                        ..\n                    })) => {\n                        let Ok(body) = Vec1::try_from_vec(body) else {\n                            return parse_error(ParseErrorType::ExpectedFunctionBody, location);\n                        };\n\n                        UntypedExpr::Fn {\n                            location: SrcSpan::new(location.start, end_position),\n                            end_of_head_byte_index: location.end,\n                            kind: FunctionLiteralKind::Anonymous { head: location },\n                            arguments,\n                            body,\n                            return_annotation,\n                        }\n                    }\n\n                    _ => {\n                        // this isn't just none, it could also be Some(UntypedExpr::..)\n                        return self.next_tok_unexpected(vec![\"An opening parenthesis.\".into()]);\n                    }\n                }\n            }\n\n            // expression block  \"{\" \"}\"\n            Some((start, Token::LeftBrace, _)) => {\n                self.advance();\n                self.parse_block(start)?\n            }\n\n            // case\n            Some((start, Token::Case, case_e)) => {\n                self.advance();\n                let subjects =\n                    Parser::series_of(self, &Parser::parse_expression, Some(&Token::Comma))?;\n                if self.maybe_one(&Token::LeftBrace).is_some() {\n                    let clauses = Parser::series_of(self, &Parser::parse_case_clause, None)?;\n                    let (_, end) =\n                        self.expect_one_following_series(&Token::RightBrace, \"a case clause\")?;\n                    if subjects.is_empty() {\n                        return parse_error(\n                            ParseErrorType::ExpectedExpr,\n                            SrcSpan { start, end: case_e },\n                        );\n                    } else {\n                        UntypedExpr::Case {\n                            location: SrcSpan { start, end },\n                            subjects,\n                            clauses: Some(clauses),\n                        }\n                    }\n                } else {\n                    UntypedExpr::Case {\n                        location: SrcSpan::new(\n                            start,\n                            subjects\n                                .last()\n                                .map(|subject| subject.location().end)\n                                .unwrap_or(case_e),\n                        ),\n                        subjects,\n                        clauses: None,\n                    }\n                }\n            }\n\n            // Helpful error if trying to write an if expression instead of a\n            // case.\n            Some((start, Token::If, end)) => {\n                return parse_error(ParseErrorType::IfExpression, SrcSpan { start, end });\n            }\n\n            // Helpful error on possibly trying to group with \"(\".\n            Some((start, Token::LeftParen, _)) => {\n                return parse_error(ParseErrorType::ExprLparStart, SrcSpan { start, end: start });\n            }\n\n            // Boolean negation\n            Some((start, Token::Bang, _end)) => {\n                self.advance();\n                match self.parse_expression_unit(ExpressionUnitContext::Other)? {\n                    Some(value) => UntypedExpr::NegateBool {\n                        location: SrcSpan {\n                            start,\n                            end: value.location().end,\n                        },\n                        value: Box::from(value),\n                    },\n                    None => {\n                        return parse_error(\n                            ParseErrorType::ExpectedExpr,\n                            SrcSpan { start, end: start },\n                        );\n                    }\n                }\n            }\n\n            // Int negation\n            Some((start, Token::Minus, _end)) => {\n                self.advance();\n                match self.parse_expression_unit(ExpressionUnitContext::Other)? {\n                    Some(value) => UntypedExpr::NegateInt {\n                        location: SrcSpan {\n                            start,\n                            end: value.location().end,\n                        },\n                        value: Box::from(value),\n                    },\n                    None => {\n                        return parse_error(\n                            ParseErrorType::ExpectedExpr,\n                            SrcSpan { start, end: start },\n                        );\n                    }\n                }\n            }\n\n            t0 => {\n                self.tok0 = t0;\n                return Ok(None);\n            }\n        };\n\n        // field access and call can stack up\n        loop {\n            match self.maybe_one(&Token::Dot) {\n                Some((dot_start, _)) => {\n                    let start = expr.location().start;\n                    // field access\n                    match self.tok0.take() {\n                        // tuple access\n                        Some((\n                            _,\n                            Token::Int {\n                                value,\n                                int_value: _,\n                            },\n                            end,\n                        )) => {\n                            self.advance();\n                            let v = value.replace(\"_\", \"\");\n                            match u64::from_str(&v) {\n                                Ok(index) => {\n                                    expr = UntypedExpr::TupleIndex {\n                                        location: SrcSpan { start, end },\n                                        index,\n                                        tuple: Box::new(expr),\n                                    }\n                                }\n                                _ => {\n                                    return parse_error(\n                                        ParseErrorType::InvalidTupleAccess,\n                                        SrcSpan { start, end },\n                                    );\n                                }\n                            }\n                        }\n\n                        Some((label_start, Token::Name { name: label }, end)) => {\n                            self.advance();\n                            expr = UntypedExpr::FieldAccess {\n                                location: SrcSpan { start, end },\n                                label_location: SrcSpan {\n                                    start: label_start,\n                                    end,\n                                },\n                                label,\n                                container: Box::new(expr),\n                            }\n                        }\n\n                        Some((label_start, Token::UpName { name: label }, end)) => {\n                            self.advance();\n                            expr = UntypedExpr::FieldAccess {\n                                location: SrcSpan { start, end },\n                                label_location: SrcSpan {\n                                    start: label_start,\n                                    end,\n                                },\n                                label,\n                                container: Box::new(expr),\n                            }\n                        }\n\n                        t0 => {\n                            // parse a field access with no label\n                            self.tok0 = t0;\n                            let end = dot_start + 1;\n                            expr = UntypedExpr::FieldAccess {\n                                location: SrcSpan { start, end },\n                                label_location: SrcSpan {\n                                    start: dot_start,\n                                    end,\n                                },\n                                label: \"\".into(),\n                                container: Box::new(expr),\n                            };\n                            return Ok(Some(expr));\n                        }\n                    }\n                }\n                _ => {\n                    if self.maybe_one(&Token::LeftParen).is_some() {\n                        let start = expr.location().start;\n                        match self.maybe_one(&Token::DotDot) {\n                            Some((dot_s, _)) => {\n                                // Record update\n                                let base = self.expect_expression()?;\n                                let base_e = base.location().end;\n                                let record = RecordBeingUpdated {\n                                    base: Box::new(base),\n                                    location: SrcSpan {\n                                        start: dot_s,\n                                        end: base_e,\n                                    },\n                                };\n                                let mut arguments = vec![];\n                                if self.maybe_one(&Token::Comma).is_some() {\n                                    arguments = Parser::series_of(\n                                        self,\n                                        &Parser::parse_record_update_arg,\n                                        Some(&Token::Comma),\n                                    )?;\n                                }\n                                let (_, end) = self.expect_one(&Token::RightParen)?;\n\n                                expr = UntypedExpr::RecordUpdate {\n                                    location: SrcSpan { start, end },\n                                    constructor: Box::new(expr),\n                                    record,\n                                    arguments,\n                                };\n                            }\n                            _ => {\n                                // Call\n                                let arguments = self.parse_fn_arguments()?;\n                                let (_, end) = self.expect_one(&Token::RightParen)?;\n                                expr = make_call(expr, arguments, start, end)?;\n                            }\n                        }\n                    } else {\n                        // done\n                        break;\n                    }\n                }\n            }\n        }\n\n        Ok(Some(expr))\n    }\n\n    fn add_comment_style_hint(&self, mut err: ParseError) -> ParseError {\n        if let ParseErrorType::UnexpectedToken { ref mut hint, .. } = err.error {\n            let text =\n                \"Maybe you meant to create a comment?\\nComments in Gleam start with `//`, not `#`\";\n            *hint = Some(text.into());\n        }\n        err\n    }\n\n    // A `use` expression\n    // use <- function\n    // use <- function()\n    // use <- function(a, b)\n    // use <- module.function(a, b)\n    // use a, b, c <- function(a, b)\n    // use a, b, c, <- function(a, b)\n    fn parse_use(&mut self, start: u32, end: u32) -> Result<UntypedStatement, ParseError> {\n        let assignments = match self.tok0 {\n            Some((_, Token::LArrow, _)) => {\n                vec![]\n            }\n            _ => Parser::series_of(self, &Parser::parse_use_assignment, Some(&Token::Comma))?,\n        };\n\n        _ = self.expect_one_following_series(&Token::LArrow, \"a use variable assignment\")?;\n        let call = self.expect_expression()?;\n\n        let assignments_location = match (assignments.first(), assignments.last()) {\n            (Some(first), Some(last)) => SrcSpan {\n                start: first.location.start,\n                end: last.location.end,\n            },\n            (_, _) => SrcSpan { start, end },\n        };\n\n        Ok(Statement::Use(Use {\n            location: SrcSpan::new(start, call.location().end),\n            assignments_location,\n            right_hand_side_location: call.location(),\n            assignments,\n            call: Box::new(call),\n        }))\n    }\n\n    fn parse_use_assignment(&mut self) -> Result<Option<UntypedUseAssignment>, ParseError> {\n        let start = self.tok0.as_ref().map(|t| t.0).unwrap_or(0);\n\n        let pattern = self\n            .parse_pattern(PatternPosition::UsePattern)?\n            .ok_or_else(|| ParseError {\n                error: ParseErrorType::ExpectedPattern,\n                location: SrcSpan { start, end: start },\n            })?;\n\n        let annotation = self.parse_type_annotation(&Token::Colon)?;\n        let end = match annotation {\n            Some(ref a) => a.location().end,\n            None => pattern.location().end,\n        };\n\n        Ok(Some(UseAssignment {\n            location: SrcSpan { start, end },\n            pattern,\n            annotation,\n        }))\n    }\n\n    fn maybe_parse_as_message(&mut self) -> Result<Option<Box<UntypedExpr>>, ParseError> {\n        let message = if self.maybe_one(&Token::As).is_some() {\n            let expression = self.expect_expression_unit(ExpressionUnitContext::Other)?;\n            Some(Box::new(expression))\n        } else {\n            None\n        };\n\n        Ok(message)\n    }\n\n    // An assignment, with `Let` already consumed\n    fn parse_assignment(&mut self, start: u32) -> Result<UntypedStatement, ParseError> {\n        let mut kind = match self.tok0 {\n            Some((assert_keyword_start, Token::Assert, assert_end)) => {\n                _ = self.next_tok();\n                AssignmentKind::Assert {\n                    location: SrcSpan::new(start, assert_end),\n                    assert_keyword_start,\n                    message: None,\n                }\n            }\n            _ => AssignmentKind::Let,\n        };\n        let pattern = match self.parse_pattern(PatternPosition::LetAssignment)? {\n            Some(p) => p,\n            _ => {\n                // DUPE: 62884\n                return self.next_tok_unexpected(vec![\"A pattern\".into()])?;\n            }\n        };\n        let annotation = self.parse_type_annotation(&Token::Colon)?;\n        let (eq_s, eq_e) = self.maybe_one(&Token::Equal).ok_or(ParseError {\n            error: ParseErrorType::ExpectedEqual,\n            location: SrcSpan {\n                start: pattern.location().start,\n                end: pattern.location().end,\n            },\n        })?;\n        let value = self.parse_expression_inner(true)?.ok_or(match self.tok0 {\n            Some((start, Token::DiscardName { .. }, end)) => ParseError {\n                error: ParseErrorType::IncorrectName,\n                location: SrcSpan { start, end },\n            },\n\n            _ => ParseError {\n                error: ParseErrorType::ExpectedValue,\n                location: SrcSpan {\n                    start: eq_s,\n                    end: eq_e,\n                },\n            },\n        })?;\n\n        let mut end = value.location().end;\n\n        match &mut kind {\n            AssignmentKind::Let | AssignmentKind::Generated => {}\n            AssignmentKind::Assert { message, .. } => {\n                if self.maybe_one(&Token::As).is_some() {\n                    let message_expression =\n                        self.expect_expression_unit(ExpressionUnitContext::Other)?;\n                    end = message_expression.location().end;\n                    *message = Some(message_expression);\n                }\n            }\n        }\n\n        Ok(Statement::Assignment(Box::new(Assignment {\n            location: SrcSpan { start, end },\n            value,\n            compiled_case: CompiledCase::failure(),\n            pattern,\n            annotation,\n            kind,\n        })))\n    }\n\n    // An assert statement, with `Assert` already consumed\n    fn parse_assert(&mut self, start: u32) -> Result<UntypedStatement, ParseError> {\n        let value = self.expect_expression()?;\n        let mut end = value.location().end;\n\n        let message = if self.maybe_one(&Token::As).is_some() {\n            let message_expression = self.expect_expression_unit(ExpressionUnitContext::Other)?;\n            end = message_expression.location().end;\n            Some(message_expression)\n        } else {\n            None\n        };\n\n        Ok(Statement::Assert(Assert {\n            location: SrcSpan { start, end },\n            value,\n            message,\n        }))\n    }\n\n    // examples:\n    //   expr\n    //   expr expr..\n    //   expr assignment..\n    //   assignment\n    //   assignment expr..\n    //   assignment assignment..\n    fn parse_statement_seq(&mut self) -> Result<Option<(Vec1<UntypedStatement>, u32)>, ParseError> {\n        let mut statements = vec![];\n        let mut start = None;\n        let mut end = 0;\n\n        // Try and parse as many expressions as possible\n        while let Some(statement) = self.parse_statement()? {\n            if start.is_none() {\n                start = Some(statement.location().start);\n            }\n            end = statement.location().end;\n            statements.push(statement);\n        }\n\n        match Vec1::try_from_vec(statements) {\n            Ok(statements) => Ok(Some((statements, end))),\n            Err(_) => Ok(None),\n        }\n    }\n\n    fn parse_statement(&mut self) -> Result<Option<UntypedStatement>, ParseError> {\n        match self.tok0.take() {\n            Some((start, Token::Use, end)) => {\n                self.advance();\n                Ok(Some(self.parse_use(start, end)?))\n            }\n\n            Some((start, Token::Let, _)) => {\n                self.advance();\n                Ok(Some(self.parse_assignment(start)?))\n            }\n\n            Some((start, Token::Assert, _)) => {\n                self.advance();\n                Ok(Some(self.parse_assert(start)?))\n            }\n\n            // Helpful error when trying to define a constant inside a function.\n            Some((start, Token::Const, end)) => parse_error(\n                ParseErrorType::ConstantInsideFunction,\n                SrcSpan { start, end },\n            ),\n\n            token => {\n                self.tok0 = token;\n                self.parse_statement_errors()?;\n                let expression = self.parse_expression()?.map(Statement::Expression);\n                Ok(expression)\n            }\n        }\n    }\n\n    fn parse_statement_errors(&mut self) -> Result<(), ParseError> {\n        // Better error: name definitions must start with `let`\n        if let Some((_, Token::Name { .. }, _)) = self.tok0.as_ref()\n            && let Some((start, Token::Equal | Token::Colon, end)) = self.tok1\n        {\n            return parse_error(ParseErrorType::NoLetBinding, SrcSpan { start, end });\n        }\n        Ok(())\n    }\n\n    fn parse_block(&mut self, start: u32) -> Result<UntypedExpr, ParseError> {\n        let body = self.parse_statement_seq()?;\n        let (_, end) = self.expect_one(&Token::RightBrace)?;\n        let location = SrcSpan { start, end };\n        let statements = match body {\n            Some((statements, _)) => statements,\n            None => vec1![Statement::Expression(UntypedExpr::Todo {\n                kind: TodoKind::EmptyBlock,\n                location,\n                message: None\n            })],\n        };\n\n        Ok(UntypedExpr::Block {\n            location,\n            statements,\n        })\n    }\n\n    // The left side of an \"=\" or a \"->\"\n    fn parse_pattern(\n        &mut self,\n        position: PatternPosition,\n    ) -> Result<Option<UntypedPattern>, ParseError> {\n        let pattern = match self.tok0.take() {\n            // Pattern::Var or Pattern::Constructor start\n            Some((start, Token::Name { name }, end)) => {\n                self.advance();\n\n                // A variable is not permitted on the left hand side of a `<>`\n                if let Some((_, Token::Concatenate, _)) = self.tok0.as_ref() {\n                    return concat_pattern_variable_left_hand_side_error(start, end);\n                }\n\n                if self.maybe_one(&Token::Dot).is_some() {\n                    // We're doing this to get a better error message instead of a generic\n                    // `I was expecting a type`, you can have a look at this issue to get\n                    // a better idea: https://github.com/gleam-lang/gleam/issues/2841.\n                    match self.expect_constructor_pattern(Some((start, name, end)), position) {\n                        Ok(result) => result,\n                        Err(ParseError {\n                            location: SrcSpan { end, .. },\n                            ..\n                        }) => {\n                            return parse_error(\n                                ParseErrorType::InvalidModuleTypePattern,\n                                SrcSpan { start, end },\n                            );\n                        }\n                    }\n                } else {\n                    Pattern::Variable {\n                        origin: VariableOrigin {\n                            syntax: VariableSyntax::Variable(name.clone()),\n                            declaration: position.to_declaration(),\n                        },\n                        location: SrcSpan { start, end },\n                        name,\n                        type_: (),\n                    }\n                }\n            }\n            // Constructor\n            Some((start, tok @ Token::UpName { .. }, end)) => {\n                self.tok0 = Some((start, tok, end));\n                self.expect_constructor_pattern(None, position)?\n            }\n\n            Some((start, Token::DiscardName { name }, end)) => {\n                self.advance();\n\n                // A discard is not permitted on the left hand side of a `<>`\n                if let Some((_, Token::Concatenate, _)) = self.tok0.as_ref() {\n                    return concat_pattern_variable_left_hand_side_error(start, end);\n                }\n\n                Pattern::Discard {\n                    location: SrcSpan { start, end },\n                    name,\n                    type_: (),\n                }\n            }\n\n            Some((start, Token::String { value }, end)) => {\n                self.advance();\n\n                match self.tok0 {\n                    // String matching with assignment, it could either be a\n                    // String prefix matching: \"Hello, \" as greeting <> name -> ...\n                    // or a full string matching: \"Hello, World!\" as greeting -> ...\n                    Some((_, Token::As, _)) => {\n                        self.advance();\n                        let (name_start, name, name_end) = self.expect_name()?;\n                        let name_span = SrcSpan {\n                            start: name_start,\n                            end: name_end,\n                        };\n\n                        match self.tok0 {\n                            // String prefix matching with assignment\n                            // \"Hello, \" as greeting <> name -> ...\n                            Some((_, Token::Concatenate, _)) => {\n                                self.advance();\n                                let (r_start, right, r_end) = self.expect_assign_name()?;\n                                Pattern::StringPrefix {\n                                    location: SrcSpan { start, end: r_end },\n                                    left_location: SrcSpan {\n                                        start,\n                                        end: name_end,\n                                    },\n                                    right_location: SrcSpan {\n                                        start: r_start,\n                                        end: r_end,\n                                    },\n                                    left_side_string: value,\n                                    left_side_assignment: Some((name, name_span)),\n                                    right_side_assignment: right,\n                                }\n                            }\n                            // Full string matching with assignment\n                            _ => {\n                                return Ok(Some(Pattern::Assign {\n                                    name,\n                                    location: name_span,\n                                    pattern: Box::new(Pattern::String {\n                                        location: SrcSpan { start, end },\n                                        value,\n                                    }),\n                                }));\n                            }\n                        }\n                    }\n\n                    // String prefix matching with no left side assignment\n                    // \"Hello, \" <> name -> ...\n                    Some((_, Token::Concatenate, _)) => {\n                        self.advance();\n                        let (r_start, right, r_end) = self.expect_assign_name()?;\n                        Pattern::StringPrefix {\n                            location: SrcSpan { start, end: r_end },\n                            left_location: SrcSpan { start, end },\n                            right_location: SrcSpan {\n                                start: r_start,\n                                end: r_end,\n                            },\n                            left_side_string: value,\n                            left_side_assignment: None,\n                            right_side_assignment: right,\n                        }\n                    }\n\n                    // Full string matching\n                    // \"Hello, World!\" -> ...\n                    _ => Pattern::String {\n                        location: SrcSpan { start, end },\n                        value,\n                    },\n                }\n            }\n            Some((start, Token::Int { value, int_value }, end)) => {\n                self.advance();\n                Pattern::Int {\n                    location: SrcSpan { start, end },\n                    value,\n                    int_value,\n                }\n            }\n            Some((start, Token::Float { value, float_value }, end)) => {\n                self.advance();\n                Pattern::Float {\n                    location: SrcSpan { start, end },\n                    value,\n                    float_value,\n                }\n            }\n            Some((start, Token::Hash, _)) => {\n                self.advance();\n                let _ = self.expect_one(&Token::LeftParen)?;\n                let elements = Parser::series_of(\n                    self,\n                    &|this| this.parse_pattern(position),\n                    Some(&Token::Comma),\n                )?;\n                let (_, end) = self.expect_one_following_series(&Token::RightParen, \"a pattern\")?;\n                Pattern::Tuple {\n                    location: SrcSpan { start, end },\n                    elements,\n                }\n            }\n            // BitArray\n            Some((start, Token::LtLt, _)) => {\n                self.advance();\n                let segments = Parser::series_of(\n                    self,\n                    &|s| {\n                        Parser::parse_bit_array_segment(\n                            s,\n                            &|s| match s.parse_pattern(position) {\n                                Ok(Some(Pattern::BitArray { location, .. })) => {\n                                    parse_error(ParseErrorType::NestedBitArrayPattern, location)\n                                }\n                                x => x,\n                            },\n                            &Parser::expect_bit_array_pattern_segment_arg,\n                            &bit_array_size_int,\n                        )\n                    },\n                    Some(&Token::Comma),\n                )?;\n                let (_, end) =\n                    self.expect_one_following_series(&Token::GtGt, \"a bit array segment pattern\")?;\n                Pattern::BitArray {\n                    location: SrcSpan { start, end },\n                    segments,\n                }\n            }\n\n            // List\n            Some((start, Token::LeftSquare, _)) => {\n                self.advance();\n                let (elements, elements_end_with_comma) = self.series_of_has_trailing_separator(\n                    &|this| this.parse_pattern(position),\n                    Some(&Token::Comma),\n                )?;\n\n                let mut elements_after_tail = None;\n                let mut dot_dot_location = None;\n                let tail = match self.tok0 {\n                    Some((dot_dot_start, Token::DotDot, dot_dot_end)) => {\n                        dot_dot_location = Some((dot_dot_start, dot_dot_end));\n                        if !elements.is_empty() && !elements_end_with_comma {\n                            self.warnings\n                                .push(DeprecatedSyntaxWarning::DeprecatedListPattern {\n                                    location: SrcSpan {\n                                        start: dot_dot_start,\n                                        end: dot_dot_end,\n                                    },\n                                });\n                        }\n\n                        self.advance();\n                        let tail = self.parse_pattern(position)?;\n                        if self.maybe_one(&Token::Comma).is_some() {\n                            // See if there's a list of items after the tail,\n                            // like `[..wibble, wobble, wabble]`\n                            let elements = Parser::series_of(\n                                self,\n                                &|this| this.parse_pattern(position),\n                                Some(&Token::Comma),\n                            );\n                            match elements {\n                                Err(_) => {}\n                                Ok(elements) => {\n                                    elements_after_tail = Some(elements);\n                                }\n                            };\n                        };\n                        Some(tail)\n                    }\n                    _ => None,\n                };\n\n                let (end, closing_square_bracket_end) =\n                    self.expect_one_following_series(&Token::RightSquare, \"a pattern\")?;\n\n                // If there are elements after the tail, return an error\n                match elements_after_tail {\n                    Some(elements) if !elements.is_empty() => {\n                        let (start, end) = match (dot_dot_location, tail) {\n                            (Some((start, _)), Some(Some(tail))) => (start, tail.location().end),\n                            (Some((start, end)), Some(None)) => (start, end),\n                            (_, _) => (start, end),\n                        };\n                        return parse_error(\n                            ParseErrorType::ListPatternSpreadFollowedByElements,\n                            SrcSpan { start, end },\n                        );\n                    }\n                    _ => {}\n                }\n\n                let tail = match tail {\n                    // There is a tail and it has a Pattern::Var or Pattern::Discard\n                    Some(Some(pattern @ (Pattern::Variable { .. } | Pattern::Discard { .. }))) => {\n                        Some(pattern)\n                    }\n                    // There is a tail and but it has no content, implicit discard\n                    Some(Some(pattern)) => {\n                        return parse_error(ParseErrorType::InvalidTailPattern, pattern.location());\n                    }\n                    Some(None) => Some(Pattern::Discard {\n                        location: SrcSpan {\n                            start: closing_square_bracket_end - 1,\n                            end: closing_square_bracket_end,\n                        },\n                        name: \"_\".into(),\n                        type_: (),\n                    }),\n                    // No tail specified\n                    None => None,\n                };\n\n                if elements.is_empty() && tail.as_ref().is_some_and(|pattern| pattern.is_discard())\n                {\n                    self.warnings\n                        .push(DeprecatedSyntaxWarning::DeprecatedListCatchAllPattern {\n                            location: SrcSpan {\n                                start,\n                                end: closing_square_bracket_end,\n                            },\n                        })\n                }\n\n                Pattern::List {\n                    location: SrcSpan {\n                        start,\n                        end: closing_square_bracket_end,\n                    },\n                    elements,\n                    tail: tail.map(|tail_pattern| {\n                        let dot_dot_start = dot_dot_location\n                            .expect(\"parsed tail with no preceding `..`\")\n                            .0;\n\n                        Box::new(TailPattern {\n                            location: SrcSpan::new(dot_dot_start, tail_pattern.location().end),\n                            pattern: tail_pattern,\n                        })\n                    }),\n                    type_: (),\n                }\n            }\n\n            // No pattern\n            t0 => {\n                self.tok0 = t0;\n                return Ok(None);\n            }\n        };\n\n        match self.tok0 {\n            Some((_, Token::As, _)) => {\n                self.advance();\n                let (start, name, end) = self.expect_name()?;\n                Ok(Some(Pattern::Assign {\n                    name,\n                    location: SrcSpan { start, end },\n                    pattern: Box::new(pattern),\n                }))\n            }\n            _ => Ok(Some(pattern)),\n        }\n    }\n\n    fn add_multi_line_clause_hint(&self, mut err: ParseError) -> ParseError {\n        if let ParseErrorType::UnexpectedToken { ref mut hint, .. } = err.error {\n            *hint = Some(\"Did you mean to wrap a multi line clause in curly braces?\".into());\n        }\n        err\n    }\n\n    // examples:\n    //   pattern -> expr\n    //   pattern, pattern if -> expr\n    //   pattern, pattern | pattern, pattern if -> expr\n    fn parse_case_clause(&mut self) -> Result<Option<UntypedClause>, ParseError> {\n        let patterns = self.parse_patterns(PatternPosition::CaseClause)?;\n        match &patterns.first() {\n            Some(lead) => {\n                let mut alternative_patterns = vec![];\n                while let Some((vbar_start, vbar_end)) = self.maybe_one(&Token::Vbar) {\n                    let patterns = self.parse_patterns(PatternPosition::CaseClause)?;\n                    if patterns.is_empty() {\n                        return parse_error(\n                            ParseErrorType::ExpectedPattern,\n                            SrcSpan {\n                                start: vbar_start,\n                                end: vbar_end,\n                            },\n                        );\n                    }\n                    alternative_patterns.push(patterns);\n                }\n                let guard = self.parse_case_clause_guard()?;\n                let (arr_s, arr_e) = self\n                    .expect_one(&Token::RArrow)\n                    .map_err(|e| self.add_multi_line_clause_hint(e))?;\n                let then = self.parse_expression()?;\n                match then {\n                    Some(then) => Ok(Some(Clause {\n                        location: SrcSpan {\n                            start: lead.location().start,\n                            end: then.location().end,\n                        },\n                        pattern: patterns,\n                        alternative_patterns,\n                        guard,\n                        then,\n                    })),\n                    _ => match self.tok0 {\n                        Some((start, Token::DiscardName { .. }, end)) => {\n                            parse_error(ParseErrorType::IncorrectName, SrcSpan { start, end })\n                        }\n                        _ => parse_error(\n                            ParseErrorType::ExpectedExpr,\n                            SrcSpan {\n                                start: arr_s,\n                                end: arr_e,\n                            },\n                        ),\n                    },\n                }\n            }\n            _ => Ok(None),\n        }\n    }\n    fn parse_patterns(\n        &mut self,\n        position: PatternPosition,\n    ) -> Result<Vec<UntypedPattern>, ParseError> {\n        Parser::series_of(\n            self,\n            &|this| this.parse_pattern(position),\n            Some(&Token::Comma),\n        )\n    }\n\n    // examples:\n    //   if a\n    //   if a < b\n    //   if a < b || b < c\n    fn parse_case_clause_guard(&mut self) -> Result<Option<UntypedClauseGuard>, ParseError> {\n        let Some((start, end)) = self.maybe_one(&Token::If) else {\n            return Ok(None);\n        };\n        let clause_guard_result = self.parse_clause_guard_inner();\n        // If inner clause is none, a warning should be shown to let the user\n        // know that empty clauses in guards are deprecated.\n        if let Ok(None) = clause_guard_result {\n            self.warnings\n                .push(DeprecatedSyntaxWarning::DeprecatedEmptyClauseGuard {\n                    location: SrcSpan { start, end },\n                });\n        }\n        clause_guard_result\n    }\n\n    fn parse_clause_guard_inner(&mut self) -> Result<Option<UntypedClauseGuard>, ParseError> {\n        let mut opstack = vec![];\n        let mut estack = vec![];\n        let mut last_op_start = 0;\n        let mut last_op_end = 0;\n        loop {\n            match self.parse_case_clause_guard_unit()? {\n                Some(unit) => estack.push(unit),\n                _ => {\n                    if estack.is_empty() {\n                        return Ok(None);\n                    } else {\n                        return parse_error(\n                            ParseErrorType::OpNakedRight,\n                            SrcSpan {\n                                start: last_op_start,\n                                end: last_op_end,\n                            },\n                        );\n                    }\n                }\n            }\n\n            let Some((op_s, t, op_e)) = self.tok0.take() else {\n                break;\n            };\n\n            let Some(precedence) = t.guard_precedence() else {\n                // Is not Op\n                self.tok0 = Some((op_s, t, op_e));\n                break;\n            };\n\n            // Is Op\n            self.advance();\n            last_op_start = op_s;\n            last_op_end = op_e;\n            let _ = handle_op(\n                Some(((op_s, t, op_e), precedence)),\n                &mut opstack,\n                &mut estack,\n                &do_reduce_clause_guard,\n            );\n        }\n\n        Ok(handle_op(\n            None,\n            &mut opstack,\n            &mut estack,\n            &do_reduce_clause_guard,\n        ))\n    }\n\n    /// Checks if we have an unexpected left parenthesis and returns appropriate\n    /// error if it is a function call.\n    fn parse_function_call_in_clause_guard(&mut self, start: u32) -> Result<(), ParseError> {\n        if let Some((l_paren_start, l_paren_end)) = self.maybe_one(&Token::LeftParen) {\n            if let Ok((_, end)) = self\n                .parse_fn_arguments()\n                .and(self.expect_one(&Token::RightParen))\n            {\n                return parse_error(ParseErrorType::CallInClauseGuard, SrcSpan { start, end });\n            }\n\n            return parse_error(\n                ParseErrorType::UnexpectedToken {\n                    token: Token::LeftParen,\n                    expected: vec![Token::RArrow.to_string().into()],\n                    hint: None,\n                },\n                SrcSpan {\n                    start: l_paren_start,\n                    end: l_paren_end,\n                },\n            )\n            .map_err(|e| self.add_multi_line_clause_hint(e));\n        }\n\n        Ok(())\n    }\n\n    // examples\n    // a\n    // 1\n    // a.1\n    // { a }\n    // a || b\n    // a < b || b < c\n    fn parse_case_clause_guard_unit(&mut self) -> Result<Option<UntypedClauseGuard>, ParseError> {\n        match self.tok0.take() {\n            Some((start, Token::Bang, _)) => {\n                self.advance();\n                match self.parse_case_clause_guard_unit()? {\n                    Some(unit) => Ok(Some(ClauseGuard::Not {\n                        location: SrcSpan {\n                            start,\n                            end: unit.location().end,\n                        },\n                        expression: Box::new(unit),\n                    })),\n                    None => {\n                        parse_error(ParseErrorType::ExpectedValue, SrcSpan { start, end: start })\n                    }\n                }\n            }\n\n            Some((start, Token::Name { name }, end)) => {\n                self.advance();\n\n                self.parse_function_call_in_clause_guard(start)?;\n\n                let mut unit =\n                    match self.parse_record_in_clause_guard(&name, SrcSpan { start, end })? {\n                        Some(record) => record,\n                        _ => ClauseGuard::Var {\n                            location: SrcSpan { start, end },\n                            type_: (),\n                            name,\n                            definition_location: SrcSpan::default(),\n                            // We don't know the origin until type analysis, so\n                            // we just put `Generated` here as a placeholder.\n                            origin: VariableOrigin {\n                                syntax: VariableSyntax::Generated,\n                                declaration: VariableDeclaration::Generated,\n                            },\n                        },\n                    };\n\n                loop {\n                    let dot_s = match self.maybe_one(&Token::Dot) {\n                        Some((dot_s, _)) => dot_s,\n                        None => return Ok(Some(unit)),\n                    };\n\n                    match self.next_tok() {\n                        Some((\n                            _,\n                            Token::Int {\n                                value,\n                                int_value: _,\n                            },\n                            int_e,\n                        )) => {\n                            let v = value.replace(\"_\", \"\");\n                            match u64::from_str(&v) {\n                                Ok(index) => {\n                                    unit = ClauseGuard::TupleIndex {\n                                        location: SrcSpan {\n                                            start: dot_s,\n                                            end: int_e,\n                                        },\n                                        index,\n                                        type_: (),\n                                        tuple: Box::new(unit),\n                                    };\n                                }\n                                _ => {\n                                    return parse_error(\n                                        ParseErrorType::InvalidTupleAccess,\n                                        SrcSpan { start, end },\n                                    );\n                                }\n                            }\n                        }\n\n                        Some((name_start, Token::Name { name: label }, name_end)) => {\n                            self.parse_function_call_in_clause_guard(start)?;\n\n                            unit = ClauseGuard::FieldAccess {\n                                label_location: SrcSpan {\n                                    start: name_start,\n                                    end: name_end,\n                                },\n                                index: None,\n                                label,\n                                type_: (),\n                                container: Box::new(unit),\n                            };\n                        }\n\n                        Some((start, _, end)) => {\n                            return parse_error(\n                                ParseErrorType::IncorrectName,\n                                SrcSpan { start, end },\n                            );\n                        }\n\n                        _ => return self.next_tok_unexpected(vec![\"A positive integer\".into()]),\n                    }\n                }\n            }\n\n            Some((start, Token::LeftBrace, _)) => {\n                self.advance();\n                Ok(Some(self.parse_case_clause_guard_block(start)?))\n            }\n\n            t0 => {\n                self.tok0 = t0;\n                match self.parse_const_value()? {\n                    Some(const_val) => {\n                        // Constant\n                        Ok(Some(ClauseGuard::Constant(const_val)))\n                    }\n                    _ => Ok(None),\n                }\n            }\n        }\n    }\n\n    fn parse_case_clause_guard_block(\n        &mut self,\n        start: u32,\n    ) -> Result<UntypedClauseGuard, ParseError> {\n        let body = self.parse_clause_guard_inner()?;\n\n        let Some(body) = body else {\n            let location = match self.next_tok() {\n                Some((_, Token::RightBrace, end)) => SrcSpan { start, end },\n                Some((_, _, _)) | None => SrcSpan {\n                    start,\n                    end: start + 1,\n                },\n            };\n\n            return parse_error(ParseErrorType::EmptyGuardBlock, location);\n        };\n\n        let (_, end) = self.expect_one(&Token::RightBrace)?;\n        Ok(ClauseGuard::Block {\n            location: SrcSpan { start, end },\n            value: Box::new(body),\n        })\n    }\n\n    fn parse_record_in_clause_guard(\n        &mut self,\n        module: &EcoString,\n        module_location: SrcSpan,\n    ) -> Result<Option<UntypedClauseGuard>, ParseError> {\n        let (name, end) = match (self.tok0.take(), self.peek_tok1()) {\n            (Some((_, Token::Dot, _)), Some(Token::UpName { .. })) => {\n                self.advance(); // dot\n                let Some((_, Token::UpName { name }, end)) = self.next_tok() else {\n                    return Ok(None);\n                };\n                (name, end)\n            }\n            (tok0, _) => {\n                self.tok0 = tok0;\n                return Ok(None);\n            }\n        };\n\n        match self.parse_const_record_finish(\n            module_location.start,\n            Some((module.clone(), module_location)),\n            name,\n            end,\n        )? {\n            Some(record) => Ok(Some(ClauseGuard::Constant(record))),\n            _ => Ok(None),\n        }\n    }\n\n    // examples:\n    //   UpName( args )\n    fn expect_constructor_pattern(\n        &mut self,\n        module: Option<(u32, EcoString, u32)>,\n        position: PatternPosition,\n    ) -> Result<UntypedPattern, ParseError> {\n        let (name_start, name, name_end) = self.expect_upname()?;\n        let mut start = name_start;\n        let (arguments, spread, end) =\n            self.parse_constructor_pattern_arguments(name_end, position)?;\n        if let Some((s, _, _)) = module {\n            start = s;\n        }\n        Ok(Pattern::Constructor {\n            location: SrcSpan { start, end },\n            name_location: SrcSpan::new(name_start, name_end),\n            arguments,\n            module: module.map(|(start, n, end)| (n, SrcSpan { start, end })),\n            name,\n            spread,\n            constructor: Inferred::Unknown,\n            type_: (),\n        })\n    }\n\n    // examples:\n    //   ( args )\n    #[allow(clippy::type_complexity)]\n    fn parse_constructor_pattern_arguments(\n        &mut self,\n        upname_end: u32,\n        position: PatternPosition,\n    ) -> Result<(Vec<CallArg<UntypedPattern>>, Option<SrcSpan>, u32), ParseError> {\n        if self.maybe_one(&Token::LeftParen).is_some() {\n            let (arguments, arguments_end_with_comma) = self.series_of_has_trailing_separator(\n                &|this| this.parse_constructor_pattern_arg(position),\n                Some(&Token::Comma),\n            )?;\n\n            let spread = self\n                .maybe_one(&Token::DotDot)\n                .map(|(start, end)| SrcSpan { start, end });\n\n            if let Some(spread_location) = spread {\n                let _ = self.maybe_one(&Token::Comma);\n                if !arguments.is_empty() && !arguments_end_with_comma {\n                    self.warnings\n                        .push(DeprecatedSyntaxWarning::DeprecatedRecordSpreadPattern {\n                            location: spread_location,\n                        })\n                }\n            }\n            let (_, end) = self.expect_one(&Token::RightParen)?;\n            Ok((arguments, spread, end))\n        } else {\n            Ok((vec![], None, upname_end))\n        }\n    }\n\n    // examples:\n    //   a: <pattern>\n    //   a:\n    //   <pattern>\n    fn parse_constructor_pattern_arg(\n        &mut self,\n        position: PatternPosition,\n    ) -> Result<Option<CallArg<UntypedPattern>>, ParseError> {\n        match (self.tok0.take(), self.tok1.take()) {\n            // named arg\n            (Some((start, Token::Name { name }, _)), Some((_, Token::Colon, end))) => {\n                self.advance();\n                self.advance();\n                match self.parse_pattern(position)? {\n                    Some(value) => Ok(Some(CallArg {\n                        implicit: None,\n                        location: SrcSpan {\n                            start,\n                            end: value.location().end,\n                        },\n                        label: Some(name),\n                        value,\n                    })),\n                    _ => {\n                        // Argument supplied with a label shorthand.\n                        Ok(Some(CallArg {\n                            implicit: None,\n                            location: SrcSpan { start, end },\n                            label: Some(name.clone()),\n                            value: UntypedPattern::Variable {\n                                origin: VariableOrigin {\n                                    syntax: VariableSyntax::LabelShorthand(name.clone()),\n                                    declaration: position.to_declaration(),\n                                },\n                                name,\n                                location: SrcSpan { start, end },\n                                type_: (),\n                            },\n                        }))\n                    }\n                }\n            }\n            // unnamed arg\n            (t0, t1) => {\n                self.tok0 = t0;\n                self.tok1 = t1;\n                match self.parse_pattern(position)? {\n                    Some(value) => Ok(Some(CallArg {\n                        implicit: None,\n                        location: value.location(),\n                        label: None,\n                        value,\n                    })),\n                    _ => Ok(None),\n                }\n            }\n        }\n    }\n\n    // examples:\n    //   a: expr\n    //   a:\n    fn parse_record_update_arg(&mut self) -> Result<Option<UntypedRecordUpdateArg>, ParseError> {\n        match self.maybe_name() {\n            Some((start, label, _)) => {\n                let (_, end) = self.expect_one(&Token::Colon)?;\n                let value = self.parse_expression()?;\n                match value {\n                    Some(value) => Ok(Some(UntypedRecordUpdateArg {\n                        label,\n                        location: SrcSpan {\n                            start,\n                            end: value.location().end,\n                        },\n                        value,\n                    })),\n                    _ => {\n                        // Argument supplied with a label shorthand.\n                        Ok(Some(UntypedRecordUpdateArg {\n                            label: label.clone(),\n                            location: SrcSpan { start, end },\n                            value: UntypedExpr::Var {\n                                name: label,\n                                location: SrcSpan { start, end },\n                            },\n                        }))\n                    }\n                }\n            }\n            _ => Ok(None),\n        }\n    }\n\n    //\n    // Parse Functions\n    //\n\n    // Starts after \"fn\"\n    //\n    // examples:\n    //   fn a(name: String) -> String { .. }\n    //   pub fn a(name name: String) -> String { .. }\n    fn parse_function(\n        &mut self,\n        start: u32,\n        public: bool,\n        is_anon: bool,\n        attributes: &mut Attributes,\n    ) -> Result<Option<UntypedDefinition>, ParseError> {\n        let documentation = if is_anon {\n            None\n        } else {\n            self.take_documentation(start)\n        };\n        let mut name = None;\n        if !is_anon {\n            let (name_start, n, name_end) = self.expect_name()?;\n            name = Some((\n                SrcSpan {\n                    start: name_start,\n                    end: name_end,\n                },\n                n,\n            ));\n        }\n        if let Some((less_start, less_end)) = self.maybe_one(&Token::Less) {\n            return Err(ParseError {\n                error: ParseErrorType::FunctionDefinitionAngleGenerics,\n                location: SrcSpan {\n                    start: less_start,\n                    end: less_end,\n                },\n            });\n        }\n        let _ = self\n            .expect_one(&Token::LeftParen)\n            .map_err(|e| self.add_anon_function_hint(e))?;\n        let arguments = Parser::series_of(\n            self,\n            &|parser| Parser::parse_fn_param(parser, is_anon),\n            Some(&Token::Comma),\n        )?;\n        let (_, rpar_e) =\n            self.expect_one_following_series(&Token::RightParen, \"a function parameter\")?;\n\n        // Check for TypeScript-style return type annotation (:) instead of arrow (->)\n        if let Some((colon_start, colon_end)) = self.maybe_one(&Token::Colon) {\n            return Err(ParseError {\n                error: ParseErrorType::UnexpectedToken {\n                    token: Token::Colon,\n                    expected: vec![\"`->`\".into()],\n                    hint: Some(\"Return type annotations are written using `->`, not `:`\".into()),\n                },\n                location: SrcSpan {\n                    start: colon_start,\n                    end: colon_end,\n                },\n            });\n        };\n\n        let return_annotation = self.parse_type_annotation(&Token::RArrow)?;\n\n        let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) {\n            Some((left_brace_start, _)) => {\n                let some_body = self.parse_statement_seq()?;\n                let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?;\n                let end = return_annotation\n                    .as_ref()\n                    .map(|l| l.location().end)\n                    .unwrap_or(rpar_e);\n                let body = match some_body {\n                    None => vec![Statement::Expression(UntypedExpr::Todo {\n                        kind: TodoKind::EmptyFunction {\n                            function_location: SrcSpan { start, end },\n                        },\n                        location: SrcSpan {\n                            start: left_brace_start + 1,\n                            end: right_brace_end,\n                        },\n                        message: None,\n                    })],\n                    Some((body, _)) => body.to_vec(),\n                };\n\n                (Some(left_brace_start), body, end, right_brace_end)\n            }\n\n            None => (None, vec![], rpar_e, rpar_e),\n        };\n\n        Ok(Some(Definition::Function(Function {\n            documentation,\n            location: SrcSpan { start, end },\n            end_position,\n            body_start,\n            publicity: self.publicity(public, attributes.internal)?,\n            name,\n            arguments,\n            body,\n            return_type: (),\n            return_annotation,\n            deprecation: std::mem::take(&mut attributes.deprecated),\n            external_erlang: attributes.external_erlang.take(),\n            external_javascript: attributes.external_javascript.take(),\n            implementations: Implementations {\n                gleam: true,\n                can_run_on_erlang: true,\n                can_run_on_javascript: true,\n                uses_erlang_externals: false,\n                uses_javascript_externals: false,\n            },\n            purity: Purity::Pure,\n        })))\n    }\n\n    fn add_anon_function_hint(&self, mut err: ParseError) -> ParseError {\n        if let ParseErrorType::UnexpectedToken {\n            ref mut hint,\n            token: Token::Name { .. },\n            ..\n        } = err.error\n        {\n            *hint = Some(\"Only module-level functions can be named.\".into());\n        }\n        err\n    }\n\n    fn publicity(\n        &self,\n        public: bool,\n        internal: InternalAttribute,\n    ) -> Result<Publicity, ParseError> {\n        match (internal, public) {\n            (InternalAttribute::Missing, true) => Ok(Publicity::Public),\n            (InternalAttribute::Missing, false) => Ok(Publicity::Private),\n            (InternalAttribute::Present(location), true) => Ok(Publicity::Internal {\n                attribute_location: Some(location),\n            }),\n            (InternalAttribute::Present(location), false) => Err(ParseError {\n                error: ParseErrorType::RedundantInternalAttribute,\n                location,\n            }),\n        }\n    }\n\n    // Parse a single function definition param\n    //\n    // examples:\n    //   _\n    //   a\n    //   a a\n    //   a _\n    //   a _:A\n    //   a a:A\n    fn parse_fn_param(&mut self, is_anon: bool) -> Result<Option<UntypedArg>, ParseError> {\n        let (start, names, mut end) = match (self.tok0.take(), self.tok1.take()) {\n            // labeled discard\n            (\n                Some((start, Token::Name { name: label }, tok0_end)),\n                Some((name_start, Token::DiscardName { name }, end)),\n            ) => {\n                if is_anon {\n                    return parse_error(\n                        ParseErrorType::UnexpectedLabel,\n                        SrcSpan {\n                            start,\n                            end: tok0_end,\n                        },\n                    );\n                }\n\n                self.advance();\n                self.advance();\n                (\n                    start,\n                    ArgNames::LabelledDiscard {\n                        name,\n                        name_location: SrcSpan::new(name_start, end),\n                        label,\n                        label_location: SrcSpan::new(start, tok0_end),\n                    },\n                    end,\n                )\n            }\n            // discard\n            (Some((start, Token::DiscardName { name }, end)), t1) => {\n                self.tok1 = t1;\n                self.advance();\n                (\n                    start,\n                    ArgNames::Discard {\n                        name,\n                        location: SrcSpan { start, end },\n                    },\n                    end,\n                )\n            }\n            // labeled name\n            (\n                Some((start, Token::Name { name: label }, tok0_end)),\n                Some((name_start, Token::Name { name }, end)),\n            ) => {\n                if is_anon {\n                    return parse_error(\n                        ParseErrorType::UnexpectedLabel,\n                        SrcSpan {\n                            start,\n                            end: tok0_end,\n                        },\n                    );\n                }\n\n                self.advance();\n                self.advance();\n                (\n                    start,\n                    ArgNames::NamedLabelled {\n                        name,\n                        name_location: SrcSpan::new(name_start, end),\n                        label,\n                        label_location: SrcSpan::new(start, tok0_end),\n                    },\n                    end,\n                )\n            }\n            // name\n            (Some((start, Token::Name { name }, end)), t1) => {\n                self.tok1 = t1;\n                self.advance();\n                (\n                    start,\n                    ArgNames::Named {\n                        name,\n                        location: SrcSpan { start, end },\n                    },\n                    end,\n                )\n            }\n            (t0, t1) => {\n                self.tok0 = t0;\n                self.tok1 = t1;\n                return Ok(None);\n            }\n        };\n        let annotation = match self.parse_type_annotation(&Token::Colon)? {\n            Some(a) => {\n                end = a.location().end;\n                Some(a)\n            }\n            _ => None,\n        };\n        Ok(Some(Arg {\n            location: SrcSpan { start, end },\n            type_: (),\n            names,\n            annotation,\n        }))\n    }\n\n    // Parse function call arguments, no parens\n    //\n    // examples:\n    //   _\n    //   expr, expr\n    //   a: _, expr\n    //   a: expr, _, b: _\n    fn parse_fn_arguments(&mut self) -> Result<Vec<ParserArg>, ParseError> {\n        let arguments = Parser::series_of(self, &Parser::parse_fn_argument, Some(&Token::Comma))?;\n        Ok(arguments)\n    }\n\n    // Parse a single function call arg\n    //\n    // examples:\n    //   _\n    //   expr\n    //   a: _\n    //   a: expr\n    fn parse_fn_argument(&mut self) -> Result<Option<ParserArg>, ParseError> {\n        let label = match (self.tok0.take(), self.tok1.take()) {\n            (Some((start, Token::Name { name }, _)), Some((_, Token::Colon, end))) => {\n                self.advance();\n                self.advance();\n                Some((start, name, end))\n            }\n            (t0, t1) => {\n                self.tok0 = t0;\n                self.tok1 = t1;\n                None\n            }\n        };\n\n        match self.parse_expression()? {\n            Some(value) => {\n                let arg = match label {\n                    Some((start, label, _)) => CallArg {\n                        implicit: None,\n                        label: Some(label),\n                        location: SrcSpan {\n                            start,\n                            end: value.location().end,\n                        },\n                        value,\n                    },\n                    _ => CallArg {\n                        implicit: None,\n                        label: None,\n                        location: value.location(),\n                        value,\n                    },\n                };\n                Ok(Some(ParserArg::Arg(Box::new(arg))))\n            }\n            _ => {\n                match self.maybe_discard_name() {\n                    Some((name_start, name, name_end)) => {\n                        let arg = match label {\n                            Some((label_start, label, _)) => ParserArg::Hole {\n                                label: Some(label),\n                                arg_location: SrcSpan {\n                                    start: label_start,\n                                    end: name_end,\n                                },\n                                discard_location: SrcSpan {\n                                    start: name_start,\n                                    end: name_end,\n                                },\n                                name,\n                            },\n                            _ => ParserArg::Hole {\n                                label: None,\n                                arg_location: SrcSpan {\n                                    start: name_start,\n                                    end: name_end,\n                                },\n                                discard_location: SrcSpan {\n                                    start: name_start,\n                                    end: name_end,\n                                },\n                                name,\n                            },\n                        };\n\n                        Ok(Some(arg))\n                    }\n                    _ => {\n                        match label {\n                            Some((start, label, end)) => {\n                                // Argument supplied with a label shorthand.\n                                Ok(Some(ParserArg::Arg(Box::new(CallArg {\n                                    implicit: None,\n                                    label: Some(label.clone()),\n                                    location: SrcSpan { start, end },\n                                    value: UntypedExpr::Var {\n                                        name: label,\n                                        location: SrcSpan { start, end },\n                                    },\n                                }))))\n                            }\n                            _ => Ok(None),\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    //\n    // Parse Custom Types\n    //\n\n    // examples:\n    //   type A { A }\n    //   type A { A(String) }\n    //   type Box(inner_type) { Box(inner: inner_type) }\n    //   type NamedBox(inner_type) { Box(String, inner: inner_type) }\n    fn parse_custom_type(\n        &mut self,\n        start: u32,\n        public: bool,\n        opaque: bool,\n        attributes: &mut Attributes,\n    ) -> Result<Option<UntypedDefinition>, ParseError> {\n        let documentation = self.take_documentation(start);\n        let (name_start, name, parameters, end, name_end) = self.expect_type_name()?;\n        let name_location = SrcSpan::new(name_start, name_end);\n        let (constructors, end_position) = if self.maybe_one(&Token::LeftBrace).is_some() {\n            // Custom Type\n            let constructors = Parser::series_of(\n                self,\n                &|p| {\n                    // The only attribute supported on constructors is @deprecated\n                    let mut attributes = Attributes::default();\n                    let attr_loc = Parser::parse_attributes(p, &mut attributes)?;\n\n                    if let Some(attr_span) = attr_loc {\n                        // Expecting all but the deprecated atterbutes to be default\n                        if attributes.external_erlang.is_some()\n                            || attributes.external_javascript.is_some()\n                            || attributes.target.is_some()\n                            || attributes.internal != InternalAttribute::Missing\n                        {\n                            return parse_error(\n                                ParseErrorType::UnknownAttributeRecordVariant,\n                                attr_span,\n                            );\n                        }\n                    }\n\n                    match Parser::maybe_upname(p) {\n                        Some((c_s, c_n, c_e)) => {\n                            let documentation = p.take_documentation(c_s);\n                            let (arguments, arguments_e) =\n                                Parser::parse_type_constructor_arguments(p)?;\n                            let end = arguments_e.max(c_e);\n                            Ok(Some(RecordConstructor {\n                                location: SrcSpan { start: c_s, end },\n                                name_location: SrcSpan {\n                                    start: c_s,\n                                    end: c_e,\n                                },\n                                name: c_n,\n                                arguments,\n                                documentation,\n                                deprecation: attributes.deprecated,\n                            }))\n                        }\n                        _ => Ok(None),\n                    }\n                },\n                // No separator\n                None,\n            )?;\n            let (_, close_end) = self.expect_custom_type_close(&name, public, opaque)?;\n            (constructors, close_end)\n        } else {\n            match self.maybe_one(&Token::Equal) {\n                Some((eq_s, eq_e)) => {\n                    // Type Alias\n                    if opaque {\n                        return parse_error(\n                            ParseErrorType::OpaqueTypeAlias,\n                            SrcSpan { start, end },\n                        );\n                    }\n\n                    match self.parse_type()? {\n                        Some(t) => {\n                            let type_end = t.location().end;\n                            return Ok(Some(Definition::TypeAlias(TypeAlias {\n                                documentation,\n                                location: SrcSpan::new(start, type_end),\n                                publicity: self.publicity(public, attributes.internal)?,\n                                alias: name,\n                                name_location,\n                                parameters,\n                                type_ast: t,\n                                type_: (),\n                                deprecation: std::mem::take(&mut attributes.deprecated),\n                            })));\n                        }\n                        _ => {\n                            return parse_error(\n                                ParseErrorType::ExpectedType,\n                                SrcSpan::new(eq_s, eq_e),\n                            );\n                        }\n                    }\n                }\n                _ => (vec![], end),\n            }\n        };\n\n        Ok(Some(Definition::CustomType(CustomType {\n            documentation,\n            location: SrcSpan { start, end },\n            end_position,\n            publicity: self.publicity(public, attributes.internal)?,\n            opaque,\n            name,\n            name_location,\n            parameters,\n            constructors,\n            typed_parameters: vec![],\n            deprecation: std::mem::take(&mut attributes.deprecated),\n            external_erlang: std::mem::take(&mut attributes.external_erlang),\n            external_javascript: std::mem::take(&mut attributes.external_javascript),\n        })))\n    }\n\n    // examples:\n    //   A\n    //   A(one, two)\n    fn expect_type_name(\n        &mut self,\n    ) -> Result<(u32, EcoString, Vec<SpannedString>, u32, u32), ParseError> {\n        let (start, upname, end) = self.expect_upname()?;\n        if let Some((par_s, _)) = self.maybe_one(&Token::LeftParen) {\n            let arguments =\n                Parser::series_of(self, &|p| Ok(Parser::maybe_name(p)), Some(&Token::Comma))?;\n            let (_, par_e) = self.expect_one_following_series(&Token::RightParen, \"a name\")?;\n            if arguments.is_empty() {\n                return parse_error(\n                    ParseErrorType::TypeDefinitionNoArguments,\n                    SrcSpan::new(par_s, par_e),\n                );\n            }\n            let arguments2 = arguments\n                .into_iter()\n                .map(|(start, name, end)| (SrcSpan { start, end }, name))\n                .collect();\n            Ok((start, upname, arguments2, par_e, end))\n        } else if let Some((less_start, less_end)) = self.maybe_one(&Token::Less) {\n            let mut arguments = Parser::series_of(\n                self,\n                &|p|\n                        // Permit either names (`a`) or upnames (`A`) in this error-handling mode,\n                        // as upnames are common in other languages. Convert to lowercase so the\n                        // example is correct whichever was used.\n                        Ok(Parser::maybe_name(p)\n                            .or_else(|| Parser::maybe_upname(p))\n                            .map(|(_, name, _)| name.to_lowercase())),\n                Some(&Token::Comma),\n            )?;\n\n            // If no type arguments were parsed, fall back to a dummy type argument as an example,\n            // because `Type()` would be invalid\n            if arguments.is_empty() {\n                arguments = vec![\"value\".into()];\n            }\n\n            Err(ParseError {\n                error: ParseErrorType::TypeDefinitionAngleGenerics {\n                    name: upname,\n                    arguments,\n                },\n                location: SrcSpan {\n                    start: less_start,\n                    end: less_end,\n                },\n            })\n        } else {\n            Ok((start, upname, vec![], end, end))\n        }\n    }\n\n    // examples:\n    //   *no args*\n    //   ()\n    //   (a, b)\n    fn parse_type_constructor_arguments(\n        &mut self,\n    ) -> Result<(Vec<RecordConstructorArg<()>>, u32), ParseError> {\n        if self.maybe_one(&Token::LeftParen).is_some() {\n            let arguments = Parser::series_of(\n                self,\n                &|p| match (p.tok0.take(), p.tok1.take()) {\n                    (\n                        Some((start, Token::Name { name }, name_end)),\n                        Some((_, Token::Colon, end)),\n                    ) => {\n                        let _ = Parser::next_tok(p);\n                        let _ = Parser::next_tok(p);\n                        let doc = p.take_documentation(start);\n                        match Parser::parse_type(p)? {\n                            Some(type_ast) => {\n                                let end = type_ast.location().end;\n                                Ok(Some(RecordConstructorArg {\n                                    label: Some((SrcSpan::new(start, name_end), name)),\n                                    ast: type_ast,\n                                    location: SrcSpan { start, end },\n                                    type_: (),\n                                    doc,\n                                }))\n                            }\n                            None => {\n                                parse_error(ParseErrorType::ExpectedType, SrcSpan { start, end })\n                            }\n                        }\n                    }\n                    (t0, t1) => {\n                        p.tok0 = t0;\n                        p.tok1 = t1;\n                        match Parser::parse_type(p)? {\n                            Some(type_ast) => {\n                                let doc = match &p.tok0 {\n                                    Some((start, _, _)) => p.take_documentation(*start),\n                                    None => None,\n                                };\n                                let type_location = type_ast.location();\n                                Ok(Some(RecordConstructorArg {\n                                    label: None,\n                                    ast: type_ast,\n                                    location: type_location,\n                                    type_: (),\n                                    doc,\n                                }))\n                            }\n                            None => Ok(None),\n                        }\n                    }\n                },\n                Some(&Token::Comma),\n            )?;\n            let (_, end) = self\n                .expect_one_following_series(&Token::RightParen, \"a constructor argument name\")?;\n            Ok((arguments, end))\n        } else {\n            Ok((vec![], 0))\n        }\n    }\n\n    //\n    // Parse Type Annotations\n    //\n\n    // examples:\n    //   :a\n    //   :Int\n    //   :Result(a, _)\n    //   :Result(Result(a, e), #(_, String))\n    fn parse_type_annotation(&mut self, start_tok: &Token) -> Result<Option<TypeAst>, ParseError> {\n        if let Some((start, end)) = self.maybe_one(start_tok) {\n            match self.parse_type() {\n                Ok(None) => parse_error(ParseErrorType::ExpectedType, SrcSpan { start, end }),\n                other => other,\n            }\n        } else {\n            Ok(None)\n        }\n    }\n\n    // Parse the type part of a type annotation, same as `parse_type_annotation` minus the \":\"\n    fn parse_type(&mut self) -> Result<Option<TypeAst>, ParseError> {\n        match self.tok0.take() {\n            // Type hole\n            Some((start, Token::DiscardName { name }, end)) => {\n                self.advance();\n                Ok(Some(TypeAst::Hole(TypeAstHole {\n                    location: SrcSpan { start, end },\n                    name,\n                })))\n            }\n\n            // Tuple\n            Some((start, Token::Hash, _)) => {\n                self.advance();\n                let _ = self.expect_one(&Token::LeftParen)?;\n                let elements = self.parse_types()?;\n                let (_, end) = self.expect_one(&Token::RightParen)?;\n                Ok(Some(TypeAst::Tuple(TypeAstTuple {\n                    location: SrcSpan { start, end },\n                    elements,\n                })))\n            }\n\n            // Function\n            Some((start, Token::Fn, _)) => {\n                self.advance();\n                let _ = self.expect_one(&Token::LeftParen)?;\n                let arguments =\n                    Parser::series_of(self, &|x| Parser::parse_type(x), Some(&Token::Comma))?;\n                let _ = self.expect_one_following_series(&Token::RightParen, \"a type\")?;\n                let (arr_s, arr_e) = self.expect_one(&Token::RArrow)?;\n                let return_ = self.parse_type()?;\n                match return_ {\n                    Some(return_) => Ok(Some(TypeAst::Fn(TypeAstFn {\n                        location: SrcSpan {\n                            start,\n                            end: return_.location().end,\n                        },\n                        return_: Box::new(return_),\n                        arguments,\n                    }))),\n                    _ => parse_error(\n                        ParseErrorType::ExpectedType,\n                        SrcSpan {\n                            start: arr_s,\n                            end: arr_e,\n                        },\n                    ),\n                }\n            }\n\n            // Constructor function\n            Some((start, Token::UpName { name }, end)) => {\n                self.advance();\n                self.parse_type_name_finish(start, start, None, name, end)\n            }\n\n            // Constructor Module or type Variable\n            Some((start, Token::Name { name: mod_name }, end)) => {\n                self.advance();\n                if self.maybe_one(&Token::Dot).is_some() {\n                    let (name_start, upname, upname_e) = self.expect_upname()?;\n                    self.parse_type_name_finish(\n                        start,\n                        name_start,\n                        Some((mod_name, SrcSpan { start, end })),\n                        upname,\n                        upname_e,\n                    )\n                } else {\n                    Ok(Some(TypeAst::Var(TypeAstVar {\n                        location: SrcSpan { start, end },\n                        name: mod_name,\n                    })))\n                }\n            }\n\n            t0 => {\n                self.tok0 = t0;\n                Ok(None)\n            }\n        }\n    }\n\n    // Parse the '( ... )' of a type name\n    fn parse_type_name_finish(\n        &mut self,\n        start: u32,\n        name_start: u32,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        end: u32,\n    ) -> Result<Option<TypeAst>, ParseError> {\n        if let Some((par_s, _)) = self.maybe_one(&Token::LeftParen) {\n            let arguments = self.parse_types()?;\n            let (_, par_e) = self.expect_one(&Token::RightParen)?;\n            Ok(Some(TypeAst::Constructor(TypeAstConstructor {\n                location: SrcSpan { start, end: par_e },\n                name_location: SrcSpan {\n                    start: name_start,\n                    end,\n                },\n                module,\n                name,\n                arguments,\n                start_parentheses: Some(par_s),\n            })))\n        } else if let Some((less_start, less_end)) = self.maybe_one(&Token::Less) {\n            let arguments = self.parse_types()?;\n            Err(ParseError {\n                error: ParseErrorType::TypeUsageAngleGenerics {\n                    name,\n                    module: module.map(|(module_name, _)| module_name),\n                    arguments,\n                },\n                location: SrcSpan {\n                    start: less_start,\n                    end: less_end,\n                },\n            })\n        } else {\n            Ok(Some(TypeAst::Constructor(TypeAstConstructor {\n                location: SrcSpan { start, end },\n                name_location: SrcSpan {\n                    start: name_start,\n                    end,\n                },\n                module,\n                name,\n                arguments: vec![],\n                start_parentheses: None,\n            })))\n        }\n    }\n\n    // For parsing a comma separated \"list\" of types, for tuple, constructor, and function\n    fn parse_types(&mut self) -> Result<Vec<TypeAst>, ParseError> {\n        let elements = Parser::series_of(self, &|p| Parser::parse_type(p), Some(&Token::Comma))?;\n        Ok(elements)\n    }\n\n    //\n    // Parse Imports\n    //\n\n    // examples:\n    //   import a\n    //   import a/b\n    //   import a/b.{c}\n    //   import a/b.{c as d} as e\n    fn parse_import(&mut self, import_start: u32) -> Result<Option<UntypedDefinition>, ParseError> {\n        let mut start = 0;\n        let mut end;\n        let mut module = EcoString::new();\n        let mut last_segment_start;\n        let mut last_segment_end;\n\n        // Gather module names\n        loop {\n            let (s, name, e) = self.expect_name()?;\n            if module.is_empty() {\n                start = s;\n            } else {\n                module.push('/');\n            }\n            module.push_str(&name);\n            end = e;\n            last_segment_start = s;\n            last_segment_end = e;\n\n            // Useful error for : import a/.{b}\n            if let Some((s, _)) = self.maybe_one(&Token::SlashDot) {\n                return parse_error(\n                    ParseErrorType::ExpectedName,\n                    SrcSpan {\n                        start: s + 1,\n                        end: s + 1,\n                    },\n                );\n            }\n\n            // break if there's no trailing slash\n            if self.maybe_one(&Token::Slash).is_none() {\n                break;\n            }\n        }\n\n        let (_, documentation) = self.take_documentation(start).unzip();\n\n        // Gather imports\n        let mut unqualified_values = vec![];\n        let mut unqualified_types = vec![];\n\n        if let Some((dot_start, dot_end)) = self.maybe_one(&Token::Dot) {\n            if let Err(e) = self.expect_one(&Token::LeftBrace) {\n                // If the module does contain a '/', then it's unlikely that the user\n                // intended for the import to be pythonic, so skip this.\n                if module.contains('/') {\n                    return Err(e);\n                }\n\n                // Catch `import gleam.io` and provide a more helpful error...\n                let ParseErrorType::UnexpectedToken {\n                    token: Token::Name { name } | Token::UpName { name },\n                    ..\n                } = &e.error\n                else {\n                    return Err(e);\n                };\n\n                return Err(ParseError {\n                    error: ParseErrorType::IncorrectImportModuleSeparator {\n                        module,\n                        item: name.clone(),\n                    },\n                    location: SrcSpan::new(dot_start, dot_end),\n                });\n            };\n\n            let parsed = self.parse_unqualified_imports()?;\n            unqualified_types = parsed.types;\n            unqualified_values = parsed.values;\n            let (_, e) = self.expect_one(&Token::RightBrace)?;\n            end = e;\n        }\n\n        // Parse as_name\n        let mut as_name = None;\n        if let Some((as_start, _)) = self.maybe_one(&Token::As) {\n            let (_, name, e) = self.expect_assign_name()?;\n\n            end = e;\n            as_name = Some((\n                name,\n                SrcSpan {\n                    start: as_start,\n                    end,\n                },\n            ));\n        }\n\n        Ok(Some(Definition::Import(Import {\n            documentation,\n            location: SrcSpan {\n                start: import_start,\n                end,\n            },\n            module_location: SrcSpan {\n                start: last_segment_start,\n                end: last_segment_end,\n            },\n            unqualified_values,\n            unqualified_types,\n            module,\n            as_name,\n            package: (),\n        })))\n    }\n\n    // [Name (as Name)? | UpName (as Name)? ](, [Name (as Name)? | UpName (as Name)?])*,?\n    fn parse_unqualified_imports(&mut self) -> Result<ParsedUnqualifiedImports, ParseError> {\n        let mut imports = ParsedUnqualifiedImports::default();\n        loop {\n            // parse imports\n            match self.tok0.take() {\n                Some((start, Token::Name { name }, end)) => {\n                    self.advance();\n                    let location = SrcSpan { start, end };\n                    let mut import = UnqualifiedImport {\n                        name,\n                        location,\n                        imported_name_location: location,\n                        as_name: None,\n                    };\n                    if self.maybe_one(&Token::As).is_some() {\n                        let (_, as_name, end) = self.expect_name()?;\n                        import.as_name = Some(as_name);\n                        import.location.end = end;\n                    }\n                    imports.values.push(import)\n                }\n\n                Some((start, Token::UpName { name }, end)) => {\n                    self.advance();\n                    let location = SrcSpan { start, end };\n                    let mut import = UnqualifiedImport {\n                        name,\n                        location,\n                        imported_name_location: location,\n                        as_name: None,\n                    };\n                    if self.maybe_one(&Token::As).is_some() {\n                        let (_, as_name, end) = self.expect_upname()?;\n                        import.as_name = Some(as_name);\n                        import.location.end = end;\n                    }\n                    imports.values.push(import)\n                }\n\n                Some((start, Token::Type, _)) => {\n                    self.advance();\n                    let (name_start, name, end) = self.expect_upname()?;\n                    let location = SrcSpan { start, end };\n                    let mut import = UnqualifiedImport {\n                        name,\n                        location,\n                        imported_name_location: SrcSpan::new(name_start, end),\n                        as_name: None,\n                    };\n                    if self.maybe_one(&Token::As).is_some() {\n                        let (_, as_name, end) = self.expect_upname()?;\n                        import.as_name = Some(as_name);\n                        import.location.end = end;\n                    }\n                    imports.types.push(import)\n                }\n\n                t0 => {\n                    self.tok0 = t0;\n                    break;\n                }\n            }\n            // parse comma\n            match self.tok0 {\n                Some((_, Token::Comma, _)) => {\n                    self.advance();\n                }\n                _ => break,\n            }\n        }\n        Ok(imports)\n    }\n\n    //\n    // Parse Constants\n    //\n\n    // examples:\n    //   const a = 1\n    //   const a:Int = 1\n    //   pub const a:Int = 1\n    fn parse_module_const(\n        &mut self,\n        start: u32,\n        public: bool,\n        attributes: &Attributes,\n    ) -> Result<Option<UntypedDefinition>, ParseError> {\n        let (name_start, name, name_end) = self.expect_name()?;\n        let documentation = self.take_documentation(name_start);\n\n        let annotation = self.parse_type_annotation(&Token::Colon)?;\n\n        let (eq_s, eq_e) = self.expect_one(&Token::Equal)?;\n        match self.parse_const_value()? {\n            Some(value) => {\n                Ok(Some(Definition::ModuleConstant(ModuleConstant {\n                    documentation,\n                    location: SrcSpan {\n                        start,\n\n                        // End after the type annotation if it's there, otherwise after the name\n                        end: annotation\n                            .as_ref()\n                            .map(|annotation| annotation.location().end)\n                            .unwrap_or(0)\n                            .max(name_end),\n                    },\n                    publicity: self.publicity(public, attributes.internal)?,\n                    name,\n                    name_location: SrcSpan::new(name_start, name_end),\n                    annotation,\n                    value: Box::new(value),\n                    type_: (),\n                    deprecation: attributes.deprecated.clone(),\n                    implementations: Implementations {\n                        gleam: true,\n                        can_run_on_erlang: true,\n                        can_run_on_javascript: true,\n                        uses_erlang_externals: false,\n                        uses_javascript_externals: false,\n                    },\n                })))\n            }\n            _ => parse_error(\n                ParseErrorType::NoValueAfterEqual,\n                SrcSpan {\n                    start: eq_s,\n                    end: eq_e,\n                },\n            ),\n        }\n    }\n\n    // examples:\n    //   1\n    //   \"hi\"\n    //   True\n    //   [1,2,3]\n    //   wibble <> \"wobble\"\n    fn parse_const_value(&mut self) -> Result<Option<UntypedConstant>, ParseError> {\n        let constant_result = self.parse_const_value_unit();\n        match constant_result {\n            Ok(Some(constant)) => self.parse_const_maybe_concatenation(constant),\n            _ => constant_result,\n        }\n    }\n\n    fn parse_const_value_unit(&mut self) -> Result<Option<UntypedConstant>, ParseError> {\n        match self.tok0.take() {\n            Some((start, Token::String { value }, end)) => {\n                self.advance();\n                Ok(Some(Constant::String {\n                    value,\n                    location: SrcSpan { start, end },\n                }))\n            }\n\n            Some((start, Token::Float { value, float_value }, end)) => {\n                self.advance();\n                Ok(Some(Constant::Float {\n                    value,\n                    location: SrcSpan { start, end },\n                    float_value,\n                }))\n            }\n\n            Some((start, Token::Int { value, int_value }, end)) => {\n                self.advance();\n                Ok(Some(Constant::Int {\n                    value,\n                    int_value,\n                    location: SrcSpan { start, end },\n                }))\n            }\n\n            Some((start, Token::Hash, _)) => {\n                self.advance();\n                let _ = self.expect_one(&Token::LeftParen)?;\n                let elements =\n                    Parser::series_of(self, &Parser::parse_const_value, Some(&Token::Comma))?;\n                let (_, end) =\n                    self.expect_one_following_series(&Token::RightParen, \"a constant value\")?;\n                Ok(Some(Constant::Tuple {\n                    elements,\n                    location: SrcSpan { start, end },\n                    type_: (),\n                }))\n            }\n\n            Some((start, Token::LeftSquare, _)) => {\n                self.advance();\n\n                let (elements, elements_end_with_comma) = self.series_of_has_trailing_separator(\n                    &Parser::parse_const_value,\n                    Some(&Token::Comma),\n                )?;\n\n                // Parse an optional tail\n                let mut tail = None;\n                let mut elements_after_tail = None;\n                let mut dot_dot_location = None;\n\n                // If there are no elements, we still want to parse a tail so\n                // that we can report a better error message.\n                if (elements_end_with_comma || elements.is_empty())\n                    && let Some((start, end)) = self.maybe_one(&Token::DotDot)\n                {\n                    dot_dot_location = Some((start, end));\n                    tail = self.parse_const_value()?.map(Box::new);\n                    if self.maybe_one(&Token::Comma).is_some() {\n                        // See if there's a list of items after the tail,\n                        // like `[..wibble, wobble, wabble]`\n                        let elements =\n                            self.series_of(&Parser::parse_const_value, Some(&Token::Comma));\n                        match elements {\n                            Err(_) => {}\n                            Ok(elements) => {\n                                elements_after_tail = Some(elements);\n                            }\n                        };\n                    };\n\n                    if tail.is_some() {\n                        // Give a better error when there are two lists being\n                        // concatenated like `[..wibble, ..wabble, woo]`, or if\n                        // there are elements after the tail.\n                        if let Some((second_start, second_end)) = self.maybe_one(&Token::DotDot) {\n                            let _second_tail = self.parse_const_value();\n\n                            if elements_after_tail.is_none()\n                                || elements_after_tail\n                                    .as_ref()\n                                    .is_some_and(|vec| vec.is_empty())\n                            {\n                                return parse_error(\n                                    ParseErrorType::ListSpreadWithAnotherSpread {\n                                        first_spread_location: SrcSpan { start, end },\n                                    },\n                                    SrcSpan {\n                                        start: second_start,\n                                        end: second_end,\n                                    },\n                                );\n                            }\n                        }\n                    }\n                }\n\n                let (_, end) =\n                    self.expect_one_following_series(&Token::RightSquare, \"a constant value\")?;\n\n                // Return errors for malformed lists\n                match dot_dot_location {\n                    Some((start, end)) if tail.is_none() => {\n                        return parse_error(\n                            ParseErrorType::ListSpreadWithoutTail,\n                            SrcSpan { start, end },\n                        );\n                    }\n                    _ => {}\n                }\n                if tail.is_some()\n                    && elements.is_empty()\n                    && elements_after_tail.as_ref().is_none_or(|e| e.is_empty())\n                {\n                    return parse_error(\n                        ParseErrorType::ListSpreadWithoutElements,\n                        SrcSpan { start, end },\n                    );\n                }\n\n                match elements_after_tail {\n                    Some(elements) if !elements.is_empty() => {\n                        let (start, end) = match (dot_dot_location, tail) {\n                            (Some((start, _)), Some(tail)) => (start, tail.location().end),\n                            (_, _) => (start, end),\n                        };\n                        return parse_error(\n                            ParseErrorType::ListSpreadFollowedByElements,\n                            SrcSpan { start, end },\n                        );\n                    }\n                    _ => {}\n                }\n\n                Ok(Some(Constant::List {\n                    elements,\n                    location: SrcSpan { start, end },\n                    type_: (),\n                    tail,\n                }))\n            }\n            // BitArray\n            Some((start, Token::LtLt, _)) => {\n                self.advance();\n                let segments = Parser::series_of(\n                    self,\n                    &|s| {\n                        Parser::parse_bit_array_segment(\n                            s,\n                            &Parser::parse_const_value,\n                            &Parser::expect_const_int,\n                            &bit_array_const_int,\n                        )\n                    },\n                    Some(&Token::Comma),\n                )?;\n                let (_, end) =\n                    self.expect_one_following_series(&Token::GtGt, \"a bit array segment\")?;\n                Ok(Some(Constant::BitArray {\n                    location: SrcSpan { start, end },\n                    segments,\n                }))\n            }\n\n            Some((start, Token::UpName { name }, end)) => {\n                self.advance();\n                self.parse_const_record_finish(start, None, name, end)\n            }\n\n            Some((start, Token::Name { name }, module_end))\n                if self.peek_tok1() == Some(&Token::Dot) =>\n            {\n                self.advance(); // name\n                self.advance(); // dot\n\n                match self.tok0.take() {\n                    Some((_, Token::UpName { name: upname }, end)) => {\n                        self.advance(); // upname\n                        self.parse_const_record_finish(\n                            start,\n                            Some((name, SrcSpan::new(start, module_end))),\n                            upname,\n                            end,\n                        )\n                    }\n                    Some((_, Token::Name { name: end_name }, end)) => {\n                        self.advance(); // name\n\n                        match self.tok0 {\n                            Some((_, Token::LeftParen, _)) => parse_error(\n                                ParseErrorType::UnexpectedFunction,\n                                SrcSpan {\n                                    start,\n                                    end: end + 1,\n                                },\n                            ),\n                            _ => Ok(Some(Constant::Var {\n                                location: SrcSpan { start, end },\n                                module: Some((name, SrcSpan::new(start, module_end))),\n                                name: end_name,\n                                constructor: None,\n                                type_: (),\n                            })),\n                        }\n                    }\n                    Some((start, token, end)) => parse_error(\n                        ParseErrorType::UnexpectedToken {\n                            token,\n                            expected: vec![\"UpName\".into(), \"Name\".into()],\n                            hint: None,\n                        },\n                        SrcSpan { start, end },\n                    ),\n                    None => {\n                        parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 })\n                    }\n                }\n            }\n\n            Some((start, Token::Name { name }, end)) => {\n                self.advance(); // name\n\n                match self.tok0 {\n                    Some((_, Token::LeftParen, _)) => parse_error(\n                        ParseErrorType::UnexpectedFunction,\n                        SrcSpan {\n                            start,\n                            end: end + 1,\n                        },\n                    ),\n                    _ => Ok(Some(Constant::Var {\n                        location: SrcSpan { start, end },\n                        module: None,\n                        name,\n                        constructor: None,\n                        type_: (),\n                    })),\n                }\n            }\n\n            // Helpful error for fn\n            Some((start, Token::Fn, end)) => {\n                parse_error(ParseErrorType::NotConstType, SrcSpan { start, end })\n            }\n\n            t0 => {\n                self.tok0 = t0;\n                Ok(None)\n            }\n        }\n    }\n\n    fn parse_const_maybe_concatenation(\n        &mut self,\n        left: UntypedConstant,\n    ) -> Result<Option<UntypedConstant>, ParseError> {\n        match self.tok0.take() {\n            Some((op_start, Token::Concatenate, op_end)) => {\n                self.advance();\n\n                match self.parse_const_value() {\n                    Ok(Some(right_constant_value)) => Ok(Some(Constant::StringConcatenation {\n                        location: SrcSpan {\n                            start: left.location().start,\n                            end: right_constant_value.location().end,\n                        },\n                        left: Box::new(left),\n                        right: Box::new(right_constant_value),\n                    })),\n                    _ => parse_error(\n                        ParseErrorType::OpNakedRight,\n                        SrcSpan {\n                            start: op_start,\n                            end: op_end,\n                        },\n                    ),\n                }\n            }\n            t0 => {\n                self.tok0 = t0;\n                Ok(Some(left))\n            }\n        }\n    }\n\n    // Parse the '( .. )' of a const type constructor\n    fn parse_const_record_finish(\n        &mut self,\n        start: u32,\n        module: Option<(EcoString, SrcSpan)>,\n        name: EcoString,\n        end: u32,\n    ) -> Result<Option<UntypedConstant>, ParseError> {\n        match self.maybe_one(&Token::LeftParen) {\n            Some((par_s, _)) => {\n                if self.maybe_one(&Token::DotDot).is_some() {\n                    let record = match self.parse_const_value()? {\n                        Some(value) => RecordBeingUpdated {\n                            location: value.location(),\n                            base: Box::new(value),\n                        },\n                        None => {\n                            return parse_error(\n                                ParseErrorType::UnexpectedEof,\n                                SrcSpan::new(par_s, par_s + 2),\n                            );\n                        }\n                    };\n\n                    let mut update_arguments = vec![];\n                    if self.maybe_one(&Token::Comma).is_some() {\n                        update_arguments = Parser::series_of(\n                            self,\n                            &Parser::parse_const_record_update_arg,\n                            Some(&Token::Comma),\n                        )?;\n                    }\n\n                    let (_, par_e) = self.expect_one_following_series(\n                        &Token::RightParen,\n                        \"a constant record update argument\",\n                    )?;\n\n                    let constructor_location = SrcSpan { start, end };\n\n                    Ok(Some(Constant::RecordUpdate {\n                        location: SrcSpan { start, end: par_e },\n                        constructor_location,\n                        module,\n                        name,\n                        record,\n                        arguments: update_arguments,\n                        tag: (),\n                        type_: (),\n                        field_map: Inferred::Unknown,\n                    }))\n                } else {\n                    let arguments = Parser::series_of(\n                        self,\n                        &Parser::parse_const_record_arg,\n                        Some(&Token::Comma),\n                    )?;\n\n                    let (_, par_e) = self.expect_one_following_series(\n                        &Token::RightParen,\n                        \"a constant record argument\",\n                    )?;\n\n                    if arguments.is_empty() {\n                        return parse_error(\n                            ParseErrorType::ConstantRecordConstructorNoArguments,\n                            SrcSpan::new(par_s, par_e),\n                        );\n                    }\n\n                    Ok(Some(Constant::Record {\n                        location: SrcSpan { start, end: par_e },\n                        module,\n                        name,\n                        arguments,\n                        tag: (),\n                        type_: (),\n                        field_map: Inferred::Unknown,\n                        record_constructor: None,\n                    }))\n                }\n            }\n            _ => Ok(Some(Constant::Record {\n                location: SrcSpan { start, end },\n                module,\n                name,\n                arguments: vec![],\n                tag: (),\n                type_: (),\n                field_map: Inferred::Unknown,\n                record_constructor: None,\n            })),\n        }\n    }\n\n    // examples:\n    //  name: const\n    //  const\n    //  name:\n    fn parse_const_record_arg(&mut self) -> Result<Option<CallArg<UntypedConstant>>, ParseError> {\n        let label = match (self.tok0.take(), self.tok1.take()) {\n            // Named arg\n            (Some((start, Token::Name { name }, _)), Some((_, Token::Colon, end))) => {\n                self.advance();\n                self.advance();\n                Some((start, name, end))\n            }\n\n            // Unnamed arg\n            (t0, t1) => {\n                self.tok0 = t0;\n                self.tok1 = t1;\n                None\n            }\n        };\n\n        match self.parse_const_value()? {\n            Some(value) => match label {\n                Some((start, label, _)) => Ok(Some(CallArg {\n                    implicit: None,\n                    location: SrcSpan {\n                        start,\n                        end: value.location().end,\n                    },\n                    value,\n                    label: Some(label),\n                })),\n                _ => Ok(Some(CallArg {\n                    implicit: None,\n                    location: value.location(),\n                    value,\n                    label: None,\n                })),\n            },\n            _ => {\n                match label {\n                    Some((start, label, end)) => {\n                        // Argument supplied with a label shorthand.\n                        Ok(Some(CallArg {\n                            implicit: None,\n                            location: SrcSpan { start, end },\n                            label: Some(label.clone()),\n                            value: UntypedConstant::Var {\n                                location: SrcSpan { start, end },\n                                constructor: None,\n                                module: None,\n                                name: label,\n                                type_: (),\n                            },\n                        }))\n                    }\n                    _ => Ok(None),\n                }\n            }\n        }\n    }\n\n    fn parse_const_record_update_arg(\n        &mut self,\n    ) -> Result<Option<RecordUpdateArg<UntypedConstant>>, ParseError> {\n        let (start, label, label_end) = match (self.tok0.take(), self.tok1.take()) {\n            // Named arg - required for record updates\n            (Some((start, Token::Name { name }, _)), Some((_, Token::Colon, end))) => {\n                self.advance();\n                self.advance();\n                (start, name, end)\n            }\n\n            // Unnamed arg or other - return error since record updates require labels\n            (Some((start, Token::Name { name }, end)), t1) => {\n                self.tok0 = Some((start, Token::Name { name: name.clone() }, end));\n                self.tok1 = t1;\n\n                // Check if this is label shorthand (name without colon)\n                // In this case, use the name as both label and value\n                match self.parse_const_value()? {\n                    Some(value) if value.location() == SrcSpan { start, end } => {\n                        return Ok(Some(RecordUpdateArg {\n                            label: name.clone(),\n                            location: SrcSpan { start, end },\n                            value,\n                        }));\n                    }\n                    _ => {\n                        self.tok0 = Some((start, Token::Name { name }, end));\n                        return parse_error(ParseErrorType::ExpectedName, SrcSpan { start, end });\n                    }\n                }\n            }\n\n            (t0, t1) => {\n                self.tok0 = t0;\n                self.tok1 = t1;\n                return Ok(None);\n            }\n        };\n\n        match self.parse_const_value()? {\n            Some(value) => Ok(Some(RecordUpdateArg {\n                label,\n                location: SrcSpan {\n                    start,\n                    end: value.location().end,\n                },\n                value,\n            })),\n            _ => {\n                // Label shorthand: field without value means field: field\n                Ok(Some(RecordUpdateArg {\n                    label: label.clone(),\n                    location: SrcSpan {\n                        start,\n                        end: label_end,\n                    },\n                    value: UntypedConstant::Var {\n                        location: SrcSpan {\n                            start,\n                            end: label_end,\n                        },\n                        constructor: None,\n                        module: None,\n                        name: label,\n                        type_: (),\n                    },\n                }))\n            }\n        }\n    }\n\n    //\n    // Bit String parsing\n    //\n\n    // The structure is roughly the same for pattern, const, and expr\n    // that's why these functions take functions\n    //\n    // pattern (: option)?\n    fn parse_bit_array_segment<A>(\n        &mut self,\n        value_parser: &impl Fn(&mut Self) -> Result<Option<A>, ParseError>,\n        arg_parser: &impl Fn(&mut Self) -> Result<A, ParseError>,\n        to_int_segment: &impl Fn(EcoString, BigInt, u32, u32) -> A,\n    ) -> Result<Option<BitArraySegment<A, ()>>, ParseError>\n    where\n        A: HasLocation + std::fmt::Debug,\n    {\n        match value_parser(self)? {\n            Some(value) => {\n                let options = if self.maybe_one(&Token::Colon).is_some() {\n                    Parser::series_of(\n                        self,\n                        &|s| Parser::parse_bit_array_option(s, &arg_parser, &to_int_segment),\n                        Some(&Token::Minus),\n                    )?\n                } else {\n                    vec![]\n                };\n                let end = options\n                    .last()\n                    .map(|o| o.location().end)\n                    .unwrap_or_else(|| value.location().end);\n                Ok(Some(BitArraySegment {\n                    location: SrcSpan {\n                        start: value.location().start,\n                        end,\n                    },\n                    value: Box::new(value),\n                    type_: (),\n                    options,\n                }))\n            }\n            _ => Ok(None),\n        }\n    }\n\n    // examples:\n    //   1\n    //   size(1)\n    //   size(five)\n    //   utf8\n    fn parse_bit_array_option<A: std::fmt::Debug>(\n        &mut self,\n        arg_parser: &impl Fn(&mut Self) -> Result<A, ParseError>,\n        to_int_segment: &impl Fn(EcoString, BigInt, u32, u32) -> A,\n    ) -> Result<Option<BitArrayOption<A>>, ParseError> {\n        match self.next_tok() {\n            // named segment\n            Some((start, Token::Name { name }, end)) => {\n                if self.maybe_one(&Token::LeftParen).is_some() {\n                    // named function segment\n                    match name.as_str() {\n                        \"unit\" => match self.next_tok() {\n                            Some((int_s, Token::Int { value, .. }, int_e)) => {\n                                let (_, end) = self.expect_one(&Token::RightParen)?;\n                                let v = value.replace(\"_\", \"\");\n                                match u8::from_str(&v) {\n                                    Ok(units) if units > 0 => Ok(Some(BitArrayOption::Unit {\n                                        location: SrcSpan { start, end },\n                                        value: units,\n                                    })),\n\n                                    _ => Err(ParseError {\n                                        error: ParseErrorType::InvalidBitArrayUnit,\n                                        location: SrcSpan {\n                                            start: int_s,\n                                            end: int_e,\n                                        },\n                                    }),\n                                }\n                            }\n                            _ => self.next_tok_unexpected(vec![\"positive integer\".into()]),\n                        },\n\n                        \"size\" => {\n                            let value = arg_parser(self)?;\n                            let (_, end) = self.expect_one(&Token::RightParen)?;\n                            Ok(Some(BitArrayOption::Size {\n                                location: SrcSpan { start, end },\n                                value: Box::new(value),\n                                short_form: false,\n                            }))\n                        }\n                        _ => parse_error(\n                            ParseErrorType::InvalidBitArraySegment,\n                            SrcSpan { start, end },\n                        ),\n                    }\n                } else {\n                    str_to_bit_array_option(&name, SrcSpan { start, end })\n                        .ok_or(ParseError {\n                            error: ParseErrorType::InvalidBitArraySegment,\n                            location: SrcSpan { start, end },\n                        })\n                        .map(Some)\n                }\n            }\n            // int segment\n            Some((start, Token::Int { value, int_value }, end)) => Ok(Some(BitArrayOption::Size {\n                location: SrcSpan { start, end },\n                value: Box::new(to_int_segment(value, int_value, start, end)),\n                short_form: true,\n            })),\n            // invalid\n            _ => self.next_tok_unexpected(vec![\n                \"A valid bit array segment type\".into(),\n                \"See: https://tour.gleam.run/data-types/bit-arrays/\".into(),\n            ]),\n        }\n    }\n\n    fn expect_bit_array_pattern_segment_arg(&mut self) -> Result<UntypedPattern, ParseError> {\n        Ok(Pattern::BitArraySize(self.expect_bit_array_size()?))\n    }\n\n    fn expect_bit_array_size(&mut self) -> Result<BitArraySize<()>, ParseError> {\n        let left = match self.next_tok() {\n            Some((start, Token::Name { name }, end)) => BitArraySize::Variable {\n                location: SrcSpan { start, end },\n                name,\n                constructor: None,\n                type_: (),\n            },\n            Some((start, Token::Int { value, int_value }, end)) => BitArraySize::Int {\n                location: SrcSpan { start, end },\n                value,\n                int_value,\n            },\n            Some((start, Token::LeftBrace, _)) => {\n                let inner = self.expect_bit_array_size()?;\n                let (_, end) = self.expect_one(&Token::RightBrace)?;\n\n                BitArraySize::Block {\n                    location: SrcSpan { start, end },\n                    inner: Box::new(inner),\n                }\n            }\n            _ => return self.next_tok_unexpected(vec![\"A variable name or an integer\".into()]),\n        };\n\n        let Some((start, token, end)) = self.tok0.take() else {\n            return Ok(left);\n        };\n\n        match token {\n            Token::Plus => {\n                _ = self.next_tok();\n                let right = self.expect_bit_array_size()?;\n\n                Ok(self.bit_array_size_binary_operator(left, right, IntOperator::Add))\n            }\n            Token::Minus => {\n                _ = self.next_tok();\n                let right = self.expect_bit_array_size()?;\n\n                Ok(self.bit_array_size_binary_operator(left, right, IntOperator::Subtract))\n            }\n            Token::Star => {\n                _ = self.next_tok();\n                let right = self.expect_bit_array_size()?;\n\n                Ok(\n                    self.bit_array_size_high_precedence_operator(\n                        left,\n                        right,\n                        IntOperator::Multiply,\n                    ),\n                )\n            }\n            Token::Slash => {\n                _ = self.next_tok();\n                let right = self.expect_bit_array_size()?;\n\n                Ok(self.bit_array_size_high_precedence_operator(left, right, IntOperator::Divide))\n            }\n            Token::Percent => {\n                _ = self.next_tok();\n                let right = self.expect_bit_array_size()?;\n\n                Ok(self.bit_array_size_high_precedence_operator(\n                    left,\n                    right,\n                    IntOperator::Remainder,\n                ))\n            }\n            Token::Name { .. }\n            | Token::UpName { .. }\n            | Token::DiscardName { .. }\n            | Token::Int { .. }\n            | Token::Float { .. }\n            | Token::String { .. }\n            | Token::CommentDoc { .. }\n            | Token::LeftParen\n            | Token::RightParen\n            | Token::LeftSquare\n            | Token::RightSquare\n            | Token::LeftBrace\n            | Token::RightBrace\n            | Token::Less\n            | Token::Greater\n            | Token::LessEqual\n            | Token::GreaterEqual\n            | Token::PlusDot\n            | Token::MinusDot\n            | Token::StarDot\n            | Token::SlashDot\n            | Token::LessDot\n            | Token::GreaterDot\n            | Token::LessEqualDot\n            | Token::GreaterEqualDot\n            | Token::Concatenate\n            | Token::Colon\n            | Token::Comma\n            | Token::Hash\n            | Token::Bang\n            | Token::Equal\n            | Token::EqualEqual\n            | Token::NotEqual\n            | Token::Vbar\n            | Token::VbarVbar\n            | Token::AmperAmper\n            | Token::LtLt\n            | Token::GtGt\n            | Token::Pipe\n            | Token::Dot\n            | Token::RArrow\n            | Token::LArrow\n            | Token::DotDot\n            | Token::At\n            | Token::EndOfFile\n            | Token::CommentNormal\n            | Token::CommentModule\n            | Token::NewLine\n            | Token::As\n            | Token::Assert\n            | Token::Auto\n            | Token::Case\n            | Token::Const\n            | Token::Delegate\n            | Token::Derive\n            | Token::Echo\n            | Token::Else\n            | Token::Fn\n            | Token::If\n            | Token::Implement\n            | Token::Import\n            | Token::Let\n            | Token::Macro\n            | Token::Opaque\n            | Token::Panic\n            | Token::Pub\n            | Token::Test\n            | Token::Todo\n            | Token::Type\n            | Token::Use => {\n                self.tok0 = Some((start, token, end));\n                Ok(left)\n            }\n        }\n    }\n\n    fn bit_array_size_binary_operator(\n        &self,\n        left: BitArraySize<()>,\n        right: BitArraySize<()>,\n        operator: IntOperator,\n    ) -> BitArraySize<()> {\n        let start = left.location().start;\n        let end = right.location().end;\n\n        BitArraySize::BinaryOperator {\n            left: Box::new(left),\n            right: Box::new(right),\n            operator,\n            location: SrcSpan { start, end },\n        }\n    }\n\n    fn bit_array_size_high_precedence_operator(\n        &self,\n        left: BitArraySize<()>,\n        right: BitArraySize<()>,\n        operator: IntOperator,\n    ) -> BitArraySize<()> {\n        match right {\n            BitArraySize::Int { .. }\n            | BitArraySize::Variable { .. }\n            | BitArraySize::Block { .. } => {\n                self.bit_array_size_binary_operator(left, right, operator)\n            }\n            // This operator has the highest precedence of the possible operators\n            // for bit array size patterns. So, `a * b + c` should be parsed as\n            // `(a * b) + c`. If the right-hand side of this operator is another\n            // operator, we rearrange it to ensure correct precedence.\n            BitArraySize::BinaryOperator {\n                operator: right_operator,\n                left: middle,\n                right,\n                ..\n            } => self.bit_array_size_binary_operator(\n                self.bit_array_size_binary_operator(left, *middle, operator),\n                *right,\n                right_operator,\n            ),\n        }\n    }\n\n    fn expect_const_int(&mut self) -> Result<UntypedConstant, ParseError> {\n        match self.next_tok() {\n            Some((start, Token::Int { value, int_value }, end)) => Ok(Constant::Int {\n                location: SrcSpan { start, end },\n                value,\n                int_value,\n            }),\n            _ => self.next_tok_unexpected(vec![\"A variable name or an integer\".into()]),\n        }\n    }\n\n    fn expect_expression(&mut self) -> Result<UntypedExpr, ParseError> {\n        match self.parse_expression()? {\n            Some(e) => Ok(e),\n            _ => self.next_tok_unexpected(vec![\"An expression\".into()]),\n        }\n    }\n\n    fn expect_expression_unit(\n        &mut self,\n        context: ExpressionUnitContext,\n    ) -> Result<UntypedExpr, ParseError> {\n        if let Some(e) = self.parse_expression_unit(context)? {\n            Ok(e)\n        } else {\n            self.next_tok_unexpected(vec![\"An expression\".into()])\n        }\n    }\n\n    //\n    // Parse Helpers\n    //\n\n    /// Expect a particular token, advances the token stream\n    fn expect_one(&mut self, wanted: &Token) -> Result<(u32, u32), ParseError> {\n        match self.maybe_one(wanted) {\n            Some((start, end)) => Ok((start, end)),\n            None => self.next_tok_unexpected(vec![wanted.to_string().into()]),\n        }\n    }\n\n    // Expect a particular token after having parsed a series, advances the token stream\n    // Used for giving a clearer error message in cases where the series item is what failed to parse\n    fn expect_one_following_series(\n        &mut self,\n        wanted: &Token,\n        series: &'static str,\n    ) -> Result<(u32, u32), ParseError> {\n        match self.maybe_one(wanted) {\n            Some((start, end)) => Ok((start, end)),\n            None => self.next_tok_unexpected(vec![wanted.to_string().into(), series.into()]),\n        }\n    }\n\n    /// Expect the end to a custom type definiton or handle an incorrect\n    /// record constructor definition.\n    ///\n    /// Used for mapping to a more specific error type and message.\n    fn expect_custom_type_close(\n        &mut self,\n        name: &EcoString,\n        public: bool,\n        opaque: bool,\n    ) -> Result<(u32, u32), ParseError> {\n        match self.maybe_one(&Token::RightBrace) {\n            Some((start, end)) => Ok((start, end)),\n            None => match self.next_tok() {\n                None => parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 }),\n                Some((start, token, end)) => {\n                    // If provided a Name, map to a more detailed error\n                    // message to nudge the user.\n                    // Else, handle as an unexpected token.\n                    let field = if let Token::Name { name } = token {\n                        name\n                    } else {\n                        let hint = match (&token, self.tok0.take()) {\n                            (&Token::Fn, _) | (&Token::Pub, Some((_, Token::Fn, _))) => {\n                                let text = \"Gleam is not an object oriented programming language so\nfunctions are declared separately from types.\";\n                                Some(wrap(text).into())\n                            }\n                            (_, _) => None,\n                        };\n\n                        return parse_error(\n                            ParseErrorType::UnexpectedToken {\n                                token,\n                                expected: vec![\n                                    Token::RightBrace.to_string().into(),\n                                    \"a record constructor\".into(),\n                                ],\n                                hint,\n                            },\n                            SrcSpan { start, end },\n                        );\n                    };\n                    let field_type = match self.parse_type_annotation(&Token::Colon) {\n                        Ok(Some(annotation)) => Some(Box::new(annotation)),\n                        _ => None,\n                    };\n                    parse_error(\n                        ParseErrorType::ExpectedRecordConstructor {\n                            name: name.clone(),\n                            public,\n                            opaque,\n                            field,\n                            field_type,\n                        },\n                        SrcSpan { start, end },\n                    )\n                }\n            },\n        }\n    }\n\n    // Expect a Name else a token dependent helpful error\n    fn expect_name(&mut self) -> Result<(u32, EcoString, u32), ParseError> {\n        let (start, token, end) = self.expect_assign_name()?;\n        match token {\n            AssignName::Variable(name) => Ok((start, name, end)),\n            AssignName::Discard(_) => {\n                parse_error(ParseErrorType::IncorrectName, SrcSpan { start, end })\n            }\n        }\n    }\n\n    fn expect_assign_name(&mut self) -> Result<(u32, AssignName, u32), ParseError> {\n        let t = self.next_tok();\n        match t {\n            Some((start, tok, end)) => match tok {\n                Token::Name { name } => Ok((start, AssignName::Variable(name), end)),\n                Token::DiscardName { name, .. } => Ok((start, AssignName::Discard(name), end)),\n                Token::UpName { .. } => {\n                    parse_error(ParseErrorType::IncorrectName, SrcSpan { start, end })\n                }\n                _ if tok.is_reserved_word() => parse_error(\n                    ParseErrorType::UnexpectedReservedWord,\n                    SrcSpan { start, end },\n                ),\n                Token::Int { .. }\n                | Token::Float { .. }\n                | Token::String { .. }\n                | Token::CommentDoc { .. }\n                | Token::LeftParen\n                | Token::RightParen\n                | Token::LeftSquare\n                | Token::RightSquare\n                | Token::LeftBrace\n                | Token::RightBrace\n                | Token::Plus\n                | Token::Minus\n                | Token::Star\n                | Token::Slash\n                | Token::Less\n                | Token::Greater\n                | Token::LessEqual\n                | Token::GreaterEqual\n                | Token::Percent\n                | Token::PlusDot\n                | Token::MinusDot\n                | Token::StarDot\n                | Token::SlashDot\n                | Token::LessDot\n                | Token::GreaterDot\n                | Token::LessEqualDot\n                | Token::GreaterEqualDot\n                | Token::Concatenate\n                | Token::Colon\n                | Token::Comma\n                | Token::Hash\n                | Token::Bang\n                | Token::Equal\n                | Token::EqualEqual\n                | Token::NotEqual\n                | Token::Vbar\n                | Token::VbarVbar\n                | Token::AmperAmper\n                | Token::LtLt\n                | Token::GtGt\n                | Token::Pipe\n                | Token::Dot\n                | Token::RArrow\n                | Token::LArrow\n                | Token::DotDot\n                | Token::At\n                | Token::EndOfFile\n                | Token::CommentNormal\n                | Token::CommentModule\n                | Token::NewLine\n                | Token::As\n                | Token::Assert\n                | Token::Auto\n                | Token::Case\n                | Token::Const\n                | Token::Delegate\n                | Token::Derive\n                | Token::Echo\n                | Token::Else\n                | Token::Fn\n                | Token::If\n                | Token::Implement\n                | Token::Import\n                | Token::Let\n                | Token::Macro\n                | Token::Opaque\n                | Token::Panic\n                | Token::Pub\n                | Token::Test\n                | Token::Todo\n                | Token::Type\n                | Token::Use => parse_error(ParseErrorType::ExpectedName, SrcSpan { start, end }),\n            },\n            None => parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 }),\n        }\n    }\n\n    // Expect an UpName else a token dependent helpful error\n    fn expect_upname(&mut self) -> Result<(u32, EcoString, u32), ParseError> {\n        let t = self.next_tok();\n        match t {\n            Some((start, tok, end)) => match tok {\n                Token::Name { .. } | Token::DiscardName { .. } => {\n                    parse_error(ParseErrorType::IncorrectUpName, SrcSpan { start, end })\n                }\n                Token::UpName { name } => Ok((start, name, end)),\n                Token::Int { .. }\n                | Token::Float { .. }\n                | Token::String { .. }\n                | Token::CommentDoc { .. }\n                | Token::LeftParen\n                | Token::RightParen\n                | Token::LeftSquare\n                | Token::RightSquare\n                | Token::LeftBrace\n                | Token::RightBrace\n                | Token::Plus\n                | Token::Minus\n                | Token::Star\n                | Token::Slash\n                | Token::Less\n                | Token::Greater\n                | Token::LessEqual\n                | Token::GreaterEqual\n                | Token::Percent\n                | Token::PlusDot\n                | Token::MinusDot\n                | Token::StarDot\n                | Token::SlashDot\n                | Token::LessDot\n                | Token::GreaterDot\n                | Token::LessEqualDot\n                | Token::GreaterEqualDot\n                | Token::Concatenate\n                | Token::Colon\n                | Token::Comma\n                | Token::Hash\n                | Token::Bang\n                | Token::Equal\n                | Token::EqualEqual\n                | Token::NotEqual\n                | Token::Vbar\n                | Token::VbarVbar\n                | Token::AmperAmper\n                | Token::LtLt\n                | Token::GtGt\n                | Token::Pipe\n                | Token::Dot\n                | Token::RArrow\n                | Token::LArrow\n                | Token::DotDot\n                | Token::At\n                | Token::EndOfFile\n                | Token::CommentNormal\n                | Token::CommentModule\n                | Token::NewLine\n                | Token::As\n                | Token::Assert\n                | Token::Auto\n                | Token::Case\n                | Token::Const\n                | Token::Delegate\n                | Token::Derive\n                | Token::Echo\n                | Token::Else\n                | Token::Fn\n                | Token::If\n                | Token::Implement\n                | Token::Import\n                | Token::Let\n                | Token::Macro\n                | Token::Opaque\n                | Token::Panic\n                | Token::Pub\n                | Token::Test\n                | Token::Todo\n                | Token::Type\n                | Token::Use => parse_error(ParseErrorType::ExpectedUpName, SrcSpan { start, end }),\n            },\n            None => parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 }),\n        }\n    }\n\n    // Expect a target name. e.g. `javascript` or `erlang`.\n    // The location of the preceding left parenthesis is required\n    // to give the correct error span in case the target name is missing.\n    fn expect_target(&mut self, paren_location: SrcSpan) -> Result<Target, ParseError> {\n        let (start, t, end) = match self.next_tok() {\n            Some(t) => t,\n            None => {\n                return parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 });\n            }\n        };\n        if let Token::Name { name } = t {\n            match name.as_str() {\n                \"javascript\" => Ok(Target::JavaScript),\n                \"erlang\" => Ok(Target::Erlang),\n                \"js\" => {\n                    self.warnings\n                        .push(DeprecatedSyntaxWarning::DeprecatedTargetShorthand {\n                            location: SrcSpan::new(start, end),\n                            target: Target::JavaScript,\n                        });\n                    Ok(Target::JavaScript)\n                }\n                \"erl\" => {\n                    self.warnings\n                        .push(DeprecatedSyntaxWarning::DeprecatedTargetShorthand {\n                            location: SrcSpan::new(start, end),\n                            target: Target::Erlang,\n                        });\n                    Ok(Target::Erlang)\n                }\n                _ => parse_error(ParseErrorType::UnknownTarget, SrcSpan::new(start, end)),\n            }\n        } else {\n            parse_error(ParseErrorType::ExpectedTargetName, paren_location)\n        }\n    }\n\n    // Expect a String else error\n    fn expect_string(&mut self) -> Result<(u32, EcoString, u32), ParseError> {\n        match self.next_tok() {\n            Some((start, Token::String { value }, end)) => Ok((start, value, end)),\n            _ => self.next_tok_unexpected(vec![\"a string\".into()]),\n        }\n    }\n\n    fn peek_tok1(&mut self) -> Option<&Token> {\n        self.tok1.as_ref().map(|(_, token, _)| token)\n    }\n\n    // If the next token matches the requested, consume it and return (start, end)\n    fn maybe_one(&mut self, tok: &Token) -> Option<(u32, u32)> {\n        match self.tok0.take() {\n            Some((s, t, e)) if t == *tok => {\n                self.advance();\n                Some((s, e))\n            }\n\n            t0 => {\n                self.tok0 = t0;\n                None\n            }\n        }\n    }\n\n    // Parse a series by repeating a parser, and possibly a separator\n    fn series_of<A>(\n        &mut self,\n        parser: &impl Fn(&mut Self) -> Result<Option<A>, ParseError>,\n        sep: Option<&Token>,\n    ) -> Result<Vec<A>, ParseError> {\n        let (res, _) = self.series_of_has_trailing_separator(parser, sep)?;\n        Ok(res)\n    }\n\n    /// Parse a series by repeating a parser, and a separator. Returns true if\n    /// the series ends with the trailing separator.\n    fn series_of_has_trailing_separator<A>(\n        &mut self,\n        parser: &impl Fn(&mut Self) -> Result<Option<A>, ParseError>,\n        sep: Option<&Token>,\n    ) -> Result<(Vec<A>, bool), ParseError> {\n        let mut results = vec![];\n        let mut final_separator = None;\n        while let Some(result) = parser(self)? {\n            results.push(result);\n            if let Some(sep) = sep {\n                if let Some(separator) = self.maybe_one(sep) {\n                    final_separator = Some(separator);\n                } else {\n                    final_separator = None;\n                    break;\n                }\n\n                // Helpful error if extra separator\n                if let Some((start, end)) = self.maybe_one(sep) {\n                    return parse_error(ParseErrorType::ExtraSeparator, SrcSpan { start, end });\n                }\n            }\n        }\n\n        // If the sequence ends with a trailing comma we want to keep track of\n        // its position.\n        if let (Some(Token::Comma), Some((_, end))) = (sep, final_separator) {\n            self.extra.trailing_commas.push(end)\n        };\n\n        Ok((results, final_separator.is_some()))\n    }\n\n    // If next token is a Name, consume it and return relevant info, otherwise, return none\n    fn maybe_name(&mut self) -> Option<(u32, EcoString, u32)> {\n        match self.tok0.take() {\n            Some((s, Token::Name { name }, e)) => {\n                self.advance();\n                Some((s, name, e))\n            }\n            t0 => {\n                self.tok0 = t0;\n                None\n            }\n        }\n    }\n\n    // if next token is an UpName, consume it and return relevant info, otherwise, return none\n    fn maybe_upname(&mut self) -> Option<(u32, EcoString, u32)> {\n        match self.tok0.take() {\n            Some((s, Token::UpName { name }, e)) => {\n                self.advance();\n                Some((s, name, e))\n            }\n            t0 => {\n                self.tok0 = t0;\n                None\n            }\n        }\n    }\n\n    // if next token is a DiscardName, consume it and return relevant info, otherwise, return none\n    fn maybe_discard_name(&mut self) -> Option<(u32, EcoString, u32)> {\n        match self.tok0.take() {\n            Some((s, Token::DiscardName { name }, e)) => {\n                self.advance();\n                Some((s, name, e))\n            }\n            t0 => {\n                self.tok0 = t0;\n                None\n            }\n        }\n    }\n\n    // Unexpected token error on the next token or EOF\n    fn next_tok_unexpected<A>(&mut self, expected: Vec<EcoString>) -> Result<A, ParseError> {\n        match self.next_tok() {\n            None => parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 }),\n            Some((start, token, end)) => parse_error(\n                ParseErrorType::UnexpectedToken {\n                    token,\n                    expected,\n                    hint: None,\n                },\n                SrcSpan { start, end },\n            ),\n        }\n    }\n\n    // Moves the token stream forward\n    fn advance(&mut self) {\n        let _ = self.next_tok();\n    }\n\n    // Moving the token stream forward\n    // returns old tok0\n    fn next_tok(&mut self) -> Option<Spanned> {\n        let t = self.tok0.take();\n        let mut previous_newline = None;\n        let mut nxt;\n        loop {\n            match self.tokens.next() {\n                // gather and skip extra\n                Some(Ok((start, Token::CommentNormal, end))) => {\n                    self.extra.comments.push(SrcSpan { start, end });\n                    previous_newline = None;\n                }\n                Some(Ok((start, Token::CommentDoc { content }, end))) => {\n                    self.extra.doc_comments.push(SrcSpan::new(start, end));\n                    self.doc_comments.push_back((start, content));\n                    previous_newline = None;\n                }\n                Some(Ok((start, Token::CommentModule, end))) => {\n                    self.extra.module_comments.push(SrcSpan { start, end });\n                    previous_newline = None;\n                }\n                Some(Ok((start, Token::NewLine, _))) => {\n                    self.extra.new_lines.push(start);\n                    // If the previous token is a newline as well that means we\n                    // have run into an empty line.\n                    if let Some(start) = previous_newline {\n                        // We increase the byte position so that newline's start\n                        // doesn't overlap with the previous token's end.\n                        self.extra.empty_lines.push(start + 1);\n                    }\n                    previous_newline = Some(start);\n                }\n\n                // die on lex error\n                Some(Err(err)) => {\n                    nxt = None;\n                    self.lex_errors.push(err);\n                    break;\n                }\n\n                Some(Ok(tok)) => {\n                    nxt = Some(tok);\n                    break;\n                }\n                None => {\n                    nxt = None;\n                    break;\n                }\n            }\n        }\n        self.tok0 = self.tok1.take();\n        self.tok1 = nxt.take();\n        t\n    }\n\n    fn take_documentation(&mut self, until: u32) -> Option<(u32, EcoString)> {\n        let mut content = String::new();\n        let mut doc_start = u32::MAX;\n        while let Some((start, line)) = self.doc_comments.front() {\n            if *start < doc_start {\n                doc_start = *start;\n            }\n            if *start >= until {\n                break;\n            }\n\n            if self.extra.has_comment_between(*start, until) {\n                // We ignore doc comments that come before a regular comment.\n                let location = SrcSpan::new(*start, start + line.len() as u32);\n                _ = self.doc_comments.pop_front();\n                self.detached_doc_comments.push(location);\n                continue;\n            }\n\n            content.push_str(line);\n            content.push('\\n');\n            _ = self.doc_comments.pop_front();\n        }\n        if content.is_empty() {\n            None\n        } else {\n            Some((doc_start, content.into()))\n        }\n    }\n\n    fn parse_attributes(\n        &mut self,\n        attributes: &mut Attributes,\n    ) -> Result<Option<SrcSpan>, ParseError> {\n        let mut attributes_span = None;\n\n        while let Some((start, end)) = self.maybe_one(&Token::At) {\n            if attributes_span.is_none() {\n                attributes_span = Some(SrcSpan { start, end });\n            }\n\n            let end = self.parse_attribute(start, attributes)?;\n            attributes_span = attributes_span.map(|span| SrcSpan {\n                start: span.start,\n                end,\n            });\n        }\n\n        Ok(attributes_span)\n    }\n\n    fn parse_attribute(\n        &mut self,\n        start: u32,\n        attributes: &mut Attributes,\n    ) -> Result<u32, ParseError> {\n        // Parse the name of the attribute.\n\n        let (_, name, end) = self.expect_name()?;\n\n        let end = match name.as_str() {\n            \"external\" => {\n                let _ = self.expect_one(&Token::LeftParen)?;\n                self.parse_external_attribute(start, end, attributes)\n            }\n            \"target\" => self.parse_target_attribute(start, end, attributes),\n            \"deprecated\" => {\n                let _ = self.expect_one(&Token::LeftParen)?;\n                self.parse_deprecated_attribute(start, end, attributes)\n            }\n            \"internal\" => self.parse_internal_attribute(start, end, attributes),\n            _ => parse_error(ParseErrorType::UnknownAttribute, SrcSpan { start, end }),\n        }?;\n\n        Ok(end)\n    }\n\n    fn parse_target_attribute(\n        &mut self,\n        start: u32,\n        end: u32,\n        attributes: &mut Attributes,\n    ) -> Result<u32, ParseError> {\n        let (paren_start, paren_end) = self.expect_one(&Token::LeftParen)?;\n        let target = self.expect_target(SrcSpan::new(paren_start, paren_end))?;\n        if attributes.target.is_some() {\n            return parse_error(ParseErrorType::DuplicateAttribute, SrcSpan { start, end });\n        }\n        let (_, end) = self.expect_one(&Token::RightParen)?;\n        if attributes.target.is_some() {\n            return parse_error(ParseErrorType::DuplicateAttribute, SrcSpan { start, end });\n        }\n        attributes.target = Some(target);\n        Ok(end)\n    }\n\n    fn parse_external_attribute(\n        &mut self,\n        start: u32,\n        end: u32,\n        attributes: &mut Attributes,\n    ) -> Result<u32, ParseError> {\n        let (_, name, _) = self.expect_name()?;\n\n        let target = match name.as_str() {\n            \"erlang\" => Target::Erlang,\n            \"javascript\" => Target::JavaScript,\n            _ => return parse_error(ParseErrorType::UnknownTarget, SrcSpan::new(start, end)),\n        };\n\n        let _ = self.expect_one(&Token::Comma)?;\n        let (_, module, _) = self.expect_string()?;\n        let _ = self.expect_one(&Token::Comma)?;\n        let (_, function, _) = self.expect_string()?;\n        let _ = self.maybe_one(&Token::Comma);\n        let (_, end) = self.expect_one(&Token::RightParen)?;\n\n        if attributes.has_external_for(target) {\n            return parse_error(ParseErrorType::DuplicateAttribute, SrcSpan { start, end });\n        }\n\n        attributes.set_external_for(target, Some((module, function, SrcSpan { start, end })));\n        Ok(end)\n    }\n\n    fn parse_deprecated_attribute(\n        &mut self,\n        start: u32,\n        end: u32,\n        attributes: &mut Attributes,\n    ) -> Result<u32, ParseError> {\n        if attributes.deprecated.is_deprecated() {\n            return parse_error(ParseErrorType::DuplicateAttribute, SrcSpan::new(start, end));\n        }\n        let (_, message, _) = self.expect_string().map_err(|_| ParseError {\n            error: ParseErrorType::ExpectedDeprecationMessage,\n            location: SrcSpan { start, end },\n        })?;\n        let (_, end) = self.expect_one(&Token::RightParen)?;\n        attributes.deprecated = Deprecation::Deprecated { message };\n        Ok(end)\n    }\n\n    fn parse_internal_attribute(\n        &mut self,\n        start: u32,\n        end: u32,\n        attributes: &mut Attributes,\n    ) -> Result<u32, ParseError> {\n        match attributes.internal {\n            // If `internal` is present that means that we have already run into\n            // another `@internal` annotation, so it results in a `DuplicateAttribute`\n            // error.\n            InternalAttribute::Present(_) => {\n                parse_error(ParseErrorType::DuplicateAttribute, SrcSpan::new(start, end))\n            }\n            InternalAttribute::Missing => {\n                attributes.internal = InternalAttribute::Present(SrcSpan::new(start, end));\n                Ok(end)\n            }\n        }\n    }\n}\n\nfn concat_pattern_variable_left_hand_side_error<T>(start: u32, end: u32) -> Result<T, ParseError> {\n    Err(ParseError {\n        error: ParseErrorType::ConcatPatternVariableLeftHandSide,\n        location: SrcSpan::new(start, end),\n    })\n}\n\n// Operator Precedence Parsing\n//\n// Higher number means higher precedence.\n// All operators are left associative.\n\n/// Simple-Precedence-Parser, handle seeing an operator or end\nfn handle_op<A>(\n    next_op: Option<(Spanned, u8)>,\n    opstack: &mut Vec<(Spanned, u8)>,\n    estack: &mut Vec<A>,\n    do_reduce: &impl Fn(Spanned, &mut Vec<A>),\n) -> Option<A> {\n    let mut next_op = next_op;\n    loop {\n        match (opstack.pop(), next_op.take()) {\n            (None, None) => match estack.pop() {\n                Some(fin) => {\n                    if estack.is_empty() {\n                        return Some(fin);\n                    } else {\n                        panic!(\"Expression not fully reduced.\")\n                    }\n                }\n                _ => {\n                    return None;\n                }\n            },\n\n            (None, Some(op)) => {\n                opstack.push(op);\n                break;\n            }\n\n            (Some((op, _)), None) => do_reduce(op, estack),\n\n            (Some((opl, pl)), Some((opr, pr))) => {\n                match pl.cmp(&pr) {\n                    // all ops are left associative\n                    Ordering::Greater | Ordering::Equal => {\n                        do_reduce(opl, estack);\n                        next_op = Some((opr, pr));\n                    }\n                    Ordering::Less => {\n                        opstack.push((opl, pl));\n                        opstack.push((opr, pr));\n                        break;\n                    }\n                }\n            }\n        }\n    }\n    None\n}\n\nfn precedence(t: &Token) -> Option<u8> {\n    if t == &Token::Pipe {\n        return Some(6);\n    };\n    tok_to_binop(t).map(|op| op.precedence())\n}\n\nfn tok_to_binop(t: &Token) -> Option<BinOp> {\n    match t {\n        Token::VbarVbar => Some(BinOp::Or),\n        Token::AmperAmper => Some(BinOp::And),\n        Token::EqualEqual => Some(BinOp::Eq),\n        Token::NotEqual => Some(BinOp::NotEq),\n        Token::Less => Some(BinOp::LtInt),\n        Token::LessEqual => Some(BinOp::LtEqInt),\n        Token::Greater => Some(BinOp::GtInt),\n        Token::GreaterEqual => Some(BinOp::GtEqInt),\n        Token::LessDot => Some(BinOp::LtFloat),\n        Token::LessEqualDot => Some(BinOp::LtEqFloat),\n        Token::GreaterDot => Some(BinOp::GtFloat),\n        Token::GreaterEqualDot => Some(BinOp::GtEqFloat),\n        Token::Plus => Some(BinOp::AddInt),\n        Token::Minus => Some(BinOp::SubInt),\n        Token::PlusDot => Some(BinOp::AddFloat),\n        Token::MinusDot => Some(BinOp::SubFloat),\n        Token::Percent => Some(BinOp::RemainderInt),\n        Token::Star => Some(BinOp::MultInt),\n        Token::StarDot => Some(BinOp::MultFloat),\n        Token::Slash => Some(BinOp::DivInt),\n        Token::SlashDot => Some(BinOp::DivFloat),\n        Token::Concatenate => Some(BinOp::Concatenate),\n        Token::Name { .. }\n        | Token::UpName { .. }\n        | Token::DiscardName { .. }\n        | Token::Int { .. }\n        | Token::Float { .. }\n        | Token::String { .. }\n        | Token::CommentDoc { .. }\n        | Token::LeftParen\n        | Token::RightParen\n        | Token::LeftSquare\n        | Token::RightSquare\n        | Token::LeftBrace\n        | Token::RightBrace\n        | Token::Colon\n        | Token::Comma\n        | Token::Hash\n        | Token::Bang\n        | Token::Equal\n        | Token::Vbar\n        | Token::LtLt\n        | Token::GtGt\n        | Token::Pipe\n        | Token::Dot\n        | Token::RArrow\n        | Token::LArrow\n        | Token::DotDot\n        | Token::At\n        | Token::EndOfFile\n        | Token::CommentNormal\n        | Token::CommentModule\n        | Token::NewLine\n        | Token::As\n        | Token::Assert\n        | Token::Auto\n        | Token::Case\n        | Token::Const\n        | Token::Delegate\n        | Token::Derive\n        | Token::Echo\n        | Token::Else\n        | Token::Fn\n        | Token::If\n        | Token::Implement\n        | Token::Import\n        | Token::Let\n        | Token::Macro\n        | Token::Opaque\n        | Token::Panic\n        | Token::Pub\n        | Token::Test\n        | Token::Todo\n        | Token::Type\n        | Token::Use => None,\n    }\n}\n/// Simple-Precedence-Parser, perform reduction for expression\nfn do_reduce_expression(op: Spanned, estack: &mut Vec<UntypedExpr>) {\n    match (estack.pop(), estack.pop()) {\n        (Some(er), Some(el)) => {\n            let new_e = expr_op_reduction(op, el, er);\n            estack.push(new_e);\n        }\n        _ => panic!(\"Tried to reduce without 2 expressions\"),\n    }\n}\n\n/// Simple-Precedence-Parser, perform reduction for clause guard\nfn do_reduce_clause_guard(op: Spanned, estack: &mut Vec<UntypedClauseGuard>) {\n    match (estack.pop(), estack.pop()) {\n        (Some(er), Some(el)) => {\n            let new_e = clause_guard_reduction(op, el, er);\n            estack.push(new_e);\n        }\n        _ => panic!(\"Tried to reduce without 2 guards\"),\n    }\n}\n\nfn expr_op_reduction(\n    (token_start, token, token_end): Spanned,\n    l: UntypedExpr,\n    r: UntypedExpr,\n) -> UntypedExpr {\n    if token == Token::Pipe {\n        let expressions = if let UntypedExpr::PipeLine { mut expressions } = l {\n            expressions.push(r);\n            expressions\n        } else {\n            vec1![l, r]\n        };\n        UntypedExpr::PipeLine { expressions }\n    } else {\n        match tok_to_binop(&token) {\n            Some(bin_op) => UntypedExpr::BinOp {\n                location: SrcSpan {\n                    start: l.location().start,\n                    end: r.location().end,\n                },\n                name: bin_op,\n                name_location: SrcSpan {\n                    start: token_start,\n                    end: token_end,\n                },\n                left: Box::new(l),\n                right: Box::new(r),\n            },\n            _ => {\n                panic!(\"Token could not be converted to binop.\")\n            }\n        }\n    }\n}\n\nfn clause_guard_reduction(\n    (_, token, _): Spanned,\n    l: UntypedClauseGuard,\n    r: UntypedClauseGuard,\n) -> UntypedClauseGuard {\n    let location = SrcSpan {\n        start: l.location().start,\n        end: r.location().end,\n    };\n    let left = Box::new(l);\n    let right = Box::new(r);\n    let operator = tok_to_binop(&token).expect(\"Token could not be converted to binop.\");\n\n    UntypedClauseGuard::BinaryOperator {\n        location,\n        operator,\n        left,\n        right,\n    }\n}\n\n// BitArray Parse Helpers\n//\n// BitArrays in patterns, guards, and expressions have a very similar structure\n// but need specific types. These are helpers for that. There is probably a\n// rustier way to do this :)\nfn bit_array_size_int(value: EcoString, int_value: BigInt, start: u32, end: u32) -> UntypedPattern {\n    Pattern::BitArraySize(BitArraySize::Int {\n        location: SrcSpan { start, end },\n        value,\n        int_value,\n    })\n}\n\nfn bit_array_expr_int(value: EcoString, int_value: BigInt, start: u32, end: u32) -> UntypedExpr {\n    UntypedExpr::Int {\n        location: SrcSpan { start, end },\n        value,\n        int_value,\n    }\n}\n\nfn bit_array_const_int(\n    value: EcoString,\n    int_value: BigInt,\n    start: u32,\n    end: u32,\n) -> UntypedConstant {\n    Constant::Int {\n        location: SrcSpan { start, end },\n        value,\n        int_value,\n    }\n}\n\nfn str_to_bit_array_option<A>(lit: &str, location: SrcSpan) -> Option<BitArrayOption<A>> {\n    match lit {\n        \"bytes\" => Some(BitArrayOption::Bytes { location }),\n        \"int\" => Some(BitArrayOption::Int { location }),\n        \"float\" => Some(BitArrayOption::Float { location }),\n        \"bits\" => Some(BitArrayOption::Bits { location }),\n        \"utf8\" => Some(BitArrayOption::Utf8 { location }),\n        \"utf16\" => Some(BitArrayOption::Utf16 { location }),\n        \"utf32\" => Some(BitArrayOption::Utf32 { location }),\n        \"utf8_codepoint\" => Some(BitArrayOption::Utf8Codepoint { location }),\n        \"utf16_codepoint\" => Some(BitArrayOption::Utf16Codepoint { location }),\n        \"utf32_codepoint\" => Some(BitArrayOption::Utf32Codepoint { location }),\n        \"signed\" => Some(BitArrayOption::Signed { location }),\n        \"unsigned\" => Some(BitArrayOption::Unsigned { location }),\n        \"big\" => Some(BitArrayOption::Big { location }),\n        \"little\" => Some(BitArrayOption::Little { location }),\n        \"native\" => Some(BitArrayOption::Native { location }),\n        _ => None,\n    }\n}\n\n//\n// Error Helpers\n//\nfn parse_error<T>(error: ParseErrorType, location: SrcSpan) -> Result<T, ParseError> {\n    Err(ParseError { error, location })\n}\n\n//\n// Misc Helpers\n//\n\n// Parsing a function call into the appropriate structure\n#[derive(Debug)]\npub enum ParserArg {\n    Arg(Box<CallArg<UntypedExpr>>),\n    Hole {\n        name: EcoString,\n        /// The whole span of the argument.\n        arg_location: SrcSpan,\n        /// Just the span of the ignore name.\n        discard_location: SrcSpan,\n        label: Option<EcoString>,\n    },\n}\n\npub fn make_call(\n    fun: UntypedExpr,\n    arguments: Vec<ParserArg>,\n    start: u32,\n    end: u32,\n) -> Result<UntypedExpr, ParseError> {\n    let mut hole_location = None;\n\n    let arguments = arguments\n        .into_iter()\n        .map(|argument| match argument {\n            ParserArg::Arg(arg) => Ok(*arg),\n            ParserArg::Hole {\n                arg_location,\n                discard_location,\n                name,\n                label,\n            } => {\n                if hole_location.is_some() {\n                    return parse_error(ParseErrorType::TooManyArgHoles, SrcSpan { start, end });\n                }\n\n                hole_location = Some(discard_location);\n                if name != \"_\" {\n                    return parse_error(\n                        ParseErrorType::UnexpectedToken {\n                            token: Token::Name { name },\n                            expected: vec![\"An expression\".into(), \"An underscore\".into()],\n                            hint: None,\n                        },\n                        arg_location,\n                    );\n                }\n\n                Ok(CallArg {\n                    implicit: None,\n                    label,\n                    location: arg_location,\n                    value: UntypedExpr::Var {\n                        location: discard_location,\n                        name: CAPTURE_VARIABLE.into(),\n                    },\n                })\n            }\n        })\n        .collect::<Result<_, _>>()?;\n\n    let call = UntypedExpr::Call {\n        location: SrcSpan { start, end },\n        fun: Box::new(fun),\n        arguments,\n    };\n\n    match hole_location {\n        // A normal call\n        None => Ok(call),\n\n        // An anon function using the capture syntax run(_, 1, 2)\n        Some(hole_location) => Ok(UntypedExpr::Fn {\n            location: call.location(),\n            end_of_head_byte_index: call.location().end,\n            kind: FunctionLiteralKind::Capture {\n                hole: hole_location,\n            },\n            arguments: vec![Arg {\n                location: hole_location,\n                annotation: None,\n                names: ArgNames::Named {\n                    name: CAPTURE_VARIABLE.into(),\n                    location: hole_location,\n                },\n                type_: (),\n            }],\n            body: vec1![Statement::Expression(call)],\n            return_annotation: None,\n        }),\n    }\n}\n\n#[derive(Debug, Default)]\nstruct ParsedUnqualifiedImports {\n    types: Vec<UnqualifiedImport>,\n    values: Vec<UnqualifiedImport>,\n}\n\n/// Parses an Int value to a bigint.\n///\npub fn parse_int_value(value: &str) -> Option<BigInt> {\n    let (radix, value) = if let Some(value) = value.strip_prefix(\"0x\") {\n        (16, value)\n    } else if let Some(value) = value.strip_prefix(\"0o\") {\n        (8, value)\n    } else if let Some(value) = value.strip_prefix(\"0b\") {\n        (2, value)\n    } else {\n        (10, value)\n    };\n\n    let value = value.trim_start_matches('_');\n\n    BigInt::parse_bytes(value.as_bytes(), radix)\n}\n\n#[derive(Debug, PartialEq, Clone, Copy)]\nenum ExpressionUnitContext {\n    FollowingPipe,\n    Other,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum PatternPosition {\n    LetAssignment,\n    CaseClause,\n    UsePattern,\n}\n\nimpl PatternPosition {\n    pub fn to_declaration(&self) -> VariableDeclaration {\n        match self {\n            PatternPosition::LetAssignment => VariableDeclaration::LetPattern,\n            PatternPosition::CaseClause => VariableDeclaration::ClausePattern,\n            PatternPosition::UsePattern => VariableDeclaration::UsePattern,\n        }\n    }\n}\n\n/// A thin f64 wrapper that does not permit NaN.\n/// This allows us to implement `Eq`, which require reflexivity.\n///\n/// Used for gleam float literals, which cannot be NaN.\n///\n/// While there is no syntax for \"infinity\", float literals might be too big and\n/// overflow into infinity. This is still allowed so we can parse big literal\n/// numbers and the error will be raised during the analysis phase.\n#[derive(Clone, Copy, Debug, PartialEq)]\npub struct LiteralFloatValue(f64);\n\nimpl LiteralFloatValue {\n    pub const ONE: Self = LiteralFloatValue(1.0);\n    pub const ZERO: Self = LiteralFloatValue(0.0);\n\n    /// Parse from a string, returning `None` if the string\n    /// is not a valid f64 or the float is `NaN``\n    pub fn parse(value: &str) -> Option<Self> {\n        value\n            .replace(\"_\", \"\")\n            .parse::<f64>()\n            .ok()\n            .filter(|float| !float.is_nan())\n            .map(LiteralFloatValue)\n    }\n\n    pub fn value(&self) -> f64 {\n        self.0\n    }\n}\n\nimpl Eq for LiteralFloatValue {}\n\nimpl Ord for LiteralFloatValue {\n    fn cmp(&self, other: &Self) -> Ordering {\n        self.0\n            .partial_cmp(&other.0)\n            .expect(\"Only NaN comparisons should fail\")\n    }\n}\n\nimpl PartialOrd for LiteralFloatValue {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Hash for LiteralFloatValue {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.0.to_bits().hash(state)\n    }\n}\n\nimpl Serialize for LiteralFloatValue {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_f64(self.0)\n    }\n}\n\nimpl<'de> Deserialize<'de> for LiteralFloatValue {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        let value = f64::deserialize(deserializer)?;\n        if value.is_nan() {\n            Err(serde::de::Error::custom(\"NaN is not allowed\"))\n        } else {\n            Ok(LiteralFloatValue(value))\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/paths.rs",
    "content": "use crate::{\n    build::{Mode, Target},\n    manifest::Base16Checksum,\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\npub const ARTEFACT_DIRECTORY_NAME: &str = \"_gleam_artefacts\";\n\n#[derive(Debug, Clone)]\npub struct ProjectPaths {\n    root: Utf8PathBuf,\n}\n\nimpl ProjectPaths {\n    pub fn new(root: Utf8PathBuf) -> Self {\n        Self { root }\n    }\n\n    pub fn at_filesystem_root() -> Self {\n        let path = if cfg!(target_family = \"windows\") {\n            r\"C:\\\"\n        } else {\n            \"/\"\n        };\n\n        Self::new(Utf8PathBuf::from(path))\n    }\n\n    pub fn root(&self) -> &Utf8Path {\n        &self.root\n    }\n\n    pub fn root_config(&self) -> Utf8PathBuf {\n        self.root.join(\"gleam.toml\")\n    }\n\n    pub fn readme(&self) -> Utf8PathBuf {\n        self.root.join(\"README.md\")\n    }\n\n    pub fn manifest(&self) -> Utf8PathBuf {\n        self.root.join(\"manifest.toml\")\n    }\n\n    pub fn src_directory(&self) -> Utf8PathBuf {\n        self.root.join(\"src\")\n    }\n\n    pub fn test_directory(&self) -> Utf8PathBuf {\n        self.root.join(\"test\")\n    }\n\n    pub fn dev_directory(&self) -> Utf8PathBuf {\n        self.root.join(\"dev\")\n    }\n\n    pub fn build_directory(&self) -> Utf8PathBuf {\n        self.root.join(\"build\")\n    }\n\n    pub fn build_packages_directory(&self) -> Utf8PathBuf {\n        self.build_directory().join(\"packages\")\n    }\n\n    pub fn build_packages_toml(&self) -> Utf8PathBuf {\n        self.build_packages_directory().join(\"packages.toml\")\n    }\n\n    pub fn build_packages_package(&self, package_name: &str) -> Utf8PathBuf {\n        self.build_packages_directory().join(package_name)\n    }\n\n    // build_deps_package_config\n    pub fn build_packages_package_config(&self, package_name: &str) -> Utf8PathBuf {\n        self.build_packages_package(package_name).join(\"gleam.toml\")\n    }\n\n    pub fn build_export_hex_tarball(&self, package_name: &str, version: &str) -> Utf8PathBuf {\n        self.build_directory()\n            .join(format!(\"{package_name}-{version}.tar\"))\n    }\n\n    pub fn build_directory_for_mode(&self, mode: Mode) -> Utf8PathBuf {\n        self.build_directory().join(mode.to_string())\n    }\n\n    pub fn erlang_shipment_directory(&self) -> Utf8PathBuf {\n        self.build_directory().join(\"erlang-shipment\")\n    }\n\n    pub fn build_documentation_directory(&self, package: &str) -> Utf8PathBuf {\n        self.build_directory_for_mode(Mode::Dev)\n            .join(\"docs\")\n            .join(package)\n    }\n\n    pub fn build_directory_for_target(&self, mode: Mode, target: Target) -> Utf8PathBuf {\n        let target = match target {\n            Target::Erlang => \"erlang\",\n            Target::JavaScript => \"javascript\",\n        };\n        self.build_directory_for_mode(mode).join(target)\n    }\n\n    /// Note this uses the \"application name\", not the name of this package.\n    /// This is because in BEAM applications one can specify an application\n    /// name that is not the same as the Hex package name. Ideally we would\n    /// always use the package name, but the BEAM runtime knows nothing\n    /// about packages, only applications, so it will look on the filesystem\n    /// for the application name when loading it.\n    pub fn build_directory_for_package(\n        &self,\n        mode: Mode,\n        target: Target,\n        application_name: &str,\n    ) -> Utf8PathBuf {\n        self.build_directory_for_target(mode, target)\n            .join(application_name)\n    }\n\n    pub fn build_packages_ebins_glob(&self, mode: Mode, target: Target) -> Utf8PathBuf {\n        self.build_directory_for_package(mode, target, \"*\")\n            .join(\"ebin\")\n    }\n\n    /// A path to a special file that contains the version of gleam that last built\n    /// the artifacts. If this file does not match the current version of gleam we\n    /// will rebuild from scratch\n    pub fn build_gleam_version(&self, mode: Mode, target: Target) -> Utf8PathBuf {\n        self.build_directory_for_target(mode, target)\n            .join(\"gleam_version\")\n    }\n\n    /// The path to the source gleam.toml file for a path dependency.\n    pub fn path_dependency_gleam_toml_path(&self, dependency_path: &Utf8Path) -> Utf8PathBuf {\n        self.root().join(dependency_path).join(\"gleam.toml\")\n    }\n\n    pub fn dependency_gleam_toml_fingerprint_path(&self, dependency_name: &str) -> Utf8PathBuf {\n        self.build_packages_directory()\n            .join(format!(\"{}.config_fingerprint\", dependency_name))\n    }\n}\n\npub fn global_package_cache_package_tarball(checksum: &Base16Checksum) -> Utf8PathBuf {\n    global_packages_cache().join(format!(\"{}.tar\", checksum.to_string()))\n}\n\npub fn global_hexpm_oauth_credentials_path() -> Utf8PathBuf {\n    global_hexpm_cache().join(\"credentials.toml\")\n}\n\npub fn global_hexpm_legacy_credentials_path() -> Utf8PathBuf {\n    global_hexpm_cache().join(\"credentials\")\n}\n\nfn global_hexpm_cache() -> Utf8PathBuf {\n    default_global_gleam_cache().join(\"hex\").join(\"hexpm\")\n}\n\nfn global_packages_cache() -> Utf8PathBuf {\n    global_hexpm_cache().join(\"packages\")\n}\n\npub fn default_global_gleam_cache() -> Utf8PathBuf {\n    Utf8PathBuf::from_path_buf(\n        dirs_next::cache_dir()\n            .expect(\"Failed to determine user cache directory\")\n            .join(\"gleam\"),\n    )\n    .expect(\"Non Utf8 Path\")\n}\n\npub fn unnest(within: &Utf8Path) -> Utf8PathBuf {\n    let mut path = Utf8PathBuf::new();\n    for _ in within {\n        path = path.join(\"..\")\n    }\n    path\n}\n\n#[test]\nfn paths() {\n    assert!(default_global_gleam_cache().ends_with(\"gleam\"));\n\n    assert!(global_packages_cache().ends_with(\"hex/hexpm/packages\"));\n\n    assert!(\n        global_package_cache_package_tarball(&Base16Checksum(vec![0, 0, 0, 0]))\n            .ends_with(\"hex/hexpm/packages/00000000.tar\")\n    );\n\n    assert!(\n        global_package_cache_package_tarball(&Base16Checksum(vec![0x3A, 0x21, 0xF4]))\n            .ends_with(\"hex/hexpm/packages/3A21F4.tar\")\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/pretty/tests.rs",
    "content": "use super::Document::*;\nuse super::Mode::*;\nuse super::*;\n\nuse im::vector;\nuse pretty_assertions::assert_eq;\n\n#[test]\nfn fits_test() {\n    // Negative limits never fit\n    assert!(!fits(-1, 0, vector![]));\n\n    // If no more documents it always fits\n    assert!(fits(0, 0, vector![]));\n\n    // ForceBreak never fits\n    let doc = ForceBroken(Box::new(nil()));\n    assert!(!fits(100, 0, vector![(0, Unbroken, &doc)]));\n    let doc = ForceBroken(Box::new(nil()));\n    assert!(!fits(100, 0, vector![(0, Broken, &doc)]));\n\n    // Break in Broken fits always\n    assert!(fits(\n        1,\n        0,\n        vector![(\n            0,\n            Broken,\n            &Break {\n                broken: \"12\",\n                unbroken: \"\",\n                kind: BreakKind::Strict,\n            }\n        )]\n    ));\n\n    // Break in Unbroken mode fits if `unbroken` fits\n    assert!(fits(\n        3,\n        0,\n        vector![(\n            0,\n            Unbroken,\n            &Break {\n                broken: \"\",\n                unbroken: \"123\",\n                kind: BreakKind::Strict,\n            }\n        )]\n    ));\n    assert!(!fits(\n        2,\n        0,\n        vector![(\n            0,\n            Unbroken,\n            &Break {\n                broken: \"\",\n                unbroken: \"123\",\n                kind: BreakKind::Strict,\n            }\n        )]\n    ));\n\n    // Line always fits\n    assert!(fits(0, 0, vector![(0, Broken, &Line(100))]));\n    assert!(fits(0, 0, vector![(0, Unbroken, &Line(100))]));\n\n    // String fits if smaller than limit\n    let doc = Document::str(\"Hello\");\n    assert!(fits(5, 0, vector![(0, Broken, &doc)]));\n    let doc = Document::str(\"Hello\");\n    assert!(fits(5, 0, vector![(0, Unbroken, &doc)]));\n    let doc = Document::str(\"Hello\");\n    assert!(!fits(4, 0, vector![(0, Broken, &doc)]));\n    let doc = Document::str(\"Hello\");\n    assert!(!fits(4, 0, vector![(0, Unbroken, &doc)]));\n\n    // Cons fits if combined smaller than limit\n    let doc = Document::str(\"1\").append(Document::str(\"2\"));\n    assert!(fits(2, 0, vector![(0, Broken, &doc)]));\n    let doc = Document::str(\"1\").append(Document::str(\"2\"));\n    assert!(fits(2, 0, vector![(0, Unbroken, &doc,)]));\n    let doc = Document::str(\"1\").append(Document::str(\"2\"));\n    assert!(!fits(1, 0, vector![(0, Broken, &doc)]));\n    let doc = Document::str(\"1\").append(Document::str(\"2\"));\n    assert!(!fits(1, 0, vector![(0, Unbroken, &doc)]));\n\n    // Nest fits if combined smaller than limit\n    let doc = Nest(\n        1,\n        NestMode::Increase,\n        NestCondition::Always,\n        Box::new(Document::str(\"12\")),\n    );\n    assert!(fits(2, 0, vector![(0, Broken, &doc)]));\n    assert!(fits(2, 0, vector![(0, Unbroken, &doc)]));\n    assert!(!fits(1, 0, vector![(0, Broken, &doc)]));\n    assert!(!fits(1, 0, vector![(0, Unbroken, &doc)]));\n\n    // Nest fits if combined smaller than limit\n    let doc = Nest(\n        0,\n        NestMode::Increase,\n        NestCondition::Always,\n        Box::new(Document::str(\"12\")),\n    );\n    assert!(fits(2, 0, vector![(0, Broken, &doc)]));\n    assert!(fits(2, 0, vector![(0, Unbroken, &doc)]));\n    assert!(!fits(1, 0, vector![(0, Broken, &doc)]));\n    assert!(!fits(1, 0, vector![(0, Unbroken, &doc)]));\n\n    let doc = ZeroWidthString {\n        string: \"this is a very long string that doesn't count towards line width\".into(),\n    };\n    assert!(fits(10, 0, vector![(0, Unbroken, &doc)]));\n    assert!(fits(10, 9, vector![(0, Unbroken, &doc)]));\n    let string_doc = \"hello!\".to_doc();\n    assert!(fits(\n        10,\n        0,\n        vector![(0, Unbroken, &string_doc), (0, Unbroken, &doc)]\n    ));\n}\n\n#[test]\nfn format_test() {\n    let doc = Document::str(\"Hi\");\n    assert_eq!(\"Hi\", doc.to_pretty_string(10));\n\n    let doc = Document::str(\"Hi\").append(Document::str(\", world!\"));\n    assert_eq!(\"Hi, world!\", doc.clone().to_pretty_string(10));\n\n    let doc = &Break {\n        broken: \"broken\",\n        unbroken: \"unbroken\",\n        kind: BreakKind::Strict,\n    }\n    .group();\n    assert_eq!(\"unbroken\", doc.clone().to_pretty_string(10));\n\n    let doc = &Break {\n        broken: \"broken\",\n        unbroken: \"unbroken\",\n        kind: BreakKind::Strict,\n    }\n    .group();\n    assert_eq!(\"broken\\n\", doc.clone().to_pretty_string(5));\n\n    let doc = Nest(\n        2,\n        NestMode::Increase,\n        NestCondition::Always,\n        Box::new(Document::str(\"1\").append(Line(1).append(Document::str(\"2\")))),\n    );\n    assert_eq!(\"1\\n  2\", doc.to_pretty_string(1));\n\n    let doc = Group(Box::new(ForceBroken(Box::new(Break {\n        broken: \"broken\",\n        unbroken: \"unbroken\",\n        kind: BreakKind::Strict,\n    }))));\n    assert_eq!(\"broken\\n\".to_string(), doc.to_pretty_string(100));\n\n    let doc = ForceBroken(Box::new(Break {\n        broken: \"broken\",\n        unbroken: \"unbroken\",\n        kind: BreakKind::Flex,\n    }));\n    assert_eq!(\"unbroken\".to_string(), doc.to_pretty_string(100));\n\n    let doc = Vec(vec![\n        Break {\n            broken: \"broken\",\n            unbroken: \"unbroken\",\n            kind: BreakKind::Strict,\n        },\n        zero_width_string(\"<This will not cause a line break>\".into()),\n        Break {\n            broken: \"broken\",\n            unbroken: \"unbroken\",\n            kind: BreakKind::Strict,\n        },\n    ]);\n    assert_eq!(\n        \"unbroken<This will not cause a line break>unbroken\",\n        doc.to_pretty_string(20)\n    );\n}\n\n#[test]\nfn forcing_test() {\n    let docs = join(\n        [\n            \"hello\".to_doc(),\n            \"a\".to_doc(),\n            \"b\".to_doc(),\n            \"c\".to_doc(),\n            \"d\".to_doc(),\n        ],\n        break_(\"\", \" \"),\n    );\n\n    assert_eq!(\n        \"hello\\na\\nb\\nc\\nd\",\n        docs.clone().force_break().group().to_pretty_string(80)\n    );\n    assert_eq!(\n        \"hello a b c d\",\n        docs.clone()\n            .force_break()\n            .next_break_fits(NextBreakFitsMode::Enabled)\n            .group()\n            .to_pretty_string(80)\n    );\n    assert_eq!(\n        \"hello\\na\\nb\\nc\\nd\",\n        docs.clone()\n            .force_break()\n            .next_break_fits(NextBreakFitsMode::Enabled)\n            .next_break_fits(NextBreakFitsMode::Disabled)\n            .group()\n            .to_pretty_string(80)\n    );\n}\n\n#[test]\nfn nest_if_broken_test() {\n    assert_eq!(\n        \"hello\\n  world\",\n        concat([\"hello\".to_doc(), break_(\"\", \" \"), \"world\".to_doc()])\n            .nest_if_broken(2)\n            .group()\n            .to_pretty_string(10)\n    );\n\n    let list_doc = concat([\n        concat([\n            break_(\"[\", \"[\"),\n            \"a,\".to_doc(),\n            break_(\"\", \" \"),\n            \"b\".to_doc(),\n        ])\n        .nest(2),\n        break_(\",\", \"\"),\n        \"]\".to_doc(),\n    ])\n    .group();\n\n    let arguments_doc = concat([\n        break_(\"\", \"\"),\n        \"one\".to_doc(),\n        \",\".to_doc(),\n        break_(\"\", \" \"),\n        list_doc.group().next_break_fits(NextBreakFitsMode::Enabled),\n    ])\n    .nest_if_broken(2)\n    .group();\n\n    let function_call_doc = concat([\n        \"some_function_call(\".to_doc(),\n        arguments_doc,\n        break_(\"\", \"\"),\n        \")\".to_doc(),\n    ])\n    .group();\n\n    assert_eq!(\n        \"some_function_call(\\n  one,\\n  [\\n    a,\\n    b,\\n  ]\\n)\",\n        function_call_doc.clone().to_pretty_string(2)\n    );\n    assert_eq!(\n        \"some_function_call(\\n  one,\\n  [a, b]\\n)\",\n        function_call_doc.clone().to_pretty_string(20)\n    );\n    assert_eq!(\n        \"some_function_call(one, [\\n  a,\\n  b,\\n])\",\n        function_call_doc.clone().to_pretty_string(25)\n    );\n    assert_eq!(\n        \"some_function_call(one, [a, b])\",\n        function_call_doc.clone().to_pretty_string(80)\n    );\n}\n\n#[test]\nfn let_left_side_fits_test() {\n    let elements = break_(\"\", \"\").append(\"1\").nest(2).append(break_(\"\", \"\"));\n    let list = \"[\".to_doc().append(elements).append(\"]\").group();\n    let doc = list.clone().append(\" = \").append(list);\n\n    assert_eq!(\n        \"[1] = [\n  1\n]\",\n        doc.clone().to_pretty_string(7)\n    );\n\n    assert_eq!(\n        \"[\n  1\n] = [\n  1\n]\",\n        doc.clone().to_pretty_string(2)\n    );\n\n    assert_eq!(\"[1] = [1]\", doc.clone().to_pretty_string(16));\n}\n\n#[test]\nfn empty_documents() {\n    // nil\n    assert!(nil().is_empty());\n\n    // lines\n    assert!(lines(0).is_empty());\n    assert!(!line().is_empty());\n\n    // force break\n    assert!(nil().force_break().is_empty());\n    assert!(!\"ok\".to_doc().force_break().is_empty());\n\n    // strings\n    assert!(\"\".to_doc().is_empty());\n    assert!(!\"wibble\".to_doc().is_empty());\n    assert!(!\" \".to_doc().is_empty());\n    assert!(!\"\\n\".to_doc().is_empty());\n\n    // containers\n    assert!(\"\".to_doc().nest(2).is_empty());\n    assert!(!\"wibble\".to_doc().nest(2).is_empty());\n    assert!(\"\".to_doc().group().is_empty());\n    assert!(!\"wibble\".to_doc().group().is_empty());\n    assert!(break_(\"\", \"\").is_empty());\n    assert!(!break_(\"wibble\", \"wibble\").is_empty());\n    assert!(!break_(\"wibble\\nwobble\", \"wibble wobble\").is_empty());\n    assert!(\"\".to_doc().append(\"\".to_doc()).is_empty());\n    assert!(!\"wibble\".to_doc().append(\"\".to_doc()).is_empty());\n    assert!(!\"\".to_doc().append(\"wibble\".to_doc()).is_empty());\n    assert!(!zero_width_string(\"wibble\".into()).is_empty());\n}\n\n#[test]\nfn set_nesting() {\n    let doc = Vec(vec![\"wibble\".to_doc(), break_(\"\", \" \"), \"wobble\".to_doc()]).group();\n    assert_eq!(\n        \"wibble\\nwobble\",\n        doc.set_nesting(0).nest(2).to_pretty_string(1)\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/pretty.rs",
    "content": "//! This module implements the functionality described in\n//! [\"Strictly Pretty\" (2000) by Christian Lindig][0], with a few\n//! extensions.\n//!\n//! This module is heavily influenced by Elixir's Inspect.Algebra and\n//! JavaScript's Prettier.\n//!\n//! [0]: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.2200\n//!\n//! ## Extensions\n//!\n//! - `ForcedBreak` from Elixir.\n//! - `FlexBreak` from Elixir.\n//!\n//! The way this module works is fairly simple conceptually, however the actual\n//! behaviour in practice can be hard to wrap one's head around.\n//!\n//! The basic premise is the `Document` type, which is a tree structure,\n//! containing some text as well as information on how it can be formatted.\n//! Once the document is constructed, it can be printed using the\n//! `to_pretty_string` function.\n//!\n//! It will then traverse the tree, and construct\n//! a string, attempting to wrap lines to that they do not exceed the line length\n//! limit specified. Where and when it wraps lines is determined by the structure\n//! of the `Document` itself.\n//!\n#![allow(clippy::wrong_self_convention)]\n\n#[cfg(test)]\nmod tests;\n\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse num_bigint::BigInt;\nuse unicode_segmentation::UnicodeSegmentation;\n\nuse crate::{Result, io::Utf8Writer};\n\n/// Join multiple documents together in a vector. This macro calls the `to_doc`\n/// method on each element, providing a concise way to write a document sequence.\n/// For example:\n///\n/// ```rust:norun\n/// docvec![\"Hello\", line(), \"world!\"]\n/// ```\n///\n/// Note: each document in a docvec is not separated in any way: the formatter\n/// will never break a line unless a `Document::Break` or `Document::Line`\n/// is used. Therefore, `docvec![\"a\", \"b\", \"c\"]` is equivalent to\n/// `\"abc\".to_doc()`.\n///\n#[macro_export]\nmacro_rules! docvec {\n    () => {\n        Document::Vec(Vec::new())\n    };\n\n    // A docvec![] with a single element\n    ($first:expr $(,)?) => {\n        Document::Vec(vec![$first.to_doc()])\n    };\n\n    // A docvec![] with multiple elements.\n    ($first:expr, $($rest:expr),+ $(,)?) => {\n        // A document that looks like this: `Vec[Vec[..rest], ..other_rest]`\n        // is exactly the same as a flat: `Vec[..rest, ..other_rest]`.\n        // So in case a `docvec!` starts with a `Vec` we flatten it out to avoid\n        // having deeply nested documents.\n        match $first.to_doc() {\n            Document::Vec(mut vec) => {\n                $(\n                    vec.push($rest.to_doc());\n                )*\n                Document::Vec(vec)\n            },\n            first => Document::Vec(vec![first, $($rest.to_doc()),+])\n        }\n    };\n}\n\n/// Coerce a value into a Document.\n/// Note we do not implement this for String as a slight pressure to favour str\n/// over String.\npub trait Documentable<'a> {\n    fn to_doc(self) -> Document<'a>;\n}\n\nimpl<'a> Documentable<'a> for char {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for &'a str {\n    fn to_doc(self) -> Document<'a> {\n        Document::str(self)\n    }\n}\n\nimpl<'a> Documentable<'a> for EcoString {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(self)\n    }\n}\n\nimpl<'a> Documentable<'a> for &EcoString {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(self.clone())\n    }\n}\n\nimpl<'a> Documentable<'a> for isize {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for i64 {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for usize {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for f64 {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self:?}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for u64 {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self:?}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for u32 {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for u16 {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for u8 {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for BigInt {\n    fn to_doc(self) -> Document<'a> {\n        Document::eco_string(eco_format!(\"{self}\"))\n    }\n}\n\nimpl<'a> Documentable<'a> for Document<'a> {\n    fn to_doc(self) -> Document<'a> {\n        self\n    }\n}\n\nimpl<'a> Documentable<'a> for Vec<Document<'a>> {\n    fn to_doc(self) -> Document<'a> {\n        Document::Vec(self)\n    }\n}\n\nimpl<'a, D: Documentable<'a>> Documentable<'a> for Option<D> {\n    fn to_doc(self) -> Document<'a> {\n        self.map(Documentable::to_doc).unwrap_or_else(nil)\n    }\n}\n\n/// Joins an iterator into a single document, in the same way as `docvec!`.\npub fn concat<'a>(docs: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {\n    Document::Vec(docs.into_iter().collect())\n}\n\n/// Joins an iterator into a single document, interspersing each element with\n/// another document. This is useful for example in argument lists, where a\n/// list of arguments must all be separated with a comma.\npub fn join<'a>(\n    docs: impl IntoIterator<Item = Document<'a>>,\n    separator: Document<'a>,\n) -> Document<'a> {\n    concat(Itertools::intersperse(docs.into_iter(), separator))\n}\n\n/// A pretty printable document. A tree structure, made up of text and other\n/// elements which determine how it can be formatted.\n///\n/// The variants of this enum should probably not be constructed directly,\n/// rather use the helper functions of the same names to construct them.\n/// For example, use `line()` instead of `Document::Line(1)`.\n///\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Document<'a> {\n    /// A mandatory linebreak. This is always printed as a string of newlines,\n    /// equal in length to the number specified.\n    Line(usize),\n\n    /// Forces the breaks of the wrapped document to be considered as not\n    /// fitting on a single line. Used in combination with a `Group` it can be\n    /// used to force its `Break`s to always break.\n    ForceBroken(Box<Self>),\n\n    /// Ignore the next break, forcing it to render as unbroken.\n    NextBreakFits(Box<Self>, NextBreakFitsMode),\n\n    /// A document after which the formatter can insert a newline. This determines\n    /// where line breaks can occur, outside of hardcoded `Line`s.\n    /// See `break_` and `flex_break` for usage.\n    Break {\n        broken: &'a str,\n        unbroken: &'a str,\n        kind: BreakKind,\n    },\n\n    /// Join multiple documents together. The documents are not separated in any\n    /// way: the formatter will only print newlines if `Document::Break` or\n    /// `Document::Line` is used.\n    Vec(Vec<Self>),\n\n    /// Nests the given document by the given indent, depending on the specified\n    /// condition. See `Document::nest`, `Document::set_nesting` and\n    /// `Document::nest_if_broken` for usages.\n    Nest(isize, NestMode, NestCondition, Box<Self>),\n\n    /// Groups a document. When pretty printing a group, the formatter will\n    /// first attempt to fit the entire group on one line. If it fails, all\n    /// `break_` documents in the group will render broken.\n    ///\n    /// Nested groups are handled separately to their parents, so if the\n    /// outermost group is broken, any sub-groups might be rendered broken\n    /// or unbroken, depending on whether they fit on a single line.\n    Group(Box<Self>),\n\n    /// Renders a string slice. This will always render the string verbatim,\n    /// without any line breaks or other modifications to it.\n    Str {\n        string: &'a str,\n        /// The number of extended grapheme clusters in the string.\n        /// This is what the pretty printer uses as the width of the string as it\n        /// is closes to what a human would consider the \"length\" of a string.\n        ///\n        /// Since computing the number of grapheme clusters requires walking over\n        /// the string we precompute it to avoid iterating through a string over\n        /// and over again in the pretty printing algorithm.\n        ///\n        graphemes: isize,\n    },\n\n    /// Renders an `EcoString`. This will always render the string verbatim,\n    /// without any line breaks or other modifications to it.\n    EcoString {\n        string: EcoString,\n        /// The number of extended grapheme clusters in the string.\n        /// This is what the pretty printer uses as the width of the string as it\n        /// is closes to what a human would consider the \"length\" of a string.\n        ///\n        /// Since computing the number of grapheme clusters requires walking over\n        /// the string we precompute it to avoid iterating through a string over\n        /// and over again in the pretty printing algorithm.\n        ///\n        graphemes: isize,\n    },\n\n    /// A string that is not taken into account when determining line length.\n    /// This is useful for additional formatting text which won't be rendered\n    /// in the final output, such as ANSI codes or HTML elements.\n    ZeroWidthString { string: EcoString },\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum Mode {\n    /// The mode used when a group doesn't fit on a single line: when `Broken`\n    /// the `Break`s inside it will be rendered as newlines, splitting the\n    /// group.\n    Broken,\n\n    /// The default mode used when a group can fit on a single line: all its\n    /// `Break`s will be rendered as their unbroken string and kept on a single\n    /// line.\n    Unbroken,\n\n    /// This mode is used by the `NextBreakFit` document to force a break to be\n    /// considered as broken.\n    ForcedBroken,\n\n    /// This mode is used to disable a `NextBreakFit` document.\n    ForcedUnbroken,\n}\n\n/// A flag that can be used to enable or disable a `NextBreakFit` document.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum NextBreakFitsMode {\n    Enabled,\n    Disabled,\n}\n\n/// A flag that can be used to conditionally disable a `Nest` document.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum NestCondition {\n    /// This always applies the nesting. This is a sensible default that will\n    /// work for most of the cases.\n    Always,\n    /// Only applies the nesting if the wrapping `Group` couldn't fit on a\n    /// single line and has been broken.\n    IfBroken,\n}\n\n/// Used to change the way nesting of documents work.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum NestMode {\n    /// If the nesting mode is `Increase`, the current indentation will be\n    /// increased by the specified value.\n    Increase,\n    /// If the nesting mode is `Set`, the current indentation is going to be set\n    /// to exactly the specified value.\n    ///\n    /// `doc.nest(2).set_nesting(0)`\n    /// \"wibble\n    /// wobble    <- no indentation is added!\n    /// wubble\"\n    Set,\n}\n\nfn fits(\n    limit: isize,\n    mut current_width: isize,\n    mut docs: im::Vector<(isize, Mode, &Document<'_>)>,\n) -> bool {\n    // The `fits` function is going to take each document from the `docs` queue\n    // and check if those can fit on a single line. In order to do so documents\n    // are going to be pushed in front of this queue and have to be accompanied\n    // by additional information:\n    // - the document indentation, that can be increased by the `Nest` block.\n    // - the current mode; this is needed to know if a group is being broken or\n    //   not and treat `Break`s differently as a consequence. You can see how\n    //   the behaviour changes in [ref:break-fit].\n    //\n    // The loop might be broken earlier without checking all documents under one\n    // of two conditions:\n    // - the documents exceed the line `limit` and surely won't fit\n    //   [ref:document-unfit].\n    // - the documents are sure to fit the line - for example, if we meet a\n    //   broken `Break` [ref:break-fit] or a newline [ref:newline-fit].\n    loop {\n        // [tag:document-unfit] If we've exceeded the maximum width allowed for\n        // a line, it means that the document won't fit on a single line, we can\n        // break the loop.\n        if current_width > limit {\n            return false;\n        };\n\n        // We start by checking the first document of the queue. If there's no\n        // documents then we can safely say that it fits (if reached this point\n        // it means that the limit wasn't exceeded).\n        let (indent, mode, document) = match docs.pop_front() {\n            Some(x) => x,\n            None => return true,\n        };\n\n        match document {\n            // If a document is marked as `ForceBroken` we can immediately say\n            // that it doesn't fit, so that every break is going to be\n            // forcefully broken.\n            Document::ForceBroken(doc) => match mode {\n                // If the mode is `ForcedBroken` it means that we have to ignore\n                // this break [ref:forced-broken], so we go check the inner\n                // document ignoring the effects of this one.\n                Mode::ForcedBroken => docs.push_front((indent, mode, doc)),\n                Mode::Broken | Mode::Unbroken | Mode::ForcedUnbroken => return false,\n            },\n\n            // [tag:newline-fit] When we run into a line we know that the\n            // document has a bit that fits in the current line; if it didn't\n            // fit (that is, it exceeded the maximum allowed width) the loop\n            // would have been broken by one of the earlier checks.\n            Document::Line(_) => return true,\n\n            // If the nesting level is increased we go on checking the wrapped\n            // document and increase its indentation level based on the nesting\n            // condition.\n            Document::Nest(i, nest_mode, condition, doc) => match condition {\n                NestCondition::IfBroken => docs.push_front((indent, mode, doc)),\n                NestCondition::Always => {\n                    let new_indent = match nest_mode {\n                        NestMode::Increase => indent + i,\n                        NestMode::Set => *i,\n                    };\n                    docs.push_front((new_indent, mode, doc))\n                }\n            },\n\n            // As a general rule, a group fits if it can stay on a single line\n            // without its breaks being broken down.\n            Document::Group(doc) => match mode {\n                // If an outer group was broken, we still try to fit the inner\n                // group on a single line, that's why for the inner document\n                // we change the mode back to `Unbroken`.\n                Mode::Broken => docs.push_front((indent, Mode::Unbroken, doc)),\n                // Any other mode is preserved as-is: if the mode is forced it\n                // has to be left unchanged, and if the mode is already unbroken\n                // there's no need to change it.\n                Mode::Unbroken | Mode::ForcedBroken | Mode::ForcedUnbroken => {\n                    docs.push_front((indent, mode, doc))\n                }\n            },\n\n            // When we run into a string we increase the current_width; looping\n            // back we will check if we've exceeded the maximum allowed width.\n            Document::Str { graphemes, .. } | Document::EcoString { graphemes, .. } => {\n                current_width += graphemes\n            }\n\n            // Zero width strings do nothing: they do not contribute to line length\n            Document::ZeroWidthString { .. } => {}\n\n            // If we get to a break we need to first see if it has to be\n            // rendered as its unbroken or broken string, depending on the mode.\n            Document::Break { unbroken, .. } => match mode {\n                // [tag:break-fit] If the break has to be broken we're done!\n                // We haven't exceeded the maximum length (otherwise the loop\n                // iteration would have stopped with one of the earlier checks),\n                // and - since it needs to be broken - we'll have to go on a new\n                // line anyway.\n                // This means that the document inspected so far will fit on a\n                // single line, thus we return true.\n                Mode::Broken | Mode::ForcedBroken => return true,\n                // If the break is not broken then it will be rendered inline as\n                // its unbroken string, so we treat it exactly as if it were a\n                // normal string.\n                Mode::Unbroken | Mode::ForcedUnbroken => current_width += unbroken.len() as isize,\n            },\n\n            // The `NextBreakFits` can alter the current mode to `ForcedBroken`\n            // or `ForcedUnbroken` based on its enabled flag.\n            Document::NextBreakFits(doc, enabled) => match enabled {\n                // [tag:disable-next-break] If it is disabled then we check the\n                // wrapped document changing the mode to `ForcedUnbroken`.\n                NextBreakFitsMode::Disabled => docs.push_front((indent, Mode::ForcedUnbroken, doc)),\n                NextBreakFitsMode::Enabled => match mode {\n                    // If we're in `ForcedUnbroken` mode it means that the check\n                    // was disabled by a document wrapping this one\n                    // [ref:disable-next-break]; that's why we do nothing and\n                    // check the wrapped document as if it were a normal one.\n                    Mode::ForcedUnbroken => docs.push_front((indent, mode, doc)),\n                    // [tag:forced-broken] Any other mode is turned into\n                    // `ForcedBroken` so that when we run into a break, the\n                    // response to the question \"Does the document fit?\" will be\n                    // yes [ref:break-fit].\n                    // This is why this is called `NextBreakFit` I think.\n                    Mode::Broken | Mode::Unbroken | Mode::ForcedBroken => {\n                        docs.push_front((indent, Mode::ForcedBroken, doc))\n                    }\n                },\n            },\n\n            // If there's a sequence of documents we will check each one, one\n            // after the other to see if - as a whole - they can fit on a single\n            // line.\n            Document::Vec(vec) => {\n                // The array needs to be reversed to preserve the order of the\n                // documents since each one is pushed _to the front_ of the\n                // queue of documents to check.\n                for doc in vec.iter().rev() {\n                    docs.push_front((indent, mode, doc));\n                }\n            }\n        }\n    }\n}\n\n/// The kind of line break this `Document::Break` is.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum BreakKind {\n    /// A `flex_break`.\n    Flex,\n    /// A `break_`.\n    Strict,\n}\n\nfn format(\n    writer: &mut impl Utf8Writer,\n    limit: isize,\n    mut width: isize,\n    mut docs: im::Vector<(isize, Mode, &Document<'_>)>,\n) -> Result<()> {\n    // As long as there are documents to print we'll take each one by one and\n    // output the corresponding string to the given writer.\n    //\n    // Each document in the `docs` queue also has an accompanying indentation\n    // and mode:\n    // - the indentation is used to keep track of the current indentation,\n    //   you might notice in [ref:format-nest] that it adds documents to the\n    //   queue increasing their current indentation.\n    // - the mode is used to keep track of the state of the documents inside a\n    //   group. For example, if a group doesn't fit on a single line its\n    //   documents will be split into multiple lines and the mode set to\n    //   `Broken` to keep track of this.\n    while let Some((indent, mode, document)) = docs.pop_front() {\n        match document {\n            // When we run into a line we print the given number of newlines and\n            // add the indentation required by the given document.\n            Document::Line(i) => {\n                for _ in 0..*i {\n                    writer.str_write(\"\\n\")?;\n                }\n                for _ in 0..indent {\n                    writer.str_write(\" \")?;\n                }\n                width = indent;\n            }\n\n            // Flex breaks are NOT conditional to the mode: if the mode is\n            // already `Unbroken`, then the break is left unbroken (like strict\n            // breaks); any other mode is ignored.\n            // A flexible break will only be split if the following documents\n            // can't fit on the same line; otherwise, it is just displayed as an\n            // unbroken `Break`.\n            Document::Break {\n                broken,\n                unbroken,\n                kind: BreakKind::Flex,\n            } => {\n                let unbroken_width = width + unbroken.len() as isize;\n                // Every time we need to check again if the remaining piece can\n                // fit. If it does, the flexible break is not broken.\n                if mode == Mode::Unbroken || fits(limit, unbroken_width, docs.clone()) {\n                    writer.str_write(unbroken)?;\n                    width = unbroken_width;\n                } else {\n                    writer.str_write(broken)?;\n                    writer.str_write(\"\\n\")?;\n                    for _ in 0..indent {\n                        writer.str_write(\" \")?;\n                    }\n                    width = indent;\n                }\n            }\n\n            // Strict breaks are conditional to the mode. They differ from\n            // flexible break because, if a group gets split - that is the mode\n            // is `Broken` or `ForceBroken` - ALL of the breaks in that group\n            // will be split. You can notice the difference with flexible breaks\n            // because here we only check the mode and then take action; before\n            // we would try and see if the remaining documents fit on a single\n            // line before deciding if the (flexible) break can be split or not.\n            Document::Break {\n                broken,\n                unbroken,\n                kind: BreakKind::Strict,\n            } => match mode {\n                // If the mode requires the break to be broken, then its broken\n                // string is printed, then we start a newline and indent it\n                // according to the current indentation level.\n                Mode::Broken | Mode::ForcedBroken => {\n                    writer.str_write(broken)?;\n                    writer.str_write(\"\\n\")?;\n                    for _ in 0..indent {\n                        writer.str_write(\" \")?;\n                    }\n                    width = indent;\n                }\n                // If the mode doesn't require the break to be broken, then its\n                // unbroken string is printed as if it were a normal string;\n                // also updating the width of the current line.\n                Mode::Unbroken | Mode::ForcedUnbroken => {\n                    writer.str_write(unbroken)?;\n                    width += unbroken.len() as isize\n                }\n            },\n\n            // Strings are printed as they are and the current width is\n            // increased accordingly.\n            Document::EcoString { string, graphemes } => {\n                width += graphemes;\n                writer.str_write(string)?;\n            }\n\n            Document::Str { string, graphemes } => {\n                width += graphemes;\n                writer.str_write(string)?;\n            }\n\n            Document::ZeroWidthString { string } => {\n                // We write the string, but do not increment the length\n                writer.str_write(string)?;\n            }\n\n            // If multiple documents need to be printed, then they are all\n            // pushed to the front of the queue and will be printed one by one.\n            Document::Vec(vec) => {\n                // Just like `fits`, the elements will be pushed _on the front_\n                // of the queue. In order to keep their original order they need\n                // to be pushed in reverse order.\n                for doc in vec.iter().rev() {\n                    docs.push_front((indent, mode, doc));\n                }\n            }\n\n            // A `Nest` document doesn't result in anything being printed, its\n            // only effect is to increase the current nesting level for the\n            // wrapped document [tag:format-nest].\n            Document::Nest(i, nest_mode, condition, doc) => match (condition, mode) {\n                // The nesting is only applied under two conditions:\n                // - either the nesting condition is `Always`.\n                // - or the condition is `IfBroken` and the group was actually\n                //   broken (that is, the current mode is `Broken`).\n                (NestCondition::Always, _) | (NestCondition::IfBroken, Mode::Broken) => {\n                    let new_indent = match nest_mode {\n                        NestMode::Increase => indent + i,\n                        NestMode::Set => *i,\n                    };\n                    docs.push_front((new_indent, mode, doc))\n                }\n                // If none of the above conditions is met, then the nesting is\n                // not applied.\n                _ => docs.push_front((indent, mode, doc)),\n            },\n\n            Document::Group(doc) => {\n                // When we see a group we first try and see if it can fit on a\n                // single line without breaking any break; that is why we use\n                // the `Unbroken` mode here: we want to try to fit everything on\n                // a single line.\n                let group_docs = im::vector![(indent, Mode::Unbroken, doc.as_ref())];\n                if fits(limit, width, group_docs) {\n                    // If everything can stay on a single line we print the\n                    // wrapped document with the `Unbroken` mode, leaving all\n                    // the group's break as unbroken.\n                    docs.push_front((indent, Mode::Unbroken, doc));\n                } else {\n                    // Otherwise, we need to break the group. We print the\n                    // wrapped document changing its mode to `Broken` so that\n                    // all its breaks will be split on newlines.\n                    docs.push_front((indent, Mode::Broken, doc));\n                }\n            }\n\n            // `ForceBroken` and `NextBreakFits` only change the way the `fit`\n            // function works but do not actually change the formatting of a\n            // document by themselves. That's why when we run into those we\n            // just go on printing the wrapped document without altering the\n            // current mode.\n            Document::ForceBroken(document) | Document::NextBreakFits(document, _) => {\n                docs.push_front((indent, mode, document));\n            }\n        }\n    }\n    Ok(())\n}\n\n/// Renders an empty document.\npub fn nil<'a>() -> Document<'a> {\n    Document::Vec(vec![])\n}\n\n/// Renders a single newline.\npub fn line<'a>() -> Document<'a> {\n    Document::Line(1)\n}\n\n/// Renders a string of newlines, equal in length to the number provided.\npub fn lines<'a>(i: usize) -> Document<'a> {\n    Document::Line(i)\n}\n\n/// A document after which the formatter can insert a newline. This determines\n/// where line breaks can occur, outside of hardcoded `Line`s.\n///\n/// If the formatter determines that a group cannot fit on a single line,\n/// all breaks in the group will be rendered as broken. Otherwise, they\n/// will be rendered as unbroken.\n///\n/// A broken `Break` renders the `broken` string, followed by a newline.\n/// An unbroken `Break` renders the `unbroken` string by itself.\n///\n/// For example:\n/// ```rust:norun\n/// let document = docvec![\"Hello\", break_(\"\", \", \"), \"world!\"];\n/// assert_eq!(document.to_pretty_string(20), \"Hello, world!\");\n/// assert_eq!(document.to_pretty_string(10), \"Hello\\nworld!\");\n/// ```\n///\npub fn break_<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> {\n    Document::Break {\n        broken,\n        unbroken,\n        kind: BreakKind::Strict,\n    }\n}\n\n/// A document after which the formatter can insert a newline, similar to\n/// `break_()`. The difference is that when a group is rendered broken, all\n/// breaks are rendered broken. However, `flex_break` decides whether to\n/// break or not for every individual `flex_break`.\n///\n/// For example:\n/// ```rust:norun\n/// let with_breaks = docvec![\"Hello\", break_(\"\", \", \"), \"pretty\", break_(\"\", \", \"), \"printed!\"];\n/// assert_eq!(with_breaks.to_pretty_string(20), \"Hello\\npretty\\nprinted!\");\n///\n/// let with_flex_breaks = docvec![\"Hello\", flex_break(\"\", \", \"), \"pretty\", flex_break(\"\", \", \"), \"printed!\"];\n/// assert_eq!(with_flex_breaks.to_pretty_string(20), \"Hello, pretty\\nprinted!\");\n/// ```\n///\npub fn flex_break<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> {\n    Document::Break {\n        broken,\n        unbroken,\n        kind: BreakKind::Flex,\n    }\n}\n\n/// A string that is not taken into account when determining line length.\n/// This is useful for additional formatting text which won't be rendered\n/// in the final output, such as ANSI codes or HTML elements.\n///\n/// For example:\n/// ```rust:norun\n/// let document = docvec![\"Hello\", zero_width_string(\"This is a very long string\"), break_(\"\", \"\"), \"world\"];\n/// assert_eq!(document.to_pretty_string(20), \"HelloThis is a very long stringworld\");\n/// ```\n///\npub fn zero_width_string<'a>(string: EcoString) -> Document<'a> {\n    Document::ZeroWidthString { string }\n}\n\nimpl<'a> Document<'a> {\n    /// Creates a document from a string slice.\n    pub fn str(string: &'a str) -> Self {\n        Document::Str {\n            graphemes: string.graphemes(true).count() as isize,\n            string,\n        }\n    }\n\n    /// Creates a document from an owned `EcoString`.\n    pub fn eco_string(string: EcoString) -> Self {\n        Document::EcoString {\n            graphemes: string.graphemes(true).count() as isize,\n            string,\n        }\n    }\n\n    /// Groups a document. When pretty printing a group, the formatter will\n    /// first attempt to fit the entire group on one line. If it fails, all\n    /// `break_` documents in the group will render broken.\n    ///\n    /// Nested groups are handled separately to their parents, so if the\n    /// outermost group is broken, any sub-groups might be rendered broken\n    /// or unbroken, depending on whether they fit on a single line.\n    pub fn group(self) -> Self {\n        Self::Group(Box::new(self))\n    }\n\n    /// Sets the indentation level of a document.\n    pub fn set_nesting(self, indent: isize) -> Self {\n        Self::Nest(indent, NestMode::Set, NestCondition::Always, Box::new(self))\n    }\n\n    /// Nests a document by a certain indentation. When rending linebreaks, the\n    /// formatter will print a new line followed by the current indentation.\n    pub fn nest(self, indent: isize) -> Self {\n        Self::Nest(\n            indent,\n            NestMode::Increase,\n            NestCondition::Always,\n            Box::new(self),\n        )\n    }\n\n    /// Nests a document by a certain indentation, but only if the current\n    /// group is broken.\n    pub fn nest_if_broken(self, indent: isize) -> Self {\n        Self::Nest(\n            indent,\n            NestMode::Increase,\n            NestCondition::IfBroken,\n            Box::new(self),\n        )\n    }\n\n    /// Forces all `break_` and `flex_break` documents in the current group\n    /// to render broken.\n    pub fn force_break(self) -> Self {\n        Self::ForceBroken(Box::new(self))\n    }\n\n    /// Force the next `Break` to render unbroken, regardless of whether it\n    /// fits on the line or not.\n    pub fn next_break_fits(self, mode: NextBreakFitsMode) -> Self {\n        Self::NextBreakFits(Box::new(self), mode)\n    }\n\n    /// Appends one document to another. Equivalent to `docvec![self, second]`,\n    /// except that it `self` is already a `Document::Vec`, it will append\n    /// directly to it instead of allocating a new vector.\n    ///\n    /// Useful when chaining multiple documents together in a fashion where\n    /// they cannot be put all into one `docvec!` macro.\n    pub fn append(self, second: impl Documentable<'a>) -> Self {\n        match self {\n            Self::Vec(mut vec) => {\n                vec.push(second.to_doc());\n                Self::Vec(vec)\n            }\n            Self::Line(..)\n            | Self::ForceBroken(..)\n            | Self::NextBreakFits(..)\n            | Self::Break { .. }\n            | Self::Nest(..)\n            | Self::Group(..)\n            | Self::Str { .. }\n            | Self::EcoString { .. }\n            | Self::ZeroWidthString { .. } => Self::Vec(vec![self, second.to_doc()]),\n        }\n    }\n\n    /// Prints a document into a `String`, attempting to limit lines to `limit`\n    /// characters in length.\n    pub fn to_pretty_string(self, limit: isize) -> String {\n        let mut buffer = String::new();\n        self.pretty_print(limit, &mut buffer)\n            .expect(\"Writing to string buffer failed\");\n        buffer\n    }\n\n    /// Surrounds a document in two delimiters. Equivalent to\n    /// `docvec![option, self, closed]`.\n    pub fn surround(self, open: impl Documentable<'a>, closed: impl Documentable<'a>) -> Self {\n        open.to_doc().append(self).append(closed)\n    }\n\n    /// Prints a document into `writer`, attempting to limit lines to `limit`\n    /// characters in length.\n    pub fn pretty_print(&self, limit: isize, writer: &mut impl Utf8Writer) -> Result<()> {\n        let docs = im::vector![(0, Mode::Unbroken, self)];\n        format(writer, limit, 0, docs)?;\n        Ok(())\n    }\n\n    /// Returns true when the document contains no printable characters\n    /// (whitespace and newlines are considered printable characters).\n    pub fn is_empty(&self) -> bool {\n        use Document::*;\n        match self {\n            Line(n) => *n == 0,\n            EcoString { string, .. } => string.is_empty(),\n            Str { string, .. } => string.is_empty(),\n            // assuming `broken` and `unbroken` are equivalent\n            Break { broken, .. } => broken.is_empty(),\n            ForceBroken(d) | Nest(_, _, _, d) | Group(d) | NextBreakFits(d, _) => d.is_empty(),\n            Vec(docs) => docs.iter().all(|d| d.is_empty()),\n            // Zero-width strings don't count towards line length, but they are\n            // still printed and so are not empty. (Unless their string contents\n            // is also empty)\n            ZeroWidthString { string } => string.is_empty(),\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/reference.rs",
    "content": "use std::collections::{HashMap, HashSet};\n\nuse crate::ast::{Publicity, SrcSpan};\nuse bimap::{BiMap, Overwritten};\nuse ecow::EcoString;\nuse petgraph::{\n    Directed, Direction,\n    stable_graph::{NodeIndex, StableGraph},\n};\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum ReferenceKind {\n    Qualified,\n    Unqualified,\n    Import,\n    Definition,\n    Alias,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct Reference {\n    pub location: SrcSpan,\n    pub kind: ReferenceKind,\n}\n\npub type ReferenceMap = HashMap<(EcoString, EcoString), Vec<Reference>>;\n\n#[derive(Debug, Clone)]\npub struct EntityInformation {\n    pub origin: SrcSpan,\n    pub kind: EntityKind,\n}\n\n/// Information about an \"Entity\". This determines how we warn about an entity\n/// being unused.\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum EntityKind {\n    Function,\n    Constant,\n    Constructor,\n    Type,\n    ImportedModule { module_name: EcoString },\n    ModuleAlias { module: EcoString },\n    ImportedConstructor { module: EcoString },\n    ImportedType { module: EcoString },\n    ImportedValue { module: EcoString },\n}\n\n/// Like `ast::Layer`, this type differentiates between different scopes. For example,\n/// there can be a `wibble` value, a `wibble` module and a `wibble` type in the same\n/// scope all at once!\n///\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nenum EntityLayer {\n    /// An entity which exists in the type layer: a custom type, type variable\n    /// or type alias.\n    Type,\n    /// An entity which exists in the value layer: a constant, function or\n    /// custom type variant constructor.\n    Value,\n    /// An entity which has been shadowed. This allows us to keep track of unused\n    /// imports even if they have been shadowed by another value in the current\n    /// module.\n    /// This extra variant is needed because we used `Entity` as a key in a hashmap,\n    /// and so a duplicate key would not be able to exist.\n    /// We also would not want to get this shadowed entity when performing a lookup\n    /// of a named entity; we only want it to register it as an entity in the\n    /// `unused` function.\n    Shadowed,\n    /// The name of an imported module. Modules are separate to values!\n    Module,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct Entity {\n    pub name: EcoString,\n    layer: EntityLayer,\n}\n\n#[derive(Debug, Default)]\npub struct ReferenceTracker {\n    /// A call-graph which tracks which values are referenced by which other value,\n    /// used for dead code detection.\n    graph: StableGraph<(), (), Directed>,\n    entities: BiMap<Entity, NodeIndex>,\n    current_node: NodeIndex,\n    public_entities: HashSet<Entity>,\n    entity_information: HashMap<Entity, EntityInformation>,\n\n    /// The locations of the references to each value in this module, used for\n    /// renaming and go-to reference.\n    pub value_references: ReferenceMap,\n    /// The locations of the references to each type in this module, used for\n    /// renaming and go-to reference.\n    pub type_references: ReferenceMap,\n\n    /// This map is used to access the nodes of modules that were not\n    /// aliased, given their name.\n    /// We need this to keep track of references made to imports by unqualified\n    /// values/types: when an unqualified item is used we want to add an edge\n    /// pointing to the import it comes from, so that if the item is used the\n    /// import won't be marked as unused:\n    ///\n    /// ```gleam\n    /// import wibble/wobble.{used}\n    ///\n    /// pub fn main() {\n    ///   used\n    /// }\n    /// ```\n    ///\n    /// And each imported entity carries around the _name of the module_ and not\n    /// just the alias (here it would be `wibble/wobble` and not just `wobble`).\n    ///\n    module_name_to_node: HashMap<EcoString, NodeIndex>,\n}\n\nimpl ReferenceTracker {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    fn get_or_create_node(&mut self, name: EcoString, layer: EntityLayer) -> NodeIndex {\n        let entity = Entity { name, layer };\n\n        match self.entities.get_by_left(&entity) {\n            Some(index) => *index,\n            None => {\n                let index = self.graph.add_node(());\n                _ = self.entities.insert(entity, index);\n                index\n            }\n        }\n    }\n\n    fn create_node(&mut self, name: EcoString, layer: EntityLayer) -> NodeIndex {\n        let entity = Entity { name, layer };\n        let index = self.graph.add_node(());\n\n        self.create_node_and_maybe_shadow(entity, index);\n\n        index\n    }\n\n    fn create_node_and_maybe_shadow(&mut self, entity: Entity, index: NodeIndex) {\n        match self.entities.insert(entity, index) {\n            Overwritten::Neither => {}\n            Overwritten::Left(mut entity, index)\n            | Overwritten::Right(mut entity, index)\n            | Overwritten::Pair(mut entity, index)\n            | Overwritten::Both((mut entity, index), _) => {\n                // If an entity with the same name as this already exists,\n                // we still need to keep track of its usage! Thought it cannot\n                // be referenced anymore, it still might have been used before this\n                // point, or need to be marked as unused.\n                // To do this, we keep track of a \"Shadowed\" entity in `entity_information`.\n                if let Some(information) = self.entity_information.get(&entity) {\n                    entity.layer = EntityLayer::Shadowed;\n                    _ = self\n                        .entity_information\n                        .insert(entity.clone(), information.clone());\n                    _ = self.entities.insert(entity, index);\n                }\n            }\n        }\n    }\n\n    /// This function exists because of a specific edge-case where constants\n    /// can shadow imported values. For example:\n    /// ```gleam\n    /// import math.{pi}\n    ///\n    /// pub const pi = pi\n    /// ```\n    /// Here, the new `pi` constant shadows the imported `pi` value, but it still\n    /// references it, so it should not be marked as unused.\n    /// In order for this to work, we must first set the `current_function` field\n    /// so that the `pi` value is referenced by the public `pi` constant.\n    /// However, we can't insert the `pi` constant into the name scope yet, since\n    /// then it would count as referencing itself. We first need to set `current_function`,\n    /// then once we have analysed the right-hand-side of the constant, we can\n    /// register it in the scope using `register_constant`.\n    ///\n    pub fn begin_constant(&mut self) {\n        self.current_node = self.graph.add_node(());\n    }\n\n    pub fn register_constant(&mut self, name: EcoString, location: SrcSpan, publicity: Publicity) {\n        let entity = Entity {\n            name,\n            layer: EntityLayer::Value,\n        };\n        self.create_node_and_maybe_shadow(entity.clone(), self.current_node);\n        match publicity {\n            Publicity::Public | Publicity::Internal { .. } => {\n                let _ = self.public_entities.insert(entity.clone());\n            }\n            Publicity::Private => {}\n        }\n\n        _ = self.entity_information.insert(\n            entity,\n            EntityInformation {\n                kind: EntityKind::Constant,\n                origin: location,\n            },\n        );\n    }\n\n    pub fn register_value(\n        &mut self,\n        name: EcoString,\n        kind: EntityKind,\n        location: SrcSpan,\n        publicity: Publicity,\n    ) {\n        self.current_node = self.create_node(name.clone(), EntityLayer::Value);\n        self.register_module_reference_from_imported_entity(&kind);\n\n        let entity = Entity {\n            name,\n            layer: EntityLayer::Value,\n        };\n        match publicity {\n            Publicity::Public | Publicity::Internal { .. } => {\n                let _ = self.public_entities.insert(entity.clone());\n            }\n            Publicity::Private => {}\n        }\n\n        _ = self.entity_information.insert(\n            entity,\n            EntityInformation {\n                kind,\n                origin: location,\n            },\n        );\n    }\n\n    pub fn set_current_node(&mut self, name: EcoString) {\n        self.current_node = self.get_or_create_node(name, EntityLayer::Value);\n    }\n\n    pub fn register_type(\n        &mut self,\n        name: EcoString,\n        kind: EntityKind,\n        location: SrcSpan,\n        publicity: Publicity,\n    ) {\n        self.current_node = self.create_node(name.clone(), EntityLayer::Type);\n        self.register_module_reference_from_imported_entity(&kind);\n\n        let entity = Entity {\n            name,\n            layer: EntityLayer::Type,\n        };\n        match publicity {\n            Publicity::Public | Publicity::Internal { .. } => {\n                let _ = self.public_entities.insert(entity.clone());\n            }\n            Publicity::Private => {}\n        }\n\n        _ = self.entity_information.insert(\n            entity,\n            EntityInformation {\n                kind,\n                origin: location,\n            },\n        );\n    }\n\n    pub fn register_aliased_module(\n        &mut self,\n        used_name: EcoString,\n        module_name: EcoString,\n        alias_location: SrcSpan,\n        import_location: SrcSpan,\n    ) {\n        // We first record a node for the module being aliased. We use its entire\n        // name to identify it in this case and keep track of the node it's\n        // associated with.\n        self.register_module(module_name.clone(), module_name.clone(), import_location);\n\n        // Then we create a node for the alias, as the alias itself might be\n        // unused!\n        self.current_node = self.create_node(used_name.clone(), EntityLayer::Module);\n        // Also we want to register the fact that if this alias is used then the\n        // import is used: so we add a reference from the alias to the import\n        // we've just added.\n        self.register_module_reference(module_name.clone());\n\n        // Finally we can add information for this alias:\n        let entity = Entity {\n            name: used_name,\n            layer: EntityLayer::Module,\n        };\n        _ = self.entity_information.insert(\n            entity,\n            EntityInformation {\n                kind: EntityKind::ModuleAlias {\n                    module: module_name,\n                },\n                origin: alias_location,\n            },\n        );\n    }\n\n    pub fn register_module(\n        &mut self,\n        used_name: EcoString,\n        module_name: EcoString,\n        location: SrcSpan,\n    ) {\n        self.current_node = self.create_node(used_name.clone(), EntityLayer::Module);\n        let _ = self\n            .module_name_to_node\n            .insert(module_name.clone(), self.current_node);\n\n        let entity = Entity {\n            name: used_name,\n            layer: EntityLayer::Module,\n        };\n\n        _ = self.entity_information.insert(\n            entity,\n            EntityInformation {\n                kind: EntityKind::ImportedModule { module_name },\n                origin: location,\n            },\n        );\n    }\n\n    fn register_module_reference_from_imported_entity(&mut self, entity_kind: &EntityKind) {\n        match entity_kind {\n            EntityKind::Function\n            | EntityKind::Constant\n            | EntityKind::Constructor\n            | EntityKind::Type\n            | EntityKind::ImportedModule { .. }\n            | EntityKind::ModuleAlias { .. } => (),\n\n            EntityKind::ImportedConstructor { module }\n            | EntityKind::ImportedType { module }\n            | EntityKind::ImportedValue { module } => {\n                self.register_module_reference(module.clone())\n            }\n        }\n    }\n\n    pub fn register_value_reference(\n        &mut self,\n        module: EcoString,\n        name: EcoString,\n        referenced_name: &EcoString,\n        location: SrcSpan,\n        kind: ReferenceKind,\n    ) {\n        match kind {\n            ReferenceKind::Qualified | ReferenceKind::Import | ReferenceKind::Definition => {}\n            ReferenceKind::Alias | ReferenceKind::Unqualified => {\n                let target = self.get_or_create_node(referenced_name.clone(), EntityLayer::Value);\n                _ = self.graph.add_edge(self.current_node, target, ());\n            }\n        }\n\n        self.value_references\n            .entry((module, name))\n            .or_default()\n            .push(Reference { location, kind });\n    }\n\n    pub fn register_type_reference(\n        &mut self,\n        module: EcoString,\n        name: EcoString,\n        referenced_name: &EcoString,\n        location: SrcSpan,\n        kind: ReferenceKind,\n    ) {\n        match kind {\n            ReferenceKind::Qualified | ReferenceKind::Import | ReferenceKind::Definition => {}\n            ReferenceKind::Alias | ReferenceKind::Unqualified => {\n                self.register_type_reference_in_call_graph(referenced_name.clone())\n            }\n        }\n\n        self.type_references\n            .entry((module, name))\n            .or_default()\n            .push(Reference { location, kind });\n    }\n\n    /// Like `register_type_reference`, but doesn't modify `self.type_references`.\n    /// This is used when we define a constructor for a custom type. The constructor\n    /// doesn't actually \"reference\" its type, but if the constructor is used, the\n    /// type should also be considered used. The best way to represent this relationship\n    /// is to make a connection between them in the call graph.\n    ///\n    pub fn register_type_reference_in_call_graph(&mut self, name: EcoString) {\n        let target = self.get_or_create_node(name, EntityLayer::Type);\n        _ = self.graph.add_edge(self.current_node, target, ());\n    }\n\n    pub fn register_module_reference(&mut self, name: EcoString) {\n        let target = match self.module_name_to_node.get(&name) {\n            Some(target) => *target,\n            None => self.get_or_create_node(name, EntityLayer::Module),\n        };\n        _ = self.graph.add_edge(self.current_node, target, ());\n    }\n\n    pub fn unused(&self) -> HashMap<Entity, EntityInformation> {\n        let mut unused_values = HashMap::with_capacity(self.entities.len());\n\n        for (entity, information) in self.entity_information.iter() {\n            _ = unused_values.insert(entity.clone(), information.clone());\n        }\n        for entity in self.public_entities.iter() {\n            if let Some(index) = self.entities.get_by_left(entity) {\n                self.mark_entity_as_used(&mut unused_values, entity, *index);\n            }\n        }\n\n        for (entity, _) in self.entities.iter() {\n            let Some(index) = self.entities.get_by_left(entity) else {\n                continue;\n            };\n\n            if self.public_entities.contains(entity) {\n                self.mark_entity_as_used(&mut unused_values, entity, *index);\n            } else {\n                // If the entity is not public, we still want to mark referenced\n                // imports as used.\n                self.mark_referenced_imports_as_used(&mut unused_values, entity, *index);\n            }\n        }\n\n        unused_values\n    }\n\n    fn mark_entity_as_used(\n        &self,\n        unused: &mut HashMap<Entity, EntityInformation>,\n        entity: &Entity,\n        index: NodeIndex,\n    ) {\n        if unused.remove(entity).is_some() {\n            for node in self.graph.neighbors_directed(index, Direction::Outgoing) {\n                if let Some(entity) = self.entities.get_by_right(&node) {\n                    self.mark_entity_as_used(unused, entity, node);\n                }\n            }\n        }\n    }\n\n    fn mark_referenced_imports_as_used(\n        &self,\n        unused: &mut HashMap<Entity, EntityInformation>,\n        entity: &Entity,\n        index: NodeIndex,\n    ) {\n        // If the entity is a module there's no way it can reference other\n        // modules so we just ignore it.\n        // This also means that module aliases do not count as using a module!\n        if entity.layer == EntityLayer::Module {\n            return;\n        }\n\n        for node in self.graph.neighbors_directed(index, Direction::Outgoing) {\n            // We only want to mark referenced modules as used, so if the node\n            // is not a module we just skip it.\n            let Some(\n                module @ Entity {\n                    layer: EntityLayer::Module,\n                    ..\n                },\n            ) = self.entities.get_by_right(&node)\n            else {\n                continue;\n            };\n\n            // If the value appears in the module import list, it doesn't count\n            // as using it!\n            let is_imported_type = self\n                .type_references\n                .contains_key(&(module.name.clone(), entity.name.clone()));\n            let is_imported_value = self\n                .value_references\n                .contains_key(&(module.name.clone(), entity.name.clone()));\n            let appears_in_module_import_list = is_imported_type || is_imported_value;\n            if !(appears_in_module_import_list) {\n                self.mark_entity_as_used(unused, module, node);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/requirement.rs",
    "content": "use std::fmt;\nuse std::str::FromStr;\n\nuse crate::Error;\nuse crate::error::Result;\nuse crate::io::make_relative;\nuse camino::{Utf8Path, Utf8PathBuf};\nuse ecow::EcoString;\nuse hexpm::version::Range;\nuse serde::Deserialize;\nuse serde::de::{self, Deserializer, MapAccess, Visitor};\nuse serde::ser::{Serialize, SerializeMap, Serializer};\n\n#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]\n#[serde(untagged, remote = \"Self\", deny_unknown_fields)]\npub enum Requirement {\n    Hex {\n        #[serde(deserialize_with = \"deserialise_range\")]\n        version: Range,\n    },\n\n    Path {\n        path: Utf8PathBuf,\n    },\n\n    Git {\n        git: EcoString,\n        #[serde(rename = \"ref\")]\n        ref_: EcoString,\n    },\n}\n\nimpl Requirement {\n    pub fn hex(range: &str) -> Result<Requirement> {\n        Ok(Requirement::Hex {\n            version: Range::new(range.to_string()).map_err(|e| Error::InvalidVersionFormat {\n                input: range.to_string(),\n                error: e.to_string(),\n            })?,\n        })\n    }\n\n    pub fn path(path: &str) -> Requirement {\n        Requirement::Path { path: path.into() }\n    }\n\n    pub fn git(url: &str, ref_: &str) -> Requirement {\n        Requirement::Git {\n            git: url.into(),\n            ref_: ref_.into(),\n        }\n    }\n\n    pub fn to_toml(&self, root_path: &Utf8Path) -> String {\n        match self {\n            Requirement::Hex { version: range } => {\n                format!(r#\"{{ version = \"{range}\" }}\"#)\n            }\n            Requirement::Path { path } => {\n                format!(\n                    r#\"{{ path = \"{}\" }}\"#,\n                    make_relative(root_path, path).as_str().replace('\\\\', \"/\")\n                )\n            }\n            Requirement::Git { git: url, ref_ } => {\n                format!(r#\"{{ git = \"{url}\", ref = \"{ref_}\" }}\"#)\n            }\n        }\n    }\n}\n\n// Serialization\n\nimpl Serialize for Requirement {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        let mut map = serializer.serialize_map(Some(1))?;\n        match self {\n            Requirement::Hex { version: range } => map.serialize_entry(\"version\", range)?,\n            Requirement::Path { path } => map.serialize_entry(\"path\", path)?,\n            Requirement::Git { git: url, ref_ } => {\n                map.serialize_entry(\"git\", url)?;\n                map.serialize_entry(\"ref\", ref_)?;\n            }\n        }\n        map.end()\n    }\n}\n\n// Deserialization\n\nfn deserialise_range<'de, D>(deserializer: D) -> Result<Range, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let version = String::deserialize(deserializer)?;\n    Range::new(version).map_err(de::Error::custom)\n}\n\n#[derive(Debug, Copy, Clone)]\npub struct Void;\n\nimpl FromStr for Requirement {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Requirement::hex(s)\n    }\n}\n\nstruct RequirementVisitor;\n\nimpl<'de> Visitor<'de> for RequirementVisitor {\n    type Value = Requirement;\n\n    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {\n        formatter.write_str(\"string or map\")\n    }\n\n    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n    where\n        E: de::Error,\n    {\n        match value.parse::<Requirement>() {\n            Ok(value) => Ok(value),\n            Err(error) => Err(de::Error::custom(error)),\n        }\n    }\n\n    fn visit_map<M>(self, visitor: M) -> Result<Self::Value, M::Error>\n    where\n        M: MapAccess<'de>,\n    {\n        Requirement::deserialize(de::value::MapAccessDeserializer::new(visitor))\n    }\n}\n\nimpl<'de> Deserialize<'de> for Requirement {\n    fn deserialize<D>(deserializer: D) -> Result<Requirement, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        deserializer.deserialize_any(RequirementVisitor)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n    use std::collections::HashMap;\n\n    #[test]\n    fn read_requirement() {\n        let toml = r#\"\n            short = \"~> 0.5\"\n            hex = { version = \"~> 1.0.0\" }\n            local = { path = \"/path/to/package\" }\n            github = { git = \"https://github.com/gleam-lang/otp.git\", ref = \"4d34935\" }\n        \"#;\n        let deps: HashMap<String, Requirement> = toml::from_str(toml).unwrap();\n        assert_eq!(deps[\"short\"], Requirement::hex(\"~> 0.5\").unwrap());\n        assert_eq!(deps[\"hex\"], Requirement::hex(\"~> 1.0.0\").unwrap());\n        assert_eq!(deps[\"local\"], Requirement::path(\"/path/to/package\"));\n        assert_eq!(\n            deps[\"github\"],\n            Requirement::git(\"https://github.com/gleam-lang/otp.git\", \"4d34935\")\n        );\n    }\n\n    #[test]\n    fn read_wrong_version() {\n        let toml = r#\"\n            short = \">= 2.0 and < 3.0.0\"\n        \"#;\n\n        let error =\n            toml::from_str::<HashMap<String, Requirement>>(toml).expect_err(\"invalid version\");\n        insta::assert_snapshot!(error.to_string());\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__config__barebones_package_config_to_json.snap",
    "content": "---\nsource: compiler-core/src/config.rs\nassertion_line: 1193\nexpression: output\nsnapshot_kind: text\n---\n--- GLEAM.TOML\n\nname = \"my_project\"\nversion = \"1.0.0\"\n\n\n--- EXPORTED JSON\n\n{\n  \"name\": \"my_project\",\n  \"version\": \"1.0.0\",\n  \"gleam\": null,\n  \"licences\": [],\n  \"description\": \"\",\n  \"documentation\": {\n    \"pages\": []\n  },\n  \"dependencies\": {},\n  \"dev_dependencies\": {},\n  \"repository\": null,\n  \"links\": [],\n  \"erlang\": {\n    \"application_start_module\": null,\n    \"application_start_argument\": null,\n    \"extra_applications\": []\n  },\n  \"javascript\": {\n    \"typescript_declarations\": false,\n    \"runtime\": \"nodejs\",\n    \"deno\": {\n      \"allow_env\": [],\n      \"allow_sys\": false,\n      \"allow_hrtime\": false,\n      \"allow_net\": [],\n      \"allow_ffi\": false,\n      \"allow_read\": [],\n      \"allow_run\": [],\n      \"allow_write\": [],\n      \"allow_all\": false,\n      \"unstable\": false,\n      \"location\": null\n    }\n  },\n  \"target\": \"erlang\",\n  \"internal_modules\": null\n}\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__config__deny_extra_deps_properties.snap",
    "content": "---\nsource: compiler-core/src/config.rs\nexpression: error.pretty_string()\n---\nerror: File IO failure\n\nAn error occurred while trying to parse this file:\n\n    gleam.toml\n\nThe error message from the file IO library was:\n\n    TOML parse error at line 6, column 18\n  |\n6 | aide_generator = { git = \"git@github.com:crowdhailer/aide.git\", ref = \"f559c5bc\", extra = \"idk what this is\" }\n  |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\ndata did not match any variant of untagged enum Requirement\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__config__name_with_dash.snap",
    "content": "---\nsource: compiler-core/src/config.rs\nexpression: \"toml::from_str::<PackageConfig>(input).unwrap_err().to_string()\"\n---\nTOML parse error at line 2, column 8\n  |\n2 | name = \"one-two\"\n  |        ^^^^^^^^^\nPackage names may only contain lowercase letters, numbers, and underscores\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__config__name_with_number_start.snap",
    "content": "---\nsource: compiler-core/src/config.rs\nexpression: \"toml::from_str::<PackageConfig>(input).unwrap_err().to_string()\"\n---\nTOML parse error at line 2, column 8\n  |\n2 | name = \"1\"\n  |        ^^^\nPackage names may only contain lowercase letters, numbers, and underscores\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__config__package_config_to_json.snap",
    "content": "---\nsource: compiler-core/src/config.rs\nassertion_line: 1177\nexpression: output\nsnapshot_kind: text\n---\n--- GLEAM.TOML\n\nname = \"my_project\"\nversion = \"1.0.0\"\nlicences = [\"Apache-2.0\", \"MIT\"]\ndescription = \"Pretty complex config\"\ntarget = \"erlang\"\nrepository = { type = \"github\", user = \"example\", repo = \"my_dep\" }\nlinks = [{ title = \"Home page\", href = \"https://example.com\" }]\ninternal_modules = [\"my_app/internal\"]\ngleam = \">= 0.30.0\"\n\n[dependencies]\ngleam_stdlib = \">= 0.18.0 and < 2.0.0\"\nmy_other_project = { path = \"../my_other_project\" }\n\n[dev_dependencies]\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n\n[documentation]\npages = [{ title = \"My Page\", path = \"my-page.html\", source = \"./path/to/my-page.md\" }]\n\n[erlang]\napplication_start_module = \"my_app/application\"\nextra_applications = [\"inets\", \"ssl\"]\n\n[javascript]\ntypescript_declarations = true\nruntime = \"node\"\n\n[javascript.deno]\nallow_all = false\nallow_ffi = true\nallow_env = [\"DATABASE_URL\"]\nallow_net = [\"example.com:443\"]\nallow_read = [\"./database.sqlite\"]\n\n\n--- EXPORTED JSON\n\n{\n  \"name\": \"my_project\",\n  \"version\": \"1.0.0\",\n  \"gleam\": \">= 0.30.0\",\n  \"licences\": [\n    \"Apache-2.0\",\n    \"MIT\"\n  ],\n  \"description\": \"Pretty complex config\",\n  \"documentation\": {\n    \"pages\": [\n      {\n        \"title\": \"My Page\",\n        \"path\": \"my-page.html\",\n        \"source\": \"./path/to/my-page.md\"\n      }\n    ]\n  },\n  \"dependencies\": {\n    \"gleam_stdlib\": {\n      \"version\": \">= 0.18.0 and < 2.0.0\"\n    },\n    \"my_other_project\": {\n      \"path\": \"../my_other_project\"\n    }\n  },\n  \"dev_dependencies\": {\n    \"gleeunit\": {\n      \"version\": \">= 1.0.0 and < 2.0.0\"\n    }\n  },\n  \"repository\": {\n    \"type\": \"github\",\n    \"user\": \"example\",\n    \"repo\": \"my_dep\",\n    \"path\": null,\n    \"tag_prefix\": null\n  },\n  \"links\": [\n    {\n      \"title\": \"Home page\",\n      \"href\": \"https://example.com/\"\n    }\n  ],\n  \"erlang\": {\n    \"application_start_module\": \"my_app/application\",\n    \"application_start_argument\": null,\n    \"extra_applications\": [\n      \"inets\",\n      \"ssl\"\n    ]\n  },\n  \"javascript\": {\n    \"typescript_declarations\": true,\n    \"runtime\": \"nodejs\",\n    \"deno\": {\n      \"allow_env\": [\n        \"DATABASE_URL\"\n      ],\n      \"allow_sys\": false,\n      \"allow_hrtime\": false,\n      \"allow_net\": [\n        \"example.com:443\"\n      ],\n      \"allow_ffi\": true,\n      \"allow_read\": [\n        \"./database.sqlite\"\n      ],\n      \"allow_run\": [],\n      \"allow_write\": [],\n      \"allow_all\": false,\n      \"unstable\": false,\n      \"location\": null\n    }\n  },\n  \"target\": \"erlang\",\n  \"internal_modules\": [\n    \"my_app/internal\"\n  ]\n}\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__dependency__tests__resolution_error_message.snap",
    "content": "---\nsource: compiler-core/src/dependency.rs\nassertion_line: 1091\nexpression: message\nsnapshot_kind: text\n---\nThere's no compatible version of `woo`:\n  - You require woo >= 2.0.0 and < 3.0.0\n  - You require wibble >= 1.0.0 and < 2.0.0\n    - wibble requires wobble >= 1.0.0 and < 3.0.0\n    - wobble requires woo >= 1.0.0 and < 2.0.0\n\nThere's no compatible version of `waa`:\n  - You require wibble >= 1.0.0 and < 2.0.0\n    - wibble requires wobble >= 1.0.0 and < 3.0.0\n    - wobble requires waa >= 1.0.0 and < 2.0.0\n  - You require waa >= 2.0.0 and < 3.0.0\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__docs__barebones_package_config_to_json.snap",
    "content": "---\nsource: compiler-core/src/docs.rs\nassertion_line: 786\nexpression: output\nsnapshot_kind: text\n---\n--- GLEAM.TOML\n\nname = \"my_project\"\nversion = \"1.0.0\"\n\n\n--- EXPORTED JSON\n\n{\n  \"gleam.toml\": {\n    \"name\": \"my_project\",\n    \"version\": \"1.0.0\",\n    \"gleam\": null,\n    \"licences\": [],\n    \"description\": \"\",\n    \"documentation\": {\n      \"pages\": []\n    },\n    \"dependencies\": {},\n    \"dev_dependencies\": {},\n    \"repository\": null,\n    \"links\": [],\n    \"erlang\": {\n      \"application_start_module\": null,\n      \"application_start_argument\": null,\n      \"extra_applications\": []\n    },\n    \"javascript\": {\n      \"typescript_declarations\": false,\n      \"runtime\": \"nodejs\",\n      \"deno\": {\n        \"allow_env\": [],\n        \"allow_sys\": false,\n        \"allow_hrtime\": false,\n        \"allow_net\": [],\n        \"allow_ffi\": false,\n        \"allow_read\": [],\n        \"allow_run\": [],\n        \"allow_write\": [],\n        \"allow_all\": false,\n        \"unstable\": false,\n        \"location\": null\n      }\n    },\n    \"target\": \"erlang\",\n    \"internal_modules\": null\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__docs__package_config_to_json.snap",
    "content": "---\nsource: compiler-core/src/docs.rs\nassertion_line: 770\nexpression: output\nsnapshot_kind: text\n---\n--- GLEAM.TOML\n\nname = \"my_project\"\nversion = \"1.0.0\"\nlicences = [\"Apache-2.0\", \"MIT\"]\ndescription = \"Pretty complex config\"\ntarget = \"erlang\"\nrepository = { type = \"github\", user = \"example\", repo = \"my_dep\" }\nlinks = [{ title = \"Home page\", href = \"https://example.com\" }]\ninternal_modules = [\"my_app/internal\"]\ngleam = \">= 0.30.0\"\n\n[dependencies]\ngleam_stdlib = \">= 0.18.0 and < 2.0.0\"\nmy_other_project = { path = \"../my_other_project\" }\n\n[dev_dependencies]\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n\n[documentation]\npages = [{ title = \"My Page\", path = \"my-page.html\", source = \"./path/to/my-page.md\" }]\n\n[erlang]\napplication_start_module = \"my_app/application\"\nextra_applications = [\"inets\", \"ssl\"]\n\n[javascript]\ntypescript_declarations = true\nruntime = \"node\"\n\n[javascript.deno]\nallow_all = false\nallow_ffi = true\nallow_env = [\"DATABASE_URL\"]\nallow_net = [\"example.com:443\"]\nallow_read = [\"./database.sqlite\"]\n\n\n--- EXPORTED JSON\n\n{\n  \"gleam.toml\": {\n    \"name\": \"my_project\",\n    \"version\": \"1.0.0\",\n    \"gleam\": \">= 0.30.0\",\n    \"licences\": [\n      \"Apache-2.0\",\n      \"MIT\"\n    ],\n    \"description\": \"Pretty complex config\",\n    \"documentation\": {\n      \"pages\": [\n        {\n          \"title\": \"My Page\",\n          \"path\": \"my-page.html\",\n          \"source\": \"./path/to/my-page.md\"\n        }\n      ]\n    },\n    \"dependencies\": {\n      \"gleam_stdlib\": {\n        \"version\": \">= 0.18.0 and < 2.0.0\"\n      },\n      \"my_other_project\": {\n        \"path\": \"../my_other_project\"\n      }\n    },\n    \"dev_dependencies\": {\n      \"gleeunit\": {\n        \"version\": \">= 1.0.0 and < 2.0.0\"\n      }\n    },\n    \"repository\": {\n      \"type\": \"github\",\n      \"user\": \"example\",\n      \"repo\": \"my_dep\",\n      \"path\": null,\n      \"tag_prefix\": null\n    },\n    \"links\": [\n      {\n        \"title\": \"Home page\",\n        \"href\": \"https://example.com/\"\n      }\n    ],\n    \"erlang\": {\n      \"application_start_module\": \"my_app/application\",\n      \"application_start_argument\": null,\n      \"extra_applications\": [\n        \"inets\",\n        \"ssl\"\n      ]\n    },\n    \"javascript\": {\n      \"typescript_declarations\": true,\n      \"runtime\": \"nodejs\",\n      \"deno\": {\n        \"allow_env\": [\n          \"DATABASE_URL\"\n        ],\n        \"allow_sys\": false,\n        \"allow_hrtime\": false,\n        \"allow_net\": [\n          \"example.com:443\"\n        ],\n        \"allow_ffi\": true,\n        \"allow_read\": [\n          \"./database.sqlite\"\n        ],\n        \"allow_run\": [],\n        \"allow_write\": [],\n        \"allow_all\": false,\n        \"unstable\": false,\n        \"location\": null\n      }\n    },\n    \"target\": \"erlang\",\n    \"internal_modules\": [\n      \"my_app/internal\"\n    ]\n  }\n}\n"
  },
  {
    "path": "compiler-core/src/snapshots/gleam_core__requirement__tests__read_wrong_version.snap",
    "content": "---\nsource: compiler-core/src/requirement.rs\nexpression: error.to_string()\n---\nTOML parse error at line 2, column 21\n  |\n2 |             short = \">= 2.0 and < 3.0.0\"\n  |                     ^^^^^^^^^^^^^^^^^^^^\n>= 2.0 and < 3.0.0 is not a valid version. missing patch version: 2.0\n"
  },
  {
    "path": "compiler-core/src/strings.rs",
    "content": "use ecow::EcoString;\nuse itertools::Itertools;\n\nuse crate::ast::Endianness;\n\n/// Converts any escape sequences from the given string to their correct\n/// bytewise UTF-8 representation and returns the resulting string.\npub fn convert_string_escape_chars(str: &EcoString) -> EcoString {\n    let mut filtered_str = EcoString::new();\n    let mut str_iter = str.chars().peekable();\n    loop {\n        match str_iter.next() {\n            Some('\\\\') => match str_iter.next() {\n                // Check for Unicode escape sequence, e.g. \\u{00012FF}\n                Some('u') => {\n                    if str_iter.peek() != Some(&'{') {\n                        // Invalid Unicode escape sequence\n                        filtered_str.push('u');\n                        continue;\n                    }\n\n                    // Consume the left brace after peeking\n                    let _ = str_iter.next();\n\n                    let codepoint_str = str_iter\n                        .peeking_take_while(char::is_ascii_hexdigit)\n                        .collect::<String>();\n\n                    if codepoint_str.is_empty() || str_iter.peek() != Some(&'}') {\n                        // Invalid Unicode escape sequence\n                        filtered_str.push_str(\"u{\");\n                        filtered_str.push_str(&codepoint_str);\n                        continue;\n                    }\n\n                    let codepoint = u32::from_str_radix(&codepoint_str, 16)\n                        .ok()\n                        .and_then(char::from_u32);\n\n                    if let Some(codepoint) = codepoint {\n                        // Consume the right brace after peeking\n                        let _ = str_iter.next();\n\n                        // Consider this codepoint's length instead of\n                        // that of the Unicode escape sequence itself\n                        filtered_str.push(codepoint);\n                    } else {\n                        // Invalid Unicode escape sequence\n                        // (codepoint value not in base 16 or too large)\n                        filtered_str.push_str(\"u{\");\n                        filtered_str.push_str(&codepoint_str);\n                    }\n                }\n                Some('n') => filtered_str.push('\\n'),\n                Some('r') => filtered_str.push('\\r'),\n                Some('f') => filtered_str.push('\\u{C}'),\n                Some('t') => filtered_str.push('\\t'),\n                Some('\"') => filtered_str.push('\\\"'),\n                Some('\\\\') => filtered_str.push('\\\\'),\n                Some(c) => filtered_str.push(c),\n                None => break,\n            },\n            Some(c) => filtered_str.push(c),\n            None => break,\n        }\n    }\n    filtered_str\n}\n\npub fn to_snake_case(string: &str) -> EcoString {\n    let mut snake_case = EcoString::with_capacity(string.len());\n    let mut is_word_boundary = true;\n\n    for char in string.chars() {\n        match char {\n            '_' | ' ' => {\n                is_word_boundary = true;\n                continue;\n            }\n            _ if char.is_uppercase() => {\n                is_word_boundary = true;\n            }\n            _ => {}\n        }\n\n        if is_word_boundary {\n            // We don't want to push an underscore at the start of the string,\n            // even if it starts with a capital letter or other delimiter.\n            if !snake_case.is_empty() {\n                snake_case.push('_');\n            }\n            is_word_boundary = false;\n        }\n        snake_case.push(char.to_ascii_lowercase());\n    }\n\n    snake_case\n}\n\npub fn to_upper_camel_case(string: &str) -> EcoString {\n    let mut pascal_case = EcoString::with_capacity(string.len());\n    let mut chars = string.chars();\n\n    while let Some(char) = chars.next() {\n        if char == '_' {\n            let Some(next) = chars.next() else { break };\n            pascal_case.push(next.to_ascii_uppercase());\n        } else {\n            pascal_case.push(char);\n        }\n    }\n\n    pascal_case\n}\n\n/// Converts a string into its UTF-16 representation in bytes\npub fn string_to_utf16_bytes(string: &str, endianness: Endianness) -> Vec<u8> {\n    let mut bytes = Vec::with_capacity(string.len() * 2);\n\n    let mut character_buffer = [0, 0];\n    for character in string.chars() {\n        let segments = character.encode_utf16(&mut character_buffer);\n\n        for segment in segments {\n            let segment_bytes = match endianness {\n                Endianness::Big => segment.to_be_bytes(),\n                Endianness::Little => segment.to_le_bytes(),\n            };\n\n            bytes.push(segment_bytes[0]);\n            bytes.push(segment_bytes[1]);\n        }\n    }\n\n    bytes\n}\n\n/// Converts a string into its UTF-32 representation in bytes\npub fn string_to_utf32_bytes(string: &str, endianness: Endianness) -> Vec<u8> {\n    let mut bytes = Vec::with_capacity(string.len() * 4);\n\n    for character in string.chars() {\n        let character_bytes = match endianness {\n            Endianness::Big => (character as u32).to_be_bytes(),\n            Endianness::Little => (character as u32).to_le_bytes(),\n        };\n        bytes.extend(character_bytes);\n    }\n\n    bytes\n}\n\n/// Gets the number of UTF-16 codepoints it would take to encode a given string.\npub fn length_utf16(string: &str) -> usize {\n    let mut length = 0;\n\n    for char in string.chars() {\n        length += char.len_utf16()\n    }\n\n    length\n}\n\n/// Gets the number of UTF-32 codepoints in a string\npub fn length_utf32(string: &str) -> usize {\n    string.chars().count()\n}\n"
  },
  {
    "path": "compiler-core/src/type_/environment.rs",
    "content": "use pubgrub::Range;\n\nuse crate::{\n    analyse::TargetSupport,\n    ast::{PIPE_VARIABLE, Publicity},\n    build::Target,\n    error::edit_distance,\n    reference::{EntityKind, ReferenceTracker},\n    uid::UniqueIdGenerator,\n};\n\nuse super::*;\nuse std::collections::HashMap;\n\n#[derive(Debug)]\npub struct EnvironmentArguments<'a> {\n    pub ids: UniqueIdGenerator,\n    pub current_package: EcoString,\n    pub gleam_version: Option<Range<Version>>,\n    pub current_module: EcoString,\n    pub target: Target,\n    pub importable_modules: &'a im::HashMap<EcoString, ModuleInterface>,\n    pub target_support: TargetSupport,\n    pub current_origin: Origin,\n    pub dev_dependencies: &'a HashSet<EcoString>,\n}\n\nimpl<'a> EnvironmentArguments<'a> {\n    pub fn build(self) -> Environment<'a> {\n        Environment::new(self)\n    }\n}\n\n#[derive(Debug)]\npub struct Environment<'a> {\n    pub current_package: EcoString,\n    pub origin: Origin,\n\n    /// The gleam version range required by the current package as stated in its\n    /// gleam.toml\n    pub gleam_version: Option<Range<Version>>,\n\n    pub current_module: EcoString,\n    pub target: Target,\n    pub ids: UniqueIdGenerator,\n    previous_id: u64,\n    /// Names of types or values that have been imported an unqualified fashion\n    /// from other modules. Used to prevent multiple imports using the same name.\n    pub unqualified_imported_names: HashMap<EcoString, SrcSpan>,\n    pub unqualified_imported_types: HashMap<EcoString, SrcSpan>,\n    pub importable_modules: &'a im::HashMap<EcoString, ModuleInterface>,\n\n    /// Modules that have been imported by the current module, along with the\n    /// location of the import statement where they were imported.\n    pub imported_modules: HashMap<EcoString, (SrcSpan, &'a ModuleInterface)>,\n\n    /// Values defined in the current function (or the prelude)\n    pub scope: im::HashMap<EcoString, ValueConstructor>,\n\n    // The names of all the ignored variables and arguments in scope:\n    // `let _var = 10` `pub fn main(_var) { todo }`.\n    pub discarded_names: im::HashMap<EcoString, SrcSpan>,\n\n    /// Types defined in the current module (or the prelude)\n    pub module_types: HashMap<EcoString, TypeConstructor>,\n\n    /// Mapping from types to constructor names in the current module (or the prelude)\n    pub module_types_constructors: HashMap<EcoString, TypeVariantConstructors>,\n\n    pub module_type_aliases: HashMap<EcoString, TypeAliasConstructor>,\n\n    /// Values defined in the current module (or the prelude)\n    pub module_values: HashMap<EcoString, ValueConstructor>,\n\n    /// Accessors defined in the current module\n    pub accessors: HashMap<EcoString, AccessorsMap>,\n\n    /// local_variable_usages is a stack of scopes. When a local variable is created it is\n    /// added to the top scope. When a local variable is used we crawl down the scope\n    /// stack for a variable with that name and mark it as used.\n    pub local_variable_usages: Vec<HashMap<EcoString, VariableUsage>>,\n\n    /// Used to determine if all functions/constants need to support the current\n    /// compilation target.\n    pub target_support: TargetSupport,\n\n    pub names: Names,\n\n    /// Deferred type variable aliases: `(source_generic_id, instantiated_type)`.\n    /// During `instantiate`, when a generic type variable is replaced with a new\n    /// unbound var, we record the pair here. After type checking, we resolve\n    /// these by following link chains in the types to find the final unbound var\n    /// IDs and register the original names for them.\n    pub deferred_type_variable_aliases: Vec<(u64, Arc<Type>)>,\n\n    /// Wether we ran into an `echo` or not while analysing the current module.\n    pub echo_found: bool,\n\n    pub references: ReferenceTracker,\n\n    pub dev_dependencies: &'a HashSet<EcoString>,\n}\n\n#[derive(Debug)]\npub struct VariableUsage {\n    origin: VariableOrigin,\n    location: SrcSpan,\n    usages: usize,\n    recursive_usages: usize,\n}\n\nimpl<'a> Environment<'a> {\n    pub fn new(\n        EnvironmentArguments {\n            ids,\n            current_package,\n            gleam_version,\n            current_module,\n            target,\n            importable_modules,\n            target_support,\n            current_origin: origin,\n            dev_dependencies,\n        }: EnvironmentArguments<'a>,\n    ) -> Self {\n        let prelude = importable_modules\n            .get(PRELUDE_MODULE_NAME)\n            .expect(\"Unable to find prelude in importable modules\");\n\n        let names = Self::build_names(prelude, importable_modules);\n\n        Self {\n            current_package,\n            gleam_version,\n            previous_id: ids.next(),\n            ids,\n            origin,\n            target,\n            module_types: prelude.types.clone(),\n            module_types_constructors: prelude.types_value_constructors.clone(),\n            module_values: HashMap::new(),\n            imported_modules: HashMap::new(),\n            unqualified_imported_names: HashMap::new(),\n            unqualified_imported_types: HashMap::new(),\n            accessors: prelude.accessors.clone(),\n            scope: prelude.values.clone().into(),\n            discarded_names: im::HashMap::new(),\n            importable_modules,\n            current_module,\n            local_variable_usages: vec![HashMap::new()],\n            target_support,\n            names,\n            deferred_type_variable_aliases: Vec::new(),\n            module_type_aliases: HashMap::new(),\n            echo_found: false,\n            references: ReferenceTracker::new(),\n            dev_dependencies,\n        }\n    }\n\n    fn build_names(\n        prelude: &ModuleInterface,\n        importable_modules: &im::HashMap<EcoString, ModuleInterface>,\n    ) -> Names {\n        let mut names = Names::new();\n\n        // Insert prelude types and values into scope\n        for name in prelude.values.keys() {\n            names.named_constructor_in_scope(\n                PRELUDE_MODULE_NAME.into(),\n                name.clone(),\n                name.clone(),\n            );\n        }\n        for name in prelude.types.keys() {\n            names.named_type_in_scope(PRELUDE_MODULE_NAME.into(), name.clone(), name.clone());\n        }\n\n        // Find potential type aliases which reexport internal types\n        for module in importable_modules.values() {\n            // Internal modules are not part of the public API so they are also\n            // not considered.\n            if module.is_internal {\n                continue;\n            }\n            for (alias_name, alias) in module.type_aliases.iter() {\n                // An alias can only be a public reexport if it is public.\n                if alias.publicity.is_public() {\n                    names.maybe_register_reexport_alias(&module.package, alias_name, alias);\n                }\n            }\n        }\n\n        names\n    }\n}\n\n#[derive(Debug)]\npub struct ScopeResetData {\n    local_values: im::HashMap<EcoString, ValueConstructor>,\n    discarded_names: im::HashMap<EcoString, SrcSpan>,\n}\n\nimpl Environment<'_> {\n    pub fn in_new_scope<T, E>(\n        &mut self,\n        problems: &mut Problems,\n        process_scope: impl FnOnce(&mut Self, &mut Problems) -> Result<T, E>,\n    ) -> Result<T, E> {\n        // Record initial scope state\n        let initial = self.open_new_scope();\n\n        // Process scope\n        let result = process_scope(self, problems);\n\n        self.close_scope(initial, result.is_ok(), problems);\n\n        // Return result of typing the scope\n        result\n    }\n\n    pub fn open_new_scope(&mut self) -> ScopeResetData {\n        let local_values = self.scope.clone();\n        let discarded_names = self.discarded_names.clone();\n        self.local_variable_usages.push(HashMap::new());\n        ScopeResetData {\n            local_values,\n            discarded_names,\n        }\n    }\n\n    pub fn close_scope(\n        &mut self,\n        data: ScopeResetData,\n        was_successful: bool,\n        problems: &mut Problems,\n    ) {\n        let ScopeResetData {\n            local_values,\n            discarded_names,\n        } = data;\n\n        let unused = self\n            .local_variable_usages\n            .pop()\n            .expect(\"There was no top entity scope.\");\n\n        // We only check for unused entities if the scope was successfully\n        // processed. If it was not then any seemingly unused entities may have\n        // been used beyond the point where the error occurred, so we don't want\n        // to incorrectly warn about them.\n        if was_successful {\n            self.handle_unused_variables(unused, problems);\n        }\n        self.scope = local_values;\n        self.discarded_names = discarded_names;\n    }\n\n    pub fn next_uid(&mut self) -> u64 {\n        let id = self.ids.next();\n        self.previous_id = id;\n        id\n    }\n\n    pub fn previous_uid(&self) -> u64 {\n        self.previous_id\n    }\n\n    /// Resolve deferred type variable aliases. During `instantiate`, generic\n    /// type variables are replaced with new unbound vars, but those vars may\n    /// later get linked to other vars during unification. This method follows\n    /// the link chains to find the final unbound var IDs and registers the\n    /// original names for them.\n    pub fn resolve_deferred_type_variable_aliases(&mut self) {\n        for (source_id, type_) in self.deferred_type_variable_aliases.drain(..) {\n            if let Some(alias) = self.names.get_type_variable(source_id) {\n                let final_id = Self::resolve_type_var_id(&type_);\n                if let Some(id) = final_id {\n                    // Only register if the target doesn't already have a name.\n                    // This avoids overwriting user-provided names (e.g. from\n                    // annotations) with names from instantiated type parameters.\n                    if self.names.get_type_variable(id).is_none() {\n                        self.names.type_variable_in_scope(id, alias.clone());\n                    }\n                }\n            }\n        }\n    }\n\n    /// Follow link chains in a type to find the final unbound or generic var ID.\n    fn resolve_type_var_id(type_: &Type) -> Option<u64> {\n        match type_ {\n            Type::Var { type_ } => match type_.borrow().deref() {\n                TypeVar::Unbound { id } | TypeVar::Generic { id } => Some(*id),\n                TypeVar::Link { type_ } => Self::resolve_type_var_id(type_),\n            },\n            Type::Named { .. } | Type::Fn { .. } | Type::Tuple { .. } => None,\n        }\n    }\n\n    /// Create a new unbound type that is a specific type, we just don't\n    /// know which one yet.\n    ///\n    pub fn new_unbound_var(&mut self) -> Arc<Type> {\n        unbound_var(self.next_uid())\n    }\n\n    /// Create a new generic type that can stand in for any type.\n    ///\n    pub fn new_generic_var(&mut self) -> Arc<Type> {\n        generic_var(self.next_uid())\n    }\n\n    /// Insert a variable in the current scope.\n    ///\n    pub fn insert_local_variable(\n        &mut self,\n        name: EcoString,\n        location: SrcSpan,\n        origin: VariableOrigin,\n        type_: Arc<Type>,\n    ) {\n        let _ = self.scope.insert(\n            name,\n            ValueConstructor::local_variable(location, origin, type_),\n        );\n    }\n\n    /// Insert a variable in the current scope.\n    ///\n    pub fn insert_variable(\n        &mut self,\n        name: EcoString,\n        variant: ValueConstructorVariant,\n        type_: Arc<Type>,\n        publicity: Publicity,\n        deprecation: Deprecation,\n    ) {\n        let _ = self.scope.insert(\n            name,\n            ValueConstructor {\n                publicity,\n                deprecation,\n                variant,\n                type_,\n            },\n        );\n    }\n\n    /// Insert (or overwrites) a value into the current module.\n    ///\n    pub fn insert_module_value(&mut self, name: EcoString, value: ValueConstructor) {\n        let _ = self.module_values.insert(name, value);\n    }\n\n    /// Lookup a variable in the current scope.\n    ///\n    pub fn get_variable(&self, name: &EcoString) -> Option<&ValueConstructor> {\n        self.scope.get(name)\n    }\n\n    /// Lookup a module constant in the current scope.\n    ///\n    pub fn get_module_const(&mut self, name: &EcoString) -> Option<&ValueConstructor> {\n        self.increment_usage(name);\n        self.module_values\n            .get(name)\n            .filter(|ValueConstructor { variant, .. }| {\n                matches!(variant, ValueConstructorVariant::ModuleConstant { .. })\n            })\n    }\n\n    /// Map a type in the current scope.\n    /// Errors if the module already has a type with that name, unless the type is from the\n    /// prelude.\n    ///\n    pub fn insert_type_constructor(\n        &mut self,\n        type_name: EcoString,\n        info: TypeConstructor,\n    ) -> Result<(), Error> {\n        let name = type_name.clone();\n        let location = info.origin;\n        match self.module_types.insert(type_name, info) {\n            None => Ok(()),\n            Some(prelude_type) if is_prelude_module(&prelude_type.module) => Ok(()),\n            Some(previous) => Err(Error::DuplicateTypeName {\n                name,\n                location,\n                previous_location: previous.origin,\n            }),\n        }\n    }\n\n    /// Map a type alias in the current scope.\n    /// Errors if the module already has a type with that name, unless the type is from the\n    /// prelude.\n    ///\n    pub fn insert_type_alias(\n        &mut self,\n        type_name: EcoString,\n        info: TypeAliasConstructor,\n    ) -> Result<(), Error> {\n        let name = type_name.clone();\n        let location = info.origin;\n        match self.module_type_aliases.insert(type_name, info) {\n            None => Ok(()),\n            Some(prelude_type) if is_prelude_module(&prelude_type.module) => Ok(()),\n            Some(previous) => Err(Error::DuplicateTypeName {\n                name,\n                location,\n                previous_location: previous.origin,\n            }),\n        }\n    }\n\n    pub fn assert_unique_type_name(\n        &mut self,\n        name: &EcoString,\n        location: SrcSpan,\n    ) -> Result<(), Error> {\n        match self.module_types.get(name) {\n            None => Ok(()),\n            Some(prelude_type) if is_prelude_module(&prelude_type.module) => Ok(()),\n            Some(previous) => Err(Error::DuplicateTypeName {\n                name: name.clone(),\n                location,\n                previous_location: previous.origin,\n            }),\n        }\n    }\n\n    /// Map a type to constructors in the current scope.\n    ///\n    pub fn insert_type_to_constructors(\n        &mut self,\n        type_name: EcoString,\n        constructors: TypeVariantConstructors,\n    ) {\n        let _ = self\n            .module_types_constructors\n            .insert(type_name, constructors);\n    }\n\n    /// Lookup a type in the current scope.\n    ///\n    pub fn get_type_constructor(\n        &mut self,\n        module: &Option<(EcoString, SrcSpan)>,\n        name: &EcoString,\n    ) -> Result<&TypeConstructor, UnknownTypeConstructorError> {\n        match module {\n            None => self\n                .module_types\n                .get(name)\n                .ok_or_else(|| UnknownTypeConstructorError::Type {\n                    name: name.clone(),\n                    hint: self.unknown_type_hint(name),\n                }),\n\n            Some((module_name, _)) => {\n                let (_, module) = self.imported_modules.get(module_name).ok_or_else(|| {\n                    UnknownTypeConstructorError::Module {\n                        name: module_name.clone(),\n                        suggestions: self\n                            .suggest_modules(module_name, Imported::Type(name.clone())),\n                    }\n                })?;\n                self.references\n                    .register_module_reference(module_name.clone());\n                module.get_public_type(name).ok_or_else(|| {\n                    UnknownTypeConstructorError::ModuleType {\n                        name: name.clone(),\n                        module_name: module.name.clone(),\n                        type_constructors: module.public_type_names(),\n                        imported_type_as_value: false,\n                    }\n                })\n            }\n        }\n    }\n\n    fn unknown_type_hint(&self, type_name: &EcoString) -> UnknownTypeHint {\n        match self.scope.contains_key(type_name) {\n            true => UnknownTypeHint::ValueInScopeWithSameName,\n            false => UnknownTypeHint::AlternativeTypes(self.module_types.keys().cloned().collect()),\n        }\n    }\n\n    /// Lookup constructors for type in the current scope.\n    ///\n    pub fn get_constructors_for_type(\n        &self,\n        module: &EcoString,\n        name: &EcoString,\n    ) -> Result<&TypeVariantConstructors, UnknownTypeConstructorError> {\n        let module = if module.is_empty() || *module == self.current_module {\n            None\n        } else {\n            Some(module)\n        };\n        match module {\n            None => self.module_types_constructors.get(name).ok_or_else(|| {\n                UnknownTypeConstructorError::Type {\n                    name: name.clone(),\n                    hint: self.unknown_type_hint(name),\n                }\n            }),\n\n            Some(m) => {\n                let module = self.importable_modules.get(m).ok_or_else(|| {\n                    UnknownTypeConstructorError::Module {\n                        name: name.clone(),\n                        suggestions: self.suggest_modules(m, Imported::Type(name.clone())),\n                    }\n                })?;\n                module.types_value_constructors.get(name).ok_or_else(|| {\n                    UnknownTypeConstructorError::ModuleType {\n                        name: name.clone(),\n                        module_name: module.name.clone(),\n                        type_constructors: module.public_type_names(),\n                        imported_type_as_value: false,\n                    }\n                })\n            }\n        }\n    }\n\n    /// Lookup a value constructor in the current scope.\n    ///\n    pub fn get_value_constructor(\n        &mut self,\n        module: Option<&EcoString>,\n        name: &EcoString,\n    ) -> Result<&ValueConstructor, UnknownValueConstructorError> {\n        match module {\n            None => self.scope.get(name).ok_or_else(|| {\n                let type_with_name_in_scope = self.module_types.keys().any(|type_| type_ == name);\n                UnknownValueConstructorError::Variable {\n                    name: name.clone(),\n                    variables: self.local_value_names(),\n                    type_with_name_in_scope,\n                }\n            }),\n\n            Some(module_name) => {\n                let (_, module) = self.imported_modules.get(module_name).ok_or_else(|| {\n                    UnknownValueConstructorError::Module {\n                        name: module_name.clone(),\n                        suggestions: self\n                            .suggest_modules(module_name, Imported::Value(name.clone())),\n                    }\n                })?;\n                self.references\n                    .register_module_reference(module_name.clone());\n                module.get_public_value(name).ok_or_else(|| {\n                    UnknownValueConstructorError::ModuleValue {\n                        name: name.clone(),\n                        module_name: module.name.clone(),\n                        value_constructors: module.public_value_names(),\n                        imported_value_as_type: false,\n                    }\n                })\n            }\n        }\n    }\n\n    pub fn get_type_variants_fields(\n        &self,\n        module: &EcoString,\n        name: &EcoString,\n    ) -> Vec<&EcoString> {\n        self.get_constructors_for_type(module, name)\n            .iter()\n            .flat_map(|c| &c.variants)\n            .filter_map(|variant| {\n                self.type_value_constructor_to_constructor(module, variant)?\n                    .variant\n                    .record_field_map()\n            })\n            .flat_map(|field_map| field_map.fields.keys())\n            .collect_vec()\n    }\n\n    fn type_value_constructor_to_constructor(\n        &self,\n        module: &EcoString,\n        variant: &TypeValueConstructor,\n    ) -> Option<&ValueConstructor> {\n        if *module == self.current_module {\n            self.scope.get(&variant.name)\n        } else {\n            let (_, module) = self.imported_modules.get(module)?;\n            module.get_public_value(&variant.name)\n        }\n    }\n\n    pub fn insert_accessors(&mut self, type_name: EcoString, accessors: AccessorsMap) {\n        let _ = self.accessors.insert(type_name, accessors);\n    }\n\n    /// Instantiate converts generic variables into unbound ones.\n    ///\n    pub fn instantiate(\n        &mut self,\n        t: Arc<Type>,\n        ids: &mut im::HashMap<u64, Arc<Type>>,\n        hydrator: &Hydrator,\n    ) -> Arc<Type> {\n        match t.deref() {\n            Type::Named {\n                publicity,\n                name,\n                package,\n                module,\n                arguments,\n                inferred_variant,\n            } => {\n                let arguments = arguments\n                    .iter()\n                    .map(|type_| self.instantiate(type_.clone(), ids, hydrator))\n                    .collect();\n                Arc::new(Type::Named {\n                    publicity: *publicity,\n                    name: name.clone(),\n                    package: package.clone(),\n                    module: module.clone(),\n                    arguments,\n                    inferred_variant: *inferred_variant,\n                })\n            }\n\n            Type::Var { type_ } => {\n                match type_.borrow().deref() {\n                    TypeVar::Link { type_ } => {\n                        return self.instantiate(type_.clone(), ids, hydrator);\n                    }\n\n                    TypeVar::Unbound { .. } => {\n                        return Arc::new(Type::Var {\n                            type_: type_.clone(),\n                        });\n                    }\n\n                    TypeVar::Generic { id } => match ids.get(id) {\n                        Some(t) => return t.clone(),\n                        None => {\n                            if !hydrator.is_rigid(id) {\n                                // Check this in the hydrator, i.e. is it a created type\n                                let v = self.new_unbound_var();\n                                let _ = ids.insert(*id, v.clone());\n\n                                // Record this pairing so that after type checking\n                                // we can resolve any link chains and register the\n                                // original name for the final unbound variable.\n                                self.deferred_type_variable_aliases.push((*id, v.clone()));\n\n                                return v;\n                            }\n                        }\n                    },\n                }\n                Arc::new(Type::Var {\n                    type_: type_.clone(),\n                })\n            }\n\n            Type::Fn {\n                arguments, return_, ..\n            } => fn_(\n                arguments\n                    .iter()\n                    .map(|type_| self.instantiate(type_.clone(), ids, hydrator))\n                    .collect(),\n                self.instantiate(return_.clone(), ids, hydrator),\n            ),\n\n            Type::Tuple { elements } => tuple(\n                elements\n                    .iter()\n                    .map(|type_| self.instantiate(type_.clone(), ids, hydrator))\n                    .collect(),\n            ),\n        }\n    }\n\n    /// Inserts a local variable at the current scope for usage tracking.\n    pub fn init_usage(\n        &mut self,\n        name: EcoString,\n        origin: VariableOrigin,\n        location: SrcSpan,\n        problems: &mut Problems,\n    ) {\n        if let Some(VariableUsage {\n            origin,\n            location,\n            usages: 0,\n            recursive_usages,\n        }) = self\n            .local_variable_usages\n            .last_mut()\n            .expect(\"Attempted to access non-existent entity usages scope\")\n            .insert(\n                name.clone(),\n                VariableUsage {\n                    origin,\n                    location,\n                    usages: 0,\n                    recursive_usages: 0,\n                },\n            )\n        {\n            // an entity was overwritten in the top most scope without being used\n            let mut unused = HashMap::with_capacity(1);\n            let _ = unused.insert(\n                name,\n                VariableUsage {\n                    origin,\n                    location,\n                    usages: 0,\n                    recursive_usages,\n                },\n            );\n            self.handle_unused_variables(unused, problems);\n        }\n    }\n\n    /// Increments an entity's usage in the current or nearest enclosing scope\n    pub fn increment_usage(&mut self, name: &EcoString) {\n        if let Some(VariableUsage { usages, .. }) = self\n            .local_variable_usages\n            .iter_mut()\n            .rev()\n            .find_map(|scope| scope.get_mut(name))\n        {\n            *usages += 1;\n        }\n    }\n\n    /// Marks an argument as being passed recursively to a function call.\n    pub fn increment_recursive_usage(&mut self, name: &EcoString) {\n        if let Some(VariableUsage {\n            recursive_usages, ..\n        }) = self\n            .local_variable_usages\n            .iter_mut()\n            .rev()\n            .find_map(|scope| scope.get_mut(name))\n        {\n            *recursive_usages += 1;\n        }\n    }\n\n    /// Emit warnings for unused definitions, imports, expressions, etc.\n    ///\n    /// Returns the source byte start positions of all unused definitions.\n    ///\n    pub fn handle_unused(&mut self, problems: &mut Problems) -> HashSet<u32> {\n        let mut unused_positions = HashSet::new();\n        let unused = self\n            .local_variable_usages\n            .pop()\n            .expect(\"Expected a bottom level of entity usages.\");\n        self.handle_unused_variables(unused, problems);\n\n        // We have to handle unused imported entites a bit differently when\n        // emitting warning: when an import list is unused all its items and\n        // the import itself are unused:\n        //\n        // ```\n        // import wibble.{unused, also_unused}\n        //        ^^^^^^  ^^^^^^  ^^^^^^^^^^^ Everything is unused here\n        // ```\n        //\n        // But instead of emitting three warnings, what we really want is to\n        // emit just a single warning encompassing the entire line! So we have\n        // to hold on all unused imported entities and emit a warning for those\n        // only if the module they come from is not also unused.\n        let mut unused_modules = HashSet::new();\n        let mut unused_imported_items = vec![];\n\n        for (entity, info) in self.references.unused() {\n            let name = entity.name;\n            let location = info.origin;\n\n            let warning = match info.kind {\n                EntityKind::Function => {\n                    let _ = unused_positions.insert(location.start);\n                    Warning::UnusedPrivateFunction { location, name }\n                }\n                EntityKind::Constant => {\n                    let _ = unused_positions.insert(location.start);\n                    Warning::UnusedPrivateModuleConstant { location, name }\n                }\n                EntityKind::Constructor => Warning::UnusedConstructor {\n                    location,\n                    name,\n                    imported: false,\n                },\n                EntityKind::Type => {\n                    let _ = unused_positions.insert(location.start);\n                    Warning::UnusedType {\n                        name,\n                        imported: false,\n                        location,\n                    }\n                }\n                EntityKind::ImportedModule { module_name } => {\n                    let _ = unused_modules.insert(module_name.clone());\n                    Warning::UnusedImportedModule { name, location }\n                }\n                EntityKind::ImportedType { module } => {\n                    unused_imported_items.push((\n                        module,\n                        Warning::UnusedType {\n                            name,\n                            imported: true,\n                            location,\n                        },\n                    ));\n                    continue;\n                }\n                EntityKind::ImportedConstructor { module } => {\n                    unused_imported_items.push((\n                        module,\n                        Warning::UnusedConstructor {\n                            name,\n                            imported: true,\n                            location,\n                        },\n                    ));\n                    continue;\n                }\n                EntityKind::ImportedValue { module } => {\n                    unused_imported_items\n                        .push((module, Warning::UnusedImportedValue { name, location }));\n                    continue;\n                }\n                EntityKind::ModuleAlias { module } => {\n                    unused_imported_items.push((\n                        module.clone(),\n                        Warning::UnusedImportedModuleAlias {\n                            module_name: module.clone(),\n                            alias: name,\n                            location,\n                        },\n                    ));\n                    continue;\n                }\n            };\n            problems.warning(warning);\n        }\n\n        unused_imported_items\n            .into_iter()\n            .filter(|(module, _)| !unused_modules.contains(module))\n            .for_each(|(_, warning)| problems.warning(warning));\n\n        unused_positions\n    }\n\n    fn handle_unused_variables(\n        &mut self,\n        unused: HashMap<EcoString, VariableUsage>,\n        problems: &mut Problems,\n    ) {\n        for VariableUsage {\n            origin,\n            location,\n            usages,\n            recursive_usages,\n        } in unused.into_values()\n        {\n            if usages == 0 {\n                problems.warning(Warning::UnusedVariable { location, origin });\n            }\n            // If the function parameter is actually used somewhere, but all the\n            // usages are just passing it along in a recursive call, then it\n            // counts as being unused too.\n            else if origin.is_function_parameter() && recursive_usages == usages {\n                problems.warning(Warning::UnusedRecursiveArgument { location });\n            }\n        }\n    }\n\n    pub fn local_value_names(&self) -> Vec<EcoString> {\n        self.scope\n            .keys()\n            .filter(|&t| PIPE_VARIABLE != t)\n            .cloned()\n            .collect()\n    }\n\n    /// Suggest modules to import or use, for an unknown module\n    pub fn suggest_modules(&self, module: &str, imported: Imported) -> Vec<ModuleSuggestion> {\n        let mut suggestions = self\n            .importable_modules\n            .iter()\n            .filter_map(|(importable, module_info)| {\n                if module_info.is_internal && module_info.package != self.current_package {\n                    return None;\n                }\n\n                match &imported {\n                    // Don't suggest importing modules if they are already imported\n                    _ if self\n                        .imported_modules\n                        .contains_key(importable.split('/').next_back().unwrap_or(importable)) =>\n                    {\n                        None\n                    }\n                    Imported::Type(name) if module_info.get_public_type(name).is_some() => {\n                        Some(ModuleSuggestion::Importable(importable.clone()))\n                    }\n                    Imported::Value(name) if module_info.get_public_value(name).is_some() => {\n                        Some(ModuleSuggestion::Importable(importable.clone()))\n                    }\n                    Imported::Module | Imported::Type(_) | Imported::Value(_) => None,\n                }\n            })\n            .collect_vec();\n\n        suggestions.extend(\n            self.imported_modules\n                .keys()\n                .map(|module| ModuleSuggestion::Imported(module.clone())),\n        );\n\n        let threshold = std::cmp::max(module.chars().count() / 3, 1);\n\n        // Filter and sort options based on edit distance.\n        suggestions\n            .into_iter()\n            .sorted()\n            .filter_map(|suggestion| {\n                edit_distance(module, suggestion.last_name_component(), threshold)\n                    .map(|distance| (suggestion, distance))\n            })\n            .sorted_by_key(|&(_, distance)| distance)\n            .map(|(suggestion, _)| suggestion)\n            .collect()\n    }\n\n    pub fn type_variant_name(\n        &self,\n        type_module: &EcoString,\n        type_name: &EcoString,\n        variant_index: u16,\n    ) -> Option<&EcoString> {\n        let type_constructors = if type_module == &self.current_module {\n            &self.module_types_constructors\n        } else {\n            &self\n                .importable_modules\n                .get(type_module)?\n                .types_value_constructors\n        };\n\n        type_constructors\n            .get(type_name)\n            .and_then(|type_constructors| type_constructors.variants.get(variant_index as usize))\n            .map(|variant| &variant.name)\n    }\n}\n\n#[derive(Debug)]\n/// An imported name, for looking up a module which exports it\npub enum Imported {\n    /// An imported module, with no extra information\n    Module,\n    /// An imported type\n    Type(EcoString),\n    /// An imported value\n    Value(EcoString),\n}\n\n/// Unify two types that should be the same.\n/// Any unbound type variables will be linked to the other type as they are the same.\n///\n/// It two types are found to not be the same an error is returned.\n///\npub fn unify(t1: Arc<Type>, t2: Arc<Type>) -> Result<(), UnifyError> {\n    if t1 == t2 {\n        return Ok(());\n    }\n\n    // Collapse right hand side type links. Left hand side will be collapsed in the next block.\n    if let Type::Var { type_ } = t2.deref()\n        && let TypeVar::Link { type_ } = type_.borrow().deref()\n    {\n        return unify(t1, type_.clone());\n    }\n\n    if let Type::Var { type_ } = t1.deref() {\n        enum Action {\n            Unify(Arc<Type>),\n            CouldNotUnify,\n            Link,\n        }\n\n        let action = match type_.borrow().deref() {\n            TypeVar::Link { type_ } => Action::Unify(type_.clone()),\n\n            TypeVar::Unbound { id } => {\n                unify_unbound_type(&t2, *id)?;\n                Action::Link\n            }\n\n            TypeVar::Generic { id } => {\n                if let Type::Var { type_ } = t2.deref()\n                    && type_.borrow().is_unbound()\n                {\n                    *type_.borrow_mut() = TypeVar::Generic { id: *id };\n                    return Ok(());\n                }\n                Action::CouldNotUnify\n            }\n        };\n\n        return match action {\n            Action::Link => {\n                let mut t2 = t2.deref().clone();\n                t2.generalise_custom_type_variant();\n                *type_.borrow_mut() = TypeVar::Link {\n                    type_: Arc::new(t2),\n                };\n                Ok(())\n            }\n\n            Action::Unify(t) => {\n                unify(t.clone(), t2)?;\n\n                // Note that type_ is always a Link in this branch.\n                // unify may replace t's inner value with another link\n                // (See the Action::Link branch just above)\n                // This can cause the compiler to build up an ever-growing chain of links.\n                // Therefore, we try to collapse the links. However, the RefCell in type_\n                // may already be borrowed by collapsing the links in t2 at the start\n                // of the function, in which case accept the extra link.\n                if let Ok(mut type_) = type_.try_borrow_mut() {\n                    *type_ = TypeVar::Link {\n                        type_: collapse_links(t.clone()),\n                    }\n                }\n                Ok(())\n            }\n\n            Action::CouldNotUnify => Err(UnifyError::CouldNotUnify {\n                expected: t1.clone(),\n                given: t2,\n                situation: None,\n            }),\n        };\n    }\n\n    if let Type::Var { .. } = t2.deref() {\n        return unify(t2, t1).map_err(flip_unify_error);\n    }\n\n    match (t1.deref(), t2.deref()) {\n        (\n            Type::Named {\n                module: m1,\n                name: n1,\n                arguments: arguments1,\n                ..\n            },\n            Type::Named {\n                module: m2,\n                name: n2,\n                arguments: arguments2,\n                ..\n            },\n        ) if m1 == m2 && n1 == n2 && arguments1.len() == arguments2.len() => {\n            for (a, b) in arguments1.iter().zip(arguments2) {\n                unify_enclosed_type(t1.clone(), t2.clone(), unify(a.clone(), b.clone()))?;\n            }\n            Ok(())\n        }\n\n        (\n            Type::Tuple {\n                elements: elements1,\n                ..\n            },\n            Type::Tuple {\n                elements: elements2,\n                ..\n            },\n        ) if elements1.len() == elements2.len() => {\n            for (a, b) in elements1.iter().zip(elements2) {\n                unify_enclosed_type(t1.clone(), t2.clone(), unify(a.clone(), b.clone()))?;\n            }\n            Ok(())\n        }\n\n        (\n            Type::Fn {\n                arguments: arguments1,\n                return_: return1,\n                ..\n            },\n            Type::Fn {\n                arguments: arguments2,\n                return_: return2,\n                ..\n            },\n        ) => {\n            if arguments1.len() != arguments2.len() {\n                Err(unify_wrong_arity(\n                    &t1,\n                    arguments1.len(),\n                    &t2,\n                    arguments2.len(),\n                ))?\n            }\n\n            for (i, (a, b)) in arguments1.iter().zip(arguments2).enumerate() {\n                unify(a.clone(), b.clone())\n                    .map_err(|_| unify_wrong_arguments(&t1, a, &t2, b, i))?;\n            }\n\n            unify(return1.clone(), return2.clone())\n                .map_err(|_| unify_wrong_returns(&t1, return1, &t2, return2))\n        }\n\n        _ => Err(UnifyError::CouldNotUnify {\n            expected: t1.clone(),\n            given: t2.clone(),\n            situation: None,\n        }),\n    }\n}\n\n#[cfg(test)]\nmod unify_tests {\n    use std::{cell::RefCell, ops::Deref, sync::Arc};\n\n    use crate::type_::{Type, TypeVar, unify};\n\n    // Repeated unification used to add a link to t1 for each branch\n    // See https://github.com/gleam-lang/gleam/issues/4805\n    #[test]\n    fn repeated_unify_does_not_add_extra_links() {\n        // The case's return type starts unbound\n        let t1 = unbound(0);\n        // In practice, this would usually be something like Result(String, _),\n        // but unify recurses into the type parameters and only the unbound one matters\n        let t2 = unbound(1);\n\n        // After unifying with the first clause, we have a direct link to the clause's return type\n        assert!(unify(t1.clone(), t2).is_ok());\n        assert_direct_link_to_unbound(t1.deref(), 1);\n\n        // Before the fix, this used to _add a new link_ into the nested Var\n        let t2 = unbound(2);\n        assert!(unify(t1.clone(), t2).is_ok());\n        assert_direct_link_to_unbound(t1.deref(), 2);\n\n        // And this would add a link to the var of the new link\n        // As unify is recursive, this eventually cause a stack overflow\n        let t2 = unbound(3);\n        assert!(unify(t1.clone(), t2).is_ok());\n        assert_direct_link_to_unbound(t1.deref(), 3);\n    }\n\n    fn assert_direct_link_to_unbound(t1: &Type, expect_id: u64) {\n        if let Type::Var { type_: var } = t1\n            && let TypeVar::Link { type_: link } = var.borrow().deref()\n            && let Type::Var { type_: var } = link.deref()\n            && let TypeVar::Unbound { id } = var.borrow().deref()\n        {\n            assert_eq!(*id, expect_id, \"Expected unbound id to be unified\")\n        } else {\n            panic!(\"Expected t1 to be a direct link but found: {t1:?}\")\n        }\n    }\n\n    fn unbound(id: u64) -> Arc<Type> {\n        Arc::new(Type::Var {\n            type_: Arc::new(RefCell::new(TypeVar::Unbound { id })),\n        })\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/type_/error.rs",
    "content": "use super::{\n    FieldAccessUsage,\n    expression::{ArgumentKind, CallKind},\n};\nuse crate::{\n    ast::{BinOp, BitArraySegmentTruncation, Layer, SrcSpan, TodoKind},\n    build::Target,\n    exhaustiveness::ImpossibleBitArraySegmentPattern,\n    parse::LiteralFloatValue,\n    type_::{Type, expression::ComparisonOutcome},\n};\n\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\nuse hexpm::version::Version;\nuse num_bigint::BigInt;\n#[cfg(test)]\nuse pretty_assertions::assert_eq;\nuse std::sync::Arc;\n\n/// Errors and warnings discovered when compiling a module.\n///\n#[derive(Debug, Eq, PartialEq, Clone, Default)]\npub struct Problems {\n    errors: Vec<Error>,\n    warnings: Vec<Warning>,\n}\n\nimpl Problems {\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    /// Sort the warnings and errors by their location.\n    ///\n    pub fn sort(&mut self) {\n        self.errors.sort_by_key(|e| e.start_location());\n        self.warnings.sort_by_key(|w| w.location().start);\n    }\n\n    /// Register an error.\n    ///\n    pub fn error(&mut self, error: Error) {\n        self.errors.push(error)\n    }\n\n    /// Register a warning.\n    ///\n    pub fn warning(&mut self, warning: Warning) {\n        self.warnings.push(warning)\n    }\n\n    /// Take all the errors, leaving an empty vector in its place.\n    ///\n    pub fn take_errors(&mut self) -> Vec<Error> {\n        std::mem::take(&mut self.errors)\n    }\n\n    /// Take all the warnings, leaving an empty vector in its place.\n    ///\n    pub fn take_warnings(&mut self) -> Vec<Warning> {\n        std::mem::take(&mut self.warnings)\n    }\n}\n\n/// This is used by the unknown record field error to tell if an unknown field\n/// is a field appearing in another variant of the same type to provide a better\n/// error message explaining why it can't be accessed:\n///\n/// ```gleam\n/// pub type Wibble {\n///   Wibble(field: Int)\n///   Wobble(thing: String)\n/// }\n///\n/// Wobble(\"hello\").field\n/// //             ^^^^^^\n/// ```\n///\n/// Here the error can be extra useful and explain that to access `field` all\n/// variants should have that field at the same position and with the same type.\n///\n#[derive(Debug, Eq, PartialEq, Clone, Copy)]\npub enum UnknownField {\n    /// The field we're trying to access appears in at least a variant, so it\n    /// can be useful to explain why it cannot be accessed and how to fix it\n    /// (adding it to all variants/making sure it has the same type/making sure\n    /// it's in the same position).\n    ///\n    AppearsInAVariant,\n\n    /// The field we are trying to access appears in a variant, but we can\n    /// infer that the value we are accessing on is never the one that this\n    /// value is, so we can give information accordingly.\n    AppearsInAnImpossibleVariant,\n\n    /// The field is not in any of the variants, this might truly be a typo and\n    /// there's no need to add further explanations.\n    ///\n    TrulyUnknown,\n\n    /// The type that the user is trying to access has no fields whatsoever,\n    /// such as Int or fn(..) -> _\n    NoFields,\n}\n\n/// A suggestion for an unknown module\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub enum ModuleSuggestion {\n    /// A module which which has a similar name, and an\n    /// exported value matching the one being accessed\n    Importable(EcoString),\n    /// A module already imported in the current scope\n    Imported(EcoString),\n}\n\nimpl ModuleSuggestion {\n    pub fn suggestion(&self, module: &str) -> String {\n        match self {\n            ModuleSuggestion::Importable(name) => {\n                // Add a little extra information if the names don't match\n                let imported_name = self.last_name_component();\n                if module == imported_name {\n                    format!(\"Did you mean to import `{name}`?\")\n                } else {\n                    format!(\"Did you mean to import `{name}` and reference `{imported_name}`?\")\n                }\n            }\n            ModuleSuggestion::Imported(name) => format!(\"Did you mean `{name}`?\"),\n        }\n    }\n\n    pub fn last_name_component(&self) -> &str {\n        match self {\n            ModuleSuggestion::Imported(name) | ModuleSuggestion::Importable(name) => {\n                name.split('/').next_back().unwrap_or(name)\n            }\n        }\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone)]\npub enum Error {\n    InvalidImport {\n        location: SrcSpan,\n        importing_module: EcoString,\n        imported_module: EcoString,\n        kind: InvalidImportKind,\n    },\n\n    BitArraySegmentError {\n        error: crate::bit_array::ErrorType,\n        location: SrcSpan,\n    },\n\n    UnknownLabels {\n        unknown: Vec<(EcoString, SrcSpan)>,\n        valid: Vec<EcoString>,\n        supplied: Vec<EcoString>,\n    },\n\n    UnknownVariable {\n        location: SrcSpan,\n        name: EcoString,\n        variables: Vec<EcoString>,\n        /// If there's a discarded variable with the same name in the same scope\n        /// this will contain its location.\n        discarded_location: Option<SrcSpan>,\n        type_with_name_in_scope: bool,\n    },\n\n    UnknownType {\n        location: SrcSpan,\n        name: EcoString,\n        hint: UnknownTypeHint,\n    },\n\n    UnknownModule {\n        location: SrcSpan,\n        name: EcoString,\n        suggestions: Vec<ModuleSuggestion>,\n    },\n\n    UnknownModuleType {\n        location: SrcSpan,\n        name: EcoString,\n        module_name: EcoString,\n        type_constructors: Vec<EcoString>,\n        value_with_same_name: bool,\n    },\n\n    UnknownModuleValue {\n        location: SrcSpan,\n        name: EcoString,\n        module_name: EcoString,\n        value_constructors: Vec<EcoString>,\n        type_with_same_name: bool,\n        context: ModuleValueUsageContext,\n    },\n\n    ModuleAliasUsedAsName {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    NotFn {\n        location: SrcSpan,\n        type_: Arc<Type>,\n    },\n\n    UnknownRecordField {\n        location: SrcSpan,\n        type_: Arc<Type>,\n        label: EcoString,\n        fields: Vec<EcoString>,\n        usage: FieldAccessUsage,\n        unknown_field: UnknownField,\n    },\n\n    IncorrectArity {\n        location: SrcSpan,\n        expected: usize,\n        context: IncorrectArityContext,\n        given: usize,\n        labels: Vec<EcoString>,\n    },\n\n    UnsafeRecordUpdate {\n        location: SrcSpan,\n        reason: UnsafeRecordUpdateReason,\n    },\n\n    UnnecessarySpreadOperator {\n        location: SrcSpan,\n        arity: usize,\n    },\n\n    IncorrectTypeArity {\n        location: SrcSpan,\n        name: EcoString,\n        expected: usize,\n        given: usize,\n    },\n\n    CouldNotUnify {\n        location: SrcSpan,\n        situation: Option<UnifyErrorSituation>,\n        expected: Arc<Type>,\n        given: Arc<Type>,\n    },\n\n    RecursiveType {\n        location: SrcSpan,\n    },\n\n    DuplicateName {\n        location_a: SrcSpan,\n        location_b: SrcSpan,\n        name: EcoString,\n    },\n\n    DuplicateImport {\n        location: SrcSpan,\n        previous_location: SrcSpan,\n        name: EcoString,\n    },\n\n    DuplicateTypeName {\n        location: SrcSpan,\n        previous_location: SrcSpan,\n        name: EcoString,\n    },\n\n    DuplicateArgument {\n        location: SrcSpan,\n        label: EcoString,\n    },\n\n    DuplicateField {\n        location: SrcSpan,\n        label: EcoString,\n    },\n\n    PrivateTypeLeak {\n        location: SrcSpan,\n        leaked: Type,\n    },\n\n    UnexpectedLabelledArg {\n        location: SrcSpan,\n        label: EcoString,\n        kind: UnexpectedLabelledArgKind,\n    },\n\n    PositionalArgumentAfterLabelled {\n        location: SrcSpan,\n    },\n\n    IncorrectNumClausePatterns {\n        location: SrcSpan,\n        expected: usize,\n        given: usize,\n    },\n\n    NonLocalClauseGuardVariable {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    ExtraVarInAlternativePattern {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    MissingVarInAlternativePattern {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    DuplicateVarInPattern {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    OutOfBoundsTupleIndex {\n        location: SrcSpan,\n        index: u64,\n        size: usize,\n    },\n\n    NotATuple {\n        location: SrcSpan,\n        given: Arc<Type>,\n    },\n\n    NotATupleUnbound {\n        location: SrcSpan,\n    },\n\n    RecordAccessUnknownType {\n        location: SrcSpan,\n    },\n\n    RecordUpdateInvalidConstructor {\n        location: SrcSpan,\n    },\n\n    UnexpectedTypeHole {\n        location: SrcSpan,\n    },\n\n    ReservedModuleName {\n        name: EcoString,\n    },\n\n    KeywordInModuleName {\n        name: EcoString,\n        keyword: EcoString,\n    },\n\n    NotExhaustivePatternMatch {\n        location: SrcSpan,\n        unmatched: Vec<EcoString>,\n        kind: PatternMatchKind,\n    },\n\n    /// A function was defined with multiple arguments with the same name\n    ///\n    /// # Examples\n    ///\n    /// ```gleam\n    /// fn main(x, x) { Nil }\n    /// ```\n    /// ```gleam\n    /// fn main() {\n    ///   fn(x, x) { Nil }\n    /// }\n    /// ```\n    ArgumentNameAlreadyUsed {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    /// A function was defined with an unlabelled argument after a labelled one.\n    UnlabelledAfterlabelled {\n        location: SrcSpan,\n    },\n\n    /// A type alias was defined directly or indirectly in terms of itself, which would\n    /// cause it to expand to infinite size.\n    /// e.g.\n    ///     type ForkBomb = #(ForkBomb, ForkBomb)\n    RecursiveTypeAlias {\n        location: SrcSpan,\n        cycle: Vec<EcoString>,\n    },\n\n    /// A function has been given an external implementation but not all the\n    /// type annotations have been given. The annotations are required as we\n    /// cannot infer the types of external implementations.\n    ExternalMissingAnnotation {\n        location: SrcSpan,\n        kind: MissingAnnotation,\n    },\n\n    /// A function has been given without either a Gleam implementation or an\n    /// external one.\n    NoImplementation {\n        location: SrcSpan,\n    },\n\n    /// A function/constant that is used doesn't have an implementation for the\n    /// current compilation target.\n    UnsupportedExpressionTarget {\n        location: SrcSpan,\n        target: Target,\n    },\n\n    /// A function's JavaScript implementation has been given but it does not\n    /// have a valid module name.\n    InvalidExternalJavascriptModule {\n        location: SrcSpan,\n        module: EcoString,\n        name: EcoString,\n    },\n\n    /// A function's JavaScript implementation has been given but it does not\n    /// have a valid function name.\n    InvalidExternalJavascriptFunction {\n        location: SrcSpan,\n        function: EcoString,\n        name: EcoString,\n    },\n\n    /// A case expression is missing one or more patterns to match all possible\n    /// values of the type.\n    InexhaustiveCaseExpression {\n        location: SrcSpan,\n        missing: Vec<EcoString>,\n    },\n\n    /// A case expression is missing its body.\n    MissingCaseBody {\n        location: SrcSpan,\n    },\n\n    /// Let assignment's pattern does not match all possible values of the type.\n    InexhaustiveLetAssignment {\n        location: SrcSpan,\n        missing: Vec<EcoString>,\n    },\n\n    /// A type alias has a type variable but it is not used in the definition.\n    ///\n    /// For example, here `unused` is not used\n    ///\n    /// ```gleam\n    /// pub type Wibble(unused) =\n    ///   Int\n    /// ```\n    UnusedTypeAliasParameter {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    /// A definition has two type parameters with the same name.\n    ///\n    /// ```gleam\n    /// pub type Wibble(a, a) =\n    ///   Int\n    /// ```\n    /// ```gleam\n    /// pub type Wibble(a, a) {\n    ///   Wibble\n    /// }\n    /// ```\n    DuplicateTypeParameter {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    /// A public function doesn't have an implementation for the current target.\n    /// This is only raised when compiling a package with `TargetSupport::Enforced`, which is\n    /// typically the root package, deps not being enforced.\n    ///\n    /// For example, if compiling to Erlang:\n    ///\n    /// ```gleam\n    /// @external(javascript, \"one\", \"two\")\n    /// pub fn wobble() -> Int\n    /// ```\n    UnsupportedPublicFunctionTarget {\n        target: Target,\n        name: EcoString,\n        location: SrcSpan,\n    },\n\n    /// When there's something that is not a function to the left of the `<-`\n    /// operator in a use expression:\n    ///\n    /// For example:\n    ///\n    /// ```gleam\n    /// use <- \"wibble\"\n    /// todo\n    /// ```\n    NotFnInUse {\n        location: SrcSpan,\n        type_: Arc<Type>,\n    },\n\n    /// When the function to the right hand side of `<-` in a `use` expression\n    /// is called with the wrong number of arguments (given already takes into\n    /// account the use callback passed to the function).\n    ///\n    UseFnIncorrectArity {\n        location: SrcSpan,\n        expected: usize,\n        given: usize,\n    },\n\n    /// When on the left hand side of `<-` in a `use` expression there is the\n    /// wrong number of patterns.\n    ///\n    /// For example:\n    ///\n    /// ```gleam\n    /// use _, _ <- result.try(res)\n    /// todo\n    /// ```\n    ///\n    UseCallbackIncorrectArity {\n        call_location: SrcSpan,\n        pattern_location: SrcSpan,\n        expected: usize,\n        given: usize,\n    },\n\n    /// When on the right hand side of use there is a function that doesn't take\n    /// a callback function as its last argument.\n    ///\n    /// For example:\n    ///\n    /// ```gleam\n    /// use <- io.println\n    /// ```\n    ///\n    UseFnDoesntTakeCallback {\n        location: SrcSpan,\n        actual_type: Option<Type>,\n    },\n\n    /// When the name assigned to a variable or function doesn't follow the gleam\n    /// naming conventions.\n    ///\n    /// For example:\n    ///\n    /// ```gleam\n    /// let myBadName = 42\n    /// ```\n    BadName {\n        location: SrcSpan,\n        kind: Named,\n        name: EcoString,\n    },\n\n    /// Occurs when all the variant types of a custom type are deprecated\n    ///\n    /// ```gleam\n    /// type Wibble {\n    ///     @deprecated(\"1\")\n    ///     Wobble1\n    ///     @deprecated(\"1\")\n    ///     Wobble1\n    /// }\n    /// ```\n    AllVariantsDeprecated {\n        location: SrcSpan,\n    },\n\n    /// Occurs when any varient of a custom type is deprecated while\n    /// the custom type itself is deprecated\n    DeprecatedVariantOnDeprecatedType {\n        location: SrcSpan,\n    },\n\n    /// Occurs when a literal floating point has a value that is outside of the\n    /// range representable by floats: -1.7976931348623157e308 to\n    /// 1.7976931348623157e308.\n    LiteralFloatOutOfRange {\n        location: SrcSpan,\n    },\n\n    /// When the echo keyword is not followed by an expression to be printed.\n    /// The only place where echo is allowed to appear on its own is as a step\n    /// of a pipeline, otherwise omitting the expression will result in this\n    /// error. For example:\n    ///\n    /// ```gleam\n    /// call(echo, 1, 2)\n    /// //   ^^^^ Error!\n    /// ```\n    ///\n    EchoWithNoFollowingExpression {\n        location: SrcSpan,\n    },\n    /// When someone tries concatenating two string values using the `+` operator.\n    ///\n    /// ```gleam\n    /// \"aaa\" + \"bbb\"\n    /// //    ^ We wont to suggest using `<>` instead!\n    /// ```\n    StringConcatenationWithAddInt {\n        location: SrcSpan,\n    },\n    /// When someone tries using an int operator on two floats.\n    ///\n    /// ```gleam\n    /// 1 +. 3\n    /// //^ We wont to suggest using `+` instead!\n    /// ```\n    FloatOperatorOnInts {\n        operator: BinOp,\n        location: SrcSpan,\n    },\n    /// When someone tries using an int operator on two floats.\n    ///\n    /// ```gleam\n    /// 1.2 + 1.0\n    /// //  ^ We wont to suggest using `+.` instead!\n    /// ```\n    IntOperatorOnFloats {\n        operator: BinOp,\n        location: SrcSpan,\n    },\n\n    DoubleVariableAssignmentInBitArray {\n        location: SrcSpan,\n    },\n\n    NonUtf8StringAssignmentInBitArray {\n        location: SrcSpan,\n    },\n\n    /// This happens when a private type is marked as opaque. Only public types\n    /// can be opaque.\n    ///\n    /// ```gleam\n    /// opaque type Wibble {\n    ///   Wobble\n    /// }\n    /// ```\n    ///\n    PrivateOpaqueType {\n        location: SrcSpan,\n    },\n\n    SrcImportingDevDependency {\n        importing_module: EcoString,\n        imported_module: EcoString,\n        package: EcoString,\n        location: SrcSpan,\n    },\n\n    /// This happens when a type has no type parameters (for example `Int`) but\n    /// it is being used as a constructor: `Int()`, `Bool(a, b)`.\n    ///\n    TypeUsedAsAConstructor {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    /// The `@external` annotation on custom types can only be used for external\n    /// types, types with no constructors.\n    ///\n    ExternalTypeWithConstructors {\n        location: SrcSpan,\n    },\n\n    LowercaseBoolPattern {\n        location: SrcSpan,\n    },\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum UnexpectedLabelledArgKind {\n    FunctionParameter,\n    RecordConstructorArgument,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum ModuleValueUsageContext {\n    UnqualifiedImport,\n    ModuleAccess,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum MissingAnnotation {\n    Parameter,\n    Return,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum PatternMatchKind {\n    Case,\n    Assignment,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum EmptyListCheckKind {\n    Empty,\n    NonEmpty,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum LiteralCollectionKind {\n    List,\n    Tuple,\n    Record,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum IncorrectArityContext {\n    Pattern,\n    Function,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum InvalidImportKind {\n    SrcImportingTest,\n    SrcImportingDev,\n    DevImportingTest,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Named {\n    Type,\n    TypeAlias,\n    TypeVariable,\n    CustomTypeVariant,\n    Variable,\n    Argument,\n    Label,\n    Constant,\n    Function,\n    Discard,\n}\n\nimpl Named {\n    pub fn as_str(self) -> &'static str {\n        match self {\n            Named::Type => \"Type\",\n            Named::TypeAlias => \"Type alias\",\n            Named::TypeVariable => \"Type variable\",\n            Named::CustomTypeVariant => \"Type variant\",\n            Named::Variable => \"Variable\",\n            Named::Argument => \"Argument\",\n            Named::Label => \"Label\",\n            Named::Constant => \"Constant\",\n            Named::Function => \"Function\",\n            Named::Discard => \"Discard\",\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct VariableOrigin {\n    pub syntax: VariableSyntax,\n    pub declaration: VariableDeclaration,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\n/// The syntax used to define a variable. Used to determine how it can be ignored\n/// when unused.\npub enum VariableSyntax {\n    /// A variable that can be ignored by prefixing with an underscore, `_name`\n    Variable(EcoString),\n    /// A variable from label shorthand syntax, which can be ignored with an underscore: `label: _`\n    LabelShorthand(EcoString),\n    /// A variable from an assignment pattern, which can be ignored by removing `as name`,\n    AssignmentPattern,\n    /// A variable generated by the compiler. This should never need to be ignored\n    Generated,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\n/// The source of a variable, such as a `let` assignment, or function parameter.\npub enum VariableDeclaration {\n    LetPattern,\n    UsePattern,\n    ClausePattern,\n    FunctionParameter {\n        /// The name of the function defining the parameter. This will be None\n        /// for parameters introduced by anoynmous functions: `fn(a) { a }`\n        ///\n        function_name: Option<EcoString>,\n        /// The index of the parameter in the function's parameter list.\n        ///\n        index: usize,\n    },\n    Generated,\n}\n\nimpl VariableOrigin {\n    pub fn how_to_ignore(&self) -> Option<String> {\n        match &self.syntax {\n            VariableSyntax::Variable(name) => {\n                Some(format!(\"You can ignore it with an underscore: `_{name}`.\"))\n            }\n            VariableSyntax::LabelShorthand(label) => Some(format!(\n                \"You can ignore it with an underscore: `{label}: _`.\"\n            )),\n            VariableSyntax::AssignmentPattern => Some(\"You can safely remove it.\".to_string()),\n            VariableSyntax::Generated => None,\n        }\n    }\n\n    pub fn generated() -> Self {\n        Self {\n            syntax: VariableSyntax::Generated,\n            declaration: VariableDeclaration::Generated,\n        }\n    }\n\n    pub fn is_function_parameter(&self) -> bool {\n        match self.declaration {\n            VariableDeclaration::FunctionParameter { .. } => true,\n\n            VariableDeclaration::LetPattern\n            | VariableDeclaration::UsePattern\n            | VariableDeclaration::ClausePattern\n            | VariableDeclaration::Generated => false,\n        }\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]\npub enum Warning {\n    Todo {\n        kind: TodoKind,\n        location: SrcSpan,\n        type_: Arc<Type>,\n    },\n\n    ImplicitlyDiscardedResult {\n        location: SrcSpan,\n    },\n\n    UnusedLiteral {\n        location: SrcSpan,\n    },\n\n    UnusedValue {\n        location: SrcSpan,\n    },\n    NoFieldsRecordUpdate {\n        location: SrcSpan,\n    },\n\n    AllFieldsRecordUpdate {\n        location: SrcSpan,\n    },\n\n    UnusedType {\n        location: SrcSpan,\n        imported: bool,\n        name: EcoString,\n    },\n\n    UnusedConstructor {\n        location: SrcSpan,\n        imported: bool,\n        name: EcoString,\n    },\n\n    UnusedImportedValue {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    UnusedImportedModule {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    UnusedImportedModuleAlias {\n        location: SrcSpan,\n        alias: EcoString,\n        module_name: EcoString,\n    },\n\n    UnusedPrivateModuleConstant {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    UnusedPrivateFunction {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    UnusedVariable {\n        location: SrcSpan,\n        origin: VariableOrigin,\n    },\n\n    UnnecessaryDoubleIntNegation {\n        location: SrcSpan,\n    },\n\n    UnnecessaryDoubleBoolNegation {\n        location: SrcSpan,\n    },\n\n    InefficientEmptyListCheck {\n        location: SrcSpan,\n        kind: EmptyListCheckKind,\n    },\n\n    TransitiveDependencyImported {\n        location: SrcSpan,\n        module: EcoString,\n        package: EcoString,\n    },\n\n    DeprecatedItem {\n        location: SrcSpan,\n        message: EcoString,\n        layer: Layer,\n    },\n\n    UnreachableCasePattern {\n        location: SrcSpan,\n        reason: UnreachablePatternReason,\n    },\n\n    UnusedDiscardPattern {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    /// This happens when someone tries to write a case expression where one of\n    /// the subjects is a literal tuple, list or bit array for example:\n    ///\n    /// ```gleam\n    /// case #(wibble, wobble) { ... }\n    /// ```\n    ///\n    /// Matching on a literal collection of elements is redundant since we can\n    /// always pass the single items it's made of separated by a comma:\n    ///\n    /// ```gleam\n    /// case wibble, wobble { ... }\n    /// ```\n    ///\n    CaseMatchOnLiteralCollection {\n        kind: LiteralCollectionKind,\n        location: SrcSpan,\n    },\n\n    /// This happens if someone tries to match on some kind of literal value\n    /// like an Int, a String, an empty List etc.\n    ///\n    /// ```gleam\n    /// case #() { ... }\n    /// ```\n    ///\n    /// The whole match becomes redundant since one can already tell beforehand\n    /// the structure of the value being matched.\n    ///\n    /// Note: for non-empty literal collection of values we want to provide a\n    ///       better error message that suggests to drop the wrapper, for that\n    ///       we have the `CaseMatchOnLiteralCollection` variant.\n    ///\n    CaseMatchOnLiteralValue {\n        location: SrcSpan,\n    },\n\n    /// This happens when someone defines an external type (with no\n    /// constructors) and marks it as opqaue:\n    ///\n    /// ```gleam\n    /// opaque type External\n    /// ```\n    ///\n    /// Since an external type already has no constructors, marking it as\n    /// opaque is redundant.\n    ///\n    OpaqueExternalType {\n        location: SrcSpan,\n    },\n\n    /// This happens when an internal type is accidentally exposed in the public\n    /// API. Since internal types are excluded from documentation, completions\n    /// and the package interface, this would lead to poor developer experience.\n    ///\n    /// ```gleam\n    /// @internal type Wibble\n    ///\n    /// pub fn wibble(thing: Wibble) { todo }\n    /// //            ^^^^^^^^^^^^^ There would be no documentation\n    /// //                          explaining what `Wibble` is in the\n    /// //                          package's doc site.\n    /// ```\n    InternalTypeLeak {\n        location: SrcSpan,\n        leaked: Type,\n    },\n\n    RedundantAssertAssignment {\n        location: SrcSpan,\n    },\n\n    AssertAssignmentOnImpossiblePattern {\n        location: SrcSpan,\n        reason: AssertImpossiblePattern,\n    },\n\n    /// When a `todo` or `panic` is used as a function instead of providing the\n    /// error message with the `as` syntax.\n    ///\n    /// ```gleam\n    /// todo(\"this won't appear in the error message\")\n    /// ```\n    ///\n    TodoOrPanicUsedAsFunction {\n        kind: TodoOrPanic,\n        location: SrcSpan,\n        arguments_location: Option<SrcSpan>,\n        arguments: usize,\n    },\n\n    UnreachableCodeAfterPanic {\n        location: SrcSpan,\n        panic_position: PanicPosition,\n    },\n\n    /// When a function capture is used in a pipe to pipe into the first\n    /// argument of a function:\n    ///\n    /// ```gleam\n    /// wibble |> wobble(_, 1)\n    ///                  ^ Redundant and can be removed\n    /// ```\n    ///\n    RedundantPipeFunctionCapture {\n        location: SrcSpan,\n    },\n\n    /// When the `gleam` range specified in the package's `gleam.toml` is too\n    /// low and would include a version that's too low to support this feature.\n    ///\n    /// For example, let's say that a package is saying `gleam = \">=1.1.0\"`\n    /// but it is using label shorthand syntax: `wibble(label:)`.\n    /// That requires a version that is `>=1.4.0`, so the constraint expressed\n    /// in the `gleam.toml` is too permissive and if someone were to run this\n    /// code with v1.1.0 they would run into compilation errors since the\n    /// compiler cannot know of label shorthands!\n    ///\n    FeatureRequiresHigherGleamVersion {\n        location: SrcSpan,\n        minimum_required_version: Version,\n        wrongfully_allowed_version: Version,\n        feature_kind: FeatureKind,\n    },\n\n    /// When targeting JavaScript and an `Int` value is specified that lies\n    /// outside the range `Number.MIN_SAFE_INTEGER` - `Number.MAX_SAFE_INTEGER`.\n    ///\n    JavaScriptIntUnsafe {\n        location: SrcSpan,\n    },\n\n    /// When we are trying to use bool assert on a literal boolean. For example:\n    /// ```gleam\n    /// assert True\n    ///        ^ The programmer knows this will never panic, so it's useless\n    /// ```\n    AssertLiteralBool {\n        location: SrcSpan,\n    },\n\n    /// When a segment has a constant value that is bigger than its size and we\n    /// know for certain is going to be truncated.\n    ///\n    BitArraySegmentTruncatedValue {\n        truncation: BitArraySegmentTruncation,\n        location: SrcSpan,\n    },\n\n    /// In Gleam v1 it is possible to import one module twice using different aliases.\n    /// This is deprecated, and likely would be removed in a Gleam v2.\n    ModuleImportedTwice {\n        name: EcoString,\n        first: SrcSpan,\n        second: SrcSpan,\n    },\n\n    /// Top-level definition should not shadow an imported one.\n    /// This includes constant or function imports.\n    TopLevelDefinitionShadowsImport {\n        location: SrcSpan,\n        name: EcoString,\n    },\n\n    /// This warning is raised when we perform a comparison that the compiler\n    /// can tell is always going to succeed or fail. For example:\n    ///\n    /// ```gleam\n    /// 1 == 1 // This always succeeds\n    /// 2 != 2 // This always fails\n    /// 1 > 10 // This always fails\n    /// a == a // This always succeeds\n    /// ```\n    RedundantComparison {\n        location: SrcSpan,\n        outcome: ComparisonOutcome,\n    },\n    /// When a function's argument is only ever used unchanged in recursive\n    /// calls. For example:\n    ///\n    /// ```gleam\n    /// pub fn wibble(x, n) {\n    /// //            ^ This argument is not needed,\n    ///   case n {\n    ///     0 -> Nil\n    ///     _ -> wibble(x, n - 1)\n    /// //              ^ It's only used in recursive calls!\n    ///   }\n    /// }\n    /// ```\n    ///\n    UnusedRecursiveArgument {\n        location: SrcSpan,\n    },\n}\n\n#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]\npub enum AssertImpossiblePattern {\n    /// When `let assert`-ing on a variant that's different from the inferred\n    /// one.\n    ///\n    /// ```gleam\n    /// let assert Error(_) = Ok(_)\n    /// ```\n    ///\n    InferredVariant,\n\n    /// When `let assert`-ing on a pattern that will never match because it's\n    /// matching on impossible segment(s).\n    ///\n    /// ```gleam\n    /// let assert <<-2:unsigned>> = bit_array\n    /// ```\n    ///\n    ImpossibleSegments {\n        segments: Vec<ImpossibleBitArraySegmentPattern>,\n    },\n}\n\n#[derive(Debug, Eq, Copy, PartialEq, Clone, serde::Serialize, serde::Deserialize)]\npub enum FeatureKind {\n    LabelShorthandSyntax,\n    ConstantStringConcatenation,\n    ArithmeticInGuards,\n    ConcatenateInGuards,\n    UnannotatedUtf8StringSegment,\n    UnannotatedFloatSegment,\n    NestedTupleAccess,\n    InternalAnnotation,\n    AtInJavascriptModules,\n    RecordUpdateVariantInference,\n    RecordAccessVariantInference,\n    LetAssertWithMessage,\n    VariantWithDeprecatedAnnotation,\n    JavaScriptUnalignedBitArray,\n    BoolAssert,\n    ExternalCustomType,\n    ConstantRecordUpdate,\n    ExpressionInSegmentSize,\n}\n\nimpl FeatureKind {\n    pub fn required_version(&self) -> Version {\n        match self {\n            FeatureKind::InternalAnnotation | FeatureKind::NestedTupleAccess => {\n                Version::new(1, 1, 0)\n            }\n\n            FeatureKind::AtInJavascriptModules => Version::new(1, 2, 0),\n\n            FeatureKind::ArithmeticInGuards => Version::new(1, 3, 0),\n\n            FeatureKind::ConcatenateInGuards => Version::new(1, 15, 0),\n\n            FeatureKind::LabelShorthandSyntax | FeatureKind::ConstantStringConcatenation => {\n                Version::new(1, 4, 0)\n            }\n\n            FeatureKind::UnannotatedUtf8StringSegment => Version::new(1, 5, 0),\n\n            FeatureKind::RecordUpdateVariantInference\n            | FeatureKind::RecordAccessVariantInference => Version::new(1, 6, 0),\n\n            FeatureKind::VariantWithDeprecatedAnnotation | FeatureKind::LetAssertWithMessage => {\n                Version::new(1, 7, 0)\n            }\n\n            FeatureKind::JavaScriptUnalignedBitArray => Version::new(1, 9, 0),\n            FeatureKind::UnannotatedFloatSegment => Version::new(1, 10, 0),\n\n            FeatureKind::BoolAssert => Version::new(1, 11, 0),\n\n            FeatureKind::ExpressionInSegmentSize => Version::new(1, 12, 0),\n\n            FeatureKind::ExternalCustomType | FeatureKind::ConstantRecordUpdate => {\n                Version::new(1, 14, 0)\n            }\n        }\n    }\n}\n#[derive(Debug, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)]\npub enum PanicPosition {\n    /// When the unreachable part is a function argument, this means that one\n    /// of the previous arguments must be a panic.\n    PreviousFunctionArgument,\n\n    /// When the unreachable part is a function call, this means that its last\n    /// argument must be a panic.\n    LastFunctionArgument,\n\n    /// When the expression to be printed by echo panics.\n    EchoExpression,\n\n    /// Any expression that doesn't fall in the previous two categories\n    PreviousExpression,\n}\n\n#[derive(Debug, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)]\npub enum TodoOrPanic {\n    Todo,\n    Panic,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum UnreachablePatternReason {\n    /// The clause is unreachable because a previous pattern\n    /// matches the same case.\n    DuplicatePattern,\n    /// The clause is unreachable because we have inferred the variant\n    /// of the custom type that we are matching on, and this matches\n    /// against one of the variants we know it isn't.\n    ImpossibleVariant,\n    /// The clause is unreachable because it is matching on a pattern segment\n    /// that we could tell is never going to match\n    ImpossibleSegments(Vec<ImpossibleBitArraySegmentPattern>),\n}\n\nimpl Error {\n    // Location where the error started\n    pub fn start_location(&self) -> u32 {\n        match self {\n            Error::InvalidImport { location, .. }\n            | Error::BitArraySegmentError { location, .. }\n            | Error::UnknownVariable { location, .. }\n            | Error::UnknownType { location, .. }\n            | Error::UnknownModule { location, .. }\n            | Error::UnknownModuleType { location, .. }\n            | Error::UnknownModuleValue { location, .. }\n            | Error::ModuleAliasUsedAsName { location, .. }\n            | Error::NotFn { location, .. }\n            | Error::UnknownRecordField { location, .. }\n            | Error::IncorrectArity { location, .. }\n            | Error::UnsafeRecordUpdate { location, .. }\n            | Error::UnnecessarySpreadOperator { location, .. }\n            | Error::IncorrectTypeArity { location, .. }\n            | Error::TypeUsedAsAConstructor { location, .. }\n            | Error::CouldNotUnify { location, .. }\n            | Error::RecursiveType { location, .. }\n            | Error::DuplicateName {\n                location_a: location,\n                ..\n            }\n            | Error::DuplicateImport { location, .. }\n            | Error::DuplicateTypeName { location, .. }\n            | Error::DuplicateArgument { location, .. }\n            | Error::DuplicateField { location, .. }\n            | Error::PrivateTypeLeak { location, .. }\n            | Error::UnexpectedLabelledArg { location, .. }\n            | Error::PositionalArgumentAfterLabelled { location, .. }\n            | Error::IncorrectNumClausePatterns { location, .. }\n            | Error::NonLocalClauseGuardVariable { location, .. }\n            | Error::ExtraVarInAlternativePattern { location, .. }\n            | Error::MissingVarInAlternativePattern { location, .. }\n            | Error::DuplicateVarInPattern { location, .. }\n            | Error::OutOfBoundsTupleIndex { location, .. }\n            | Error::NotATuple { location, .. }\n            | Error::NotATupleUnbound { location, .. }\n            | Error::RecordAccessUnknownType { location, .. }\n            | Error::RecordUpdateInvalidConstructor { location, .. }\n            | Error::UnexpectedTypeHole { location, .. }\n            | Error::NotExhaustivePatternMatch { location, .. }\n            | Error::ArgumentNameAlreadyUsed { location, .. }\n            | Error::UnlabelledAfterlabelled { location, .. }\n            | Error::RecursiveTypeAlias { location, .. }\n            | Error::ExternalMissingAnnotation { location, .. }\n            | Error::NoImplementation { location, .. }\n            | Error::UnsupportedExpressionTarget { location, .. }\n            | Error::InvalidExternalJavascriptModule { location, .. }\n            | Error::InvalidExternalJavascriptFunction { location, .. }\n            | Error::InexhaustiveCaseExpression { location, .. }\n            | Error::MissingCaseBody { location }\n            | Error::InexhaustiveLetAssignment { location, .. }\n            | Error::UnusedTypeAliasParameter { location, .. }\n            | Error::DuplicateTypeParameter { location, .. }\n            | Error::UnsupportedPublicFunctionTarget { location, .. }\n            | Error::NotFnInUse { location, .. }\n            | Error::UseCallbackIncorrectArity {\n                pattern_location: location,\n                ..\n            }\n            | Error::UseFnDoesntTakeCallback { location, .. }\n            | Error::UseFnIncorrectArity { location, .. }\n            | Error::BadName { location, .. }\n            | Error::AllVariantsDeprecated { location }\n            | Error::EchoWithNoFollowingExpression { location }\n            | Error::DeprecatedVariantOnDeprecatedType { location }\n            | Error::LiteralFloatOutOfRange { location }\n            | Error::FloatOperatorOnInts { location, .. }\n            | Error::IntOperatorOnFloats { location, .. }\n            | Error::StringConcatenationWithAddInt { location }\n            | Error::DoubleVariableAssignmentInBitArray { location }\n            | Error::NonUtf8StringAssignmentInBitArray { location }\n            | Error::PrivateOpaqueType { location }\n            | Error::SrcImportingDevDependency { location, .. }\n            | Error::ExternalTypeWithConstructors { location, .. }\n            | Error::LowercaseBoolPattern { location } => location.start,\n            Error::UnknownLabels { unknown, .. } => {\n                unknown.iter().map(|(_, s)| s.start).min().unwrap_or(0)\n            }\n            Error::ReservedModuleName { .. } => 0,\n            Error::KeywordInModuleName { .. } => 0,\n        }\n    }\n\n    pub fn with_unify_error_situation(mut self, new_situation: UnifyErrorSituation) -> Self {\n        if let Error::CouldNotUnify {\n            ref mut situation, ..\n        } = self\n        {\n            *situation = Some(new_situation);\n            self\n        } else {\n            self\n        }\n    }\n}\n\nimpl Warning {\n    pub fn into_warning(self, path: Utf8PathBuf, src: EcoString) -> crate::Warning {\n        crate::Warning::Type {\n            path,\n            src,\n            warning: self,\n        }\n    }\n\n    pub(crate) fn location(&self) -> SrcSpan {\n        match self {\n            Warning::Todo { location, .. }\n            | Warning::ImplicitlyDiscardedResult { location, .. }\n            | Warning::UnusedLiteral { location, .. }\n            | Warning::UnusedValue { location, .. }\n            | Warning::NoFieldsRecordUpdate { location, .. }\n            | Warning::AllFieldsRecordUpdate { location, .. }\n            | Warning::UnusedType { location, .. }\n            | Warning::UnusedConstructor { location, .. }\n            | Warning::UnusedImportedValue { location, .. }\n            | Warning::UnusedImportedModule { location, .. }\n            | Warning::UnusedImportedModuleAlias { location, .. }\n            | Warning::UnusedPrivateModuleConstant { location, .. }\n            | Warning::UnusedPrivateFunction { location, .. }\n            | Warning::UnusedVariable { location, .. }\n            | Warning::UnnecessaryDoubleIntNegation { location, .. }\n            | Warning::UnnecessaryDoubleBoolNegation { location, .. }\n            | Warning::InefficientEmptyListCheck { location, .. }\n            | Warning::TransitiveDependencyImported { location, .. }\n            | Warning::DeprecatedItem { location, .. }\n            | Warning::UnreachableCasePattern { location, .. }\n            | Warning::CaseMatchOnLiteralCollection { location, .. }\n            | Warning::CaseMatchOnLiteralValue { location, .. }\n            | Warning::OpaqueExternalType { location, .. }\n            | Warning::InternalTypeLeak { location, .. }\n            | Warning::RedundantAssertAssignment { location, .. }\n            | Warning::AssertAssignmentOnImpossiblePattern { location, .. }\n            | Warning::TodoOrPanicUsedAsFunction { location, .. }\n            | Warning::UnreachableCodeAfterPanic { location, .. }\n            | Warning::RedundantPipeFunctionCapture { location, .. }\n            | Warning::FeatureRequiresHigherGleamVersion { location, .. }\n            | Warning::JavaScriptIntUnsafe { location, .. }\n            | Warning::AssertLiteralBool { location, .. }\n            | Warning::BitArraySegmentTruncatedValue { location, .. }\n            | Warning::TopLevelDefinitionShadowsImport { location, .. }\n            | Warning::UnusedDiscardPattern { location, .. }\n            | Warning::ModuleImportedTwice {\n                second: location, ..\n            }\n            | Warning::RedundantComparison { location, .. }\n            | Warning::UnusedRecursiveArgument { location, .. } => *location,\n        }\n    }\n\n    pub(crate) fn is_todo(&self) -> bool {\n        matches!(self, Self::Todo { .. })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub enum UnknownValueConstructorError {\n    Variable {\n        name: EcoString,\n        variables: Vec<EcoString>,\n        type_with_name_in_scope: bool,\n    },\n\n    Module {\n        name: EcoString,\n        suggestions: Vec<ModuleSuggestion>,\n    },\n\n    ModuleValue {\n        name: EcoString,\n        module_name: EcoString,\n        value_constructors: Vec<EcoString>,\n        imported_value_as_type: bool,\n    },\n}\n\npub fn convert_get_value_constructor_error(\n    e: UnknownValueConstructorError,\n    location: SrcSpan,\n    module_location: Option<SrcSpan>,\n) -> Error {\n    match e {\n        UnknownValueConstructorError::Variable {\n            name,\n            variables,\n            type_with_name_in_scope,\n        } => Error::UnknownVariable {\n            location,\n            name,\n            variables,\n            discarded_location: None,\n            type_with_name_in_scope,\n        },\n\n        UnknownValueConstructorError::Module { name, suggestions } => Error::UnknownModule {\n            location: module_location.unwrap_or(location),\n            name,\n            suggestions,\n        },\n\n        UnknownValueConstructorError::ModuleValue {\n            name,\n            module_name,\n            value_constructors,\n            imported_value_as_type,\n        } => Error::UnknownModuleValue {\n            location,\n            name,\n            module_name,\n            value_constructors,\n            type_with_same_name: imported_value_as_type,\n            context: ModuleValueUsageContext::ModuleAccess,\n        },\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone)]\npub enum UnsafeRecordUpdateReason {\n    UnknownVariant {\n        constructed_variant: EcoString,\n    },\n    WrongVariant {\n        constructed_variant: EcoString,\n        spread_variant: EcoString,\n    },\n    IncompatibleFieldTypes {\n        constructed_variant: Arc<Type>,\n        record_variant: Arc<Type>,\n        expected_field_type: Arc<Type>,\n        record_field_type: Arc<Type>,\n        field: RecordField,\n    },\n}\n\n#[derive(Debug, Eq, PartialEq, Clone)]\npub enum RecordField {\n    Labelled(EcoString),\n    Unlabelled(u32),\n}\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum UnknownTypeHint {\n    AlternativeTypes(Vec<EcoString>),\n    ValueInScopeWithSameName,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub enum UnknownTypeConstructorError {\n    Type {\n        name: EcoString,\n        hint: UnknownTypeHint,\n    },\n\n    Module {\n        name: EcoString,\n        suggestions: Vec<ModuleSuggestion>,\n    },\n\n    ModuleType {\n        name: EcoString,\n        module_name: EcoString,\n        type_constructors: Vec<EcoString>,\n        imported_type_as_value: bool,\n    },\n}\n\npub fn convert_get_type_constructor_error(\n    e: UnknownTypeConstructorError,\n    location: &SrcSpan,\n    module_location: Option<SrcSpan>,\n) -> Error {\n    match e {\n        UnknownTypeConstructorError::Type { name, hint } => Error::UnknownType {\n            location: *location,\n            name,\n            hint,\n        },\n\n        UnknownTypeConstructorError::Module { name, suggestions } => Error::UnknownModule {\n            location: module_location.unwrap_or(*location),\n            name,\n            suggestions,\n        },\n\n        UnknownTypeConstructorError::ModuleType {\n            name,\n            module_name,\n            type_constructors,\n            imported_type_as_value,\n        } => Error::UnknownModuleType {\n            location: *location,\n            name,\n            module_name,\n            type_constructors,\n            value_with_same_name: imported_type_as_value,\n        },\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum MatchFunTypeError {\n    IncorrectArity {\n        expected: usize,\n        given: usize,\n        arguments: Vec<Arc<Type>>,\n        return_type: Arc<Type>,\n    },\n    NotFn {\n        type_: Arc<Type>,\n    },\n}\n\npub fn convert_not_fun_error(\n    e: MatchFunTypeError,\n    fn_location: SrcSpan,\n    call_location: SrcSpan,\n    call_kind: CallKind,\n) -> Error {\n    match (call_kind, e) {\n        (\n            CallKind::Function,\n            MatchFunTypeError::IncorrectArity {\n                expected, given, ..\n            },\n        ) => Error::IncorrectArity {\n            labels: vec![],\n            location: call_location,\n            context: IncorrectArityContext::Function,\n            expected,\n            given,\n        },\n\n        (CallKind::Function, MatchFunTypeError::NotFn { type_ }) => Error::NotFn {\n            location: fn_location,\n            type_,\n        },\n\n        (\n            CallKind::Use { call_location, .. },\n            MatchFunTypeError::IncorrectArity {\n                expected, given, ..\n            },\n        ) => Error::UseFnIncorrectArity {\n            location: call_location,\n            expected,\n            given,\n        },\n\n        (CallKind::Use { call_location, .. }, MatchFunTypeError::NotFn { type_ }) => {\n            Error::NotFnInUse {\n                location: call_location,\n                type_,\n            }\n        }\n    }\n}\n\npub fn flip_unify_error(e: UnifyError) -> UnifyError {\n    match e {\n        UnifyError::CouldNotUnify {\n            expected,\n            given,\n            situation: note,\n        } => UnifyError::CouldNotUnify {\n            expected: given,\n            given: expected,\n            situation: note,\n        },\n        UnifyError::ExtraVarInAlternativePattern { .. }\n        | UnifyError::MissingVarInAlternativePattern { .. }\n        | UnifyError::DuplicateVarInPattern { .. }\n        | UnifyError::RecursiveType => e,\n    }\n}\n\n#[test]\nfn flip_unify_error_test() {\n    assert_eq!(\n        UnifyError::CouldNotUnify {\n            expected: crate::type_::int(),\n            given: crate::type_::float(),\n            situation: Some(UnifyErrorSituation::CaseClauseMismatch {\n                clause_location: SrcSpan::default()\n            }),\n        },\n        flip_unify_error(UnifyError::CouldNotUnify {\n            expected: crate::type_::float(),\n            given: crate::type_::int(),\n            situation: Some(UnifyErrorSituation::CaseClauseMismatch {\n                clause_location: SrcSpan::default()\n            }),\n        })\n    );\n}\n\npub fn unify_enclosed_type(\n    e1: Arc<Type>,\n    e2: Arc<Type>,\n    result: Result<(), UnifyError>,\n) -> Result<(), UnifyError> {\n    // If types cannot unify, show the type error with the enclosing types, e1 and e2.\n    match result {\n        Err(UnifyError::CouldNotUnify {\n            situation: note, ..\n        }) => Err(UnifyError::CouldNotUnify {\n            expected: e1,\n            given: e2,\n            situation: note,\n        }),\n\n        _ => result,\n    }\n}\n\n#[test]\nfn unify_enclosed_type_test() {\n    assert_eq!(\n        Err(UnifyError::CouldNotUnify {\n            expected: crate::type_::int(),\n            given: crate::type_::float(),\n            situation: Some(UnifyErrorSituation::CaseClauseMismatch {\n                clause_location: SrcSpan::default()\n            })\n        }),\n        unify_enclosed_type(\n            crate::type_::int(),\n            crate::type_::float(),\n            Err(UnifyError::CouldNotUnify {\n                expected: crate::type_::string(),\n                given: crate::type_::bit_array(),\n                situation: Some(UnifyErrorSituation::CaseClauseMismatch {\n                    clause_location: SrcSpan::default()\n                })\n            })\n        )\n    );\n}\n\npub fn unify_wrong_arity(\n    t1: &Arc<Type>,\n    arity1: usize,\n    t2: &Arc<Type>,\n    arity2: usize,\n) -> UnifyError {\n    UnifyError::CouldNotUnify {\n        expected: t1.clone(),\n        given: t2.clone(),\n        situation: Some(UnifyErrorSituation::FunctionsMismatch {\n            reason: FunctionsMismatchReason::Arity {\n                expected: arity1,\n                given: arity2,\n            },\n        }),\n    }\n}\n\npub fn unify_wrong_arguments(\n    expected: &Arc<Type>,\n    expected_arg: &Arc<Type>,\n    given: &Arc<Type>,\n    given_arg: &Arc<Type>,\n    position: usize,\n) -> UnifyError {\n    UnifyError::CouldNotUnify {\n        expected: expected.clone(),\n        given: given.clone(),\n        situation: Some(UnifyErrorSituation::FunctionsMismatch {\n            reason: FunctionsMismatchReason::Argument {\n                expected: expected_arg.clone(),\n                given: given_arg.clone(),\n                position,\n            },\n        }),\n    }\n}\n\npub fn unify_wrong_returns(\n    expected: &Arc<Type>,\n    expected_return: &Arc<Type>,\n    given: &Arc<Type>,\n    given_return: &Arc<Type>,\n) -> UnifyError {\n    UnifyError::CouldNotUnify {\n        expected: expected.clone(),\n        given: given.clone(),\n        situation: Some(UnifyErrorSituation::FunctionsMismatch {\n            reason: FunctionsMismatchReason::Results {\n                expected: expected_return.clone(),\n                given: given_return.clone(),\n            },\n        }),\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum UnifyErrorSituation {\n    /// Clauses in a case expression were found to return different types.\n    CaseClauseMismatch {\n        clause_location: SrcSpan,\n    },\n\n    /// A function was found to return a value that did not match its return\n    /// annotation.\n    ReturnAnnotationMismatch,\n\n    PipeTypeMismatch,\n\n    /// The operands of a binary operator were incorrect.\n    Operator(BinOp),\n\n    /// One of the elements of a list was not the same type as the others.\n    ListElementMismatch,\n\n    /// The tail of the list is not the same type as the other elements.\n    ListTailMismatch,\n\n    /// When two functions cannot be unified.\n    FunctionsMismatch {\n        reason: FunctionsMismatchReason,\n    },\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum FunctionsMismatchReason {\n    Results {\n        expected: Arc<Type>,\n        given: Arc<Type>,\n    },\n    Arity {\n        expected: usize,\n        given: usize,\n    },\n    Argument {\n        expected: Arc<Type>,\n        given: Arc<Type>,\n        position: usize,\n    },\n}\n\nimpl UnifyErrorSituation {\n    pub fn description(&self) -> Option<&'static str> {\n        match self {\n            Self::CaseClauseMismatch { clause_location: _ } => Some(\n                \"This case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\",\n            ),\n            Self::ReturnAnnotationMismatch => Some(\n                \"The type of this returned value doesn't match the return type\nannotation of this function.\",\n            ),\n            Self::PipeTypeMismatch => {\n                Some(\"This function cannot handle the argument sent through the (|>) pipe:\")\n            }\n            Self::Operator(_op) => None,\n\n            Self::ListElementMismatch => Some(\n                \"All elements of a list must be the same type, but this one doesn't\nmatch the one before it.\",\n            ),\n\n            Self::ListTailMismatch => Some(\n                \"All elements in a list must have the same type, but the elements of\nthis list don't match the type of the elements being prepended to it.\",\n            ),\n\n            Self::FunctionsMismatch { .. } => None,\n        }\n    }\n}\n\n#[derive(Debug, PartialEq)]\npub enum UnifyError {\n    CouldNotUnify {\n        expected: Arc<Type>,\n        given: Arc<Type>,\n        situation: Option<UnifyErrorSituation>,\n    },\n\n    ExtraVarInAlternativePattern {\n        name: EcoString,\n    },\n\n    MissingVarInAlternativePattern {\n        name: EcoString,\n    },\n\n    DuplicateVarInPattern {\n        name: EcoString,\n    },\n\n    RecursiveType,\n}\n\nimpl UnifyError {\n    pub fn with_unify_error_situation(self, situation: UnifyErrorSituation) -> Self {\n        match self {\n            Self::CouldNotUnify {\n                expected, given, ..\n            } => Self::CouldNotUnify {\n                expected,\n                given,\n                situation: Some(situation),\n            },\n            Self::ExtraVarInAlternativePattern { .. }\n            | Self::MissingVarInAlternativePattern { .. }\n            | Self::DuplicateVarInPattern { .. }\n            | Self::RecursiveType => self,\n        }\n    }\n\n    pub fn case_clause_mismatch(self, clause_location: SrcSpan) -> Self {\n        self.with_unify_error_situation(UnifyErrorSituation::CaseClauseMismatch { clause_location })\n    }\n\n    pub fn list_element_mismatch(self) -> Self {\n        self.with_unify_error_situation(UnifyErrorSituation::ListElementMismatch)\n    }\n\n    pub fn list_tail_mismatch(self) -> Self {\n        self.with_unify_error_situation(UnifyErrorSituation::ListTailMismatch)\n    }\n\n    pub fn return_annotation_mismatch(self) -> Self {\n        self.with_unify_error_situation(UnifyErrorSituation::ReturnAnnotationMismatch)\n    }\n\n    pub fn operator_situation(self, binop: BinOp) -> Self {\n        self.with_unify_error_situation(UnifyErrorSituation::Operator(binop))\n    }\n\n    pub fn into_error(self, location: SrcSpan) -> Error {\n        match self {\n            Self::CouldNotUnify {\n                expected,\n                given,\n                situation: note,\n            } => Error::CouldNotUnify {\n                location,\n                expected,\n                given,\n                situation: note,\n            },\n\n            Self::ExtraVarInAlternativePattern { name } => {\n                Error::ExtraVarInAlternativePattern { location, name }\n            }\n\n            Self::MissingVarInAlternativePattern { name } => {\n                Error::MissingVarInAlternativePattern { location, name }\n            }\n\n            Self::DuplicateVarInPattern { name } => Error::DuplicateVarInPattern { location, name },\n\n            Self::RecursiveType => Error::RecursiveType { location },\n        }\n    }\n\n    pub fn into_use_unify_error(\n        self,\n        function_location: SrcSpan,\n        pattern_location: SrcSpan,\n        last_statement_location: SrcSpan,\n        body_location: SrcSpan,\n    ) -> Error {\n        match &self {\n            // If the expected value is not a function, that means we're trying\n            // to pass something that doesn't take a function as callback to the\n            // right hand side of use.\n            Self::CouldNotUnify {\n                expected,\n                given: _,\n                situation: _,\n            } if !expected.as_ref().is_fun() => Error::UseFnDoesntTakeCallback {\n                location: function_location,\n                actual_type: Some(expected.as_ref().clone()),\n            },\n\n            Self::CouldNotUnify {\n                situation: Some(UnifyErrorSituation::FunctionsMismatch { reason }),\n                ..\n            } => match reason {\n                // If both the expected and given values are functions we can be a\n                // bit more specific with the error and highlight the reason of the\n                // problem instead of having a generic type mismatch error.\n                FunctionsMismatchReason::Results {\n                    expected: one,\n                    given: other,\n                } => Error::CouldNotUnify {\n                    location: last_statement_location,\n                    expected: one.clone(),\n                    given: other.clone(),\n                    situation: None,\n                },\n\n                FunctionsMismatchReason::Arity {\n                    expected: one,\n                    given: other,\n                } => Error::UseCallbackIncorrectArity {\n                    call_location: function_location,\n                    pattern_location,\n                    expected: *one,\n                    given: *other,\n                },\n\n                // For this one we just fallback to the generic cannot unify error\n                // as it is already plenty clear in a `use` expression.\n                FunctionsMismatchReason::Argument { .. } => self.into_error(body_location),\n            },\n\n            // In all other cases we fallback to the generic cannot unify error.\n            Self::CouldNotUnify { .. }\n            | Self::ExtraVarInAlternativePattern { .. }\n            | Self::MissingVarInAlternativePattern { .. }\n            | Self::DuplicateVarInPattern { .. }\n            | Self::RecursiveType => self.into_error(body_location),\n        }\n    }\n}\n\npub fn convert_unify_error(e: UnifyError, location: SrcSpan) -> Error {\n    e.into_error(location)\n}\n\npub fn convert_unify_call_error(e: UnifyError, location: SrcSpan, kind: ArgumentKind) -> Error {\n    match kind {\n        ArgumentKind::UseCallback {\n            function_location,\n            assignments_location,\n            last_statement_location,\n        } => e.into_use_unify_error(\n            function_location,\n            assignments_location,\n            last_statement_location,\n            location,\n        ),\n        ArgumentKind::Regular => convert_unify_error(e, location),\n    }\n}\n\n/// When targeting JavaScript, adds a warning if the given Int value is outside the range of\n/// safe integers as defined by Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER.\n///\npub fn check_javascript_int_safety(int_value: &BigInt, location: SrcSpan, problems: &mut Problems) {\n    let js_min_safe_integer = -9007199254740991i64;\n    let js_max_safe_integer = 9007199254740991i64;\n\n    if *int_value < js_min_safe_integer.into() || *int_value > js_max_safe_integer.into() {\n        problems.warning(Warning::JavaScriptIntUnsafe { location });\n    }\n}\n\n/// When targeting Erlang, adds an error if the given Float value is outside the range\n/// -1.7976931348623157e308 to 1.7976931348623157e308 which is the allowed range for\n/// Erlang's floating point numbers\n///\npub fn check_float_safety(value: LiteralFloatValue, location: SrcSpan, problems: &mut Problems) {\n    let min_float = -1.7976931348623157e308f64;\n    let max_float = 1.7976931348623157e308f64;\n\n    let float_value = value.value();\n    if float_value < min_float || float_value > max_float {\n        problems.error(Error::LiteralFloatOutOfRange { location });\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/type_/expression.rs",
    "content": "use super::{pipe::PipeTyper, *};\nuse crate::{\n    STDLIB_PACKAGE_NAME,\n    analyse::{Inferred, infer_bit_array_option, name::check_argument_names},\n    ast::{\n        Arg, Assert, Assignment, AssignmentKind, BinOp, BitArrayOption, BitArraySegment,\n        CAPTURE_VARIABLE, CallArg, Clause, ClauseGuard, Constant, FunctionLiteralKind, HasLocation,\n        ImplicitCallArgOrigin, InvalidExpression, Layer, RECORD_UPDATE_VARIABLE,\n        RecordBeingUpdated, SrcSpan, Statement, TodoKind, TypeAst, TypedArg, TypedAssert,\n        TypedAssignment, TypedClause, TypedClauseGuard, TypedConstant, TypedExpr,\n        TypedMultiPattern, TypedStatement, USE_ASSIGNMENT_VARIABLE, UntypedArg, UntypedAssert,\n        UntypedAssignment, UntypedClause, UntypedClauseGuard, UntypedConstant,\n        UntypedConstantBitArraySegment, UntypedExpr, UntypedExprBitArraySegment,\n        UntypedMultiPattern, UntypedStatement, UntypedUse, UntypedUseAssignment, Use,\n        UseAssignment,\n    },\n    build::Target,\n    exhaustiveness::{self, CompileCaseResult, CompiledCase, Reachability},\n    parse::{LiteralFloatValue, PatternPosition},\n    reference::ReferenceKind,\n};\nuse ecow::eco_format;\nuse hexpm::version::{LowestVersion, Version};\nuse im::hashmap;\nuse itertools::Itertools;\nuse num_bigint::BigInt;\nuse vec1::Vec1;\n\n#[derive(\n    Clone, Copy, Debug, Eq, PartialOrd, Ord, PartialEq, serde::Serialize, serde::Deserialize,\n)]\npub struct Implementations {\n    /// Whether the function has a pure-gleam implementation.\n    ///\n    /// It's important to notice that, even if all individual targets are\n    /// supported, it would not be the same as being pure Gleam.\n    /// Imagine this scenario:\n    ///\n    /// ```gleam\n    /// @external(javascript, \"wibble\", \"wobble\")\n    /// @external(erlang, \"wibble\", \"wobble\")\n    /// pub fn func() -> Int\n    /// ```\n    ///\n    /// `func` supports all _current_ Gleam targets; however, if a new target\n    /// is added - say a WASM target - `func` wouldn't support it! On the other\n    /// hand, a pure Gleam function will support all future targets.\n    pub gleam: bool,\n    pub can_run_on_erlang: bool,\n    pub can_run_on_javascript: bool,\n    /// Whether the function has an implementation that uses external erlang\n    /// code.\n    pub uses_erlang_externals: bool,\n    /// Whether the function has an implementation that uses external javascript\n    /// code.\n    pub uses_javascript_externals: bool,\n}\n\nimpl Implementations {\n    pub fn supporting_all() -> Self {\n        Self {\n            gleam: true,\n            can_run_on_erlang: true,\n            can_run_on_javascript: true,\n            uses_javascript_externals: false,\n            uses_erlang_externals: false,\n        }\n    }\n}\n\n/// The purity of a function.\n///\n/// This is not actually proper purity tracking, rather an approximation, which\n/// is good enough for the purpose it is currently used for: warning for unused\n/// pure functions. The current system contains some false negatives, i.e. some\n/// cases where it will fail to emit a warning when it probably should.\n///\n/// If we wanted to properly track function side effects - say to perform\n/// optimisations on pure Gleam code - we would probably need to lift that\n/// tracking into the type system, the same way that variant inference currently\n/// works. This would require quite a lot of work and doesn't seem a worthwhile\n/// amount of effort for a single warning message, where a much simpler solution\n/// is generally going to be good enough.\n///\n/// In the future we may want to implement a full side effect tracking system;\n/// this current implementation will not be sufficient for anything beyond a\n/// warning message to help people out in certain cases.\n///\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Purity {\n    /// The function is in pure Gleam, and does not reference any language\n    /// feature that can cause side effects, such as `panic`, `assert` or `echo`.\n    /// It also does not call any impure functions.\n    Pure,\n    /// This function is part of the standard library, or an otherwise trusted\n    /// source, and though it might use FFI, we can trust that the FFI function\n    /// will not cause any side effects.\n    TrustedPure,\n    /// This function is impure because it either uses FFI, panics, uses `echo`,\n    /// or calls another impure function.\n    Impure,\n    /// We don't know the purity of this function. This highlights the main issue\n    /// with the current purity tracking system. In the following code for example:\n    ///\n    /// ```gleam\n    /// let f = function.identity\n    ///\n    /// f(10)\n    /// ```\n    ///\n    /// Since purity is not currently part of the type system, when analysing the\n    /// call of the local `f` function, we now have no information about the\n    /// purity of it, and therefore cannot infer the consequences of calling it.\n    ///\n    /// If there was a `purity` or `side_effects` field in the `Type::Fn` variant,\n    /// we would be able to properly infer it.\n    ///\n    Unknown,\n}\n\nimpl Purity {\n    pub fn is_pure(&self) -> bool {\n        match self {\n            Purity::Pure | Purity::TrustedPure => true,\n            Purity::Impure | Purity::Unknown => false,\n        }\n    }\n\n    #[must_use]\n    pub fn merge(self, other: Purity) -> Purity {\n        match (self, other) {\n            // If we call a trusted pure function, the current function remains pure\n            (Purity::Pure, Purity::TrustedPure) => Purity::Pure,\n            (Purity::Pure, other) => other,\n\n            // If we call a pure function, the current function remains trusted pure\n            (Purity::TrustedPure, Purity::Pure) => Purity::TrustedPure,\n            (Purity::TrustedPure, other) => other,\n\n            // Nothing can make an already impure function pure again\n            (Purity::Impure, _) => Purity::Impure,\n\n            // If we call an impure function from a function we don't know the\n            // purity of, we are now certain that it is impure.\n            (Purity::Unknown, Purity::Impure) => Purity::Impure,\n            (Purity::Unknown, _) => Purity::Impure,\n        }\n    }\n}\n\n/// Tracking whether the function being currently type checked has externals\n/// implementations or not.\n/// This is used to determine whether an error should be raised in the case when\n/// a value is used that does not have an implementation for the current target.\n#[derive(Clone, Copy, Debug)]\npub struct FunctionDefinition {\n    /// The function has { ... } after the function head\n    pub has_body: bool,\n    /// The function has @external(erlang, \"...\", \"...\")\n    pub has_erlang_external: bool,\n    /// The function has @external(JavaScript, \"...\", \"...\")\n    pub has_javascript_external: bool,\n}\n\nimpl FunctionDefinition {\n    pub fn has_external_for_target(&self, target: Target) -> bool {\n        match target {\n            Target::Erlang => self.has_erlang_external,\n            Target::JavaScript => self.has_javascript_external,\n        }\n    }\n}\n\nimpl Implementations {\n    /// Given the implementations of a function update those with taking into\n    /// account the `implementations` of another function (or constant) used\n    /// inside its body.\n    pub fn update_from_use(\n        &mut self,\n        implementations: &Implementations,\n        current_function_definition: &FunctionDefinition,\n    ) {\n        // With this pattern matching we won't forget to deal with new targets\n        // when those are added :)\n        let Implementations {\n            gleam,\n            uses_erlang_externals: other_uses_erlang_externals,\n            uses_javascript_externals: other_uses_javascript_externals,\n            can_run_on_erlang: other_can_run_on_erlang,\n            can_run_on_javascript: other_can_run_on_javascript,\n        } = implementations;\n        let FunctionDefinition {\n            has_body: _,\n            has_erlang_external,\n            has_javascript_external,\n        } = current_function_definition;\n\n        // If a pure-Gleam function uses a function that doesn't have a pure\n        // Gleam implementation, then it's no longer pure-Gleam.\n        self.gleam = self.gleam && *gleam;\n\n        // A function can run on a target if the code that it uses can run on on\n        // the same target,\n        self.can_run_on_erlang = *has_erlang_external\n            || (self.can_run_on_erlang && (*gleam || *other_can_run_on_erlang));\n        self.can_run_on_javascript = *has_javascript_external\n            || (self.can_run_on_javascript && (*gleam || *other_can_run_on_javascript));\n\n        // If a function uses a function that relies on external code (be it\n        // javascript or erlang) then it's considered as using external code as\n        // well.\n        //\n        // For example:\n        // ```gleam\n        // @external(erlang, \"wibble\", \"wobble\")\n        // pub fn erlang_only_with_pure_gleam_default() -> Int {\n        //   1 + 1\n        // }\n        //\n        // pub fn main() { erlang_only_with_pure_gleam_default() }\n        // ```\n        // Both functions will end up using external erlang code and have the\n        // following implementations:\n        // `Implementations { gleam: true, uses_erlang_externals: true, uses_javascript_externals: false}`.\n        // They have a pure gleam implementation and an erlang specific external\n        // implementation.\n        self.uses_erlang_externals = self.uses_erlang_externals || *other_uses_erlang_externals;\n        self.uses_javascript_externals =\n            self.uses_javascript_externals || *other_uses_javascript_externals;\n    }\n\n    /// Returns true if the current target is supported by the given\n    /// implementations.\n    /// If something has a pure gleam implementation then it supports all\n    /// targets automatically.\n    pub fn supports(&self, target: Target) -> bool {\n        self.gleam\n            || match target {\n                Target::Erlang => self.can_run_on_erlang,\n                Target::JavaScript => self.can_run_on_javascript,\n            }\n    }\n}\n\n/// This is used to tell apart regular function calls and `use` expressions:\n/// a `use` is still typed as if it were a normal function call but we want to\n/// be able to tell the difference in order to provide better error message.\n///\n#[derive(Eq, PartialEq, Debug, Copy, Clone)]\npub enum CallKind {\n    Function,\n    Use {\n        call_location: SrcSpan,\n        assignments_location: SrcSpan,\n        last_statement_location: SrcSpan,\n    },\n}\n\n/// This is used to tell apart regular call arguments and the callback that is\n/// implicitly passed to a `use` function call.\n/// Both are going to be typed as usual but we want to tell them apart in order\n/// to report better error messages for `use` expressions.\n///\n#[derive(Eq, PartialEq, Debug, Copy, Clone)]\npub enum ArgumentKind {\n    Regular,\n    UseCallback {\n        function_location: SrcSpan,\n        assignments_location: SrcSpan,\n        last_statement_location: SrcSpan,\n    },\n}\n\n#[derive(Debug)]\npub(crate) struct ExprTyper<'a, 'b> {\n    pub(crate) environment: &'a mut Environment<'b>,\n\n    /// The minimum Gleam version required to compile the typed expression.\n    pub minimum_required_version: Version,\n\n    // This is set to true if the previous expression that has been typed is\n    // determined to always panic.\n    // For example when typing a literal `panic`, this flag will be set to true.\n    // The same goes, for example, if the branches of a case expression all\n    // panic.\n    pub(crate) previous_panics: bool,\n\n    // This is used to track if we've already warned for unreachable code.\n    // After emitting the first unreachable code warning we never emit another\n    // one to avoid flooding with repetitive warnings.\n    pub(crate) already_warned_for_unreachable_code: bool,\n\n    pub(crate) implementations: Implementations,\n    pub(crate) purity: Purity,\n    pub(crate) current_function_definition: FunctionDefinition,\n\n    // Type hydrator for creating types from annotations\n    pub(crate) hydrator: Hydrator,\n\n    // Accumulated errors and warnings found while typing the expression\n    pub(crate) problems: &'a mut Problems,\n}\n\nimpl<'a, 'b> ExprTyper<'a, 'b> {\n    pub fn new(\n        environment: &'a mut Environment<'b>,\n        definition: FunctionDefinition,\n        problems: &'a mut Problems,\n    ) -> Self {\n        let mut hydrator = Hydrator::new();\n\n        let implementations = Implementations {\n            // We start assuming the function is pure Gleam and narrow it down\n            // if we run into functions/constants that have only external\n            // implementations for some of the targets.\n            gleam: definition.has_body,\n            can_run_on_erlang: definition.has_body || definition.has_erlang_external,\n            can_run_on_javascript: definition.has_body || definition.has_javascript_external,\n            uses_erlang_externals: definition.has_erlang_external,\n            uses_javascript_externals: definition.has_javascript_external,\n        };\n\n        let uses_externals = match environment.target {\n            Target::Erlang => implementations.uses_erlang_externals,\n            Target::JavaScript => implementations.uses_javascript_externals,\n        };\n\n        let purity = if is_trusted_pure_module(environment) {\n            // The standard library uses a lot of FFI, but as we are the\n            // maintainers we know that it can be trusted to be pure.\n            Purity::TrustedPure\n        } else if uses_externals {\n            Purity::Impure\n        } else {\n            Purity::Pure\n        };\n\n        hydrator.permit_holes(true);\n        Self {\n            hydrator,\n            previous_panics: false,\n            already_warned_for_unreachable_code: false,\n            environment,\n            implementations,\n            purity,\n            current_function_definition: definition,\n            minimum_required_version: Version::new(0, 1, 0),\n            problems,\n        }\n    }\n\n    fn in_new_scope<T, E>(\n        &mut self,\n        process_scope: impl FnOnce(&mut Self) -> Result<T, E>,\n    ) -> Result<T, E> {\n        self.scoped(|this| {\n            let result = process_scope(this);\n            let was_successful = result.is_ok();\n            (result, was_successful)\n        })\n    }\n\n    fn value_in_new_scope<A>(&mut self, process_scope: impl FnOnce(&mut Self) -> A) -> A {\n        self.scoped(|this| (process_scope(this), true))\n    }\n\n    fn expr_in_new_scope(\n        &mut self,\n        process_scope: impl FnOnce(&mut Self) -> TypedExpr,\n    ) -> TypedExpr {\n        self.scoped(|this| {\n            let expr = process_scope(this);\n            let was_successful = !expr.is_invalid();\n            (expr, was_successful)\n        })\n    }\n\n    fn scoped<A>(&mut self, process_scope: impl FnOnce(&mut Self) -> (A, bool)) -> A {\n        // Create new scope\n        let environment_reset_data = self.environment.open_new_scope();\n        let hydrator_reset_data = self.hydrator.open_new_scope();\n\n        // Process the scope\n        let (result, was_successful) = process_scope(self);\n\n        // Close scope, discarding any scope local state\n        self.environment\n            .close_scope(environment_reset_data, was_successful, self.problems);\n        self.hydrator.close_scope(hydrator_reset_data);\n        result\n    }\n\n    pub fn type_from_ast(&mut self, ast: &TypeAst) -> Result<Arc<Type>, Error> {\n        self.hydrator\n            .type_from_ast(ast, self.environment, self.problems)\n    }\n\n    fn instantiate(&mut self, t: Arc<Type>, ids: &mut im::HashMap<u64, Arc<Type>>) -> Arc<Type> {\n        self.environment.instantiate(t, ids, &self.hydrator)\n    }\n\n    pub fn new_unbound_var(&mut self) -> Arc<Type> {\n        self.environment.new_unbound_var()\n    }\n\n    pub fn infer_or_error(&mut self, expr: UntypedExpr) -> Result<TypedExpr, Error> {\n        if self.previous_panics {\n            self.warn_for_unreachable_code(expr.location(), PanicPosition::PreviousExpression);\n        }\n\n        match expr {\n            UntypedExpr::Todo {\n                location,\n                message: label,\n                kind,\n                ..\n            } => Ok(self.infer_todo(location, kind, label)),\n\n            UntypedExpr::Panic {\n                location, message, ..\n            } => Ok(self.infer_panic(location, message)),\n\n            UntypedExpr::Echo {\n                location,\n                keyword_end,\n                expression,\n                message,\n            } => Ok(self.infer_echo(location, keyword_end, expression, message)),\n\n            UntypedExpr::Var { location, name, .. } => {\n                self.infer_var(name, location, ReferenceRegistration::Register)\n            }\n\n            UntypedExpr::Int {\n                location,\n                value,\n                int_value,\n                ..\n            } => {\n                if self.environment.target == Target::JavaScript\n                    && !self.current_function_definition.has_javascript_external\n                {\n                    check_javascript_int_safety(&int_value, location, self.problems);\n                }\n\n                Ok(self.infer_int(value, int_value, location))\n            }\n\n            UntypedExpr::Block {\n                statements,\n                location,\n            } => Ok(self.infer_block(statements, location)),\n\n            UntypedExpr::Tuple {\n                location, elements, ..\n            } => Ok(self.infer_tuple(elements, location)),\n\n            UntypedExpr::Float {\n                location,\n                value,\n                float_value,\n            } => {\n                check_float_safety(float_value, location, self.problems);\n                Ok(self.infer_float(value, float_value, location))\n            }\n\n            UntypedExpr::String {\n                location, value, ..\n            } => Ok(self.infer_string(value, location)),\n\n            UntypedExpr::PipeLine { expressions } => Ok(self.infer_pipeline(expressions)),\n\n            UntypedExpr::Fn {\n                location,\n                kind,\n                arguments,\n                body,\n                return_annotation,\n                ..\n            } => Ok(self.infer_fn(arguments, &[], body, kind, return_annotation, location)),\n\n            UntypedExpr::Case {\n                location,\n                subjects,\n                clauses,\n                ..\n            } => Ok(self.infer_case(subjects, clauses, location)),\n\n            UntypedExpr::List {\n                location,\n                elements,\n                tail,\n            } => Ok(self.infer_list(elements, tail, location)),\n\n            UntypedExpr::Call {\n                location,\n                fun,\n                arguments,\n                ..\n            } => Ok(self.infer_call(*fun, arguments, location, CallKind::Function)),\n\n            UntypedExpr::BinOp {\n                location,\n                name,\n                name_location,\n                left,\n                right,\n            } => Ok(self.infer_binop(name, name_location, *left, *right, location)),\n\n            UntypedExpr::FieldAccess {\n                label_location,\n                label,\n                container,\n                location,\n            } => Ok(self.infer_field_access(\n                *container,\n                location,\n                label,\n                label_location,\n                FieldAccessUsage::Other,\n            )),\n\n            UntypedExpr::TupleIndex {\n                location,\n                index,\n                tuple,\n                ..\n            } => self.infer_tuple_index(*tuple, index, location),\n\n            UntypedExpr::BitArray { location, segments } => {\n                self.infer_bit_array(segments, location)\n            }\n\n            UntypedExpr::RecordUpdate {\n                location,\n                constructor,\n                record,\n                arguments,\n            } => self.infer_record_update(*constructor, record, arguments, location),\n\n            UntypedExpr::NegateBool { location, value } => {\n                Ok(self.infer_negate_bool(location, *value))\n            }\n\n            UntypedExpr::NegateInt { location, value } => {\n                Ok(self.infer_negate_int(location, *value))\n            }\n        }\n    }\n\n    fn infer_pipeline(&mut self, expressions: Vec1<UntypedExpr>) -> TypedExpr {\n        PipeTyper::infer(self, expressions)\n    }\n\n    fn infer_todo(\n        &mut self,\n        location: SrcSpan,\n        kind: TodoKind,\n        message: Option<Box<UntypedExpr>>,\n    ) -> TypedExpr {\n        // Type the todo as whatever it would need to be to type check.\n        let type_ = self.new_unbound_var();\n\n        // Emit a warning that there is a todo in the code.\n        let warning_location = match kind {\n            TodoKind::Keyword | TodoKind::IncompleteUse | TodoKind::EmptyBlock => location,\n            TodoKind::EmptyFunction { function_location } => function_location,\n        };\n        self.problems.warning(Warning::Todo {\n            kind,\n            location: warning_location,\n            type_: type_.clone(),\n        });\n\n        self.purity = Purity::Impure;\n\n        let message = message.map(|message| Box::new(self.infer_and_unify(*message, string())));\n        TypedExpr::Todo {\n            location,\n            type_,\n            message,\n            kind,\n        }\n    }\n\n    fn infer_panic(&mut self, location: SrcSpan, message: Option<Box<UntypedExpr>>) -> TypedExpr {\n        let type_ = self.new_unbound_var();\n        self.purity = Purity::Impure;\n\n        let message = message.map(|message| Box::new(self.infer_and_unify(*message, string())));\n        self.previous_panics = true;\n        TypedExpr::Panic {\n            location,\n            type_,\n            message,\n        }\n    }\n\n    fn infer_echo(\n        &mut self,\n        location: SrcSpan,\n        keyword_end: u32,\n        expression: Option<Box<UntypedExpr>>,\n        message: Option<Box<UntypedExpr>>,\n    ) -> TypedExpr {\n        self.environment.echo_found = true;\n        self.purity = Purity::Impure;\n\n        let expression = if let Some(expression) = expression {\n            let expression = self.infer(*expression);\n            if self.previous_panics {\n                self.warn_for_unreachable_code(location, PanicPosition::EchoExpression);\n            }\n            expression\n        } else {\n            let location = SrcSpan {\n                start: location.start,\n                end: keyword_end,\n            };\n            self.problems\n                .error(Error::EchoWithNoFollowingExpression { location });\n            self.error_expr(location)\n        };\n\n        TypedExpr::Echo {\n            location,\n            type_: expression.type_(),\n            expression: Some(Box::new(expression)),\n            message: message.map(|message| Box::new(self.infer_and_unify(*message, string()))),\n        }\n    }\n\n    pub(crate) fn warn_for_unreachable_code(\n        &mut self,\n        location: SrcSpan,\n        panic_position: PanicPosition,\n    ) {\n        // We don't want to warn twice for unreachable code inside the same\n        // block, so we have to keep track if we've already emitted a warning of\n        // this kind.\n        if !self.already_warned_for_unreachable_code {\n            self.already_warned_for_unreachable_code = true;\n            self.problems.warning(Warning::UnreachableCodeAfterPanic {\n                location,\n                panic_position,\n            })\n        }\n    }\n\n    fn infer_string(&mut self, value: EcoString, location: SrcSpan) -> TypedExpr {\n        TypedExpr::String {\n            location,\n            value,\n            type_: string(),\n        }\n    }\n\n    fn infer_int(&mut self, value: EcoString, int_value: BigInt, location: SrcSpan) -> TypedExpr {\n        TypedExpr::Int {\n            location,\n            value,\n            int_value,\n            type_: int(),\n        }\n    }\n\n    fn infer_float(\n        &mut self,\n        value: EcoString,\n        float_value: LiteralFloatValue,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        TypedExpr::Float {\n            location,\n            value,\n            float_value,\n            type_: float(),\n        }\n    }\n\n    /// Emit a warning if the given expressions should not be discarded.\n    /// e.g. because it's a literal (why was it made in the first place?)\n    /// e.g. because it's of the `Result` type (errors should be handled)\n    fn expression_discarded(&mut self, discarded: &TypedExpr) {\n        if discarded.is_literal() {\n            self.problems.warning(Warning::UnusedLiteral {\n                location: discarded.location(),\n            });\n        } else if discarded.type_().is_result() {\n            self.problems.warning(Warning::ImplicitlyDiscardedResult {\n                location: discarded.location(),\n            });\n        } else if discarded.is_pure_value_constructor() {\n            self.problems.warning(Warning::UnusedValue {\n                location: discarded.location(),\n            })\n        }\n    }\n\n    pub(crate) fn infer_statements(\n        &mut self,\n        untyped: Vec1<UntypedStatement>,\n    ) -> Vec1<TypedStatement> {\n        let count = untyped.len();\n        let location = SrcSpan::new(\n            untyped.first().location().start,\n            untyped.last().location().end,\n        );\n        self.infer_iter_statements(location, count, untyped.into_iter())\n    }\n\n    // Helper to create a new error expr.\n    fn error_expr(&mut self, location: SrcSpan) -> TypedExpr {\n        TypedExpr::Invalid {\n            location,\n            type_: self.new_unbound_var(),\n            extra_information: None,\n        }\n    }\n\n    fn error_expr_with_information(\n        &mut self,\n        location: SrcSpan,\n        extra_information: Option<InvalidExpression>,\n    ) -> TypedExpr {\n        TypedExpr::Invalid {\n            location,\n            type_: self.new_unbound_var(),\n            extra_information,\n        }\n    }\n\n    fn infer_iter_statements<StatementsIter: Iterator<Item = UntypedStatement>>(\n        &mut self,\n        location: SrcSpan,\n        count: usize,\n        mut untyped: StatementsIter,\n    ) -> Vec1<TypedStatement> {\n        let mut i = 0;\n        let mut statements: Vec<TypedStatement> = Vec::with_capacity(count);\n\n        while let Some(statement) = untyped.next() {\n            i += 1;\n\n            match statement {\n                Statement::Use(use_) => {\n                    let statement = self.infer_use(use_, location, untyped.collect());\n                    statements.push(statement);\n                    break; // Inferring the use has consumed the rest of the exprs\n                }\n                Statement::Expression(expression) => {\n                    let location = expression.location();\n                    let expression = match self.infer_or_error(expression) {\n                        Ok(expression) => expression,\n                        Err(error) => {\n                            self.problems.error(error);\n                            self.error_expr(location)\n                        }\n                    };\n\n                    // This isn't the final expression in the sequence, so call the\n                    // `expression_discarded` function to see if anything is being\n                    // discarded that we think shouldn't be.\n                    if i < count {\n                        self.expression_discarded(&expression);\n                    }\n                    statements.push(Statement::Expression(expression));\n                }\n                Statement::Assignment(assignment) => {\n                    let assignment = self.infer_assignment(*assignment);\n                    statements.push(Statement::Assignment(Box::new(assignment)));\n                }\n                Statement::Assert(assert) => {\n                    let assert = self.infer_assert(assert);\n                    statements.push(Statement::Assert(assert));\n                }\n            }\n        }\n\n        Vec1::try_from_vec(statements).expect(\"empty sequence\")\n    }\n\n    fn infer_use(\n        &mut self,\n        use_: UntypedUse,\n        sequence_location: SrcSpan,\n        mut following_expressions: Vec<UntypedStatement>,\n    ) -> TypedStatement {\n        let use_call_location = use_.call.location();\n        let mut call = get_use_expression_call(*use_.call);\n        let assignments = UseAssignments::from_use_expression(use_.assignments);\n\n        let assignments_count = assignments.body_assignments.len();\n        let mut statements = assignments.body_assignments;\n\n        if following_expressions.is_empty() {\n            let todo = Statement::Expression(UntypedExpr::Todo {\n                location: use_.location,\n                message: None,\n                kind: TodoKind::IncompleteUse,\n            });\n            statements.push(todo);\n        } else {\n            statements.append(&mut following_expressions);\n        }\n\n        let statements = Vec1::try_from_vec(statements).expect(\"safe: todo added above\");\n\n        // We need this to report good error messages in case there's a type error\n        // in use. We consider `use` to be the last statement of a block since\n        // it consumes everything that comes below it and returns a single value.\n        let last_statement_location = statements\n            .iter()\n            .find_or_last(|statement| statement.is_use())\n            .expect(\"safe: iter from non empty vec\")\n            .location();\n\n        let first = statements.first().location();\n\n        // Collect the following expressions into a function to be passed as a\n        // callback to the use's call function.\n        let callback = UntypedExpr::Fn {\n            arguments: assignments.function_arguments,\n            location: SrcSpan::new(first.start, sequence_location.end),\n            end_of_head_byte_index: sequence_location.end,\n            return_annotation: None,\n            kind: FunctionLiteralKind::Use {\n                location: use_.location,\n            },\n            body: statements,\n        };\n\n        // Add this new callback function to the arguments to function call\n        call.arguments.push(CallArg {\n            label: None,\n            location: SrcSpan::new(first.start, sequence_location.end),\n            value: callback,\n            // This argument is implicitly given by Gleam's use syntax so we\n            // mark it as such.\n            implicit: Some(ImplicitCallArgOrigin::Use),\n        });\n\n        let call_location = SrcSpan {\n            start: use_.location.start,\n            end: sequence_location.end,\n        };\n\n        // We use `stacker` to prevent overflowing the stack when many `use`\n        // expressions are chained. See https://github.com/gleam-lang/gleam/issues/4287\n        let infer_call = || {\n            self.infer_call(\n                *call.function,\n                call.arguments,\n                call_location,\n                CallKind::Use {\n                    call_location: use_call_location,\n                    assignments_location: use_.assignments_location,\n                    last_statement_location,\n                },\n            )\n        };\n        let call = stacker::maybe_grow(128 * 1024, 2 * 1024 * 1024, infer_call);\n\n        // After typing the call we know that the last argument must be an\n        // anonymous function and the first assignments in its body are the\n        // typed assignments on the left hand side of a `use`.\n        let assignments = extract_typed_use_call_assignments(&call, assignments_count);\n\n        Statement::Use(Use {\n            call: Box::new(call),\n            location: use_.location,\n            right_hand_side_location: use_.right_hand_side_location,\n            assignments_location: use_.assignments_location,\n            assignments,\n        })\n    }\n\n    fn infer_negate_bool(&mut self, location: SrcSpan, value: UntypedExpr) -> TypedExpr {\n        self.infer_multiple_negate_bool(location, 1, location, value)\n    }\n\n    fn infer_multiple_negate_bool(\n        &mut self,\n        starting_location: SrcSpan,\n        negations: usize,\n        location: SrcSpan,\n        value: UntypedExpr,\n    ) -> TypedExpr {\n        // If we're typing a double negation we just keep going increasing the\n        // number of consecutive negations, inferring the wrapped value.\n        if let UntypedExpr::NegateBool {\n            location: inner_location,\n            value,\n        } = value\n        {\n            return TypedExpr::NegateBool {\n                location,\n                value: Box::new(self.infer_multiple_negate_bool(\n                    starting_location,\n                    negations + 1,\n                    inner_location,\n                    *value,\n                )),\n            };\n        }\n\n        // We know the last value can't be a bool negation if we're here, so\n        // we're ready to produce a typed value!\n        let value = self.infer(value);\n        if let Err(error) = unify(bool(), value.type_()) {\n            self.problems\n                .error(convert_unify_error(error, value.location()));\n        }\n\n        // If there's more than a single negation we can raise a warning\n        // highlighting the unneded ones. How many negations are highlighted\n        // depends if they're an even or odd number:\n        //\n        // ```gleam\n        // !!True   // all negations are superfluous.\n        // !!!True  // we can remove all but one negation.\n        // ```\n        if negations > 1 {\n            let location = if negations.is_multiple_of(2) {\n                SrcSpan {\n                    start: starting_location.start,\n                    end: location.start + 1,\n                }\n            } else {\n                SrcSpan {\n                    start: starting_location.start,\n                    end: location.start,\n                }\n            };\n\n            self.problems\n                .warning(Warning::UnnecessaryDoubleBoolNegation { location });\n        }\n\n        TypedExpr::NegateBool {\n            location,\n            value: Box::new(value),\n        }\n    }\n\n    fn infer_negate_int(&mut self, location: SrcSpan, value: UntypedExpr) -> TypedExpr {\n        self.infer_multiple_negate_int(location, 1, location, value)\n    }\n\n    fn infer_multiple_negate_int(\n        &mut self,\n        starting_location: SrcSpan,\n        mut negations: usize,\n        location: SrcSpan,\n        value: UntypedExpr,\n    ) -> TypedExpr {\n        // If we're typing a double negation we just keep going increasing the\n        // number of consecutive negations, inferring the wrapped value.\n        if let UntypedExpr::NegateInt {\n            location: inner_location,\n            value,\n        } = value\n        {\n            return TypedExpr::NegateInt {\n                location,\n                value: Box::new(self.infer_multiple_negate_int(\n                    starting_location,\n                    negations + 1,\n                    inner_location,\n                    *value,\n                )),\n            };\n        }\n\n        // We know the last value can't be an int negation, so we're ready to\n        // produce a typed value!\n        let value = self.infer(value);\n        if let Err(error) = unify(int(), value.type_()) {\n            self.problems\n                .error(convert_unify_error(error, value.location()));\n        }\n\n        // This is used to emit a warning in case there's multiple negations.\n        let mut end = location.start;\n\n        // There's one special case where the final integer being typed might be\n        // negated as well, in that case we need to update the number of\n        // consecutive negations.\n        if let TypedExpr::Int {\n            value: ref v,\n            ref location,\n            ..\n        } = value\n            && v.starts_with('-')\n        {\n            negations += 1;\n            end = location.start;\n        }\n\n        // If there's more than a single negation we can raise a warning\n        // highlighting the unneded ones. How many negations are highlighted\n        // depends if they're an even or odd number:\n        //\n        // ```gleam\n        // --1   // all negations are superfluous.\n        // ---1  // we can remove all but one negation.\n        // ```\n        if negations > 1 {\n            let location = if negations.is_multiple_of(2) {\n                SrcSpan {\n                    start: starting_location.start,\n                    end: end + 1,\n                }\n            } else {\n                SrcSpan {\n                    start: starting_location.start,\n                    end,\n                }\n            };\n\n            self.problems\n                .warning(Warning::UnnecessaryDoubleIntNegation { location });\n        }\n\n        TypedExpr::NegateInt {\n            location,\n            value: Box::new(value),\n        }\n    }\n\n    fn infer_fn(\n        &mut self,\n        arguments: Vec<UntypedArg>,\n        expected_arguments: &[Arc<Type>],\n        body: Vec1<UntypedStatement>,\n        kind: FunctionLiteralKind,\n        return_annotation: Option<TypeAst>,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        for Arg { names, .. } in arguments.iter() {\n            check_argument_names(names, self.problems);\n        }\n\n        let already_warned_for_unreachable_code = self.already_warned_for_unreachable_code;\n        self.already_warned_for_unreachable_code = false;\n        self.previous_panics = false;\n\n        let outer_purity = self.purity;\n\n        // If an anonymous function can panic, that doesn't mean that the outer\n        // function can too, so we track the purity separately. For example, in\n        // this code:\n        //\n        // ```gleam\n        // pub fn divide_partial(dividend: Int) {\n        //   fn(divisor) {\n        //     case divisor {\n        //       0 -> panic as \"Cannot divide by 0\"\n        //       _ -> dividend / divisor\n        //     }\n        //   }\n        // }\n        // ```\n        //\n        // Although the `divide_partial` function uses the `panic` keyword, it is\n        // actually pure. Only the anonymous function that it constructs is impure;\n        // constructing and returning it does not have any side effects, so there is\n        // no way for a call to `divide_partial` to produce any side effects.\n        self.purity = Purity::Pure;\n\n        let (arguments, body) = match self.do_infer_fn(\n            None,\n            arguments,\n            expected_arguments,\n            body,\n            &return_annotation,\n        ) {\n            Ok(result) => result,\n            Err(error) => {\n                self.problems.error(error);\n                return self.error_expr(location);\n            }\n        };\n        let arguments_types = arguments.iter().map(|a| a.type_.clone()).collect();\n        let type_ = fn_(arguments_types, body.last().type_());\n\n        // Defining an anonymous function never panics.\n        self.already_warned_for_unreachable_code = already_warned_for_unreachable_code;\n        self.previous_panics = false;\n\n        let function_purity = self.purity;\n        self.purity = outer_purity;\n\n        TypedExpr::Fn {\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n            purity: function_purity,\n        }\n    }\n\n    fn infer_arg(\n        &mut self,\n        arg: UntypedArg,\n        expected: Option<Arc<Type>>,\n    ) -> Result<TypedArg, Error> {\n        let Arg {\n            names,\n            annotation,\n            location,\n            ..\n        } = arg;\n        let type_ = annotation\n            .clone()\n            .map(|type_| self.type_from_ast(&type_))\n            .unwrap_or_else(|| Ok(self.new_unbound_var()))?;\n\n        match &names {\n            ArgNames::Named { .. } | ArgNames::NamedLabelled { .. } => (),\n            ArgNames::Discard { name, .. } | ArgNames::LabelledDiscard { name, .. } => {\n                let _ = self\n                    .environment\n                    .discarded_names\n                    .insert(name.clone(), location);\n            }\n        }\n\n        // If we know the expected type of the argument from its contextual\n        // usage then unify the newly constructed type with the expected type.\n        // We do this here because then there is more type information for the\n        // function being type checked, resulting in better type errors and the\n        // record field access syntax working.\n        if let Some(expected) = expected {\n            unify(expected, type_.clone()).map_err(|e| convert_unify_error(e, location))?;\n        }\n\n        Ok(Arg {\n            names,\n            location,\n            annotation,\n            type_,\n        })\n    }\n\n    fn infer_call(\n        &mut self,\n        fun: UntypedExpr,\n        arguments: Vec<CallArg<UntypedExpr>>,\n        location: SrcSpan,\n        kind: CallKind,\n    ) -> TypedExpr {\n        let (fun, arguments, type_) = self.do_infer_call(fun, arguments, location, kind);\n\n        // One common mistake is to think that the syntax for adding a message\n        // to a `todo` or a `panic` exception is to `todo(\"...\")`, but really\n        // this does nothing as the `todo` or `panic` throws the exception\n        // before it gets to the function call `(\"...\")`.\n        // If we find code doing this then emit a warning.\n        let todopanic = match fun {\n            TypedExpr::Todo { .. } => Some((location, TodoOrPanic::Todo)),\n            TypedExpr::Panic { .. } => Some((location, TodoOrPanic::Panic)),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        };\n        if let Some((location, kind)) = todopanic {\n            let arguments_location = match (arguments.first(), arguments.last()) {\n                (Some(first), Some(last)) => Some(SrcSpan {\n                    start: first.location().start,\n                    end: last.location().end,\n                }),\n                _ => None,\n            };\n            self.problems.warning(Warning::TodoOrPanicUsedAsFunction {\n                kind,\n                location,\n                arguments_location,\n                arguments: arguments.len(),\n            });\n        }\n\n        self.purity = self.purity.merge(fun.called_function_purity());\n\n        TypedExpr::Call {\n            location,\n            type_,\n            arguments,\n            fun: Box::new(fun),\n        }\n    }\n\n    fn infer_list(\n        &mut self,\n        elements: Vec<UntypedExpr>,\n        tail: Option<Box<UntypedExpr>>,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        let type_ = self.new_unbound_var();\n        // Type check each elements\n        let mut inferred_elements = Vec::with_capacity(elements.len());\n        for element in elements {\n            let element = self.infer(element);\n            if let Err(error) = unify(type_.clone(), element.type_()) {\n                self.problems.error(convert_unify_error(\n                    error.list_element_mismatch(),\n                    element.location(),\n                ))\n            };\n            inferred_elements.push(element);\n        }\n\n        // Type check the ..tail, if there is one\n        let type_ = list(type_);\n        let tail = match tail {\n            Some(tail) => {\n                let tail = self.infer(*tail);\n                // Ensure the tail has the same type as the preceding elements\n                if let Err(error) = unify(type_.clone(), tail.type_()) {\n                    self.problems.error(convert_unify_error(\n                        error.list_tail_mismatch(),\n                        tail.location(),\n                    ))\n                }\n                Some(Box::new(tail))\n            }\n            None => None,\n        };\n        TypedExpr::List {\n            location,\n            type_,\n            elements: inferred_elements,\n            tail,\n        }\n    }\n\n    fn infer_tuple(&mut self, elements: Vec<UntypedExpr>, location: SrcSpan) -> TypedExpr {\n        let elements = elements\n            .into_iter()\n            .map(|element| self.infer(element))\n            .collect_vec();\n        let type_ = tuple(elements.iter().map(HasType::type_).collect_vec());\n        TypedExpr::Tuple {\n            location,\n            elements,\n            type_,\n        }\n    }\n\n    fn infer_var(\n        &mut self,\n        name: EcoString,\n        location: SrcSpan,\n        register_reference: ReferenceRegistration,\n    ) -> Result<TypedExpr, Error> {\n        let constructor =\n            self.do_infer_value_constructor(&None, &name, &location, register_reference)?;\n        self.narrow_implementations(location, &constructor.variant)?;\n        Ok(TypedExpr::Var {\n            constructor,\n            location,\n            name,\n        })\n    }\n\n    fn narrow_implementations(\n        &mut self,\n        location: SrcSpan,\n        variant: &ValueConstructorVariant,\n    ) -> Result<(), Error> {\n        let variant_implementations = match variant {\n            ValueConstructorVariant::ModuleConstant {\n                implementations, ..\n            } => implementations,\n            ValueConstructorVariant::ModuleFn {\n                implementations, ..\n            } => implementations,\n            ValueConstructorVariant::Record { .. }\n            | ValueConstructorVariant::LocalVariable { .. } => return Ok(()),\n        };\n\n        self.implementations\n            .update_from_use(variant_implementations, &self.current_function_definition);\n\n        if self.environment.target_support.is_enforced()\n            // If the value used doesn't have an implementation that can be used\n            // for the current target...\n            && !variant_implementations.supports(self.environment.target)\n            // ... and there is not an external implementation for it\n            && !self\n                    .current_function_definition\n                    .has_external_for_target(self.environment.target)\n        {\n            Err(Error::UnsupportedExpressionTarget {\n                target: self.environment.target,\n                location,\n            })\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Attempts to infer a record access. If the attempt fails, then will fallback to attempting to infer a module access.\n    /// If both fail, then the error from the record access will be used.\n    fn infer_field_access(\n        &mut self,\n        container: UntypedExpr,\n\n        // The SrcSpan of the entire field access:\n        // ```gleam\n        //    wibble.wobble\n        // // ^^^^^^^^^^^^^ This\n        // ```\n        //\n        location: SrcSpan,\n        label: EcoString,\n\n        // The SrcSpan of the selection label:\n        // ```gleam\n        //    wibble.wobble\n        // // ^^^^^^ This\n        // ```\n        //\n        label_location: SrcSpan,\n        usage: FieldAccessUsage,\n    ) -> TypedExpr {\n        let container_location = container.location();\n\n        // Computes a potential module access. This will be used if a record access can't be used.\n        // Computes both the inferred access and if it shadows a variable.\n        let module_access = if let UntypedExpr::Var { name, .. } = &container {\n            let module_access =\n                self.infer_module_access(name, label.clone(), &container_location, label_location);\n            // Returns the result and if it shadows an existing variable in scope\n            Some((module_access, self.environment.scope.contains_key(name)))\n        } else {\n            None\n        };\n        let record = if let UntypedExpr::Var { location, name } = container {\n            // If the left-hand-side of the record access is a variable, this might actually be\n            // module access. In that case, we only want to register a reference to the variable\n            // if we actually referencing it in the record access.\n            self.infer_var(name, location, ReferenceRegistration::DoNotRegister)\n        } else {\n            self.infer_or_error(container)\n        };\n        // TODO: is this clone avoidable? we need to box the record for inference in both\n        // the success case and in the valid record but invalid label case\n        let record_access = match record.clone() {\n            Ok(record) => self.infer_known_record_expression_access(\n                record,\n                label.clone(),\n                location,\n                label_location,\n                container_location.start,\n                usage,\n            ),\n            Err(e) => Err(e),\n        };\n        match (record_access, module_access) {\n            // Record access is valid\n            (Ok(record_access), _) => {\n                // If this is actually record access and not module access, and we didn't register\n                // the reference earlier, we register it now.\n                if let TypedExpr::RecordAccess { record, .. } = &record_access\n                    && let TypedExpr::Var {\n                        location,\n                        constructor,\n                        name,\n                    } = record.as_ref()\n                {\n                    self.register_value_constructor_reference(\n                        name,\n                        &constructor.variant,\n                        *location,\n                        ReferenceKind::Unqualified,\n                    )\n                }\n                record_access\n            }\n            // Record access is invalid but module access is valid\n            (\n                _,\n                Some((\n                    Ok(TypedExpr::ModuleSelect {\n                        location,\n                        field_start,\n                        type_,\n                        label,\n                        module_name,\n                        module_alias,\n                        constructor,\n                    }),\n                    _,\n                )),\n            ) => {\n                // We only register the reference here, if we know that this is a module access.\n                // Otherwise we would register module access even if we are actually accessing\n                // the field on a record\n                self.environment.references.register_value_reference(\n                    module_name.clone(),\n                    label.clone(),\n                    &label,\n                    SrcSpan::new(field_start, location.end),\n                    ReferenceKind::Qualified,\n                );\n                TypedExpr::ModuleSelect {\n                    location,\n                    field_start,\n                    type_,\n                    label,\n                    module_name,\n                    module_alias,\n                    constructor,\n                }\n            }\n            // If module access failed because the module exists but that module does not export\n            // the referenced value, we return extra information about the invalid module select,\n            // so that we have information about the attempted module select and can use it, for\n            // example, in the \"Generate function\" code action to support other modules.\n            (\n                _,\n                Some((\n                    Err(Error::UnknownModuleValue {\n                        name,\n                        module_name,\n                        location,\n                        value_constructors,\n                        type_with_same_name,\n                        context,\n                    }),\n                    false,\n                )),\n            ) => {\n                self.problems.error(Error::UnknownModuleValue {\n                    name: name.clone(),\n                    module_name: module_name.clone(),\n                    location,\n                    value_constructors,\n                    type_with_same_name,\n                    context,\n                });\n                TypedExpr::Invalid {\n                    location,\n                    type_: self.new_unbound_var(),\n                    extra_information: Some(InvalidExpression::ModuleSelect { module_name, label }),\n                }\n            }\n            // If module access failed for some other reason, and no local variable shadows the\n            // module, we just return an invalid expression.\n            (_, Some((Err(module_access_err), false))) => {\n                self.problems.error(module_access_err);\n                TypedExpr::Invalid {\n                    location,\n                    type_: self.new_unbound_var(),\n                    extra_information: None,\n                }\n            }\n            // In any other case use the record access for the error\n            (Err(record_access_err), _) => {\n                self.problems.error(record_access_err);\n                match record {\n                    // If the record is valid then use a placeholder access\n                    // This allows autocomplete to know a record access is being attempted\n                    // Even if the access is not valid\n                    Ok(record) => TypedExpr::RecordAccess {\n                        location,\n                        field_start: container_location.start,\n                        type_: self.new_unbound_var(),\n                        label: \"\".into(),\n                        index: u64::MAX,\n                        record: Box::new(record),\n                        documentation: None,\n                    },\n                    Err(_) => TypedExpr::Invalid {\n                        location,\n                        type_: self.new_unbound_var(),\n                        extra_information: None,\n                    },\n                }\n            }\n        }\n    }\n\n    fn infer_tuple_index(\n        &mut self,\n        tuple: UntypedExpr,\n        index: u64,\n        location: SrcSpan,\n    ) -> Result<TypedExpr, Error> {\n        if let UntypedExpr::TupleIndex { .. } = tuple {\n            self.track_feature_usage(FeatureKind::NestedTupleAccess, location);\n        }\n\n        let tuple = self.infer_or_error(tuple)?;\n        match collapse_links(tuple.type_()).as_ref() {\n            Type::Tuple { elements } => {\n                let type_ = elements\n                    .get(index as usize)\n                    .ok_or_else(|| Error::OutOfBoundsTupleIndex {\n                        location: SrcSpan {\n                            start: tuple.location().end,\n                            end: location.end,\n                        },\n                        index,\n                        size: elements.len(),\n                    })?\n                    .clone();\n                Ok(TypedExpr::TupleIndex {\n                    location,\n                    index,\n                    tuple: Box::new(tuple),\n                    type_,\n                })\n            }\n\n            type_ if type_.is_unbound() => Err(Error::NotATupleUnbound {\n                location: tuple.location(),\n            }),\n\n            Type::Named { .. } | Type::Fn { .. } | Type::Var { .. } => Err(Error::NotATuple {\n                location: tuple.location(),\n                given: tuple.type_(),\n            }),\n        }\n    }\n\n    fn infer_bit_array(\n        &mut self,\n        segments: Vec<UntypedExprBitArraySegment>,\n        location: SrcSpan,\n    ) -> Result<TypedExpr, Error> {\n        let segments = segments\n            .into_iter()\n            .map(|mut segment| {\n                // If the segment doesn't have an explicit type option we add a default\n                // one ourselves if the pattern is unambiguous: literal strings are\n                // implicitly considered utf-8 encoded strings, while floats are\n                // implicitly given the float type option.\n                if !segment.has_type_option() {\n                    match segment.value.as_ref() {\n                        UntypedExpr::String { location, .. } => {\n                            self.track_feature_usage(\n                                FeatureKind::UnannotatedUtf8StringSegment,\n                                *location,\n                            );\n                            segment.options.push(BitArrayOption::Utf8 {\n                                location: SrcSpan::default(),\n                            });\n                        }\n\n                        UntypedExpr::Float { location, .. } => {\n                            self.track_feature_usage(\n                                FeatureKind::UnannotatedFloatSegment,\n                                *location,\n                            );\n                            segment.options.push(BitArrayOption::Float {\n                                location: SrcSpan::default(),\n                            })\n                        }\n\n                        UntypedExpr::Int { .. }\n                        | UntypedExpr::Block { .. }\n                        | UntypedExpr::Var { .. }\n                        | UntypedExpr::Fn { .. }\n                        | UntypedExpr::List { .. }\n                        | UntypedExpr::Call { .. }\n                        | UntypedExpr::BinOp { .. }\n                        | UntypedExpr::PipeLine { .. }\n                        | UntypedExpr::Case { .. }\n                        | UntypedExpr::FieldAccess { .. }\n                        | UntypedExpr::Tuple { .. }\n                        | UntypedExpr::TupleIndex { .. }\n                        | UntypedExpr::Todo { .. }\n                        | UntypedExpr::Panic { .. }\n                        | UntypedExpr::Echo { .. }\n                        | UntypedExpr::BitArray { .. }\n                        | UntypedExpr::RecordUpdate { .. }\n                        | UntypedExpr::NegateBool { .. }\n                        | UntypedExpr::NegateInt { .. } => (),\n                    }\n                }\n\n                let segment = self.infer_bit_segment(\n                    *segment.value,\n                    segment.options,\n                    segment.location,\n                    |env, expr| env.infer_or_error(expr),\n                );\n\n                if let Ok(segment) = &segment {\n                    // If we could successfully infer the segment we need to\n                    // check if it's `size` option uses any feature that has to\n                    // be tracked!\n                    self.check_segment_size_expression(&segment.options);\n                };\n\n                segment\n            })\n            .try_collect()?;\n\n        Ok(TypedExpr::BitArray {\n            location,\n            segments,\n            type_: bit_array(),\n        })\n    }\n\n    fn infer_constant_bit_array(\n        &mut self,\n        segments: Vec<UntypedConstantBitArraySegment>,\n        location: SrcSpan,\n    ) -> Result<TypedConstant, Error> {\n        let segments = segments\n            .into_iter()\n            .map(|mut segment| {\n                // If the segment doesn't have an explicit type option we add a default\n                // one ourselves if the pattern is unambiguous: literal strings are\n                // implicitly considered utf-8 encoded strings, while floats are\n                // implicitly given the float type option.\n                if !segment.has_type_option() {\n                    match segment.value.as_ref() {\n                        Constant::String { location, .. } => {\n                            self.track_feature_usage(\n                                FeatureKind::UnannotatedUtf8StringSegment,\n                                *location,\n                            );\n                            segment.options.push(BitArrayOption::Utf8 {\n                                location: SrcSpan::default(),\n                            });\n                        }\n\n                        Constant::Float { location, .. } => {\n                            self.track_feature_usage(\n                                FeatureKind::UnannotatedFloatSegment,\n                                *location,\n                            );\n                            segment.options.push(BitArrayOption::Float {\n                                location: SrcSpan::default(),\n                            })\n                        }\n\n                        Constant::Int { .. }\n                        | Constant::Tuple { .. }\n                        | Constant::List { .. }\n                        | Constant::Record { .. }\n                        | Constant::RecordUpdate { .. }\n                        | Constant::BitArray { .. }\n                        | Constant::Var { .. }\n                        | Constant::StringConcatenation { .. }\n                        | Constant::Invalid { .. } => (),\n                    }\n                }\n\n                let segment = self.infer_bit_segment(\n                    *segment.value,\n                    segment.options,\n                    segment.location,\n                    |env, expr| Ok(env.infer_const(&None, expr)),\n                );\n\n                if let Ok(segment) = &segment {\n                    // If we could successfully infer the segment we need to\n                    // check if it's `size` option uses any feature that has to\n                    // be tracked!\n                    self.check_constant_segment_size_expression(&segment.options);\n                }\n\n                segment\n            })\n            .try_collect()?;\n\n        Ok(Constant::BitArray { location, segments })\n    }\n\n    fn infer_bit_segment<UntypedValue, TypedValue, InferFn>(\n        &mut self,\n        value: UntypedValue,\n        options: Vec<BitArrayOption<UntypedValue>>,\n        location: SrcSpan,\n        mut infer: InferFn,\n    ) -> Result<BitArraySegment<TypedValue, Arc<Type>>, Error>\n    where\n        InferFn: FnMut(&mut Self, UntypedValue) -> Result<TypedValue, Error>,\n        TypedValue: HasType + HasLocation + Clone + bit_array::GetLiteralValue,\n    {\n        let value = infer(self, value)?;\n\n        let infer_option = |segment_option: BitArrayOption<UntypedValue>| {\n            infer_bit_array_option(segment_option, |value, type_| {\n                let typed_value = infer(self, value)?;\n                unify(type_, typed_value.type_())\n                    .map_err(|e| convert_unify_error(e, typed_value.location()))?;\n                Ok(typed_value)\n            })\n        };\n\n        let options: Vec<_> = options.into_iter().map(infer_option).try_collect()?;\n\n        let type_ = bit_array::type_options_for_value(&options, self.environment.target).map_err(\n            |error| Error::BitArraySegmentError {\n                error: error.error,\n                location: error.location,\n            },\n        )?;\n\n        // Track usage of the unaligned bit arrays feature on JavaScript so that\n        // warnings can be emitted if the Gleam version constraint is too low\n        if self.environment.target == Target::JavaScript\n            && !self.current_function_definition.has_javascript_external\n        {\n            for option in options.iter() {\n                if let BitArrayOption::<TypedValue>::Size {\n                    value, location, ..\n                } = option\n                {\n                    let mut using_unaligned_bit_array = false;\n\n                    if type_.is_int() {\n                        match &(**value).as_int_literal() {\n                            Some(size) if size % 8 != BigInt::ZERO => {\n                                using_unaligned_bit_array = true;\n                            }\n                            _ => (),\n                        }\n                    } else if type_.is_bit_array() {\n                        using_unaligned_bit_array = true;\n                    }\n\n                    if using_unaligned_bit_array {\n                        self.track_feature_usage(\n                            FeatureKind::JavaScriptUnalignedBitArray,\n                            *location,\n                        );\n                        break;\n                    }\n                }\n            }\n        }\n\n        unify(type_.clone(), value.type_())\n            .map_err(|e| convert_unify_error(e, value.location()))?;\n\n        let segment = BitArraySegment {\n            location,\n            type_,\n            value: Box::new(value),\n            options,\n        };\n\n        if let Some(truncation) = segment.check_for_truncated_value() {\n            self.problems\n                .warning(Warning::BitArraySegmentTruncatedValue {\n                    location,\n                    truncation,\n                });\n        }\n\n        Ok(segment)\n    }\n\n    /// Same as `self.infer_or_error` but instead of returning a `Result` with an error,\n    /// records the error and returns an invalid expression.\n    ///\n    pub fn infer(&mut self, expression: UntypedExpr) -> TypedExpr {\n        let location = expression.location();\n        match self.infer_or_error(expression) {\n            Ok(result) => result,\n            Err(error) => {\n                let information = if let Error::UnknownVariable { name, .. } = &error {\n                    Some(InvalidExpression::UnknownVariable { name: name.clone() })\n                } else {\n                    None\n                };\n\n                self.problems.error(error);\n                self.error_expr_with_information(location, information)\n            }\n        }\n    }\n\n    /// Infers the type of the given function and tries to unify it with the\n    /// given type, recording any unification error that might take place.\n    /// The typed expression is returned in any case.\n    ///\n    pub fn infer_and_unify(&mut self, expression: UntypedExpr, type_: Arc<Type>) -> TypedExpr {\n        let expression = self.infer(expression);\n        if let Err(error) = unify(type_, expression.type_()) {\n            self.problems\n                .error(convert_unify_error(error, expression.location()))\n        }\n        expression\n    }\n\n    fn infer_binop(\n        &mut self,\n        name: BinOp,\n        name_location: SrcSpan,\n        left: UntypedExpr,\n        right: UntypedExpr,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        let (input_type, output_type) = match &name {\n            BinOp::Eq | BinOp::NotEq => {\n                let left = self.infer(left);\n                let right = self.infer(right);\n                if let Err(error) = unify(left.type_(), right.type_()) {\n                    self.problems\n                        .error(convert_unify_error(error, right.location()));\n                } else {\n                    // We only want to warn for redundant comparisons if it\n                    // makes sense to compare the two values.\n                    // That is, their types should match!\n                    self.check_for_redundant_comparison(name, &left, &right, location);\n                }\n\n                self.check_for_inefficient_empty_list_check(name, &left, &right, location);\n\n                return TypedExpr::BinOp {\n                    location,\n                    name,\n                    name_location,\n                    type_: bool(),\n                    left: Box::new(left),\n                    right: Box::new(right),\n                };\n            }\n            BinOp::And => (bool(), bool()),\n            BinOp::Or => (bool(), bool()),\n            BinOp::LtInt => (int(), bool()),\n            BinOp::LtEqInt => (int(), bool()),\n            BinOp::LtFloat => (float(), bool()),\n            BinOp::LtEqFloat => (float(), bool()),\n            BinOp::GtEqInt => (int(), bool()),\n            BinOp::GtInt => (int(), bool()),\n            BinOp::GtEqFloat => (float(), bool()),\n            BinOp::GtFloat => (float(), bool()),\n            BinOp::AddInt => (int(), int()),\n            BinOp::AddFloat => (float(), float()),\n            BinOp::SubInt => (int(), int()),\n            BinOp::SubFloat => (float(), float()),\n            BinOp::MultInt => (int(), int()),\n            BinOp::MultFloat => (float(), float()),\n            BinOp::DivInt => (int(), int()),\n            BinOp::DivFloat => (float(), float()),\n            BinOp::RemainderInt => (int(), int()),\n            BinOp::Concatenate => (string(), string()),\n        };\n\n        let left = self.infer(left);\n        let right = self.infer(right);\n        let unify_left = unify(input_type.clone(), left.type_());\n        let unify_right = unify(input_type.clone(), right.type_());\n\n        if unify_left.is_ok() && unify_right.is_ok() {\n            // We only want to warn for redundant comparisons if it makes sense\n            // to compare the two values. That is, their types should match!\n            self.check_for_redundant_comparison(name, &left, &right, location);\n        }\n\n        // There's some common cases in which we can provide nicer error messages:\n        // - if we're using a float operator on int values\n        // - if we're using an int operator on float values\n        // - if we're using `+` on strings\n        if name.is_float_operator() && left.type_().is_int() && right.type_().is_int() {\n            self.problems.error(Error::FloatOperatorOnInts {\n                operator: name,\n                location: name_location,\n            })\n        } else if name.is_int_operator() && left.type_().is_float() && right.type_().is_float() {\n            self.problems.error(Error::IntOperatorOnFloats {\n                operator: name,\n                location: name_location,\n            })\n        } else if name == BinOp::AddInt && left.type_().is_string() && right.type_().is_string() {\n            self.problems.error(Error::StringConcatenationWithAddInt {\n                location: name_location,\n            })\n        } else {\n            // In all other cases we just report an error for each of the operands.\n            if let Err(error) = unify_left {\n                self.problems.error(\n                    error\n                        .operator_situation(name)\n                        .into_error(left.type_defining_location()),\n                );\n            }\n            if let Err(error) = unify_right {\n                self.problems.error(\n                    error\n                        .operator_situation(name)\n                        .into_error(right.type_defining_location()),\n                );\n            }\n        }\n\n        self.check_for_inefficient_empty_list_check(name, &left, &right, location);\n\n        TypedExpr::BinOp {\n            location,\n            name,\n            name_location,\n            type_: output_type,\n            left: Box::new(left),\n            right: Box::new(right),\n        }\n    }\n\n    /// Checks for inefficient usage of `list.length` for checking for the empty list.\n    ///\n    /// If we find one of these usages, emit a warning to use comparison with empty list instead.\n    fn check_for_inefficient_empty_list_check(\n        &mut self,\n        binop: BinOp,\n        left: &TypedExpr,\n        right: &TypedExpr,\n        location: SrcSpan,\n    ) {\n        // Look for a call expression as either of the binary operands.\n        let fun = match (&left, &right) {\n            (TypedExpr::Call { fun, .. }, _) | (_, TypedExpr::Call { fun, .. }) => fun,\n            _ => return,\n        };\n\n        // Extract the module information from the call expression.\n        let (module_name, module_alias, label) = if let TypedExpr::ModuleSelect {\n            module_name,\n            module_alias,\n            label,\n            ..\n        } = fun.as_ref()\n        {\n            (module_name, module_alias, label)\n        } else {\n            return;\n        };\n\n        // Check if we have a `list.length` call from `gleam/list`.\n        if module_name != \"gleam/list\" || label != \"length\" {\n            return;\n        }\n\n        // Resolve the module against the imported modules we have available.\n        let list_module = match self.environment.imported_modules.get(module_alias) {\n            Some((_, list_module)) => list_module,\n            None => return,\n        };\n\n        // Check that we're actually using `list.length` from the standard library.\n        if list_module.package != STDLIB_PACKAGE_NAME {\n            return;\n        }\n\n        // Check the kind of the empty list check so we know whether to recommend\n        // `== []` or `!= []` syntax as a replacement.\n        let kind = match get_empty_list_check_kind(binop, left, right) {\n            Some(kind) => kind,\n            None => return,\n        };\n\n        // If we've gotten this far, go ahead and emit the warning.\n        self.problems\n            .warning(Warning::InefficientEmptyListCheck { location, kind });\n    }\n\n    fn check_for_redundant_comparison(\n        &mut self,\n        binop: BinOp,\n        left: &TypedExpr,\n        right: &TypedExpr,\n        location: SrcSpan,\n    ) {\n        let outcome = match (left, binop, right) {\n            (left, BinOp::Eq, right) => match static_compare(left, right) {\n                StaticComparison::CertainlyEqual => ComparisonOutcome::AlwaysSucceeds,\n                StaticComparison::CertainlyDifferent => ComparisonOutcome::AlwaysFails,\n                StaticComparison::CantTell => return,\n            },\n\n            (left, BinOp::NotEq, right) => match static_compare(left, right) {\n                StaticComparison::CertainlyEqual => ComparisonOutcome::AlwaysFails,\n                StaticComparison::CertainlyDifferent => ComparisonOutcome::AlwaysSucceeds,\n                StaticComparison::CantTell => return,\n            },\n\n            // We special handle int literals as there's other comparisons we\n            // might want to perform\n            (TypedExpr::Int { int_value: n, .. }, op, TypedExpr::Int { int_value: m, .. }) => {\n                match op {\n                    BinOp::LtInt if n < m => ComparisonOutcome::AlwaysSucceeds,\n                    BinOp::LtInt => ComparisonOutcome::AlwaysFails,\n                    BinOp::LtEqInt if n <= m => ComparisonOutcome::AlwaysSucceeds,\n                    BinOp::LtEqInt => ComparisonOutcome::AlwaysFails,\n                    BinOp::GtInt if n > m => ComparisonOutcome::AlwaysSucceeds,\n                    BinOp::GtInt => ComparisonOutcome::AlwaysFails,\n                    BinOp::GtEqInt if n >= m => ComparisonOutcome::AlwaysSucceeds,\n                    BinOp::GtEqInt => ComparisonOutcome::AlwaysFails,\n                    BinOp::And\n                    | BinOp::Or\n                    | BinOp::Eq\n                    | BinOp::NotEq\n                    | BinOp::LtFloat\n                    | BinOp::LtEqFloat\n                    | BinOp::GtEqFloat\n                    | BinOp::GtFloat\n                    | BinOp::AddInt\n                    | BinOp::AddFloat\n                    | BinOp::SubInt\n                    | BinOp::SubFloat\n                    | BinOp::MultInt\n                    | BinOp::MultFloat\n                    | BinOp::DivInt\n                    | BinOp::DivFloat\n                    | BinOp::RemainderInt\n                    | BinOp::Concatenate => return,\n                }\n            }\n\n            (\n                TypedExpr::Float { float_value: n, .. },\n                op,\n                TypedExpr::Float { float_value: m, .. },\n            ) => match op {\n                BinOp::LtFloat if n < m => ComparisonOutcome::AlwaysSucceeds,\n                BinOp::LtFloat => ComparisonOutcome::AlwaysFails,\n                BinOp::LtEqFloat if n <= m => ComparisonOutcome::AlwaysSucceeds,\n                BinOp::LtEqFloat => ComparisonOutcome::AlwaysFails,\n                BinOp::GtFloat if n > m => ComparisonOutcome::AlwaysSucceeds,\n                BinOp::GtFloat => ComparisonOutcome::AlwaysFails,\n                BinOp::GtEqFloat if n >= m => ComparisonOutcome::AlwaysSucceeds,\n                BinOp::GtEqFloat => ComparisonOutcome::AlwaysFails,\n                BinOp::And\n                | BinOp::Or\n                | BinOp::Eq\n                | BinOp::NotEq\n                | BinOp::LtInt\n                | BinOp::LtEqInt\n                | BinOp::GtEqInt\n                | BinOp::GtInt\n                | BinOp::AddInt\n                | BinOp::AddFloat\n                | BinOp::SubInt\n                | BinOp::SubFloat\n                | BinOp::MultInt\n                | BinOp::MultFloat\n                | BinOp::DivInt\n                | BinOp::DivFloat\n                | BinOp::RemainderInt\n                | BinOp::Concatenate => return,\n            },\n\n            _ => return,\n        };\n\n        self.problems\n            .warning(Warning::RedundantComparison { location, outcome });\n    }\n\n    fn infer_assignment(&mut self, assignment: UntypedAssignment) -> TypedAssignment {\n        let Assignment {\n            pattern,\n            value,\n            kind,\n            annotation,\n            location,\n            compiled_case: _,\n        } = assignment;\n        let value = self.expr_in_new_scope(|this| this.infer(value));\n        let type_ = value.type_();\n        let kind = self.infer_assignment_kind(kind.clone());\n\n        // Ensure the pattern matches the type of the value\n        let mut pattern_typer = pattern::PatternTyper::new(\n            self.environment,\n            &self.current_function_definition,\n            &self.hydrator,\n            self.problems,\n            PatternPosition::LetAssignment,\n        );\n\n        let pattern = pattern_typer.infer_single_pattern(pattern, &value);\n\n        let minimum_required_version = pattern_typer.minimum_required_version;\n        if minimum_required_version > self.minimum_required_version {\n            self.minimum_required_version = minimum_required_version;\n        }\n\n        let pattern_typechecked_successfully = !pattern_typer.error_encountered;\n\n        // Check that any type annotation is accurate.\n        if let Some(annotation) = &annotation {\n            match self\n                .type_from_ast(annotation)\n                .map(|type_| self.instantiate(type_, &mut hashmap![]))\n            {\n                Ok(annotated_type) => {\n                    if let Err(error) = unify(annotated_type, type_.clone())\n                        .map_err(|e| convert_unify_error(e, value.type_defining_location()))\n                    {\n                        self.problems.error(error);\n                    }\n                }\n                Err(error) => {\n                    self.problems.error(error);\n                }\n            }\n        }\n\n        // The exhaustiveness checker expects patterns to be valid and to type check;\n        // if they are invalid, it will crash. Therefore, if any errors were found\n        // when type checking the pattern, we don't perform the exhaustiveness check.\n        if !pattern_typechecked_successfully {\n            return Assignment {\n                location,\n                annotation,\n                kind,\n                compiled_case: CompiledCase::failure(),\n                pattern,\n                value,\n            };\n        }\n\n        let (output, not_exhaustive_error) =\n            self.check_let_exhaustiveness(location, value.type_(), &pattern);\n\n        match (&kind, not_exhaustive_error) {\n            // The pattern is exhaustive in a let assignment, there's no problem here.\n            (AssignmentKind::Let | AssignmentKind::Generated, Ok(_)) => (),\n\n            // If the pattern is not exhaustive and we're not asserting we want to\n            // report the error!\n            (AssignmentKind::Let | AssignmentKind::Generated, Err(e)) => {\n                self.problems.error(e);\n            }\n\n            // If we're asserting but the pattern already covers all cases then the\n            // `assert` is redundant and can be safely removed.\n            (\n                AssignmentKind::Assert {\n                    location,\n                    assert_keyword_start,\n                    ..\n                },\n                Ok(_),\n            ) => self.problems.warning(Warning::RedundantAssertAssignment {\n                location: SrcSpan::new(*assert_keyword_start, location.end),\n            }),\n\n            // Otherwise, if the pattern is never reachable (through variant inference),\n            // we can warn the user about this.\n            (AssignmentKind::Assert { .. }, Err(_)) => {\n                // There is only one pattern to match, so it is index 0\n                match output.is_reachable(0, 0) {\n                    Reachability::Unreachable(UnreachablePatternReason::ImpossibleVariant) => self\n                        .problems\n                        .warning(Warning::AssertAssignmentOnImpossiblePattern {\n                            location: pattern.location(),\n                            reason: AssertImpossiblePattern::InferredVariant,\n                        }),\n\n                    Reachability::Unreachable(UnreachablePatternReason::ImpossibleSegments(\n                        segments,\n                    )) => self\n                        .problems\n                        .warning(Warning::AssertAssignmentOnImpossiblePattern {\n                            location: pattern.location(),\n                            reason: AssertImpossiblePattern::ImpossibleSegments { segments },\n                        }),\n                    // A duplicate pattern warning should not happen, since there is only one pattern.\n                    Reachability::Reachable\n                    | Reachability::Unreachable(UnreachablePatternReason::DuplicatePattern) => {}\n                }\n            }\n        };\n\n        Assignment {\n            location,\n            annotation,\n            kind,\n            compiled_case: output.compiled_case,\n            pattern,\n            value,\n        }\n    }\n\n    fn infer_assignment_kind(\n        &mut self,\n        kind: AssignmentKind<UntypedExpr>,\n    ) -> AssignmentKind<TypedExpr> {\n        match kind {\n            AssignmentKind::Let => AssignmentKind::Let,\n            AssignmentKind::Generated => AssignmentKind::Generated,\n            AssignmentKind::Assert {\n                location,\n                message,\n                assert_keyword_start,\n            } => {\n                self.purity = Purity::Impure;\n                let message = match message {\n                    Some(message) => {\n                        self.track_feature_usage(\n                            FeatureKind::LetAssertWithMessage,\n                            message.location(),\n                        );\n                        Some(self.infer_and_unify(message, string()))\n                    }\n                    None => None,\n                };\n                AssignmentKind::Assert {\n                    location,\n                    message,\n                    assert_keyword_start,\n                }\n            }\n        }\n    }\n\n    fn infer_assert(&mut self, assert: UntypedAssert) -> TypedAssert {\n        let Assert {\n            value,\n            location,\n            message,\n        } = assert;\n        let value_location = value.location();\n\n        let value = self.infer(value);\n\n        self.purity = Purity::Impure;\n\n        if value.is_known_bool() {\n            self.problems.warning(Warning::AssertLiteralBool {\n                location: value_location,\n            });\n        }\n\n        match unify(bool(), value.type_()) {\n            Ok(()) => {}\n            Err(error) => self\n                .problems\n                .error(convert_unify_error(error, value_location)),\n        }\n\n        let message = message.map(|message| self.infer_and_unify(message, string()));\n        self.track_feature_usage(FeatureKind::BoolAssert, location);\n\n        Assert {\n            location,\n            value,\n            message,\n        }\n    }\n\n    fn infer_case(\n        &mut self,\n        subjects: Vec<UntypedExpr>,\n        clauses: Option<Vec<UntypedClause>>,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        let subjects_count = subjects.len();\n        let mut typed_subjects = Vec::with_capacity(subjects_count);\n        let mut subject_types = Vec::with_capacity(subjects_count);\n\n        let return_type = self.new_unbound_var();\n\n        self.previous_panics = false;\n        let mut any_subject_panics = false;\n        for subject in subjects {\n            let subject = self.expr_in_new_scope(|this| this.infer(subject));\n            any_subject_panics = any_subject_panics || self.previous_panics;\n            subject_types.push(subject.type_());\n            typed_subjects.push(subject);\n        }\n\n        let clauses = match clauses {\n            Some(clauses) => clauses,\n            None => {\n                self.problems.error(Error::MissingCaseBody { location });\n                return TypedExpr::Case {\n                    location,\n                    type_: return_type,\n                    compiled_case: CompiledCase::failure(),\n                    subjects: typed_subjects,\n                    clauses: Vec::new(),\n                };\n            }\n        };\n\n        let mut typed_clauses = Vec::with_capacity(clauses.len());\n        let mut has_a_guard = false;\n        let mut all_patterns_are_discards = true;\n        // NOTE: if there are 0 clauses then there are 0 panics\n        let mut all_clauses_panic = !clauses.is_empty();\n        let mut patterns_typechecked_successfully = true;\n\n        for clause in clauses {\n            has_a_guard = has_a_guard || clause.guard.is_some();\n            all_patterns_are_discards =\n                all_patterns_are_discards && clause.pattern.iter().all(|p| p.is_discard());\n\n            self.previous_panics = false;\n            let (typed_clause, error_typing_patterns) = self.infer_clause(clause, &typed_subjects);\n            if error_typing_patterns {\n                patterns_typechecked_successfully = false\n            }\n            all_clauses_panic = all_clauses_panic && self.previous_panics;\n\n            if let Err(error) = unify(return_type.clone(), typed_clause.then.type_()) {\n                self.problems.error(\n                    error\n                        .case_clause_mismatch(typed_clause.location)\n                        .into_error(typed_clause.then.type_defining_location()),\n                );\n            }\n            typed_clauses.push(typed_clause);\n        }\n\n        self.previous_panics = all_clauses_panic || any_subject_panics;\n\n        // The exhaustiveness checker expects patterns to be valid and to type check;\n        // if they are invalid, it will crash. Therefore, if any errors were found\n        // when type checking the pattern, we don't perform the exhaustiveness check.\n        let compiled_case = if patterns_typechecked_successfully {\n            self.check_case_exhaustiveness(location, &subject_types, &typed_clauses)\n        } else {\n            CompiledCase::failure()\n        };\n\n        // We track if the case expression is used like an if: that is all its\n        // patterns are discarded and there's at least a guard. For example:\n        // ```gleam\n        // case True {\n        //   _ if condition -> todo\n        //   _ if other_condition -> todo\n        //   _ -> todo\n        // }\n        // ```\n        // This is the only case were it actually makes sense to match on a\n        // constant value so when checking, we won't emit warnings for matching\n        // on a literal value in this case.\n        let case_used_like_if = all_patterns_are_discards && has_a_guard;\n        typed_subjects\n            .iter()\n            .filter_map(|subject| check_subject_for_redundant_match(subject, case_used_like_if))\n            .for_each(|warning| self.problems.warning(warning));\n\n        TypedExpr::Case {\n            location,\n            compiled_case,\n            type_: return_type,\n            subjects: typed_subjects,\n            clauses: typed_clauses,\n        }\n    }\n\n    /// Returns a tuple with the typed clause and a bool that is true if an error\n    /// was encountered while typing the clause patterns.\n    ///\n    fn infer_clause(\n        &mut self,\n        clause: UntypedClause,\n        subjects: &[TypedExpr],\n    ) -> (TypedClause, bool) {\n        let Clause {\n            pattern,\n            alternative_patterns,\n            guard,\n            then,\n            location,\n        } = clause;\n        self.value_in_new_scope(|this| {\n            let (typed_pattern, typed_alternatives, error_encountered) =\n                this.infer_clause_pattern(pattern, alternative_patterns, subjects, &location);\n\n            let guard = match this.infer_optional_clause_guard(guard) {\n                Ok(guard) => guard,\n                // If an error occurs inferring guard then assume no guard\n                Err(error) => {\n                    this.problems.error(error);\n                    None\n                }\n            };\n            let then = this.infer(then);\n            let clause = Clause {\n                location,\n                pattern: typed_pattern,\n                alternative_patterns: typed_alternatives,\n                guard,\n                then,\n            };\n            (clause, error_encountered)\n        })\n    }\n\n    fn infer_clause_pattern(\n        &mut self,\n        pattern: UntypedMultiPattern,\n        alternatives: Vec<UntypedMultiPattern>,\n        subjects: &[TypedExpr],\n        location: &SrcSpan,\n    ) -> (TypedMultiPattern, Vec<TypedMultiPattern>, bool) {\n        let mut pattern_typer = pattern::PatternTyper::new(\n            self.environment,\n            &self.current_function_definition,\n            &self.hydrator,\n            self.problems,\n            PatternPosition::CaseClause,\n        );\n\n        let typed_pattern = pattern_typer.infer_multi_pattern(pattern, subjects);\n\n        // Each case clause has one or more patterns that may match the\n        // subject in order for the clause to be selected, so we must type\n        // check every pattern.\n        let mut typed_alternatives = Vec::with_capacity(alternatives.len());\n        for m in alternatives {\n            typed_alternatives\n                .push(pattern_typer.infer_alternative_multi_pattern(m, subjects, location));\n        }\n\n        let minimum_required_version = pattern_typer.minimum_required_version;\n        if minimum_required_version > self.minimum_required_version {\n            self.minimum_required_version = minimum_required_version;\n        }\n\n        (\n            typed_pattern,\n            typed_alternatives,\n            pattern_typer.error_encountered,\n        )\n    }\n\n    fn infer_optional_clause_guard(\n        &mut self,\n        guard: Option<UntypedClauseGuard>,\n    ) -> Result<Option<TypedClauseGuard>, Error> {\n        match guard {\n            // If there is no guard we do nothing\n            None => Ok(None),\n\n            // If there is a guard we assert that it is of type Bool\n            Some(guard) => {\n                let guard = self.infer_clause_guard(guard)?;\n                unify(bool(), guard.type_())\n                    .map_err(|e| convert_unify_error(e, guard.location()))?;\n                Ok(Some(guard))\n            }\n        }\n    }\n\n    fn infer_clause_guard(&mut self, guard: UntypedClauseGuard) -> Result<TypedClauseGuard, Error> {\n        match guard {\n            ClauseGuard::Var { location, name, .. } => {\n                let constructor = self.infer_value_constructor(&None, &name, &location)?;\n\n                // We cannot support all values in guard expressions as the BEAM does not\n                let (definition_location, origin) = match &constructor.variant {\n                    ValueConstructorVariant::LocalVariable {\n                        location, origin, ..\n                    } => (*location, origin.clone()),\n                    ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::Record { .. } => {\n                        return Err(Error::NonLocalClauseGuardVariable { location, name });\n                    }\n\n                    ValueConstructorVariant::ModuleConstant { literal, .. } => {\n                        return Ok(ClauseGuard::Constant(literal.clone()));\n                    }\n                };\n\n                Ok(ClauseGuard::Var {\n                    location,\n                    name,\n                    origin,\n                    type_: constructor.type_,\n                    definition_location,\n                })\n            }\n\n            ClauseGuard::TupleIndex {\n                location,\n                tuple,\n                index,\n                ..\n            } => {\n                let tuple = self.infer_clause_guard(*tuple)?;\n                match tuple.type_().as_ref() {\n                    Type::Tuple { elements } => {\n                        let type_ = elements\n                            .get(index as usize)\n                            .ok_or(Error::OutOfBoundsTupleIndex {\n                                location,\n                                index,\n                                size: elements.len(),\n                            })?\n                            .clone();\n                        Ok(ClauseGuard::TupleIndex {\n                            location,\n                            index,\n                            type_,\n                            tuple: Box::new(tuple),\n                        })\n                    }\n\n                    type_ if type_.is_unbound() => Err(Error::NotATupleUnbound {\n                        location: tuple.location(),\n                    }),\n\n                    Type::Named { .. } | Type::Fn { .. } | Type::Var { .. } => {\n                        Err(Error::NotATuple {\n                            location: tuple.location(),\n                            given: tuple.type_(),\n                        })\n                    }\n                }\n            }\n\n            ClauseGuard::FieldAccess {\n                label_location,\n                label,\n                container,\n                index: _,\n                type_: (),\n            } => match self.infer_clause_guard(*container.clone()) {\n                Ok(container) => self.infer_guard_record_access(container, label, label_location),\n\n                Err(err) => {\n                    if let ClauseGuard::Var { name, location, .. } = *container {\n                        self.infer_guard_module_access(name, label, location, label_location, err)\n                    } else {\n                        Err(Error::RecordAccessUnknownType {\n                            location: label_location,\n                        })\n                    }\n                }\n            },\n\n            ClauseGuard::ModuleSelect { location, .. } => {\n                Err(Error::RecordAccessUnknownType { location })\n            }\n\n            ClauseGuard::Not {\n                location,\n                expression,\n            } => {\n                let expression = self.infer_clause_guard(*expression)?;\n                unify(bool(), expression.type_())\n                    .map_err(|e| convert_unify_error(e, expression.location()))?;\n                Ok(ClauseGuard::Not {\n                    location,\n                    expression: Box::new(expression),\n                })\n            }\n\n            ClauseGuard::Constant(constant) => {\n                Ok(ClauseGuard::Constant(self.infer_const(&None, constant)))\n            }\n\n            ClauseGuard::Block { value, location } => {\n                let value = self.infer_clause_guard(*value)?;\n                Ok(ClauseGuard::Block {\n                    location,\n                    value: Box::new(value),\n                })\n            }\n\n            ClauseGuard::BinaryOperator {\n                location,\n                operator,\n                left,\n                right,\n            } => {\n                let left = self.infer_clause_guard(*left)?;\n                let right = self.infer_clause_guard(*right)?;\n\n                match operator {\n                    BinOp::And | BinOp::Or => {\n                        unify(bool(), left.type_())\n                            .map_err(|e| convert_unify_error(e, left.location()))?;\n                        unify(bool(), right.type_())\n                            .map_err(|e| convert_unify_error(e, right.location()))?;\n                    }\n\n                    BinOp::Eq | BinOp::NotEq => {\n                        unify(left.type_(), right.type_())\n                            .map_err(|e| convert_unify_error(e, location))?;\n                    }\n\n                    BinOp::GtInt\n                    | BinOp::GtEqInt\n                    | BinOp::LtInt\n                    | BinOp::LtEqInt\n                    | BinOp::AddInt\n                    | BinOp::SubInt\n                    | BinOp::DivInt\n                    | BinOp::MultInt\n                    | BinOp::RemainderInt => {\n                        self.track_feature_usage(FeatureKind::ArithmeticInGuards, location);\n\n                        if left.type_().is_float() && right.type_().is_float() {\n                            return Err(Error::IntOperatorOnFloats { operator, location });\n                        }\n\n                        unify(int(), left.type_())\n                            .map_err(|e| convert_unify_error(e, left.location()))?;\n                        unify(int(), right.type_())\n                            .map_err(|e| convert_unify_error(e, right.location()))?;\n                    }\n\n                    BinOp::GtFloat\n                    | BinOp::GtEqFloat\n                    | BinOp::LtFloat\n                    | BinOp::LtEqFloat\n                    | BinOp::AddFloat\n                    | BinOp::SubFloat\n                    | BinOp::DivFloat\n                    | BinOp::MultFloat => {\n                        self.track_feature_usage(FeatureKind::ArithmeticInGuards, location);\n\n                        if left.type_().is_int() && right.type_().is_int() {\n                            return Err(Error::FloatOperatorOnInts { operator, location });\n                        }\n\n                        unify(float(), left.type_())\n                            .map_err(|e| convert_unify_error(e, left.location()))?;\n                        unify(float(), right.type_())\n                            .map_err(|e| convert_unify_error(e, right.location()))?;\n                    }\n\n                    BinOp::Concatenate => {\n                        self.track_feature_usage(FeatureKind::ConcatenateInGuards, location);\n\n                        unify(string(), left.type_())\n                            .map_err(|e| convert_unify_error(e, left.location()))?;\n                        unify(string(), right.type_())\n                            .map_err(|e| convert_unify_error(e, right.location()))?;\n                    }\n                }\n\n                Ok(ClauseGuard::BinaryOperator {\n                    location,\n                    operator,\n                    left: Box::new(left),\n                    right: Box::new(right),\n                })\n            }\n        }\n    }\n\n    fn infer_guard_record_access(\n        &mut self,\n        container: TypedClauseGuard,\n        label: EcoString,\n        location: SrcSpan,\n    ) -> Result<TypedClauseGuard, Error> {\n        let container = Box::new(container);\n        let container_type = container.type_();\n        let RecordAccessor {\n            index,\n            label,\n            type_,\n            documentation: _,\n        } = self.infer_known_record_access(\n            container_type,\n            container.location(),\n            FieldAccessUsage::Other,\n            location,\n            label,\n        )?;\n        Ok(ClauseGuard::FieldAccess {\n            container,\n            label,\n            index: Some(index),\n            label_location: location,\n            type_,\n        })\n    }\n\n    fn infer_guard_module_access(\n        &mut self,\n        name: EcoString,\n        label: EcoString,\n        module_location: SrcSpan,\n        label_location: SrcSpan,\n        record_access_error: Error,\n    ) -> Result<TypedClauseGuard, Error> {\n        let module_access = self\n            .infer_module_access(&name, label, &module_location, label_location)\n            .and_then(|ma| {\n                if let TypedExpr::ModuleSelect {\n                    location,\n                    field_start: _,\n                    type_,\n                    label,\n                    module_name,\n                    module_alias,\n                    constructor,\n                } = ma\n                {\n                    match constructor {\n                        ModuleValueConstructor::Constant {\n                            literal,\n                            location: definition_location,\n                            ..\n                        } => {\n                            self.environment.references.register_value_reference(\n                                module_name.clone(),\n                                label.clone(),\n                                &label,\n                                label_location,\n                                ReferenceKind::Qualified,\n                            );\n\n                            Ok(ClauseGuard::ModuleSelect {\n                                location,\n                                field_start: label_location.start,\n                                definition_location,\n                                type_,\n                                label,\n                                module_name,\n                                module_alias,\n                                literal,\n                            })\n                        }\n\n                        ModuleValueConstructor::Record { .. }\n                        | ModuleValueConstructor::Fn { .. } => {\n                            Err(Error::RecordAccessUnknownType { location })\n                        }\n                    }\n                } else {\n                    Err(Error::RecordAccessUnknownType {\n                        location: module_location,\n                    })\n                }\n            });\n\n        // If the name is in the environment, use the original error from\n        // inferring the record access, so that we can suggest possible\n        // misspellings of field names\n        if self.environment.scope.contains_key(&name) {\n            module_access.map_err(|_| record_access_error)\n        } else {\n            module_access\n        }\n    }\n\n    fn infer_module_access(\n        &mut self,\n        // This is the name of the module coming before the `.`: for example\n        // in `result.try` it's `result`.\n        module_alias: &EcoString,\n        label: EcoString,\n        module_location: &SrcSpan,\n        select_location: SrcSpan,\n    ) -> Result<TypedExpr, Error> {\n        let location = module_location.merge(&select_location);\n\n        let (module_name, constructor) = {\n            let (_, module) = self\n                .environment\n                .imported_modules\n                .get(module_alias)\n                .ok_or_else(|| Error::UnknownModule {\n                    name: module_alias.clone(),\n                    location: *module_location,\n                    suggestions: self\n                        .environment\n                        .suggest_modules(module_alias, Imported::Value(label.clone())),\n                })?;\n\n            let constructor =\n                module\n                    .get_public_value(&label)\n                    .ok_or_else(|| Error::UnknownModuleValue {\n                        name: label.clone(),\n                        location: select_location,\n                        module_name: module.name.clone(),\n                        value_constructors: module.public_value_names(),\n                        type_with_same_name: module.get_public_type(&label).is_some(),\n                        context: ModuleValueUsageContext::ModuleAccess,\n                    })?;\n\n            // Emit a warning if the value being used is deprecated.\n            if let Deprecation::Deprecated { message } = &constructor.deprecation {\n                self.problems.warning(Warning::DeprecatedItem {\n                    location: select_location,\n                    message: message.clone(),\n                    layer: Layer::Value,\n                })\n            }\n\n            self.environment\n                .references\n                .register_module_reference(module_alias.clone());\n\n            (module.name.clone(), constructor.clone())\n        };\n\n        let type_ = self.instantiate(constructor.type_, &mut hashmap![]);\n\n        self.narrow_implementations(select_location, &constructor.variant)?;\n\n        let constructor = match &constructor.variant {\n            variant @ ValueConstructorVariant::ModuleFn { name, module, .. } => {\n                variant.to_module_value_constructor(Arc::clone(&type_), module, name)\n            }\n\n            variant @ (ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::Record { .. }) => {\n                variant.to_module_value_constructor(Arc::clone(&type_), &module_name, &label)\n            }\n        };\n\n        Ok(TypedExpr::ModuleSelect {\n            location,\n            field_start: select_location.start,\n            label,\n            type_: Arc::clone(&type_),\n            module_name,\n            module_alias: module_alias.clone(),\n            constructor,\n        })\n    }\n\n    fn infer_known_record_expression_access(\n        &mut self,\n        record: TypedExpr,\n        label: EcoString,\n        location: SrcSpan,\n        label_location: SrcSpan,\n        field_start: u32,\n        usage: FieldAccessUsage,\n    ) -> Result<TypedExpr, Error> {\n        let record = Box::new(record);\n        let record_type = record.type_();\n        let RecordAccessor {\n            index,\n            label,\n            type_,\n            documentation,\n        } = self.infer_known_record_access(\n            record_type,\n            record.location(),\n            usage,\n            label_location,\n            label,\n        )?;\n        Ok(TypedExpr::RecordAccess {\n            record,\n            label,\n            field_start,\n            index,\n            location,\n            type_,\n            documentation,\n        })\n    }\n\n    fn infer_known_record_access(\n        &mut self,\n        record_type: Arc<Type>,\n        record_location: SrcSpan,\n        usage: FieldAccessUsage,\n        location: SrcSpan,\n        label: EcoString,\n    ) -> Result<RecordAccessor, Error> {\n        if record_type.is_unbound() {\n            return Err(Error::RecordAccessUnknownType {\n                location: record_location,\n            });\n        }\n\n        let unknown_field = |fields| {\n            self.unknown_field_error(fields, record_type.clone(), location, label.clone(), usage)\n        };\n        let (accessors_map, variant_accessors) = match collapse_links(record_type.clone()).as_ref()\n        {\n            // A type in the current module which may have fields\n            Type::Named {\n                module,\n                name,\n                inferred_variant,\n                ..\n            } if module == &self.environment.current_module => {\n                self.environment.accessors.get(name).map(|accessors_map| {\n                    (\n                        accessors_map,\n                        accessors_map.accessors_for_variant(*inferred_variant),\n                    )\n                })\n            }\n\n            // A type in another module which may have fields\n            Type::Named {\n                module,\n                name,\n                inferred_variant,\n                ..\n            } => self\n                .environment\n                .importable_modules\n                .get(module)\n                .and_then(|module| module.accessors.get(name))\n                .filter(|a| {\n                    a.publicity.is_importable() || module == &self.environment.current_module\n                })\n                .map(|accessors_map| {\n                    (\n                        accessors_map,\n                        accessors_map.accessors_for_variant(*inferred_variant),\n                    )\n                }),\n\n            // Non-named types do not have fields\n            Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                return Err(unknown_field(vec![]));\n            }\n        }\n        .ok_or_else(|| unknown_field(vec![]))?;\n\n        let RecordAccessor {\n            index,\n            label,\n            type_,\n            documentation,\n        } = variant_accessors\n            .get(&label)\n            .ok_or_else(|| unknown_field(variant_accessors.keys().cloned().collect()))?\n            .clone();\n\n        let accessor_record_type = accessors_map.type_.clone();\n\n        // If the accessor isn't shared across variants, this requires variant inference\n        if !accessors_map.shared_accessors.contains_key(&label) {\n            match usage {\n                FieldAccessUsage::MethodCall | FieldAccessUsage::Other => {\n                    self.track_feature_usage(FeatureKind::RecordAccessVariantInference, location);\n                }\n                // This feature for record updates should be tracked in\n                // `infer_record_update`, so we don't track it here as it would lead\n                // to a duplicate warning with a confusing message.\n                FieldAccessUsage::RecordUpdate => {}\n            }\n        }\n\n        let mut type_vars = hashmap![];\n        let accessor_record_type = self.instantiate(accessor_record_type, &mut type_vars);\n        let type_ = self.instantiate(type_, &mut type_vars);\n        unify(accessor_record_type, record_type)\n            .map_err(|e| convert_unify_error(e, record_location))?;\n        Ok(RecordAccessor {\n            index,\n            label,\n            type_,\n            documentation,\n        })\n    }\n\n    fn infer_record_update(\n        &mut self,\n        constructor: UntypedExpr,\n        record: RecordBeingUpdated<UntypedExpr>,\n        arguments: Vec<UntypedRecordUpdateArg>,\n        location: SrcSpan,\n    ) -> Result<TypedExpr, Error> {\n        // infer the constructor being used\n        let typed_constructor = self.infer_or_error(constructor.clone())?;\n        let (module, name) = match &typed_constructor {\n            TypedExpr::ModuleSelect {\n                module_alias,\n                label,\n                location,\n                ..\n            } => (Some((module_alias, location)), label),\n\n            TypedExpr::Var { name, .. } => (None, name),\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => {\n                return Err(Error::RecordUpdateInvalidConstructor {\n                    location: typed_constructor.location(),\n                });\n            }\n        };\n\n        let value_constructor = self\n            .environment\n            .get_value_constructor(module.map(|(module, _)| module), name)\n            .map_err(|error| {\n                convert_get_value_constructor_error(\n                    error,\n                    location,\n                    module.map(|(_, location)| *location),\n                )\n            })?\n            .clone();\n\n        // infer the record being updated\n        let record = self.infer_or_error(*record.base)?;\n        let record_location = record.location();\n        let record_type = record.type_();\n\n        let (record_var, record_assignment) = if record.is_var() {\n            (record, None)\n        } else {\n            // We create an Assignment for the old record expression and will\n            // use a Var expression to refer back to it while constructing the\n            // arguments.\n            let record_assignment = Assignment {\n                location: record_location,\n                pattern: Pattern::Variable {\n                    location: record_location,\n                    name: RECORD_UPDATE_VARIABLE.into(),\n                    type_: record_type.clone(),\n                    origin: VariableOrigin::generated(),\n                },\n                annotation: None,\n                compiled_case: CompiledCase::failure(),\n                kind: AssignmentKind::Generated,\n                value: record,\n            };\n\n            let record_var = TypedExpr::Var {\n                location: record_location,\n                constructor: ValueConstructor {\n                    publicity: Publicity::Private,\n                    deprecation: Deprecation::NotDeprecated,\n                    type_: record_type,\n                    variant: ValueConstructorVariant::LocalVariable {\n                        location: record_location,\n                        origin: VariableOrigin::generated(),\n                    },\n                },\n                name: RECORD_UPDATE_VARIABLE.into(),\n            };\n            (record_var, Some(Box::new(record_assignment)))\n        };\n\n        // infer the fields of the variant we want to update\n        let variant =\n            self.infer_record_update_variant(&typed_constructor, &value_constructor, &record_var)?;\n\n        let arguments =\n            self.infer_record_update_arguments(&variant, &record_var, arguments, location)?;\n\n        Ok(TypedExpr::RecordUpdate {\n            location,\n            type_: variant.return_type,\n            record_assignment,\n            constructor: Box::new(typed_constructor),\n            arguments,\n        })\n    }\n\n    fn infer_record_update_arguments(\n        &mut self,\n        variant: &RecordUpdateVariant<'_>,\n        record: &TypedExpr,\n        arguments: Vec<UntypedRecordUpdateArg>,\n        location: SrcSpan,\n    ) -> Result<Vec<TypedCallArg>, Error> {\n        let record_location = record.location();\n        let record_type = record.type_();\n        let return_type = variant.return_type.clone();\n\n        // We clone the fields to remove all explicitly mentioned fields in the\n        // record update.\n        let mut fields = variant.field_map.fields.clone();\n\n        // We go over all arguments used in the record update and infer those.\n        let mut explicit_arguments = vec![];\n        for argument in arguments.iter() {\n            let UntypedRecordUpdateArg {\n                label,\n                value,\n                location,\n            } = argument;\n            let value = self.infer(value.clone());\n            if argument.uses_label_shorthand() {\n                self.track_feature_usage(FeatureKind::LabelShorthandSyntax, *location);\n            }\n\n            if let Some(index) = fields.remove(label) {\n                // If the variant has the given field, we need to check it's\n                // inferred type is correct.\n                // If an error happens we record it, but don't early return.\n                // We still want to accumulate errors for all field to come!\n                if let Err(error) = unify(variant.arg_type(index), value.type_()) {\n                    self.problems.error(convert_unify_error(error, *location));\n                };\n\n                explicit_arguments.push((\n                    index,\n                    CallArg {\n                        label: Some(label.clone()),\n                        location: *location,\n                        value,\n                        implicit: None,\n                    },\n                ))\n            } else if variant.has_field(label) {\n                // The variant has this field but it was already removed in a\n                // previous iteration. This means we've found a duplicate field!\n                self.problems.error(Error::DuplicateArgument {\n                    location: *location,\n                    label: label.clone(),\n                })\n            } else {\n                // Otherwise, it's just an unknown field!\n                self.problems.error(self.unknown_field_error(\n                    variant.field_names(),\n                    record_type.clone(),\n                    *location,\n                    label.clone(),\n                    FieldAccessUsage::RecordUpdate,\n                ))\n            };\n        }\n\n        // Generate the remaining copied arguments, making sure they unify with\n        // our return type.\n        let convert_incompatible_fields_error = |error: UnifyError, field: RecordField| match error\n        {\n            UnifyError::CouldNotUnify {\n                expected, given, ..\n            } => Error::UnsafeRecordUpdate {\n                location: record_location,\n                reason: UnsafeRecordUpdateReason::IncompatibleFieldTypes {\n                    constructed_variant: return_type.clone(),\n                    record_variant: record_type.clone(),\n                    expected_field_type: expected,\n                    record_field_type: given,\n                    field,\n                },\n            },\n            UnifyError::ExtraVarInAlternativePattern { .. }\n            | UnifyError::MissingVarInAlternativePattern { .. }\n            | UnifyError::DuplicateVarInPattern { .. }\n            | UnifyError::RecursiveType => convert_unify_error(error, record_location),\n        };\n\n        let indices_to_labels = variant.field_map.indices_to_labels();\n        let mut implicit_arguments = Vec::new();\n\n        for index in 0..variant.field_map.arity {\n            if let Some(&label) = indices_to_labels.get(&index) {\n                if !fields.contains_key(label) {\n                    continue;\n                }\n\n                let record_access = self.infer_known_record_expression_access(\n                    record.clone(),\n                    label.clone(),\n                    record_location,\n                    record_location,\n                    record_location.start,\n                    FieldAccessUsage::RecordUpdate,\n                )?;\n\n                unify(variant.arg_type(index), record_access.type_()).map_err(|e| {\n                    convert_incompatible_fields_error(e, RecordField::Labelled(label.clone()))\n                })?;\n\n                implicit_arguments.push((\n                    index,\n                    CallArg {\n                        location: record_location,\n                        label: Some(label.clone()),\n                        value: record_access,\n                        implicit: Some(ImplicitCallArgOrigin::RecordUpdate),\n                    },\n                ))\n            } else {\n                let (accessor_type, positional_fields) =\n                    match collapse_links(record.type_()).as_ref() {\n                        // A type in the current module\n                        Type::Named {\n                            module,\n                            name,\n                            inferred_variant,\n                            ..\n                        } if module == &self.environment.current_module => {\n                            self.environment\n                                .accessors\n                                .get(name)\n                                .and_then(|accessors_map| {\n                                    Some((\n                                        accessors_map.type_.clone(),\n                                        // For record updates we must know the variant of the record, so if the\n                                        // variant has not been inferred, that means there must only be one.\n                                        accessors_map\n                                            .positional_accessors(inferred_variant.unwrap_or(0))?,\n                                    ))\n                                })\n                        }\n\n                        // A type in another module\n                        Type::Named {\n                            module,\n                            name,\n                            inferred_variant,\n                            ..\n                        } => self\n                            .environment\n                            .importable_modules\n                            .get(module)\n                            .and_then(|module| module.accessors.get(name))\n                            .filter(|a| {\n                                a.publicity.is_importable()\n                                    || module == &self.environment.current_module\n                            })\n                            .and_then(|accessors_map| {\n                                Some((\n                                    accessors_map.type_.clone(),\n                                    accessors_map\n                                        .positional_accessors(inferred_variant.unwrap_or(0))?,\n                                ))\n                            }),\n\n                        Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                            panic!(\"Type has already checked to be valid\")\n                        }\n                    }\n                    .expect(\"Variant has already checked to be valid\");\n\n                // Positional fields must always be defined before any labelled fields.\n                // As such, we expect that field indices 0..(positional_fields.length)\n                // all correspond to positional fields. If this is not the case, then the\n                // user currently has a mistake in the definition of their custom type.\n                //\n                // However, we do not want to show an error here, because it would be\n                // confusing for the programmer. They can already see the error at the type\n                // definition site.\n                let type_ = if let Some(type_) = positional_fields.get(index as usize) {\n                    type_.clone()\n                } else {\n                    continue;\n                };\n\n                let mut type_vars = im::HashMap::new();\n                let accessor_type = self.instantiate(accessor_type, &mut type_vars);\n                let type_ = self.instantiate(type_, &mut type_vars);\n                unify(accessor_type, record_type.clone()).map_err(|e| {\n                    convert_incompatible_fields_error(e, RecordField::Unlabelled(index))\n                })?;\n\n                let record_access = TypedExpr::PositionalAccess {\n                    record: Box::new(record.clone()),\n                    index: index as u64,\n                    location: record_location,\n                    type_: type_.clone(),\n                };\n\n                unify(variant.arg_type(index), type_.clone()).map_err(|e| {\n                    convert_incompatible_fields_error(e, RecordField::Unlabelled(index))\n                })?;\n\n                implicit_arguments.push((\n                    index,\n                    CallArg {\n                        location: record_location,\n                        label: None,\n                        value: record_access,\n                        implicit: Some(ImplicitCallArgOrigin::RecordUpdate),\n                    },\n                ))\n            }\n        }\n\n        if arguments.is_empty() {\n            self.problems\n                .warning(Warning::NoFieldsRecordUpdate { location });\n        }\n\n        if implicit_arguments.is_empty() {\n            self.problems\n                .warning(Warning::AllFieldsRecordUpdate { location });\n        }\n\n        let arguments = explicit_arguments\n            .into_iter()\n            .chain(implicit_arguments)\n            .sorted_by_key(|(index, _)| *index)\n            .map(|(_, value)| value)\n            .collect();\n\n        Ok(arguments)\n    }\n\n    fn infer_record_update_variant<'c>(\n        &mut self,\n        constructor: &TypedExpr,\n        value_constructor: &'c ValueConstructor,\n        record: &TypedExpr,\n    ) -> Result<RecordUpdateVariant<'c>, Error> {\n        let record_type = record.type_();\n        // The record constructor needs to be a function.\n        let (arguments_types, return_type) = match constructor.type_().as_ref() {\n            Type::Fn { arguments, return_ } => (arguments.clone(), return_.clone()),\n            Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                return Err(Error::RecordUpdateInvalidConstructor {\n                    location: constructor.location(),\n                });\n            }\n        };\n\n        // It must be a record with a field map for us to be able to update it\n        let (field_map, variants_count, variant_index, name) = match &value_constructor.variant {\n            ValueConstructorVariant::Record {\n                field_map: Some(field_map),\n                variants_count,\n                variant_index,\n                name,\n                ..\n            } => (field_map, *variants_count, *variant_index, name.clone()),\n            ValueConstructorVariant::Record {\n                field_map: None, ..\n            } => {\n                return Err(Error::RecordUpdateInvalidConstructor {\n                    location: constructor.location(),\n                });\n            }\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::ModuleFn { .. } => {\n                return Err(Error::RecordUpdateInvalidConstructor {\n                    location: constructor.location(),\n                });\n            }\n        };\n\n        // Check that the record type unifies with the return type of the constructor, and is\n        // not some unrelated other type. This should not affect our returned type, so we\n        // instantiate a new copy of the generic return type for our value constructor.\n        let return_type_copy = match value_constructor.type_.as_ref() {\n            Type::Fn { return_, .. } => self.instantiate(return_.clone(), &mut hashmap![]),\n            Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                return Err(Error::RecordUpdateInvalidConstructor {\n                    location: constructor.location(),\n                });\n            }\n        };\n\n        unify(return_type_copy, record_type.clone())\n            .map_err(|e| convert_unify_error(e, record.location()))?;\n\n        let record_index = record_type.custom_type_inferred_variant();\n        // Updating a record with only one variant is always safe\n        if variants_count == 1 {\n            return Ok(RecordUpdateVariant {\n                arguments: arguments_types,\n                return_type,\n                field_map,\n            });\n        }\n\n        // if we know the record that is being spread, and it does match the one being constructed,\n        // we can safely perform this record update due to variant inference.\n        if record_index.is_some_and(|index| index == variant_index) {\n            self.track_feature_usage(FeatureKind::RecordUpdateVariantInference, record.location());\n            return Ok(RecordUpdateVariant {\n                arguments: arguments_types,\n                return_type,\n                field_map,\n            });\n        }\n\n        // We definitely know that we can't do this record update safely.\n        //\n        // If we know the variant of the value being spread, and it doesn't match the\n        // one being constructed, we can tell the user that it's always wrong\n        if record_index.is_some() {\n            let Type::Named {\n                module: record_module,\n                name: record_name,\n                inferred_variant: Some(record_index),\n                ..\n            } = record_type.deref()\n            else {\n                panic!(\"Spread type must be named and with an index\")\n            };\n\n            return Err(Error::UnsafeRecordUpdate {\n                location: record.location(),\n                reason: UnsafeRecordUpdateReason::WrongVariant {\n                    constructed_variant: name,\n                    spread_variant: self\n                        .environment\n                        .type_variant_name(record_module, record_name, *record_index)\n                        .expect(\"Spread type must exist and variant must be valid\")\n                        .clone(),\n                },\n            });\n        }\n\n        // If we don't have information about the variant being spread, we tell the user\n        // that it's not safe to update it as it could be any variant\n        Err(Error::UnsafeRecordUpdate {\n            location: record.location(),\n            reason: UnsafeRecordUpdateReason::UnknownVariant {\n                constructed_variant: name,\n            },\n        })\n    }\n\n    fn unknown_field_error(\n        &self,\n        fields: Vec<EcoString>,\n        record_type: Arc<Type>,\n        location: SrcSpan,\n        label: EcoString,\n        usage: FieldAccessUsage,\n    ) -> Error {\n        let error = |unknown_field| Error::UnknownRecordField {\n            usage,\n            type_: record_type.clone(),\n            location,\n            label: label.clone(),\n            fields,\n            unknown_field,\n        };\n\n        let Type::Named {\n            module,\n            name,\n            inferred_variant,\n            ..\n        } = record_type.deref()\n        else {\n            return error(UnknownField::NoFields);\n        };\n\n        let all_fields = self.environment.get_type_variants_fields(module, name);\n\n        if all_fields.is_empty() {\n            return error(UnknownField::NoFields);\n        }\n\n        if !all_fields.iter().contains(&&label) {\n            return error(UnknownField::TrulyUnknown);\n        }\n\n        // If we know the variant, the field must exist on a different\n        // variant from the one we have inferred.\n        if inferred_variant.is_some() {\n            error(UnknownField::AppearsInAnImpossibleVariant)\n        } else {\n            error(UnknownField::AppearsInAVariant)\n        }\n    }\n\n    fn infer_value_constructor(\n        &mut self,\n        module: &Option<(EcoString, SrcSpan)>,\n        name: &EcoString,\n        location: &SrcSpan,\n    ) -> Result<ValueConstructor, Error> {\n        self.do_infer_value_constructor(module, name, location, ReferenceRegistration::Register)\n    }\n\n    fn do_infer_value_constructor(\n        &mut self,\n        module: &Option<(EcoString, SrcSpan)>,\n        name: &EcoString,\n        location: &SrcSpan,\n        register_reference: ReferenceRegistration,\n    ) -> Result<ValueConstructor, Error> {\n        let constructor = match module {\n            // Look in the current scope for a binding with this name\n            None => self\n                .environment\n                .get_variable(name)\n                .cloned()\n                .ok_or_else(|| self.report_name_error(name, location))?,\n\n            // Look in an imported module for a binding with this name\n            Some((module_name, module_location)) => {\n                let (_, module) = &self\n                    .environment\n                    .imported_modules\n                    .get(module_name)\n                    .ok_or_else(|| Error::UnknownModule {\n                        location: *module_location,\n                        name: module_name.clone(),\n                        suggestions: self\n                            .environment\n                            .suggest_modules(module_name, Imported::Value(name.clone())),\n                    })?;\n\n                self.environment\n                    .references\n                    .register_module_reference(module_name.clone());\n\n                module\n                    .values\n                    .get(name)\n                    .cloned()\n                    .ok_or_else(|| Error::UnknownModuleValue {\n                        location: *location,\n                        module_name: module_name.clone(),\n                        name: name.clone(),\n                        value_constructors: module.public_value_names(),\n                        type_with_same_name: module.get_public_type(name).is_some(),\n                        context: ModuleValueUsageContext::ModuleAccess,\n                    })?\n            }\n        };\n\n        let ValueConstructor {\n            publicity,\n            variant,\n            type_,\n            deprecation,\n        } = constructor;\n\n        self.check_recursive_argument_usage(name, &variant, &register_reference);\n\n        // Emit a warning if the value being used is deprecated.\n        if let Deprecation::Deprecated { message } = &deprecation {\n            self.problems.warning(Warning::DeprecatedItem {\n                location: *location,\n                message: message.clone(),\n                layer: Layer::Value,\n            })\n        }\n\n        self.narrow_implementations(*location, &variant)?;\n\n        match register_reference {\n            ReferenceRegistration::DoNotRegister => (),\n\n            ReferenceRegistration::Register | ReferenceRegistration::VariableArgument { .. } => {\n                self.register_value_constructor_reference(\n                    name,\n                    &variant,\n                    *location,\n                    if module.is_some() {\n                        ReferenceKind::Qualified\n                    } else {\n                        ReferenceKind::Unqualified\n                    },\n                );\n            }\n        }\n\n        // Instantiate generic variables into unbound variables for this usage\n        let type_ = self.instantiate(type_, &mut hashmap![]);\n        Ok(ValueConstructor {\n            publicity,\n            deprecation,\n            variant,\n            type_,\n        })\n    }\n\n    fn check_recursive_argument_usage(\n        &mut self,\n        name: &EcoString,\n        variant: &ValueConstructorVariant,\n        register_reference: &ReferenceRegistration,\n    ) {\n        // If we are registering references for a call argument\n        let ReferenceRegistration::VariableArgument {\n            called_function,\n            argument_index,\n        } = register_reference\n        else {\n            return;\n        };\n\n        // If the passed argument is a function's parameter.\n        let ValueConstructorVariant::LocalVariable { origin, .. } = variant else {\n            return;\n        };\n\n        let VariableDeclaration::FunctionParameter {\n            function_name: declaration_function,\n            index: declaration_index,\n        } = &origin.declaration\n        else {\n            return;\n        };\n\n        // If the called function is the same where the argument is defined,\n        // and the argument is passed unchanged.\n        if declaration_function.as_ref() == Some(called_function)\n            && declaration_index == argument_index\n        {\n            self.environment.increment_recursive_usage(name);\n        }\n    }\n\n    fn register_value_constructor_reference(\n        &mut self,\n        referenced_name: &EcoString,\n        variant: &ValueConstructorVariant,\n        location: SrcSpan,\n        kind: ReferenceKind,\n    ) {\n        match variant {\n            ValueConstructorVariant::ModuleFn {\n                module,\n                name: value_name,\n                ..\n            }\n            | ValueConstructorVariant::Record {\n                module,\n                name: value_name,\n                ..\n            }\n            | ValueConstructorVariant::ModuleConstant {\n                module,\n                name: value_name,\n                ..\n            } if value_name != referenced_name => {\n                self.environment.references.register_value_reference(\n                    module.clone(),\n                    value_name.clone(),\n                    referenced_name,\n                    location,\n                    ReferenceKind::Alias,\n                )\n            }\n            ValueConstructorVariant::ModuleFn { name, module, .. }\n            | ValueConstructorVariant::Record { name, module, .. }\n            | ValueConstructorVariant::ModuleConstant { name, module, .. } => {\n                self.environment.references.register_value_reference(\n                    module.clone(),\n                    name.clone(),\n                    referenced_name,\n                    location,\n                    kind,\n                )\n            }\n            ValueConstructorVariant::LocalVariable { .. } => {\n                self.environment.increment_usage(referenced_name)\n            }\n        }\n    }\n\n    fn report_name_error(&mut self, name: &EcoString, location: &SrcSpan) -> Error {\n        // First try to see if this is a module alias:\n        // `import gleam/io`\n        // `io.debug(io)`\n        // Show nice error message for this case.\n        let module = self.environment.imported_modules.get(name);\n        match module {\n            Some(_) => Error::ModuleAliasUsedAsName {\n                location: *location,\n                name: name.clone(),\n            },\n            None => Error::UnknownVariable {\n                location: *location,\n                name: name.clone(),\n                variables: self.environment.local_value_names(),\n                discarded_location: self\n                    .environment\n                    .discarded_names\n                    .get(&eco_format!(\"_{name}\"))\n                    .cloned(),\n                type_with_name_in_scope: self\n                    .environment\n                    .module_types\n                    .keys()\n                    .any(|typ| typ == name),\n            },\n        }\n    }\n\n    // helper for infer_const to get the value of a constant ignoring annotations\n    fn infer_const_value(&mut self, value: UntypedConstant) -> TypedConstant {\n        match value {\n            Constant::Int {\n                location,\n                value,\n                int_value,\n            } => {\n                if self.environment.target == Target::JavaScript {\n                    check_javascript_int_safety(&int_value, location, self.problems);\n                }\n\n                Constant::Int {\n                    location,\n                    value,\n                    int_value,\n                }\n            }\n\n            Constant::Float {\n                location,\n                value,\n                float_value,\n            } => {\n                check_float_safety(float_value, location, self.problems);\n                Constant::Float {\n                    location,\n                    value,\n                    float_value,\n                }\n            }\n\n            Constant::String {\n                location, value, ..\n            } => Constant::String { location, value },\n\n            Constant::Tuple {\n                elements, location, ..\n            } => self.infer_const_tuple(elements, location),\n\n            Constant::List {\n                elements,\n                location,\n                tail,\n                ..\n            } => self.infer_const_list(elements, location, tail),\n\n            Constant::BitArray { location, segments } => {\n                match self.infer_constant_bit_array(segments, location) {\n                    Ok(inferred) => inferred,\n                    Err(error) => {\n                        self.problems.error(error);\n                        Constant::Invalid {\n                            location,\n                            type_: bit_array(),\n                            extra_information: None,\n                        }\n                    }\n                }\n            }\n\n            Constant::RecordUpdate {\n                constructor_location,\n                module,\n                location,\n                name,\n                record,\n                arguments,\n                ..\n            } => {\n                self.track_feature_usage(FeatureKind::ConstantRecordUpdate, location);\n                let constructor = match self.infer_value_constructor(&module, &name, &location) {\n                    Ok(constructor) => constructor,\n                    Err(error) => {\n                        self.problems.error(error);\n                        return self.new_invalid_constant(location);\n                    }\n                };\n\n                let (tag, field_map) = match &constructor.variant {\n                    ValueConstructorVariant::Record {\n                        name,\n                        field_map: Some(field_map),\n                        ..\n                    } => (name.clone(), field_map.clone()),\n\n                    ValueConstructorVariant::Record {\n                        field_map: None, ..\n                    } => {\n                        self.problems.error(Error::RecordUpdateInvalidConstructor {\n                            location: constructor_location,\n                        });\n                        return self.new_invalid_constant(location);\n                    }\n\n                    ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::LocalVariable { .. } => {\n                        self.problems\n                            .error(Error::NonLocalClauseGuardVariable { location, name });\n                        return self.new_invalid_constant(location);\n                    }\n\n                    ValueConstructorVariant::ModuleConstant { literal, .. } => {\n                        return literal.clone();\n                    }\n                };\n\n                // Type-check the record being updated\n                let typed_record = self.infer_const(&None, *record.base.clone());\n                let typed_record_type = typed_record.type_();\n\n                // Instantiate the constructor type to enable generic re-specialization.\n                let instantiated_constructor_type =\n                    self.instantiate(constructor.type_.clone(), &mut hashmap![]);\n\n                // Extract field types and return type from the instantiated constructor\n                let (field_types, expected_type) = match instantiated_constructor_type.as_ref() {\n                    Type::Fn { arguments, return_ } => (arguments.clone(), return_.clone()),\n                    Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                        self.problems.error(Error::RecordUpdateInvalidConstructor {\n                            location: constructor_location,\n                        });\n                        return self.new_invalid_constant(location);\n                    }\n                };\n\n                // If the record being updated is a reference to a constant variable, resolve\n                // it to get the actual record value\n                let resolved_record = match &typed_record {\n                    Constant::Var {\n                        constructor: Some(value_constructor),\n                        ..\n                    } => match &value_constructor.variant {\n                        ValueConstructorVariant::ModuleConstant { literal, .. } => literal.clone(),\n                        ValueConstructorVariant::LocalVariable { .. }\n                        | ValueConstructorVariant::ModuleFn { .. }\n                        | ValueConstructorVariant::Record { .. } => typed_record,\n                    },\n                    Constant::Int { .. }\n                    | Constant::Float { .. }\n                    | Constant::String { .. }\n                    | Constant::Tuple { .. }\n                    | Constant::List { .. }\n                    | Constant::Record { .. }\n                    | Constant::RecordUpdate { .. }\n                    | Constant::BitArray { .. }\n                    | Constant::Var { .. }\n                    | Constant::StringConcatenation { .. }\n                    | Constant::Invalid { .. } => typed_record,\n                };\n\n                // Get the field arguments from the record that we'll use as the base.\n                let (base_arguments, base_tag) =\n                    if let Constant::Record { arguments, tag, .. } = resolved_record {\n                        (arguments, tag)\n                    } else {\n                        self.problems.error(convert_unify_error(\n                            UnifyError::CouldNotUnify {\n                                expected: expected_type.clone(),\n                                given: typed_record_type,\n                                situation: None,\n                            },\n                            record.location,\n                        ));\n                        return self.new_invalid_constant(location);\n                    };\n\n                // Check that the variant being spread matches the constructor variant\n                // For multi-variant custom types, you can't spread Dog to create Cat\n                if tag != base_tag {\n                    self.problems.error(Error::UnsafeRecordUpdate {\n                        location: record.location,\n                        reason: UnsafeRecordUpdateReason::WrongVariant {\n                            constructed_variant: tag,\n                            spread_variant: base_tag,\n                        },\n                    });\n                    return self.new_invalid_constant(location);\n                }\n\n                // Emit warning if no fields are being overridden\n                if arguments.is_empty() {\n                    self.problems\n                        .warning(Warning::NoFieldsRecordUpdate { location });\n                }\n\n                let mut implicit_labelled_arguments = field_map.fields.clone();\n                let mut update_argument_indices = HashSet::new();\n\n                let mut final_arguments = base_arguments;\n                for argument in arguments {\n                    if argument.uses_label_shorthand() {\n                        self.track_feature_usage(\n                            FeatureKind::LabelShorthandSyntax,\n                            argument.location,\n                        );\n                    }\n\n                    let label = &argument.label;\n                    let typed_value = self.infer_const(&None, argument.value);\n\n                    let Some(index) = implicit_labelled_arguments.remove(label) else {\n                        if field_map.fields.contains_key(label) {\n                            self.problems.error(Error::DuplicateArgument {\n                                location: argument.location,\n                                label: label.clone(),\n                            });\n                        } else {\n                            self.problems.error(self.unknown_field_error(\n                                field_map.fields.keys().cloned().collect(),\n                                expected_type.clone(),\n                                argument.location,\n                                label.clone(),\n                                FieldAccessUsage::Other,\n                            ));\n                        }\n\n                        return self.new_invalid_constant(location);\n                    };\n\n                    // Record update argument value must match the field type\n                    if let Some(expected_type) = field_types.get(index as usize)\n                        && let Err(error) = unify(expected_type.clone(), typed_value.type_())\n                    {\n                        self.problems\n                            .error(convert_unify_error(error, typed_value.location()));\n                        return self.new_invalid_constant(location);\n                    }\n\n                    let _ = update_argument_indices.insert(index as usize);\n\n                    *final_arguments\n                        .get_mut(index as usize)\n                        .expect(\"Index out of bounds\") = CallArg {\n                        label: Some(label.clone()),\n                        value: typed_value,\n                        location: argument.location,\n                        implicit: None,\n                    };\n                }\n\n                // Emit warning if all fields are being overriden\n                if implicit_labelled_arguments.is_empty() {\n                    self.problems\n                        .warning(Warning::AllFieldsRecordUpdate { location });\n                }\n\n                // Check that fields implicitly overridden (including unlabelled ones) have compatible types.\n                for (index, field_arg) in final_arguments.iter().enumerate() {\n                    // Skip fields that were record update arguments, as they've already been type-checked above\n                    if update_argument_indices.contains(&index) {\n                        continue;\n                    }\n\n                    if let Some(expected_field_type) = field_types.get(index)\n                        && let Err(unify_error) =\n                            unify(expected_field_type.clone(), field_arg.value.type_())\n                    {\n                        let field = field_map\n                            .fields\n                            .iter()\n                            .find(|(_, i)| **i == index as u32)\n                            .map(|(name, _)| RecordField::Labelled(name.clone()))\n                            .unwrap_or_else(|| RecordField::Unlabelled(index as u32));\n\n                        self.problems.error(\n                            if let UnifyError::CouldNotUnify {\n                                expected, given, ..\n                            } = unify_error\n                            {\n                                Error::UnsafeRecordUpdate {\n                                    location: record.location,\n                                    reason: UnsafeRecordUpdateReason::IncompatibleFieldTypes {\n                                        constructed_variant: expected_type.clone(),\n                                        record_variant: typed_record_type.clone(),\n                                        expected_field_type: expected,\n                                        record_field_type: given,\n                                        field,\n                                    },\n                                }\n                            } else {\n                                convert_unify_error(unify_error, location)\n                            },\n                        );\n                        return self.new_invalid_constant(location);\n                    }\n                }\n\n                Constant::Record {\n                    module,\n                    location,\n                    name,\n                    arguments: final_arguments,\n                    type_: expected_type,\n                    tag,\n                    field_map: Inferred::Known(field_map),\n                    record_constructor: Some(Box::new(constructor)),\n                }\n            }\n\n            Constant::Record {\n                module,\n                location,\n                name,\n                arguments,\n                ..\n            } if arguments.is_empty() => {\n                // Type check the record constructor\n                let constructor = match self.infer_value_constructor(&module, &name, &location) {\n                    Ok(constructor) => constructor,\n                    Err(error) => {\n                        self.problems.error(error);\n                        return self.new_invalid_constant(location);\n                    }\n                };\n\n                let (tag, field_map) = match &constructor.variant {\n                    ValueConstructorVariant::Record {\n                        name, field_map, ..\n                    } => (\n                        name.clone(),\n                        match field_map {\n                            Some(fm) => Inferred::Known(fm.clone()),\n                            None => Inferred::Unknown,\n                        },\n                    ),\n\n                    ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::LocalVariable { .. } => {\n                        self.problems\n                            .error(Error::NonLocalClauseGuardVariable { location, name });\n                        return self.new_invalid_constant(location);\n                    }\n\n                    // TODO: remove this clone. Could use an rc instead\n                    ValueConstructorVariant::ModuleConstant { literal, .. } => {\n                        return literal.clone();\n                    }\n                };\n\n                Constant::Record {\n                    module,\n                    location,\n                    name,\n                    arguments: vec![],\n                    type_: constructor.type_.clone(),\n                    tag,\n                    field_map,\n                    record_constructor: Some(Box::new(constructor)),\n                }\n            }\n\n            Constant::Record {\n                module,\n                location,\n                name,\n                mut arguments,\n                ..\n            } => {\n                let constructor = match self.infer_value_constructor(&module, &name, &location) {\n                    Ok(constructor) => constructor,\n                    Err(error) => {\n                        self.problems.error(error);\n                        return self.new_invalid_constant(location);\n                    }\n                };\n\n                let (tag, field_map, variant_index) = match &constructor.variant {\n                    ValueConstructorVariant::Record {\n                        name,\n                        field_map,\n                        variant_index,\n                        ..\n                    } => (\n                        name.clone(),\n                        match field_map {\n                            Some(fm) => Inferred::Known(fm.clone()),\n                            None => Inferred::Unknown,\n                        },\n                        *variant_index,\n                    ),\n\n                    ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::LocalVariable { .. } => {\n                        self.problems\n                            .error(Error::NonLocalClauseGuardVariable { location, name });\n                        return self.new_invalid_constant(location);\n                    }\n\n                    // TODO: remove this clone. Could be an rc instead\n                    ValueConstructorVariant::ModuleConstant { literal, .. } => {\n                        return literal.clone();\n                    }\n                };\n\n                // Pretty much all the other infer functions operate on UntypedExpr\n                // or TypedExpr rather than ClauseGuard. To make things easier we\n                // build the TypedExpr equivalent of the constructor and use that\n                // TODO: resvisit this. It is rather awkward at present how we\n                // have to convert to this other data structure.\n                let fun = match &module {\n                    Some((module_alias, module_location)) => {\n                        let type_ = Arc::clone(&constructor.type_);\n                        let module_name = self\n                            .environment\n                            .imported_modules\n                            // TODO: remove\n                            .get(module_alias)\n                            .expect(\"Failed to find previously located module import\")\n                            .1\n                            .name\n                            .clone();\n                        let module_value_constructor = ModuleValueConstructor::Record {\n                            name: name.clone(),\n                            variant_index,\n                            field_map: match &field_map {\n                                Inferred::Known(fm) => Some(fm.clone()),\n                                Inferred::Unknown => None,\n                            },\n                            arity: arguments.len() as u16,\n                            type_: Arc::clone(&type_),\n                            location: constructor.variant.definition_location(),\n                            documentation: None,\n                        };\n\n                        TypedExpr::ModuleSelect {\n                            location: module_location.merge(&location),\n                            field_start: location.start,\n                            label: name.clone(),\n                            module_alias: module_alias.clone(),\n                            module_name,\n                            type_,\n                            constructor: module_value_constructor,\n                        }\n                    }\n\n                    None => TypedExpr::Var {\n                        constructor: constructor.clone(),\n                        location,\n                        name: name.clone(),\n                    },\n                };\n\n                // This is basically the same code as do_infer_call_with_known_fun()\n                // except the args are typed with infer_clause_guard() here.\n                // This duplication is a bit awkward but it works!\n                // Potentially this could be improved later\n                let result = match self.get_field_map(&fun) {\n                    // There's an error retrieving the field map, in that case we\n                    // return an invalid constant.\n                    Err(error) => {\n                        self.problems\n                            .error(convert_get_value_constructor_error(error, location, None));\n                        return self.new_invalid_constant(location);\n                    }\n                    // The fun has a field map so labelled arguments may be present\n                    // and need to be reordered.\n                    Ok(Some(field_map)) => {\n                        field_map.reorder(&mut arguments, location, IncorrectArityContext::Function)\n                    }\n                    // The fun or constructor has no field map and so we error\n                    // if arguments have been labelled.\n                    Ok(None) if fun.is_record_constructor_function() => {\n                        assert_no_labelled_arguments(\n                            &arguments,\n                            UnexpectedLabelledArgKind::RecordConstructorArgument,\n                        )\n                    }\n                    Ok(None) => assert_no_labelled_arguments(\n                        &arguments,\n                        UnexpectedLabelledArgKind::FunctionParameter,\n                    ),\n                };\n\n                // If there's an error reordering the fields, or there's labelled\n                // arguments with no field map, then we return an invalid expression.\n                if let Err(error) = result {\n                    self.problems.error(error);\n                    return self.new_invalid_constant(location);\n                }\n\n                let (mut arguments_types, return_type) =\n                    match match_fun_type(fun.type_(), arguments.len(), self.environment) {\n                        Ok((arguments_types, return_type)) => (arguments_types, return_type),\n                        Err(error) => {\n                            self.problems.error(convert_not_fun_error(\n                                error,\n                                fun.location(),\n                                location,\n                                CallKind::Function,\n                            ));\n                            return self.new_invalid_constant(location);\n                        }\n                    };\n\n                let arguments = arguments_types\n                    .iter_mut()\n                    .zip(arguments)\n                    .map(|(type_, argument): (&mut Arc<Type>, _)| {\n                        if argument.uses_label_shorthand() {\n                            self.track_feature_usage(\n                                FeatureKind::LabelShorthandSyntax,\n                                argument.location,\n                            );\n                        }\n                        let CallArg {\n                            label,\n                            value,\n                            location,\n                            implicit,\n                        } = argument;\n                        let value = self.infer_const(&None, value);\n                        if let Err(error) = unify(type_.clone(), value.type_()) {\n                            self.problems\n                                .error(convert_unify_error(error, value.location()))\n                        }\n                        CallArg {\n                            label,\n                            value,\n                            implicit,\n                            location,\n                        }\n                    })\n                    .collect_vec();\n\n                Constant::Record {\n                    module,\n                    location,\n                    name,\n                    arguments,\n                    type_: return_type,\n                    tag,\n                    field_map,\n                    record_constructor: Some(Box::new(constructor)),\n                }\n            }\n\n            Constant::Var {\n                location,\n                module,\n                name,\n                ..\n            } => {\n                // Infer the type of this constant\n                let constructor = match self.infer_value_constructor(&module, &name, &location) {\n                    Ok(constructor) => constructor,\n                    Err(error) => {\n                        self.problems.error(error);\n                        return Constant::Invalid {\n                            location,\n                            type_: self.new_unbound_var(),\n                            extra_information: Some(match module {\n                                Some((module_name, _)) => InvalidExpression::ModuleSelect {\n                                    module_name,\n                                    label: name,\n                                },\n                                None => InvalidExpression::UnknownVariable { name },\n                            }),\n                        };\n                    }\n                };\n\n                match constructor.variant {\n                    ValueConstructorVariant::ModuleConstant { .. }\n                    | ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::LocalVariable { .. } => Constant::Var {\n                        location,\n                        module,\n                        name,\n                        type_: Arc::clone(&constructor.type_),\n                        constructor: Some(Box::from(constructor)),\n                    },\n                    // It cannot be a Record because then this constant would have been\n                    // parsed as a Constant::Record. Therefore this code is unreachable.\n                    ValueConstructorVariant::Record { .. } => unreachable!(),\n                }\n            }\n\n            Constant::StringConcatenation {\n                location,\n                left,\n                right,\n            } => {\n                self.track_feature_usage(FeatureKind::ConstantStringConcatenation, location);\n                let left = self.infer_const(&None, *left);\n\n                if let Err(error) = unify(string(), left.type_()) {\n                    self.problems.error(\n                        error\n                            .operator_situation(BinOp::Concatenate)\n                            .into_error(left.location()),\n                    )\n                };\n\n                let right = self.infer_const(&None, *right);\n                if let Err(error) = unify(string(), right.type_()) {\n                    self.problems.error(\n                        error\n                            .operator_situation(BinOp::Concatenate)\n                            .into_error(right.location()),\n                    )\n                };\n\n                Constant::StringConcatenation {\n                    location,\n                    left: Box::new(left),\n                    right: Box::new(right),\n                }\n            }\n\n            Constant::Invalid { .. } => panic!(\"invalid constants can not be in an untyped ast\"),\n        }\n    }\n\n    /// Returns an invalid constant with an unbound type and no extra information\n    /// attached.\n    fn new_invalid_constant(&mut self, location: SrcSpan) -> TypedConstant {\n        Constant::Invalid {\n            location,\n            type_: self.new_unbound_var(),\n            extra_information: None,\n        }\n    }\n\n    pub fn infer_const(\n        &mut self,\n        annotation: &Option<TypeAst>,\n        value: UntypedConstant,\n    ) -> TypedConstant {\n        let inferred = self.infer_const_value(value);\n\n        match annotation\n            .as_ref()\n            .map(|annotation| self.type_from_ast(annotation))\n        {\n            Some(Err(error)) => {\n                self.problems.error(error);\n                inferred\n            }\n\n            // If there's an annotation we try and unify it with the inferred\n            // type.\n            Some(Ok(annotated_type)) => {\n                if let Err(error) = unify(annotated_type.clone(), inferred.type_()) {\n                    self.problems\n                        .error(convert_unify_error(error, inferred.location()));\n                    invalid_with_annotated_type(inferred, annotated_type)\n                } else {\n                    inferred\n                }\n            }\n\n            None => inferred,\n        }\n    }\n\n    fn infer_const_tuple(\n        &mut self,\n        untyped_elements: Vec<UntypedConstant>,\n        location: SrcSpan,\n    ) -> TypedConstant {\n        let mut elements = Vec::with_capacity(untyped_elements.len());\n\n        for element in untyped_elements {\n            let element = self.infer_const(&None, element);\n            elements.push(element);\n        }\n\n        let type_ = tuple(elements.iter().map(HasType::type_).collect_vec());\n\n        Constant::Tuple {\n            elements,\n            location,\n            type_,\n        }\n    }\n\n    fn infer_const_list(\n        &mut self,\n        untyped_elements: Vec<UntypedConstant>,\n        location: SrcSpan,\n        tail: Option<Box<UntypedConstant>>,\n    ) -> TypedConstant {\n        let element_type = self.new_unbound_var();\n        let mut elements = Vec::with_capacity(untyped_elements.len());\n\n        for element in untyped_elements {\n            let element = self.infer_const(&None, element);\n            if let Err(error) = unify(element_type.clone(), element.type_()) {\n                self.problems\n                    .error(convert_unify_error(error, element.location()));\n            }\n\n            elements.push(element);\n        }\n\n        let type_ = list(element_type);\n\n        let tail = if let Some(tail) = tail {\n            let tail = self.infer_const(&None, *tail);\n            if let Err(error) = unify(type_.clone(), tail.type_()) {\n                self.problems\n                    .error(convert_unify_error(error, tail.location()))\n            }\n            Some(Box::new(tail))\n        } else {\n            None\n        };\n\n        Constant::List {\n            elements,\n            location,\n            type_,\n            tail,\n        }\n    }\n\n    fn get_field_map(\n        &mut self,\n        constructor: &TypedExpr,\n    ) -> Result<Option<&FieldMap>, UnknownValueConstructorError> {\n        let (module, name) = match constructor {\n            TypedExpr::ModuleSelect {\n                module_alias,\n                label,\n                ..\n            } => (Some(module_alias), label),\n\n            TypedExpr::Var { name, .. } => (None, name),\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => return Ok(None),\n        };\n\n        Ok(self\n            .environment\n            .get_value_constructor(module, name)?\n            .field_map())\n    }\n\n    pub fn do_infer_call(\n        &mut self,\n        fun: UntypedExpr,\n        arguments: Vec<CallArg<UntypedExpr>>,\n        location: SrcSpan,\n        kind: CallKind,\n    ) -> (TypedExpr, Vec<TypedCallArg>, Arc<Type>) {\n        let fun = match fun {\n            UntypedExpr::FieldAccess {\n                label,\n                container,\n                label_location,\n                location,\n            } => self.infer_field_access(\n                *container,\n                location,\n                label,\n                label_location,\n                FieldAccessUsage::MethodCall,\n            ),\n\n            UntypedExpr::Fn {\n                location,\n                kind,\n                arguments: fn_arguments,\n                body,\n                return_annotation,\n                ..\n            } if fn_arguments.len() == arguments.len() => self.infer_fn_with_call_context(\n                fn_arguments,\n                &arguments,\n                body,\n                kind,\n                return_annotation,\n                location,\n            ),\n\n            UntypedExpr::Int { .. }\n            | UntypedExpr::Float { .. }\n            | UntypedExpr::String { .. }\n            | UntypedExpr::Block { .. }\n            | UntypedExpr::Var { .. }\n            | UntypedExpr::Fn { .. }\n            | UntypedExpr::List { .. }\n            | UntypedExpr::Call { .. }\n            | UntypedExpr::BinOp { .. }\n            | UntypedExpr::PipeLine { .. }\n            | UntypedExpr::Case { .. }\n            | UntypedExpr::Tuple { .. }\n            | UntypedExpr::TupleIndex { .. }\n            | UntypedExpr::Todo { .. }\n            | UntypedExpr::Panic { .. }\n            | UntypedExpr::Echo { .. }\n            | UntypedExpr::BitArray { .. }\n            | UntypedExpr::RecordUpdate { .. }\n            | UntypedExpr::NegateBool { .. }\n            | UntypedExpr::NegateInt { .. } => self.infer(fun),\n        };\n\n        let (fun, arguments, type_) =\n            self.do_infer_call_with_known_fun(fun, arguments, location, kind);\n        (fun, arguments, type_)\n    }\n\n    fn infer_fn_with_call_context(\n        &mut self,\n        arguments: Vec<UntypedArg>,\n        call_arguments: &[CallArg<UntypedExpr>],\n        body: Vec1<UntypedStatement>,\n        kind: FunctionLiteralKind,\n        return_annotation: Option<TypeAst>,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        let typed_call_arguments: Vec<Arc<Type>> = call_arguments\n            .iter()\n            .map(|argument| {\n                match self.infer_or_error(argument.value.clone()) {\n                    Ok(argument) => argument,\n                    Err(_e) => self.error_expr(location),\n                }\n                .type_()\n            })\n            .collect_vec();\n        self.infer_fn(\n            arguments,\n            &typed_call_arguments,\n            body,\n            kind,\n            return_annotation,\n            location,\n        )\n    }\n\n    pub fn do_infer_call_with_known_fun(\n        &mut self,\n        fun: TypedExpr,\n        mut arguments: Vec<CallArg<UntypedExpr>>,\n        location: SrcSpan,\n        kind: CallKind,\n    ) -> (TypedExpr, Vec<TypedCallArg>, Arc<Type>) {\n        let mut labelled_arity_error = false;\n\n        // Check to see if the function accepts labelled arguments\n        let field_map = self\n            .get_field_map(&fun)\n            .map_err(|e| convert_get_value_constructor_error(e, location, None))\n            .and_then(|field_map| {\n                match field_map {\n                    // The fun has a field map so labelled arguments may be\n                    // present and need to be reordered.\n                    Some(field_map) => {\n                        field_map.reorder(&mut arguments, location, IncorrectArityContext::Function)\n                    }\n\n                    // The fun or constructor has no field map and so we error\n                    // if arguments have been labelled.\n                    // There's an exception to this rule: if the function itself\n                    // doesn't exist (that is it's an `Invalid` expression), then\n                    // we don't want to error on any labels that might have been\n                    // used as it would be quite noisy. Once the function is\n                    // known to be a valid function we can make sure that there's\n                    // no labelled arguments if it doesn't actually have a field map.\n                    None if fun.is_invalid() => Ok(()),\n                    None if fun.is_record_constructor_function() => assert_no_labelled_arguments(\n                        &arguments,\n                        UnexpectedLabelledArgKind::RecordConstructorArgument,\n                    ),\n                    None => assert_no_labelled_arguments(\n                        &arguments,\n                        UnexpectedLabelledArgKind::FunctionParameter,\n                    ),\n                }\n            });\n\n        if let Err(e) = field_map {\n            if let Error::IncorrectArity {\n                expected,\n                given,\n                context,\n                labels,\n                location,\n            } = e\n            {\n                labelled_arity_error = true;\n                self.problems.error(Error::IncorrectArity {\n                    expected,\n                    given,\n                    context,\n                    labels,\n                    location,\n                });\n            } else {\n                self.problems.error(e);\n            }\n        }\n\n        let mut missing_arguments = 0;\n        let mut ignored_labelled_arguments = vec![];\n        // Extract the type of the fun, ensuring it actually is a function\n        let (mut arguments_types, return_type) =\n            match match_fun_type(fun.type_(), arguments.len(), self.environment) {\n                Ok(function) => function,\n                Err(error) => {\n                    let converted_error =\n                        convert_not_fun_error(error.clone(), fun.location(), location, kind);\n                    match error {\n                        // If the function was valid but had the wrong number of arguments passed.\n                        // Then we keep the error but still want to continue analysing the arguments that were passed.\n                        MatchFunTypeError::IncorrectArity {\n                            arguments: arg_types,\n                            return_type,\n                            expected,\n                            given,\n                            ..\n                        } => {\n                            missing_arguments = expected.saturating_sub(given);\n                            // If the function has labels then arity issues will already\n                            // be handled by the field map so we can ignore them here.\n                            if !labelled_arity_error {\n                                self.problems.error(converted_error);\n                                (arg_types, return_type)\n                            } else {\n                                // Since arity errors with labels cause incorrect\n                                // ordering, we can't type check the labelled arguments here.\n                                let first_labelled_arg =\n                                    arguments.iter().position(|arg| arg.label.is_some());\n                                ignored_labelled_arguments = arguments\n                                    .iter()\n                                    .skip_while(|argument| argument.label.is_none())\n                                    .map(|argument| {\n                                        (\n                                            argument.label.clone(),\n                                            argument.location,\n                                            argument.implicit,\n                                        )\n                                    })\n                                    .collect_vec();\n                                let arguments_to_keep =\n                                    first_labelled_arg.unwrap_or(arguments.len());\n                                (\n                                    arg_types.iter().take(arguments_to_keep).cloned().collect(),\n                                    return_type,\n                                )\n                            }\n                        }\n                        MatchFunTypeError::NotFn { .. } => {\n                            self.problems.error(converted_error);\n                            (vec![], self.new_unbound_var())\n                        }\n                    }\n                }\n            };\n\n        // When typing the function's arguments we don't care if the previous\n        // expression panics or not because we want to provide a specialised\n        // error message for this particular case.\n        // So we set `previous_panics` to false to avoid raising any\n        // unnecessarily generic warning.\n        self.previous_panics = false;\n\n        // Now if we had a mismatched arity error and we're typing a use call,\n        // we want to insert all the missing arguments before the callback\n        // argument that is implicitly passed by the compiler.\n        // This way we can provide better argument hints for incomplete use\n        // expressions.\n        if let CallKind::Use { .. } = kind\n            && let Some(last) = arguments.pop()\n        {\n            for _ in 0..missing_arguments {\n                arguments.push(CallArg {\n                    label: None,\n                    location,\n                    value: UntypedExpr::Panic {\n                        // We intentionally give this an empty span since it\n                        // is an implicit argument being passed by the compiler\n                        // that doesn't appear in the source code.\n                        location: SrcSpan {\n                            start: last.location().start,\n                            end: last.location().start,\n                        },\n                        message: None,\n                    },\n                    implicit: Some(ImplicitCallArgOrigin::IncorrectArityUse),\n                });\n            }\n            arguments.push(last);\n        };\n\n        // Ensure that the given args have the correct types\n        let arguments_count = arguments_types.len();\n        let mut typed_arguments: Vec<_> = arguments_types\n            .iter_mut()\n            .zip(arguments)\n            .enumerate()\n            .map(|(argument_index, (type_, arg))| {\n                if arg.uses_label_shorthand() {\n                    self.track_feature_usage(FeatureKind::LabelShorthandSyntax, arg.location);\n                }\n\n                let CallArg {\n                    label,\n                    value,\n                    location,\n                    implicit,\n                } = arg;\n\n                // If we're typing a `use` call then the last argument is the\n                // use callback and we want to treat it differently to report\n                // better errors.\n                let argument_kind = match kind {\n                    CallKind::Use {\n                        call_location,\n                        last_statement_location,\n                        assignments_location,\n                    } if argument_index == arguments_count - 1 => ArgumentKind::UseCallback {\n                        function_location: call_location,\n                        assignments_location,\n                        last_statement_location,\n                    },\n                    CallKind::Use { .. } | CallKind::Function => ArgumentKind::Regular,\n                };\n\n                // We don't want to emit a warning for unreachable function call if the\n                // function being called is itself `panic`, for that we emit a more\n                // specialised warning.\n                if self.previous_panics && !fun.is_panic() {\n                    self.warn_for_unreachable_code(\n                        value.location(),\n                        PanicPosition::PreviousFunctionArgument,\n                    )\n                }\n\n                let value = self.infer_call_argument(\n                    &fun,\n                    value,\n                    argument_index,\n                    type_.clone(),\n                    argument_kind,\n                );\n\n                CallArg {\n                    label,\n                    value,\n                    implicit,\n                    location,\n                }\n            })\n            .collect();\n\n        // Now if we had supplied less arguments than required and some of those\n        // were labelled, in the previous step we would have got rid of those\n        // _before_ typing.\n        // That is because we can only reliably type positional arguments in\n        // case of mismatched arity, as labelled arguments cannot be reordered.\n        //\n        // So now what we want to do is add back those labelled arguments to\n        // make sure the LS can still see that those were explicitly supplied.\n        for (label, location, implicit) in ignored_labelled_arguments {\n            typed_arguments.push(CallArg {\n                label,\n                value: TypedExpr::Invalid {\n                    location,\n                    type_: self.new_unbound_var(),\n                    extra_information: None,\n                },\n                implicit,\n                location,\n            })\n        }\n\n        // We don't want to emit a warning for unreachable function call if the\n        // function being called is itself `panic`, for that we emit a more\n        // specialised warning.\n        if self.previous_panics && !fun.is_panic() {\n            self.warn_for_unreachable_code(fun.location(), PanicPosition::LastFunctionArgument);\n        }\n\n        (fun, typed_arguments, return_type)\n    }\n\n    fn infer_call_argument(\n        &mut self,\n        called_function: &TypedExpr,\n        argument: UntypedExpr,\n        argument_index: usize,\n        type_: Arc<Type>,\n        kind: ArgumentKind,\n    ) -> TypedExpr {\n        let type_ = collapse_links(type_);\n        let value = match (&*type_, argument) {\n            // If the argument is expected to be a function and we are passed a\n            // function literal with the correct number of arguments then we\n            // have special handling of this argument, passing in information\n            // about what the expected arguments are. This extra information\n            // when type checking the function body means that the\n            // `record.field` access syntax can be used, and improves error\n            // messages.\n            (\n                Type::Fn {\n                    arguments: expected_arguments,\n                    ..\n                },\n                UntypedExpr::Fn {\n                    arguments,\n                    body,\n                    return_annotation,\n                    location,\n                    kind,\n                    ..\n                },\n            ) if expected_arguments.len() == arguments.len() => self.infer_fn(\n                arguments,\n                expected_arguments,\n                body,\n                kind,\n                return_annotation,\n                location,\n            ),\n\n            // If the argument is a regular var then we want to add some extra\n            // checks. The value will be inferred regularly, but we also want to\n            // see if this is an argument that is being passed recursively to\n            // the same function that defined it!\n            (_, UntypedExpr::Var { location, name }) => {\n                self.infer_variable_call_arg(called_function, name, location, argument_index)\n            }\n\n            // Otherwise just perform normal type inference.\n            (_, argument) => self.infer(argument),\n        };\n\n        if let Err(error) = unify(type_.clone(), value.type_()) {\n            self.problems\n                .error(convert_unify_call_error(error, value.location(), kind));\n        }\n\n        value\n    }\n\n    fn infer_variable_call_arg(\n        &mut self,\n        called_function: &TypedExpr,\n        argument_name: EcoString,\n        argument_location: SrcSpan,\n        argument_index: usize,\n    ) -> TypedExpr {\n        // If the called function is a function defined in this same module we\n        // pass it along to the `infer_var` function so that we can check if the\n        // argument is being passed recursively to the function that is defining\n        // it.\n        let references = if let TypedExpr::Var {\n            constructor:\n                ValueConstructor {\n                    variant: ValueConstructorVariant::ModuleFn { name, module, .. },\n                    ..\n                },\n            ..\n        } = called_function\n            && *module == self.environment.current_module\n        {\n            ReferenceRegistration::VariableArgument {\n                called_function: name.clone(),\n                argument_index,\n            }\n        } else {\n            ReferenceRegistration::Register\n        };\n\n        match self.infer_var(argument_name.clone(), argument_location, references) {\n            Ok(result) => result,\n            Err(error) => {\n                self.problems.error(error);\n                self.error_expr_with_information(\n                    argument_location,\n                    Some(InvalidExpression::UnknownVariable {\n                        name: argument_name,\n                    }),\n                )\n            }\n        }\n    }\n\n    pub fn do_infer_fn(\n        &mut self,\n        function_name: Option<EcoString>,\n        arguments: Vec<UntypedArg>,\n        expected_arguments: &[Arc<Type>],\n        body: Vec1<UntypedStatement>,\n        return_annotation: &Option<TypeAst>,\n    ) -> Result<(Vec<TypedArg>, Vec1<TypedStatement>), Error> {\n        // Construct an initial type for each argument of the function- either an unbound\n        // type variable or a type provided by an annotation.\n        let arguments: Vec<_> = arguments\n            .into_iter()\n            .enumerate()\n            .map(|(i, argument)| self.infer_arg(argument, expected_arguments.get(i).cloned()))\n            .try_collect()?;\n\n        let return_type = match return_annotation {\n            Some(ann) => Some(self.type_from_ast(ann)?),\n            None => None,\n        };\n\n        let (arguments, body) =\n            self.infer_fn_with_known_types(function_name, arguments, body.to_vec(), return_type)?;\n        let body =\n            Vec1::try_from_vec(body).expect(\"body guaranteed to have at least one statement\");\n        Ok((arguments, body))\n    }\n\n    pub fn infer_fn_with_known_types(\n        &mut self,\n        function_name: Option<EcoString>,\n        arguments: Vec<TypedArg>,\n        body: Vec<UntypedStatement>,\n        return_type: Option<Arc<Type>>,\n    ) -> Result<(Vec<TypedArg>, Vec<TypedStatement>), Error> {\n        // If a function has an empty body then it doesn't have a pure gleam\n        // implementation.\n        if body.is_empty() {\n            self.implementations.gleam = false;\n        }\n\n        self.in_new_scope(|body_typer| {\n            // Used to track if any argument names are used more than once\n            let mut argument_names = HashSet::with_capacity(arguments.len());\n\n            for (argument_index, argument) in arguments.iter().enumerate() {\n                match &argument.names {\n                    ArgNames::Named { name, location }\n                    | ArgNames::NamedLabelled {\n                        name,\n                        name_location: location,\n                        ..\n                    } => {\n                        // Check that this name has not already been used for\n                        // another argument\n                        if !argument_names.insert(name) {\n                            return Err(Error::ArgumentNameAlreadyUsed {\n                                location: argument.location,\n                                name: name.clone(),\n                            });\n                        }\n\n                        let syntax = if name == CAPTURE_VARIABLE {\n                            VariableSyntax::Generated\n                        } else {\n                            VariableSyntax::Variable(name.clone())\n                        };\n\n                        let origin = VariableOrigin {\n                            syntax,\n                            declaration: VariableDeclaration::FunctionParameter {\n                                function_name: function_name.clone(),\n                                index: argument_index,\n                            },\n                        };\n\n                        // Insert a variable for the argument into the environment\n                        body_typer.environment.insert_local_variable(\n                            name.clone(),\n                            *location,\n                            origin.clone(),\n                            argument.type_.clone(),\n                        );\n\n                        if !body.is_empty() {\n                            // Register the variable in the usage tracker so that we\n                            // can identify if it is unused\n                            body_typer.environment.init_usage(\n                                name.clone(),\n                                origin,\n                                *location,\n                                body_typer.problems,\n                            );\n                        }\n                    }\n                    ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => (),\n                };\n            }\n\n            if let Ok(body) = Vec1::try_from_vec(body) {\n                let mut body = body_typer.infer_statements(body);\n\n                // Check that any return type is accurate.\n                if let Some(return_type) = return_type\n                    && let Err(error) = unify(return_type, body.last().type_())\n                {\n                    let error = error\n                        .return_annotation_mismatch()\n                        .into_error(body.last().type_defining_location());\n                    body_typer.problems.error(error);\n\n                    // If the return type doesn't match with the annotation we\n                    // add a new expression to the end of the function to match\n                    // the annotated type and allow type inference to keep\n                    // going.\n                    body.push(Statement::Expression(TypedExpr::Invalid {\n                        // This is deliberately an empty span since this\n                        // placeholder expression is implicitly inserted by the\n                        // compiler and doesn't actually appear in the source\n                        // code.\n                        location: SrcSpan {\n                            start: body.last().location().end,\n                            end: body.last().location().end,\n                        },\n                        type_: body_typer.new_unbound_var(),\n                        extra_information: None,\n                    }))\n                };\n\n                Ok((arguments, body.to_vec()))\n            } else {\n                Ok((arguments, vec![]))\n            }\n        })\n    }\n\n    fn infer_block(&mut self, statements: Vec1<UntypedStatement>, location: SrcSpan) -> TypedExpr {\n        self.expr_in_new_scope(|typer| {\n            let statements = typer.infer_statements(statements);\n            TypedExpr::Block {\n                statements,\n                location,\n            }\n        })\n    }\n\n    /// Returns `Ok(())` if the let is exhaustive, returns an `InexhaustiveLetAssignment`\n    /// error if the given pattern doesn't cover all possible cases.\n    ///\n    fn check_let_exhaustiveness(\n        &self,\n        location: SrcSpan,\n        subject: Arc<Type>,\n        pattern: &TypedPattern,\n    ) -> (CompileCaseResult, Result<(), Error>) {\n        let mut case = exhaustiveness::CaseToCompile::new(&[subject]);\n        case.add_pattern(pattern);\n        let output = case.compile(self.environment);\n\n        // Error for missing clauses that would cause a crash\n        let result = if output.diagnostics.missing {\n            Err(Error::InexhaustiveLetAssignment {\n                location,\n                missing: output.missing_patterns(self.environment),\n            })\n        } else {\n            Ok(())\n        };\n\n        (output, result)\n    }\n\n    fn check_case_exhaustiveness(\n        &mut self,\n        location: SrcSpan,\n        subject_types: &[Arc<Type>],\n        clauses: &[TypedClause],\n    ) -> CompiledCase {\n        let mut case = exhaustiveness::CaseToCompile::new(subject_types);\n        clauses.iter().for_each(|clause| case.add_clause(clause));\n        let result = case.compile(self.environment);\n\n        // Error for missing clauses that would cause a crash\n        if result.diagnostics.missing {\n            self.problems.error(Error::InexhaustiveCaseExpression {\n                location,\n                missing: result.missing_patterns(self.environment),\n            });\n        }\n\n        // Emit warnings for unreachable patterns\n        for (clause_index, clause) in clauses.iter().enumerate() {\n            let patterns_iterator =\n                std::iter::once(&clause.pattern).chain(clause.alternative_patterns.iter());\n\n            for (pattern_index, multi_pattern) in patterns_iterator.enumerate() {\n                match result.is_reachable(clause_index, pattern_index) {\n                    Reachability::Reachable => {}\n                    Reachability::Unreachable(reason) => {\n                        let first = multi_pattern\n                            .first()\n                            .expect(\"All case expressions match at least one subject\");\n                        let last = multi_pattern\n                            .last()\n                            .expect(\"All case expressions match at least one subject\");\n\n                        let location = SrcSpan::new(first.location().start, last.location().end);\n\n                        self.problems\n                            .warning(Warning::UnreachableCasePattern { location, reason })\n                    }\n                }\n            }\n        }\n\n        result.compiled_case\n    }\n\n    fn track_feature_usage(&mut self, feature_kind: FeatureKind, location: SrcSpan) {\n        let minimum_required_version = feature_kind.required_version();\n\n        // Then if the required version is not in the specified version for the\n        // range we emit a warning highlighting the usage of the feature.\n        if let Some(gleam_version) = &self.environment.gleam_version\n            && let Some(lowest_allowed_version) = gleam_version.lowest_version()\n        {\n            // There is a version in the specified range that is lower than\n            // the one required by this feature! This means that the\n            // specified range is wrong and would allow someone to run a\n            // compiler that is too old to know of this feature.\n            if minimum_required_version > lowest_allowed_version {\n                self.problems\n                    .warning(Warning::FeatureRequiresHigherGleamVersion {\n                        location,\n                        feature_kind,\n                        minimum_required_version: minimum_required_version.clone(),\n                        wrongfully_allowed_version: lowest_allowed_version,\n                    })\n            }\n        }\n\n        if minimum_required_version > self.minimum_required_version {\n            self.minimum_required_version = minimum_required_version;\n        }\n    }\n\n    /// Checks if one of the options is a size option using an expression.\n    /// This needs to be tracked as it was introduced in Gleam 1.12.0.\n    fn check_segment_size_expression(&mut self, options: &[BitArrayOption<TypedExpr>]) {\n        let Some(size_value) = options.iter().find_map(|option| match option {\n            BitArrayOption::Size { value, .. } => Some(value),\n\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n        }) else {\n            return;\n        };\n\n        match size_value.as_ref() {\n            // Ints and vars were always allowed from the start\n            TypedExpr::Int { .. } | TypedExpr::Var { .. } => (),\n\n            // Blocks and binops were added in Gleam 1.12.0!\n            TypedExpr::Block { location, .. } | TypedExpr::BinOp { location, .. } => {\n                self.track_feature_usage(FeatureKind::ExpressionInSegmentSize, *location)\n            }\n\n            // None of these are currently supported... for now!\n            TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => (),\n        }\n    }\n\n    /// Checks if one of the options is a size option using an expression.\n    /// This needs to be tracked as it was introduced in Gleam 1.12.0.\n    ///\n    /// This is basically the same as the function above working on expressions!\n    fn check_constant_segment_size_expression(&self, options: &[BitArrayOption<TypedConstant>]) {\n        let Some(size_value) = options.iter().find_map(|option| match option {\n            BitArrayOption::Size { value, .. } => Some(value),\n\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n        }) else {\n            return;\n        };\n\n        // Expressions are not allowed in constants so for now nothing needs\n        // tracking. Though this is handy to have already in place if we were to\n        // lift this restriction for constant bit arrays as well!\n        match size_value.as_ref() {\n            // Ints and vars were always allowed from the start\n            TypedConstant::Int { .. } | TypedConstant::Var { .. } => (),\n\n            // None of these are currently supported... for now!\n            Constant::Float { .. }\n            | Constant::String { .. }\n            | Constant::Tuple { .. }\n            | Constant::List { .. }\n            | Constant::Record { .. }\n            | Constant::RecordUpdate { .. }\n            | Constant::BitArray { .. }\n            | Constant::StringConcatenation { .. }\n            | Constant::Invalid { .. } => (),\n        }\n    }\n}\n\n/// Given a constants, this will change its type into the given one, turning\n/// the constant into an `Invalid` one if necessary.\n///\nfn invalid_with_annotated_type(constant: TypedConstant, new_type: Arc<Type>) -> TypedConstant {\n    // In case the types cannot be unified we change the inferred we\n    // return a constant where the type matches the annotated one.\n    // This can help minimise fals positive later on!\n    match constant {\n        // For simple variants that don't carry their own type we\n        // replace them with an invalid constant with the same\n        // location and the new annotated type.\n        Constant::Int { location, .. }\n        | Constant::Float { location, .. }\n        | Constant::String { location, .. }\n        | Constant::BitArray { location, .. }\n        | Constant::StringConcatenation { location, .. } => TypedConstant::Invalid {\n            location,\n            type_: new_type,\n            extra_information: None,\n        },\n\n        // In all other cases we don't want to lose information on\n        // the actual structure of the invalid expression. So we just\n        // replace the type with the annotated one.\n        Constant::Invalid {\n            location,\n            type_: _,\n            extra_information,\n        } => Constant::Invalid {\n            location,\n            type_: new_type,\n            extra_information,\n        },\n\n        Constant::Tuple {\n            location,\n            elements,\n            type_: _,\n        } => Constant::Tuple {\n            location,\n            elements,\n            type_: new_type,\n        },\n\n        Constant::List {\n            location,\n            elements,\n            type_: _,\n            tail,\n        } => Constant::List {\n            location,\n            elements,\n            type_: new_type,\n            tail,\n        },\n\n        Constant::Record {\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_: _,\n            field_map,\n            record_constructor,\n        } => Constant::Record {\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_: new_type,\n            field_map,\n            record_constructor,\n        },\n\n        Constant::RecordUpdate {\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag,\n            type_: _,\n            field_map,\n        } => Constant::RecordUpdate {\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag,\n            type_: new_type,\n            field_map,\n        },\n\n        Constant::Var {\n            location,\n            module,\n            name,\n            constructor,\n            type_: _,\n        } => Constant::Var {\n            location,\n            module,\n            name,\n            constructor,\n            type_: new_type,\n        },\n    }\n}\n\n/// Returns `true` if the current module is one that the Gleam core team\n/// maintains and we know it to be pure.\n/// Used in purity tracking.\nfn is_trusted_pure_module(environment: &Environment<'_>) -> bool {\n    if environment.current_package != STDLIB_PACKAGE_NAME {\n        return false;\n    }\n\n    // The gleam/io module has side effects\n    if environment.current_module == \"gleam/io\" {\n        return false;\n    }\n\n    // Test and dev modules may have side effects\n    environment.origin == Origin::Src\n}\n\n#[derive(Debug, Clone)]\nenum ReferenceRegistration {\n    Register,\n    DoNotRegister,\n\n    /// A special case that happens if we're registering references for\n    /// a variable call argument being passed to a function defined in the\n    /// current module.\n    VariableArgument {\n        /// The name of the function being called, the function is defined in\n        /// the current module.\n        called_function: EcoString,\n        /// The position where the variable is being passed as an argument.\n        argument_index: usize,\n    },\n}\n\nfn extract_typed_use_call_assignments(\n    call: &TypedExpr,\n    assignments_count: usize,\n) -> Vec<UseAssignment<Arc<Type>>> {\n    // A use call function has the use callback as its last argument, the\n    // assignments will be the first statements in its body.\n    let Some(use_callback_body) = call\n        .call_arguments()\n        .and_then(|call_arguments| call_arguments.last())\n        .and_then(|last_call_argument| last_call_argument.value.fn_expression_body())\n    else {\n        return vec![];\n    };\n\n    // Once we get a hold of the callback function body we take out the first\n    // `assignments_count` statements and turn those into typed\n    // `UseAssignments`.\n    //\n    // Note how we can't just `.expect` them to be a `Statement::Assignment`\n    // because in case of type errors those might be invalid expressions and we\n    // don't want to crash the compiler in that case!\n    use_callback_body\n        .iter()\n        .take(assignments_count)\n        .map(|statement| match statement {\n            Statement::Expression(_) | Statement::Use(_) | Statement::Assert(_) => None,\n            Statement::Assignment(assignment) => Some(UseAssignment {\n                location: assignment.location,\n                pattern: assignment.pattern.clone(),\n                annotation: assignment.annotation.clone(),\n            }),\n        })\n        .collect::<Option<Vec<_>>>()\n        .unwrap_or(vec![])\n}\n\nfn check_subject_for_redundant_match(\n    subject: &TypedExpr,\n    case_used_like_if: bool,\n) -> Option<Warning> {\n    match subject {\n        TypedExpr::Tuple { elements, .. } if !elements.is_empty() => {\n            Some(Warning::CaseMatchOnLiteralCollection {\n                kind: LiteralCollectionKind::Tuple,\n                location: subject.location(),\n            })\n        }\n\n        TypedExpr::List { elements, tail, .. } if !elements.is_empty() || tail.is_some() => {\n            Some(Warning::CaseMatchOnLiteralCollection {\n                kind: LiteralCollectionKind::List,\n                location: subject.location(),\n            })\n        }\n\n        TypedExpr::BitArray { segments, .. } if !segments.is_empty() => {\n            // We don't want a warning when matching on literal bit arrays\n            // because it can make sense to do it; for example if one is\n            // matching on segments that do not align with the segments used\n            // for construction.\n            None\n        }\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => match subject.record_constructor_arity() {\n            // We make sure to not emit warnings if the case is being used like an\n            // if expression:\n            // ```gleam\n            // case True {\n            //   _ if condition -> todo\n            //   _ if other_condition -> todo\n            //   _ -> todo\n            // }\n            // ```\n            Some(0) if !case_used_like_if => Some(Warning::CaseMatchOnLiteralValue {\n                location: subject.location(),\n            }),\n            Some(0) => None,\n            Some(_) => Some(Warning::CaseMatchOnLiteralCollection {\n                kind: LiteralCollectionKind::Record,\n                location: subject.location(),\n            }),\n            None if subject.is_literal() && !case_used_like_if => {\n                Some(Warning::CaseMatchOnLiteralValue {\n                    location: subject.location(),\n                })\n            }\n            None => None,\n        },\n    }\n}\n\n/// Returns the kind of an empty list check.\n///\n/// Based on the binary operator being used and the position of the operands we\n/// can categorize an empty list check in one of two ways:\n///   - Checking for the empty list\n///   - Checking for a non-empty list\nfn get_empty_list_check_kind<'a>(\n    binop: BinOp,\n    left: &'a TypedExpr,\n    right: &'a TypedExpr,\n) -> Option<EmptyListCheckKind> {\n    match (&left, &right) {\n        // For `==` and `!=` we don't care which side each of the operands are on.\n        (_, TypedExpr::Int { value, .. }) | (TypedExpr::Int { value, .. }, _)\n            if binop == BinOp::Eq || binop == BinOp::NotEq =>\n        {\n            match (binop, value.as_str()) {\n                (BinOp::Eq, \"0\" | \"-0\") => Some(EmptyListCheckKind::Empty),\n                (BinOp::NotEq, \"0\" | \"-0\") => Some(EmptyListCheckKind::NonEmpty),\n                _ => None,\n            }\n        }\n        (_, TypedExpr::Int { value, .. }) => match (binop, value.as_str()) {\n            (BinOp::LtEqInt, \"0\" | \"-0\") | (BinOp::LtInt, \"1\") => Some(EmptyListCheckKind::Empty),\n            (BinOp::GtInt, \"0\" | \"-0\") => Some(EmptyListCheckKind::NonEmpty),\n            _ => None,\n        },\n        (TypedExpr::Int { value, .. }, _) => match (binop, value.as_str()) {\n            (BinOp::GtEqInt | BinOp::LtInt, \"0\" | \"-0\") | (BinOp::GtInt, \"1\") => {\n                Some(EmptyListCheckKind::NonEmpty)\n            }\n            _ => None,\n        },\n        _ => None,\n    }\n}\n\nstruct UseCall {\n    function: Box<UntypedExpr>,\n    arguments: Vec<CallArg<UntypedExpr>>,\n}\n\nfn get_use_expression_call(call: UntypedExpr) -> UseCall {\n    // Ensure that the use's call is of the right structure. i.e. it is a\n    // call to a function.\n    if let UntypedExpr::Call {\n        fun: function,\n        arguments,\n        ..\n    } = call\n    {\n        UseCall {\n            arguments,\n            function,\n        }\n    } else {\n        UseCall {\n            function: Box::new(call),\n            arguments: vec![],\n        }\n    }\n}\n\n#[derive(Debug, Default)]\nstruct UseAssignments {\n    /// With sugar\n    /// ```gleam\n    /// use Box(x) = ...\n    /// ```\n    /// Without sugar\n    /// ```gleam\n    /// fn(_use1) { let Box(x) = _use1 }\n    /// // ^^^^^ The function arguments\n    /// ```\n    function_arguments: Vec<UntypedArg>,\n\n    /// With sugar\n    /// ```gleam\n    /// use Box(x) = ...\n    /// ```\n    /// Without sugar\n    /// ```gleam\n    /// fn(_use1) { let Box(x) = _use1 }\n    /// //          ^^^^^^^^^^^^^^^^^^ The body assignments\n    /// ```\n    body_assignments: Vec<UntypedStatement>,\n}\n\nimpl UseAssignments {\n    fn from_use_expression(sugar_assignments: Vec<UntypedUseAssignment>) -> UseAssignments {\n        let mut assignments = UseAssignments::default();\n\n        for (index, assignment) in sugar_assignments.into_iter().enumerate() {\n            let UseAssignment {\n                location,\n                pattern,\n                annotation,\n            } = assignment;\n            match pattern {\n                // For discards we add a discard function arguments.\n                Pattern::Discard { name, .. } => assignments.function_arguments.push(Arg {\n                    location,\n                    names: ArgNames::Discard { name, location },\n                    annotation: None,\n                    type_: (),\n                }),\n\n                // For simple patterns of a single variable we add a regular\n                // function argument.\n                Pattern::Variable { name, .. } => assignments.function_arguments.push(Arg {\n                    location,\n                    annotation,\n                    names: ArgNames::Named { name, location },\n                    type_: (),\n                }),\n\n                // For more complex patterns we add a function argument and also\n                // an assignment in the function body to handle the pattern.\n                pattern @ (Pattern::Int { .. }\n                | Pattern::Float { .. }\n                | Pattern::String { .. }\n                | Pattern::BitArraySize { .. }\n                | Pattern::Assign { .. }\n                | Pattern::List { .. }\n                | Pattern::Constructor { .. }\n                | Pattern::Tuple { .. }\n                | Pattern::BitArray { .. }\n                | Pattern::StringPrefix { .. }\n                | Pattern::Invalid { .. }) => {\n                    let name: EcoString = format!(\"{USE_ASSIGNMENT_VARIABLE}{index}\").into();\n                    assignments.function_arguments.push(Arg {\n                        location,\n                        names: ArgNames::Named {\n                            name: name.clone(),\n                            location,\n                        },\n                        annotation: None,\n                        type_: (),\n                    });\n                    let assignment = Assignment {\n                        location,\n                        pattern,\n                        annotation,\n                        compiled_case: CompiledCase::failure(),\n                        kind: AssignmentKind::Generated,\n                        value: UntypedExpr::Var { location, name },\n                    };\n                    assignments\n                        .body_assignments\n                        .push(Statement::Assignment(Box::new(assignment)))\n                }\n            }\n        }\n\n        assignments\n    }\n}\n\n#[derive(Debug)]\nstruct RecordUpdateVariant<'a> {\n    arguments: Vec<Arc<Type>>,\n    return_type: Arc<Type>,\n    field_map: &'a FieldMap,\n}\n\nimpl RecordUpdateVariant<'_> {\n    fn arg_type(&self, index: u32) -> Arc<Type> {\n        self.arguments\n            .get(index as usize)\n            .expect(\"Failed to get record argument type after successfully inferring that field\")\n            .clone()\n    }\n\n    fn has_field(&self, str: &EcoString) -> bool {\n        self.field_map.fields.contains_key(str)\n    }\n\n    fn field_names(&self) -> Vec<EcoString> {\n        self.field_map.fields.keys().cloned().collect()\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)]\npub enum ComparisonOutcome {\n    AlwaysFails,\n    AlwaysSucceeds,\n}\n\nenum StaticComparison {\n    /// When we can statically tell that two values are going to be exactly the\n    /// same.\n    CertainlyEqual,\n    /// When we can statically tell that two values are not going to be the\n    /// same.\n    CertainlyDifferent,\n    /// When it's impossible to statically tell if two values are the same.\n    CantTell,\n}\n\nfn static_compare(one: &TypedExpr, other: &TypedExpr) -> StaticComparison {\n    if one.is_record_constructor_function() && other.is_record_constructor_function() {\n        return StaticComparison::CantTell;\n    }\n\n    match (one, other) {\n        (\n            TypedExpr::Var {\n                name: one,\n                constructor: constructor_one,\n                ..\n            },\n            TypedExpr::Var {\n                name: other,\n                constructor: constructor_other,\n                ..\n            },\n        ) => match (&constructor_one.variant, &constructor_other.variant) {\n            (\n                ValueConstructorVariant::LocalVariable { .. },\n                ValueConstructorVariant::LocalVariable { .. },\n            )\n            | (\n                ValueConstructorVariant::ModuleConstant { .. },\n                ValueConstructorVariant::ModuleConstant { .. },\n            )\n            | (ValueConstructorVariant::Record { .. }, ValueConstructorVariant::Record { .. })\n                if one == other =>\n            {\n                StaticComparison::CertainlyEqual\n            }\n\n            (\n                ValueConstructorVariant::Record {\n                    variant_index: index_one,\n                    ..\n                },\n                ValueConstructorVariant::Record {\n                    variant_index: index_other,\n                    ..\n                },\n            ) if index_one != index_other => StaticComparison::CertainlyDifferent,\n\n            (\n                ValueConstructorVariant::LocalVariable { .. }\n                | ValueConstructorVariant::ModuleConstant { .. }\n                | ValueConstructorVariant::ModuleFn { .. }\n                | ValueConstructorVariant::Record { .. },\n                _,\n            ) => StaticComparison::CantTell,\n        },\n\n        (TypedExpr::Int { int_value: n, .. }, TypedExpr::Int { int_value: m, .. }) => {\n            if n == m {\n                StaticComparison::CertainlyEqual\n            } else {\n                StaticComparison::CertainlyDifferent\n            }\n        }\n\n        (TypedExpr::Float { float_value: n, .. }, TypedExpr::Float { float_value: m, .. }) => {\n            if n == m {\n                StaticComparison::CertainlyEqual\n            } else {\n                StaticComparison::CertainlyDifferent\n            }\n        }\n\n        (TypedExpr::String { value: one, .. }, TypedExpr::String { value: other, .. }) => {\n            if one == other {\n                StaticComparison::CertainlyEqual\n            } else {\n                StaticComparison::CertainlyDifferent\n            }\n        }\n\n        (TypedExpr::NegateInt { value: one, .. }, TypedExpr::NegateInt { value: other, .. })\n        | (TypedExpr::NegateBool { value: one, .. }, TypedExpr::NegateBool { value: other, .. }) => {\n            static_compare(one, other)\n        }\n\n        (\n            TypedExpr::List {\n                elements: elements_one,\n                tail: tail_one,\n                ..\n            },\n            TypedExpr::List {\n                elements: elements_other,\n                tail: tail_other,\n                ..\n            },\n        ) => {\n            match (tail_one, tail_other) {\n                (Some(one_tail), Some(other_tail)) => match static_compare(one_tail, other_tail) {\n                    StaticComparison::CertainlyDifferent => {\n                        return StaticComparison::CertainlyDifferent;\n                    }\n                    StaticComparison::CantTell => return StaticComparison::CantTell,\n                    StaticComparison::CertainlyEqual => (),\n                },\n                (None, Some(_)) | (Some(_), None) => return StaticComparison::CantTell,\n                (None, None) => (),\n            };\n\n            // If we can tell the two lists have a different number of items\n            // then we know it's never going to match.\n            if elements_one.len() != elements_other.len() {\n                return StaticComparison::CertainlyDifferent;\n            }\n\n            let mut comparison = StaticComparison::CertainlyEqual;\n            for (one, other) in elements_one.iter().zip(elements_other.iter()) {\n                match static_compare(one, other) {\n                    StaticComparison::CertainlyEqual => (),\n                    StaticComparison::CertainlyDifferent => {\n                        return StaticComparison::CertainlyDifferent;\n                    }\n                    StaticComparison::CantTell => comparison = StaticComparison::CantTell,\n                }\n            }\n            comparison\n        }\n\n        (\n            TypedExpr::Tuple {\n                elements: elements_one,\n                ..\n            },\n            TypedExpr::Tuple {\n                elements: elements_other,\n                ..\n            },\n        ) => {\n            let mut comparison = StaticComparison::CertainlyEqual;\n            for (one, other) in elements_one.iter().zip(elements_other.iter()) {\n                match static_compare(one, other) {\n                    StaticComparison::CertainlyEqual => (),\n                    StaticComparison::CertainlyDifferent => {\n                        return StaticComparison::CertainlyDifferent;\n                    }\n                    StaticComparison::CantTell => comparison = StaticComparison::CantTell,\n                }\n            }\n            comparison\n        }\n\n        (\n            TypedExpr::ModuleSelect {\n                constructor: constructor_one,\n                module_name: module_name_one,\n                ..\n            },\n            TypedExpr::ModuleSelect {\n                constructor: constructor_other,\n                module_name: module_name_other,\n                ..\n            },\n        ) => {\n            if module_name_one == module_name_other && constructor_one == constructor_other {\n                StaticComparison::CertainlyEqual\n            } else {\n                StaticComparison::CantTell\n            }\n        }\n\n        (\n            TypedExpr::Call {\n                fun: fun_one,\n                arguments: arguments_one,\n                ..\n            },\n            TypedExpr::Call {\n                fun: fun_other,\n                arguments: arguments_other,\n                ..\n            },\n        ) => match (fun_one.variant_index(), fun_other.variant_index()) {\n            // Both have to be literal record builders, otherwise we can't really tell\n            // anything at compile time!\n            (None, _) | (_, None) => StaticComparison::CantTell,\n\n            // If they're both literal record builders and are building different\n            // variants, then we know they'll always be different.\n            (Some(index_one), Some(index_other)) if index_one != index_other => {\n                StaticComparison::CertainlyDifferent\n            }\n\n            // Otherwise we need to check their arguments pairwise:\n            (Some(_), Some(_)) => {\n                let mut comparison = StaticComparison::CertainlyEqual;\n                for (one, other) in arguments_one.iter().zip(arguments_other.iter()) {\n                    match static_compare(&one.value, &other.value) {\n                        StaticComparison::CertainlyEqual => (),\n                        // If we can tell any of the arguments are never going to\n                        // be the same then we can short circuit and be sure\n                        // that the two variants are not the same as well!\n                        StaticComparison::CertainlyDifferent => {\n                            return StaticComparison::CertainlyDifferent;\n                        }\n                        // If we can't compare two of the arguments then there's\n                        // nothing we can tell at compile time. Notice how we\n                        // don't short circuit here: we still want to go over all\n                        // the other arguments because we might find two that are\n                        // certainly going to be different!\n                        StaticComparison::CantTell => comparison = StaticComparison::CantTell,\n                    }\n                }\n                comparison\n            }\n        },\n\n        // If we're building two variants with a different index then we can\n        // tell for sure they're going to be different.\n        (one, other)\n            if one\n                .variant_index()\n                .is_some_and(|one| other.variant_index().is_some_and(|other| one != other)) =>\n        {\n            StaticComparison::CertainlyDifferent\n        }\n\n        (\n            TypedExpr::RecordAccess {\n                index: index_one,\n                record: record_one,\n                ..\n            },\n            TypedExpr::RecordAccess {\n                index: index_other,\n                record: record_other,\n                ..\n            },\n        ) => match static_compare(record_one, record_other) {\n            StaticComparison::CertainlyEqual if index_one == index_other => {\n                StaticComparison::CertainlyEqual\n            }\n            StaticComparison::CertainlyEqual\n            | StaticComparison::CertainlyDifferent\n            | StaticComparison::CantTell => StaticComparison::CantTell,\n        },\n\n        // TODO: For complex expressions we just give up, maybe in future we\n        // could be smarter and perform further comparisons but it sounds like\n        // there's no huge value in this.\n        //\n        (_, _) => StaticComparison::CantTell,\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/type_/fields.rs",
    "content": "use super::Error;\nuse crate::{\n    ast::{CallArg, SrcSpan},\n    type_::error::IncorrectArityContext,\n};\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse std::collections::{HashMap, HashSet};\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct FieldMap {\n    /// Number of accepted arguments, including unlabelled fields.\n    pub arity: u32,\n    /// Map of labels to argument indices\n    pub fields: HashMap<EcoString, u32>,\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct DuplicateField;\n\nimpl FieldMap {\n    pub fn new(arity: u32) -> Self {\n        Self {\n            arity,\n            fields: HashMap::new(),\n        }\n    }\n\n    pub fn insert(&mut self, label: EcoString, index: u32) -> Result<(), DuplicateField> {\n        match self.fields.insert(label, index) {\n            Some(_) => Err(DuplicateField),\n            None => Ok(()),\n        }\n    }\n\n    pub fn into_option(self) -> Option<Self> {\n        if self.fields.is_empty() {\n            None\n        } else {\n            Some(self)\n        }\n    }\n\n    /// Reorder an argument list so that labelled fields supplied out-of-order are\n    /// in the correct order.\n    ///\n    pub fn reorder<A>(\n        &self,\n        arguments: &mut Vec<CallArg<A>>,\n        location: SrcSpan,\n        context: IncorrectArityContext,\n    ) -> Result<(), Error> {\n        let mut labelled_arguments_given = false;\n        let mut seen_labels = HashSet::new();\n        let mut unknown_labels = Vec::new();\n        let number_of_arguments = arguments.len();\n\n        if self.arity as usize != arguments.len() {\n            return Err(Error::IncorrectArity {\n                labels: self.missing_labels(arguments),\n                location,\n                context,\n                expected: self.arity as usize,\n                given: arguments.len(),\n            });\n        }\n\n        for argument in arguments.iter() {\n            match &argument.label {\n                Some(_) => {\n                    labelled_arguments_given = true;\n                }\n\n                None => {\n                    if labelled_arguments_given && !argument.is_implicit() {\n                        return Err(Error::PositionalArgumentAfterLabelled {\n                            location: argument.location,\n                        });\n                    }\n                }\n            }\n        }\n\n        // Keeps track of which labelled arguments need to be inserted into which indices\n        let mut labelled_arguments = HashMap::new();\n\n        // We iterate the argument in reverse order, because we have to remove elements\n        // from the `args` list quite a lot, and removing from the end of a list is more\n        // efficient than removing from the beginning or the middle.\n        let mut i = arguments.len();\n        while i > 0 {\n            i -= 1;\n            let (label, &location) =\n                match &arguments.get(i).expect(\"Field indexing to get label\").label {\n                    // A labelled argument, we may need to reposition it\n                    Some(l) => (\n                        l,\n                        &arguments\n                            .get(i)\n                            .expect(\"Indexing in labelled field reordering\")\n                            .location,\n                    ),\n\n                    // Not a labelled argument\n                    None => {\n                        continue;\n                    }\n                };\n\n            let position = match self.fields.get(label) {\n                None => {\n                    unknown_labels.push((label.clone(), location));\n                    continue;\n                }\n\n                Some(&p) => p,\n            };\n\n            if seen_labels.contains(label) {\n                return Err(Error::DuplicateArgument {\n                    location,\n                    label: label.clone(),\n                });\n            }\n            let _ = seen_labels.insert(label.clone());\n\n            // Add this argument to the `labelled_arguments` map, and remove if from the\n            // existing arguments list. It will be reinserted later in the correct index\n            let _ = labelled_arguments.insert(position as usize, arguments.remove(i));\n        }\n\n        // The labelled arguments must be reinserted in order\n        for i in 0..number_of_arguments {\n            if let Some(argument) = labelled_arguments.remove(&i) {\n                arguments.insert(i, argument);\n            }\n        }\n\n        if unknown_labels.is_empty() {\n            Ok(())\n        } else {\n            Err(Error::UnknownLabels {\n                valid: self.fields.keys().cloned().collect(),\n                unknown: unknown_labels,\n                supplied: seen_labels.into_iter().collect(),\n            })\n        }\n    }\n\n    /// This returns an array of the labels that are unused given an argument\n    /// list.\n    /// The unused labels are in the order they are expected to be passed in\n    /// to a call using those.\n    ///\n    /// ## Examples\n    ///\n    /// ```gleam\n    /// pub fn wibble(label1 a, label2 b, label3 c) { todo }\n    ///\n    /// wibble(1, label3: 2) // -> unused labels: [label2]\n    /// ```\n    ///\n    pub fn missing_labels<A>(&self, arguments: &[CallArg<A>]) -> Vec<EcoString> {\n        // We need to know how many positional arguments are in the function\n        // arguments. That's given by the position of the first labelled\n        // argument; if the first label argument is third, then we know the\n        // function also needs two unlabelled arguments first.\n        let Some(positional_arguments) = self.fields.values().min().cloned() else {\n            return vec![];\n        };\n\n        // We need to count how many positional arguments were actually supplied\n        // in the call, to remove the corresponding labelled arguments that have\n        // been taken by any positional argument.\n        let given_positional_arguments = arguments\n            .iter()\n            .filter(|argument| argument.label.is_none() && !argument.is_use_implicit_callback())\n            .count();\n\n        let explicit_labels = arguments\n            .iter()\n            .filter_map(|argument| argument.label.as_ref())\n            .collect::<HashSet<&EcoString>>();\n\n        self.fields\n            .iter()\n            // As a start we remove all the labels that are already used explicitly,\n            // for sure those are not going to be unused!\n            .filter(|(label, _)| !explicit_labels.contains(label))\n            // ...then we sort all the labels in order by their original position in\n            // the function definition\n            .sorted_by_key(|(_, position)| *position)\n            // ... finally we remove all the ones that are taken by a positional\n            // argument\n            .dropping(given_positional_arguments.saturating_sub(positional_arguments as usize))\n            .map(|(label, _)| label.clone())\n            .collect_vec()\n    }\n\n    pub fn indices_to_labels(&self) -> HashMap<u32, &EcoString> {\n        self.fields\n            .iter()\n            .map(|(name, index)| (*index, name))\n            .collect()\n    }\n}\n\n#[derive(Debug)]\npub struct FieldMapBuilder {\n    index: u32,\n    any_labels: bool,\n    field_map: FieldMap,\n}\n\nimpl FieldMapBuilder {\n    pub fn new(size: u32) -> Self {\n        Self {\n            index: 0,\n            any_labels: false,\n            field_map: FieldMap::new(size),\n        }\n    }\n\n    pub fn add(&mut self, label: Option<&EcoString>, location: SrcSpan) -> Result<(), Error> {\n        match label {\n            Some(label) => self.labelled(label, location)?,\n            None => self.unlabelled(location)?,\n        }\n        self.index += 1;\n        Ok(())\n    }\n\n    fn labelled(&mut self, label: &EcoString, location: SrcSpan) -> Result<(), Error> {\n        if self.field_map.insert(label.clone(), self.index).is_err() {\n            return Err(Error::DuplicateField {\n                label: label.clone(),\n                location,\n            });\n        };\n        self.any_labels = true;\n        Ok(())\n    }\n\n    fn unlabelled(&mut self, location: SrcSpan) -> Result<(), Error> {\n        if self.any_labels {\n            return Err(Error::UnlabelledAfterlabelled { location });\n        }\n        Ok(())\n    }\n\n    pub fn finish(self) -> Option<FieldMap> {\n        self.field_map.into_option()\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/type_/hydrator.rs",
    "content": "use super::*;\nuse crate::{\n    analyse::name::check_name_case,\n    ast::{Layer, TypeAst, TypeAstConstructor, TypeAstFn, TypeAstHole, TypeAstTuple, TypeAstVar},\n    reference::ReferenceKind,\n};\nuse std::sync::Arc;\n\nuse im::hashmap;\n\n/// The Hydrator takes an AST representing a type (i.e. a type annotation\n/// for a function argument) and returns a Type for that annotation.\n///\n/// If a valid Type cannot be constructed it returns an error.\n///\n/// It keeps track of any type variables created. This is useful for:\n///\n/// - Determining if a generic type variable should be made into an\n///   unbound type variable during type instantiation.\n/// - Ensuring that the same type is constructed if the programmer\n///   uses the same name for a type variable multiple times.\n///\n#[derive(Debug)]\npub struct Hydrator {\n    created_type_variables: im::HashMap<EcoString, CreatedTypeVariable>,\n    /// A rigid type is a generic type that was specified as being generic in\n    /// an annotation. As such it should never be instantiated into an unbound\n    /// variable. This type_id => name map is used for reporting the original\n    /// annotated name on error.\n    rigid_type_names: im::HashMap<u64, EcoString>,\n    permit_new_type_variables: bool,\n    permit_holes: bool,\n}\n\n#[derive(Debug)]\npub struct ScopeResetData {\n    created_type_variables: im::HashMap<EcoString, CreatedTypeVariable>,\n    rigid_type_names: im::HashMap<u64, EcoString>,\n}\n\nimpl Default for Hydrator {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Hydrator {\n    pub fn new() -> Self {\n        Self {\n            created_type_variables: hashmap![],\n            rigid_type_names: hashmap![],\n            permit_new_type_variables: true,\n            permit_holes: false,\n        }\n    }\n\n    pub fn named_type_variables(&self) -> im::HashMap<EcoString, CreatedTypeVariable> {\n        self.created_type_variables.clone()\n    }\n\n    pub fn open_new_scope(&mut self) -> ScopeResetData {\n        let created_type_variables = self.created_type_variables.clone();\n        let rigid_type_names = self.rigid_type_names.clone();\n        ScopeResetData {\n            created_type_variables,\n            rigid_type_names,\n        }\n    }\n\n    pub fn close_scope(&mut self, data: ScopeResetData) {\n        self.created_type_variables = data.created_type_variables;\n        self.rigid_type_names = data.rigid_type_names;\n    }\n\n    pub fn disallow_new_type_variables(&mut self) {\n        self.permit_new_type_variables = false\n    }\n\n    pub fn permit_holes(&mut self, flag: bool) {\n        self.permit_holes = flag\n    }\n\n    /// A rigid type is a generic type that was specified as being generic in\n    /// an annotation. As such it should never be instantiated into an unbound\n    /// variable.\n    pub fn is_rigid(&self, id: &u64) -> bool {\n        self.rigid_type_names.contains_key(id)\n    }\n\n    pub fn rigid_names(&self) -> im::HashMap<u64, EcoString> {\n        self.rigid_type_names.clone()\n    }\n\n    pub fn type_from_option_ast(\n        &mut self,\n        ast: &Option<TypeAst>,\n        environment: &mut Environment<'_>,\n        problems: &mut Problems,\n    ) -> Result<Arc<Type>, Error> {\n        match ast {\n            Some(ast) => self.type_from_ast(ast, environment, problems),\n            None => Ok(environment.new_unbound_var()),\n        }\n    }\n\n    /// Construct a Type from an AST Type annotation.\n    ///\n    pub fn type_from_ast(\n        &mut self,\n        ast: &TypeAst,\n        environment: &mut Environment<'_>,\n        problems: &mut Problems,\n    ) -> Result<Arc<Type>, Error> {\n        match ast {\n            TypeAst::Constructor(TypeAstConstructor {\n                location,\n                name_location,\n                module,\n                name,\n                arguments,\n                start_parentheses,\n            }) => {\n                // Hydrate the type argument AST into types\n                let mut argument_types = Vec::with_capacity(arguments.len());\n                for argument in arguments {\n                    let type_ = self.type_from_ast(argument, environment, problems)?;\n                    argument_types.push((argument.location(), type_));\n                }\n\n                // Look up the constructor\n                let TypeConstructor {\n                    parameters,\n                    type_: return_type,\n                    deprecation,\n                    ..\n                } = environment\n                    .get_type_constructor(module, name)\n                    .map_err(|e| {\n                        convert_get_type_constructor_error(\n                            e,\n                            location,\n                            module.as_ref().map(|(_, location)| *location),\n                        )\n                    })?\n                    .clone();\n\n                if let Some((type_module, type_name)) = return_type.named_type_name() {\n                    let reference_kind = if module.is_some() {\n                        ReferenceKind::Qualified\n                    } else if name != &type_name {\n                        ReferenceKind::Alias\n                    } else {\n                        ReferenceKind::Unqualified\n                    };\n                    environment.references.register_type_reference(\n                        type_module,\n                        type_name,\n                        name,\n                        *name_location,\n                        reference_kind,\n                    );\n                } else {\n                    environment\n                        .references\n                        .register_type_reference_in_call_graph(name.clone());\n                }\n\n                match deprecation {\n                    Deprecation::NotDeprecated => {}\n                    Deprecation::Deprecated { message } => {\n                        problems.warning(Warning::DeprecatedItem {\n                            location: *location,\n                            message: message.clone(),\n                            layer: Layer::Type,\n                        })\n                    }\n                }\n\n                // Register the type constructor as being used if it is unqualified.\n                // We do not track use of qualified type constructors as they may be\n                // used in another module.\n                if module.is_none() {\n                    environment.increment_usage(name);\n                }\n\n                // Ensure that the correct number of arguments have been given\n                // to the constructor.\n                //\n                // This is a special case for when a type is being called as a\n                // type constructor. For example: `Int()` or `Bool(a, b)`\n                if let Some(start_parentheses) = start_parentheses\n                    && parameters.is_empty()\n                {\n                    return Err(Error::TypeUsedAsAConstructor {\n                        location: SrcSpan::new(*start_parentheses, location.end),\n                        name: name.clone(),\n                    });\n                } else if arguments.len() != parameters.len() {\n                    return Err(Error::IncorrectTypeArity {\n                        location: *location,\n                        name: name.clone(),\n                        expected: parameters.len(),\n                        given: arguments.len(),\n                    });\n                }\n\n                // Instantiate the constructor type for this specific usage\n                let mut type_vars = hashmap![];\n                #[allow(clippy::needless_collect)] // Not needless, used for side effects\n                let parameter_types: Vec<_> = parameters\n                    .into_iter()\n                    .map(|type_| environment.instantiate(type_, &mut type_vars, self))\n                    .collect();\n\n                let return_type = environment.instantiate(return_type, &mut type_vars, self);\n\n                // Unify argument types with instantiated parameter types so that the correct types\n                // are inserted into the return type\n                for (parameter, (location, argument)) in\n                    parameter_types.into_iter().zip(argument_types)\n                {\n                    unify(parameter, argument).map_err(|e| convert_unify_error(e, location))?;\n                }\n\n                Ok(return_type)\n            }\n\n            TypeAst::Tuple(TypeAstTuple { elements, .. }) => Ok(tuple(\n                elements\n                    .iter()\n                    .map(|type_| self.type_from_ast(type_, environment, problems))\n                    .try_collect()?,\n            )),\n\n            TypeAst::Fn(TypeAstFn {\n                arguments, return_, ..\n            }) => {\n                let arguments = arguments\n                    .iter()\n                    .map(|type_| self.type_from_ast(type_, environment, problems))\n                    .try_collect()?;\n                let return_ = self.type_from_ast(return_, environment, problems)?;\n                Ok(fn_(arguments, return_))\n            }\n\n            TypeAst::Var(TypeAstVar { name, location }) => {\n                match self.created_type_variables.get_mut(name) {\n                    Some(var) => {\n                        var.usage_count += 1;\n                        Ok(var.type_.clone())\n                    }\n\n                    None if self.permit_new_type_variables => {\n                        if let Err(error) = check_name_case(*location, name, Named::TypeVariable) {\n                            problems.error(error);\n                        }\n                        let t = environment.new_generic_var();\n                        let _ = self\n                            .rigid_type_names\n                            .insert(environment.previous_uid(), name.clone());\n                        environment\n                            .names\n                            .type_variable_in_scope(environment.previous_uid(), name.clone());\n                        let _ = self.created_type_variables.insert(\n                            name.clone(),\n                            CreatedTypeVariable {\n                                type_: t.clone(),\n                                usage_count: 1,\n                            },\n                        );\n                        Ok(t)\n                    }\n\n                    None => {\n                        let hint = match environment.scope.contains_key(name) {\n                            true => UnknownTypeHint::ValueInScopeWithSameName,\n                            false => UnknownTypeHint::AlternativeTypes(\n                                environment.module_types.keys().cloned().collect(),\n                            ),\n                        };\n\n                        Err(Error::UnknownType {\n                            name: name.clone(),\n                            location: *location,\n                            hint,\n                        })\n                    }\n                }\n            }\n\n            TypeAst::Hole(TypeAstHole { .. }) if self.permit_holes => {\n                Ok(environment.new_unbound_var())\n            }\n\n            TypeAst::Hole(TypeAstHole { location, .. }) => Err(Error::UnexpectedTypeHole {\n                location: *location,\n            }),\n        }\n    }\n\n    pub fn clear_ridgid_type_names(&mut self) {\n        self.rigid_type_names.clear();\n    }\n\n    /// All the type variables that were created but never used.\n    pub fn unused_type_variables(&self) -> impl Iterator<Item = &EcoString> {\n        self.created_type_variables\n            .iter()\n            .filter(|(_, var)| var.usage_count == 0)\n            .map(|(name, _)| name)\n    }\n\n    /// Create a new type variable with the given name.\n    pub fn add_type_variable(\n        &mut self,\n        name: &EcoString,\n        environment: &mut Environment<'_>,\n    ) -> Result<Arc<Type>, Arc<Type>> {\n        let t = environment.new_generic_var();\n        let v = CreatedTypeVariable {\n            type_: t.clone(),\n            usage_count: 0,\n        };\n\n        environment\n            .names\n            .type_variable_in_scope(environment.previous_uid(), name.clone());\n        match self.created_type_variables.insert(name.clone(), v) {\n            Some(_) => Err(t),\n            None => Ok(t),\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct CreatedTypeVariable {\n    pub type_: Arc<Type>,\n    pub usage_count: usize,\n}\n"
  },
  {
    "path": "compiler-core/src/type_/pattern.rs",
    "content": "use ecow::eco_format;\nuse hexpm::version::{LowestVersion, Version};\nuse im::hashmap;\nuse itertools::Itertools;\nuse num_bigint::BigInt;\n\n/// Type inference and checking of patterns used in case expressions\n/// and variables bindings.\n///\nuse super::*;\nuse crate::{\n    analyse::{self, Inferred, name::check_name_case},\n    ast::{\n        AssignName, BitArrayOption, BitArraySize, ImplicitCallArgOrigin, Layer, TailPattern,\n        TypedBitArraySize, UntypedPatternBitArraySegment,\n    },\n    parse::PatternPosition,\n    reference::ReferenceKind,\n    type_::expression::FunctionDefinition,\n};\nuse std::sync::Arc;\n\npub struct PatternTyper<'a, 'b> {\n    environment: &'a mut Environment<'b>,\n    current_function: &'a FunctionDefinition,\n    hydrator: &'a Hydrator,\n    mode: PatternMode,\n    initial_pattern_vars: HashSet<EcoString>,\n    /// Variables which have been inferred to a specific variant of their type\n    /// from this pattern-matching. Key is the variable name, Value is the inferred variant index.\n    inferred_variant_variables: HashMap<EcoString, u16>,\n    problems: &'a mut Problems,\n\n    /// The minimum Gleam version required to compile the typed pattern.\n    pub minimum_required_version: Version,\n\n    pub error_encountered: bool,\n\n    /// Variables which have been assigned in the current pattern. We can't\n    /// register them immediately. If we're in a bit array, variables that are\n    /// assigned in the pattern can be used as part of the pattern, e.g.\n    /// `<<a, b:size(a)>>`. However, if we are not in a bit array pattern,\n    /// variables cannot be used within the pattern. This is invalid:\n    /// `#(size, <<a:size(size)>>)`. This is due to a limitation of Erlang.\n    ///\n    /// What we do instead is store the variables in this map. Each variable\n    /// keeps track of whether it is in scope, so that we can correctly detect\n    /// valid/invalid uses.\n    variables: HashMap<EcoString, LocalVariable>,\n\n    /// What kind of pattern we are typing\n    position: PatternPosition,\n}\n\n#[derive(Debug)]\nstruct LocalVariable {\n    location: SrcSpan,\n    origin: VariableOrigin,\n    type_: Arc<Type>,\n    usage: Usage,\n    scope: Scope,\n}\n\nimpl LocalVariable {\n    fn in_scope(&self) -> bool {\n        match self.scope {\n            Scope::CurrentBitArrayPattern => true,\n            Scope::OtherPattern => false,\n        }\n    }\n\n    fn was_used(&self) -> bool {\n        match self.usage {\n            Usage::UsedInPattern => true,\n            Usage::UnusedSoFar => false,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Usage {\n    UsedInPattern,\n    UnusedSoFar,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Scope {\n    CurrentBitArrayPattern,\n    OtherPattern,\n}\n\nenum PatternMode {\n    Initial,\n    Alternative(Vec<EcoString>),\n}\n\nimpl<'a, 'b> PatternTyper<'a, 'b> {\n    pub fn new(\n        environment: &'a mut Environment<'b>,\n        current_function: &'a FunctionDefinition,\n        hydrator: &'a Hydrator,\n        problems: &'a mut Problems,\n        position: PatternPosition,\n    ) -> Self {\n        Self {\n            environment,\n            current_function,\n            hydrator,\n            mode: PatternMode::Initial,\n            initial_pattern_vars: HashSet::new(),\n            inferred_variant_variables: HashMap::new(),\n            minimum_required_version: Version::new(0, 1, 0),\n            problems,\n            error_encountered: false,\n            variables: HashMap::new(),\n            position,\n        }\n    }\n\n    fn insert_variable(\n        &mut self,\n        name: &EcoString,\n        type_: Arc<Type>,\n        location: SrcSpan,\n        origin: VariableOrigin,\n    ) {\n        self.check_name_case(location, name, Named::Variable);\n\n        match &mut self.mode {\n            PatternMode::Initial => {\n                // Ensure there are no duplicate variable names in the pattern\n                if self.initial_pattern_vars.contains(name) {\n                    self.error(convert_unify_error(\n                        UnifyError::DuplicateVarInPattern { name: name.clone() },\n                        location,\n                    ));\n                    return;\n                }\n                // We no longer have access to the variable from the subject of the pattern\n                // so it doesn't need to be inferred any more.\n                let _ = self.inferred_variant_variables.remove(name);\n                // Record that this variable originated in this pattern so any\n                // following alternative patterns can be checked to ensure they\n                // have the same variables.\n                let _ = self.initial_pattern_vars.insert(name.clone());\n\n                _ = self.variables.insert(\n                    name.clone(),\n                    LocalVariable {\n                        location,\n                        origin: origin.clone(),\n                        type_: type_.clone(),\n                        usage: Usage::UnusedSoFar,\n                        scope: Scope::CurrentBitArrayPattern,\n                    },\n                );\n            }\n\n            PatternMode::Alternative(assigned) => {\n                match self.environment.scope.get_mut(name) {\n                    // This variable was defined in the Initial multi-pattern\n                    Some(initial) if self.initial_pattern_vars.contains(name) => {\n                        if assigned.contains(name) {\n                            self.error(convert_unify_error(\n                                UnifyError::DuplicateVarInPattern { name: name.clone() },\n                                location,\n                            ));\n                            return;\n                        }\n\n                        assigned.push(name.clone());\n                        let initial_type = initial.type_.clone();\n                        match unify(initial_type, type_.clone()) {\n                            Ok(()) => {}\n                            Err(error) => {\n                                self.problems.error(convert_unify_error(error, location));\n                                self.error_encountered = true;\n                            }\n                        };\n                        unify_constructor_variants(Arc::make_mut(&mut initial.type_), &type_);\n                    }\n\n                    // This variable was not defined in the Initial multi-pattern\n                    _ => self.error(convert_unify_error(\n                        UnifyError::ExtraVarInAlternativePattern { name: name.clone() },\n                        location,\n                    )),\n                }\n            }\n        }\n    }\n\n    fn set_subject_variable_variant(&mut self, name: EcoString, variant_index: u16) {\n        match &self.mode {\n            PatternMode::Initial => {\n                // If this name is reassigned in the pattern itself, we don't need to infer\n                // it, since it isn't accessible in this scope anymore.\n                if self.initial_pattern_vars.contains(&name) {\n                    return;\n                }\n\n                let variable = self\n                    .environment\n                    .scope\n                    .get(&name)\n                    .expect(\"Variable already exists in the case subjects\");\n\n                // The type in this scope is now separate from the parent scope, so we\n                // remove any links to ensure that they aren't linked in any way and that\n                // we don't accidentally set the variant of the variable outside of this scope\n                let mut type_ = collapse_links(variable.type_.clone());\n                Arc::make_mut(&mut type_).set_custom_type_variant(variant_index);\n                // Mark this variable as having been inferred\n                let _ = self\n                    .inferred_variant_variables\n                    .insert(name.clone(), variant_index);\n\n                let origin = match &variable.variant {\n                    ValueConstructorVariant::LocalVariable { origin, .. } => origin.clone(),\n                    ValueConstructorVariant::ModuleConstant { .. }\n                    | ValueConstructorVariant::ModuleFn { .. }\n                    | ValueConstructorVariant::Record { .. } => VariableOrigin::generated(),\n                };\n\n                // This variable is only inferred in this branch of the case expression\n                self.environment.insert_local_variable(\n                    name.clone(),\n                    variable.definition_location().span,\n                    origin,\n                    type_,\n                );\n            }\n\n            PatternMode::Alternative(_) => {\n                // If we haven't inferred this variable in all alternative patterns so far,\n                // we can't set its variant here\n                let Some(inferred_variant) = self.inferred_variant_variables.get(&name) else {\n                    return;\n                };\n\n                // If multiple variants are possible in this pattern, we can't infer it at all\n                // and we have to remove the variant index\n                if *inferred_variant != variant_index {\n                    // This variable's variant is no longer known\n                    let _ = self.inferred_variant_variables.remove(&name);\n                    let variable = self\n                        .environment\n                        .scope\n                        .get_mut(&name)\n                        .expect(\"Variable already exists in the case subjects\");\n\n                    Arc::make_mut(&mut variable.type_).generalise_custom_type_variant();\n                }\n            }\n        }\n    }\n\n    pub fn infer_alternative_multi_pattern(\n        &mut self,\n        multi_pattern: UntypedMultiPattern,\n        subjects: &[TypedExpr],\n        location: &SrcSpan,\n    ) -> Vec<TypedPattern> {\n        self.mode = PatternMode::Alternative(vec![]);\n        let typed_multi = self.infer_multi_pattern(multi_pattern, subjects);\n\n        if self.error_encountered {\n            return typed_multi;\n        }\n\n        match &self.mode {\n            PatternMode::Initial => panic!(\"Pattern mode switched from Alternative to Initial\"),\n            PatternMode::Alternative(assigned)\n                if assigned.len() < self.initial_pattern_vars.len() =>\n            {\n                for name in assigned {\n                    let _ = self.initial_pattern_vars.remove(name);\n                }\n                self.error(Error::MissingVarInAlternativePattern {\n                    location: *location,\n                    // It is safe to use expect here as we checked the length above\n                    name: self\n                        .initial_pattern_vars\n                        .iter()\n                        .next()\n                        .expect(\"Getting undefined pattern variable\")\n                        .clone(),\n                });\n                typed_multi\n            }\n            PatternMode::Alternative(_) => typed_multi,\n        }\n    }\n\n    pub fn infer_multi_pattern(\n        &mut self,\n        multi_pattern: UntypedMultiPattern,\n        subjects: &[TypedExpr],\n    ) -> Vec<TypedPattern> {\n        // If there are N subjects the multi-pattern is expected to be N patterns\n        if subjects.len() != multi_pattern.len() {\n            let first = multi_pattern\n                .first()\n                .expect(\"multi-pattern to contain at least one pattern\");\n            let last = multi_pattern\n                .last()\n                .expect(\"multi-pattern to contain at least one pattern\");\n\n            self.error(Error::IncorrectNumClausePatterns {\n                location: first.location().merge(&last.location()),\n                expected: subjects.len(),\n                given: multi_pattern.len(),\n            });\n            return Vec::new();\n        }\n\n        // Unify each pattern in the multi-pattern with the corresponding subject\n        let mut typed_multi = Vec::with_capacity(multi_pattern.len());\n        for (pattern, subject) in multi_pattern.into_iter().zip(subjects) {\n            let subject_variable = Self::subject_variable(subject);\n\n            let pattern = self.unify(pattern, subject.type_(), subject_variable);\n            typed_multi.push(pattern);\n        }\n\n        self.register_variables();\n\n        typed_multi\n    }\n\n    pub fn infer_single_pattern(\n        &mut self,\n        pattern: UntypedPattern,\n        subject: &TypedExpr,\n    ) -> TypedPattern {\n        let subject_variable = Self::subject_variable(subject);\n\n        let typed_pattern = self.unify(pattern, subject.type_(), subject_variable);\n        self.register_variables();\n        typed_pattern\n    }\n\n    fn subject_variable(subject: &TypedExpr) -> Option<EcoString> {\n        match subject {\n            TypedExpr::Var {\n                constructor:\n                    ValueConstructor {\n                        // Records should not be considered local variables\n                        // See: https://github.com/gleam-lang/gleam/issues/3861\n                        variant: ValueConstructorVariant::Record { .. },\n                        ..\n                    },\n                ..\n            } => None,\n            TypedExpr::Var { name, .. } => Some(name.clone()),\n            // If the subject of a `case` expression is something like\n            // `echo some_variable`, we still want to narrow the variant for\n            // `some_variable`.\n            TypedExpr::Echo {\n                expression: Some(subject),\n                ..\n            } => Self::subject_variable(subject),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    /// Register the variables bound in this pattern in the environment\n    fn register_variables(&mut self) {\n        for (name, variable) in std::mem::take(&mut self.variables) {\n            let was_used = variable.was_used();\n\n            let LocalVariable {\n                location,\n                origin,\n                type_,\n                usage: _,\n                scope: _,\n            } = variable;\n\n            // If this variable has already been referenced in another part of\n            // the pattern, we don't need to register it for usage tracking as\n            // it has already been used.\n            if !was_used {\n                self.environment\n                    .init_usage(name.clone(), origin.clone(), location, self.problems);\n            }\n\n            self.environment\n                .insert_local_variable(name, location, origin, type_);\n        }\n    }\n\n    fn infer_pattern_bit_array(\n        &mut self,\n        mut segments: Vec<UntypedPatternBitArraySegment>,\n        location: SrcSpan,\n    ) -> TypedPattern {\n        // Any variables from other parts of the pattern are no longer in scope.\n        // Only variables from the bit array pattern itself can be used.\n        for (_, variable) in self.variables.iter_mut() {\n            variable.scope = Scope::OtherPattern;\n        }\n\n        let last_segment = segments.pop();\n\n        let mut typed_segments: Vec<_> = segments\n            .into_iter()\n            .map(|s| self.infer_pattern_segment(s, false))\n            .collect();\n\n        if let Some(s) = last_segment {\n            let typed_last_segment = self.infer_pattern_segment(s, true);\n            typed_segments.push(typed_last_segment)\n        }\n\n        TypedPattern::BitArray {\n            location,\n            segments: typed_segments,\n        }\n    }\n\n    fn infer_pattern_segment(\n        &mut self,\n        mut segment: UntypedPatternBitArraySegment,\n        is_last_segment: bool,\n    ) -> TypedPatternBitArraySegment {\n        // If the segment doesn't have an explicit type option we add a default\n        // one ourselves if the pattern is unambiguous: literal strings are\n        // implicitly considered utf-8 encoded strings, while floats are\n        // implicitly given the float type option.\n        if !segment.has_type_option() {\n            match segment.value_unwrapping_assign() {\n                Pattern::String { location, .. } => {\n                    self.track_feature_usage(FeatureKind::UnannotatedUtf8StringSegment, *location);\n                    segment.options.push(BitArrayOption::Utf8 {\n                        location: SrcSpan::default(),\n                    });\n                }\n\n                Pattern::Float { location, .. } => {\n                    self.track_feature_usage(FeatureKind::UnannotatedFloatSegment, *location);\n                    segment.options.push(BitArrayOption::Float {\n                        location: SrcSpan::default(),\n                    })\n                }\n\n                Pattern::Int { .. }\n                | Pattern::Variable { .. }\n                | Pattern::BitArraySize(_)\n                | Pattern::Assign { .. }\n                | Pattern::Discard { .. }\n                | Pattern::List { .. }\n                | Pattern::Constructor { .. }\n                | Pattern::Tuple { .. }\n                | Pattern::BitArray { .. }\n                | Pattern::StringPrefix { .. }\n                | Pattern::Invalid { .. } => (),\n            }\n        }\n\n        let has_non_utf8_string_option = segment.has_utf16_option() || segment.has_utf32_option();\n\n        let options: Vec<_> = segment\n            .options\n            .into_iter()\n            .map(|option| {\n                analyse::infer_bit_array_option(option, |value, type_| {\n                    Ok(self.unify(value, type_, None))\n                })\n            })\n            .try_collect()\n            .expect(\"The function always returns Ok\");\n\n        self.check_pattern_segment_size_expression(&options);\n\n        let segment_type = match bit_array::type_options_for_pattern(\n            &options,\n            !is_last_segment,\n            self.environment.target,\n        ) {\n            Ok(type_) => type_,\n            Err(error) => {\n                self.error(Error::BitArraySegmentError {\n                    error: error.error,\n                    location: error.location,\n                });\n                self.environment.new_unbound_var()\n            }\n        };\n\n        // Track usage of the unaligned bit arrays feature on JavaScript so that\n        // warnings can be emitted if the Gleam version constraint is too low\n        if self.environment.target == Target::JavaScript\n            && !self.current_function.has_javascript_external\n        {\n            for option in options.iter() {\n                match option {\n                    // Use of the `bits` segment type\n                    BitArrayOption::Bits { location } => {\n                        self.track_feature_usage(\n                            FeatureKind::JavaScriptUnalignedBitArray,\n                            *location,\n                        );\n                    }\n\n                    // Int segments that aren't a whole number of bytes\n                    BitArrayOption::Size { value, .. } if segment_type.is_int() => match &**value {\n                        Pattern::BitArraySize(BitArraySize::Int {\n                            location,\n                            int_value,\n                            ..\n                        }) if int_value % 8 != BigInt::ZERO => {\n                            self.track_feature_usage(\n                                FeatureKind::JavaScriptUnalignedBitArray,\n                                *location,\n                            );\n                        }\n                        Pattern::Int { .. }\n                        | Pattern::Float { .. }\n                        | Pattern::String { .. }\n                        | Pattern::Variable { .. }\n                        | Pattern::BitArraySize(_)\n                        | Pattern::Assign { .. }\n                        | Pattern::Discard { .. }\n                        | Pattern::List { .. }\n                        | Pattern::Constructor { .. }\n                        | Pattern::Tuple { .. }\n                        | Pattern::BitArray { .. }\n                        | Pattern::StringPrefix { .. }\n                        | Pattern::Invalid { .. } => (),\n                    },\n\n                    BitArrayOption::Bytes { .. }\n                    | BitArrayOption::Int { .. }\n                    | BitArrayOption::Float { .. }\n                    | BitArrayOption::Utf8 { .. }\n                    | BitArrayOption::Utf16 { .. }\n                    | BitArrayOption::Utf32 { .. }\n                    | BitArrayOption::Utf8Codepoint { .. }\n                    | BitArrayOption::Utf16Codepoint { .. }\n                    | BitArrayOption::Utf32Codepoint { .. }\n                    | BitArrayOption::Signed { .. }\n                    | BitArrayOption::Unsigned { .. }\n                    | BitArrayOption::Big { .. }\n                    | BitArrayOption::Little { .. }\n                    | BitArrayOption::Native { .. }\n                    | BitArrayOption::Size { .. }\n                    | BitArrayOption::Unit { .. } => (),\n                }\n            }\n        }\n\n        let type_ = match segment.value.deref() {\n            Pattern::Assign { pattern, .. } if pattern.is_discard() && segment_type.is_string() => {\n                self.error(Error::BitArraySegmentError {\n                    error: bit_array::ErrorType::VariableUtfSegmentInPattern,\n                    location: segment.location,\n                });\n                self.environment.new_unbound_var()\n            }\n            Pattern::Variable { .. } if segment_type.is_string() => {\n                self.error(Error::BitArraySegmentError {\n                    error: bit_array::ErrorType::VariableUtfSegmentInPattern,\n                    location: segment.location,\n                });\n                self.environment.new_unbound_var()\n            }\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Variable { .. }\n            | Pattern::BitArraySize(_)\n            | Pattern::Assign { .. }\n            | Pattern::Discard { .. }\n            | Pattern::List { .. }\n            | Pattern::Constructor { .. }\n            | Pattern::Tuple { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => segment_type,\n        };\n\n        let typed_value = self.unify(*segment.value, type_.clone(), None);\n\n        match &typed_value {\n            // We can't directly match on the contents of a `Box`, so we must\n            // use a guard here.\n            Pattern::Assign {\n                location, pattern, ..\n            } if pattern.is_variable() => {\n                // It is tricky to generate code on Erlang for a pattern like\n                // `<<a as b>>`, since assignment patterns are not allowed in\n                // bit array patterns in Erlang. Since there is basically no\n                // reason to ever need to do this anyway, we simply emit an error\n                // here.\n                self.error(Error::DoubleVariableAssignmentInBitArray {\n                    location: *location,\n                });\n            }\n            Pattern::Assign { location, .. } if has_non_utf8_string_option => {\n                self.error(Error::NonUtf8StringAssignmentInBitArray {\n                    location: *location,\n                });\n            }\n            Pattern::Int { .. }\n            | Pattern::Float { .. }\n            | Pattern::String { .. }\n            | Pattern::Variable { .. }\n            | Pattern::BitArraySize(_)\n            | Pattern::Assign { .. }\n            | Pattern::Discard { .. }\n            | Pattern::List { .. }\n            | Pattern::Constructor { .. }\n            | Pattern::Tuple { .. }\n            | Pattern::BitArray { .. }\n            | Pattern::StringPrefix { .. }\n            | Pattern::Invalid { .. } => {}\n        };\n\n        BitArraySegment {\n            location: segment.location,\n            value: Box::new(typed_value),\n            options,\n            type_,\n        }\n    }\n\n    /// When we have an assignment or a case expression we unify the pattern with the\n    /// inferred type of the subject in order to determine what variables to insert\n    /// into the environment (or to detect a type error).\n    ///\n    fn unify(\n        &mut self,\n        pattern: UntypedPattern,\n        type_: Arc<Type>,\n        // The name of the variable this pattern matches on, if any. Used for variant inference.\n        //\n        // Example:\n        // ```gleam\n        // case some_wibble {\n        //   Wibble(..) -> {\n        //     some_wibble.field_only_present_in_wibble\n        //   }\n        //   _ -> panic\n        // }\n        // ```\n        //\n        // Here, the pattern `Wibble(..)` has the subject variable `some_wibble`, meaning that\n        // in the inner scope, we can infer that the `some_wibble` variable is the `Wibble` variant\n        //\n        subject_variable: Option<EcoString>,\n    ) -> TypedPattern {\n        match pattern {\n            Pattern::Discard { name, location, .. } => {\n                self.check_name_case(location, &name, Named::Discard);\n                let _ = self\n                    .environment\n                    .discarded_names\n                    .insert(name.clone(), location);\n                Pattern::Discard {\n                    type_,\n                    name,\n                    location,\n                }\n            }\n\n            Pattern::Invalid { location, .. } => Pattern::Invalid { type_, location },\n\n            Pattern::Variable {\n                name,\n                location,\n                origin,\n                ..\n            } => match name.as_str() {\n                \"true\" | \"false\" => {\n                    self.error(Error::LowercaseBoolPattern { location });\n                    Pattern::Invalid { location, type_ }\n                }\n                _ => {\n                    self.insert_variable(&name, type_.clone(), location, origin.clone());\n\n                    Pattern::Variable {\n                        type_,\n                        name,\n                        location,\n                        origin,\n                    }\n                }\n            },\n\n            Pattern::BitArraySize(size) => {\n                let location = size.location();\n                match self.bit_array_size(size, type_.clone()) {\n                    Ok(size) => Pattern::BitArraySize(size),\n                    Err(error) => {\n                        self.error(error);\n                        Pattern::Invalid { location, type_ }\n                    }\n                }\n            }\n\n            Pattern::StringPrefix {\n                location,\n                left_location,\n                right_location,\n                left_side_string,\n                left_side_assignment,\n                right_side_assignment,\n            } => {\n                // The entire concatenate pattern must be a string\n                self.unify_types(type_, string(), location);\n\n                // The left hand side may assign a variable, which is the prefix of the string\n                if let Some((left, left_location)) = &left_side_assignment {\n                    self.insert_variable(\n                        left,\n                        string(),\n                        *left_location,\n                        VariableOrigin {\n                            syntax: VariableSyntax::AssignmentPattern,\n                            declaration: self.position.to_declaration(),\n                        },\n                    );\n                }\n\n                // The right hand side may assign a variable, which is the suffix of the string\n                match &right_side_assignment {\n                    AssignName::Variable(right) => {\n                        self.insert_variable(\n                            right,\n                            string(),\n                            right_location,\n                            VariableOrigin {\n                                syntax: VariableSyntax::Variable(right.clone()),\n                                declaration: self.position.to_declaration(),\n                            },\n                        );\n                    }\n                    AssignName::Discard(right) => {\n                        let _ = self\n                            .environment\n                            .discarded_names\n                            .insert(right.clone(), right_location);\n                        self.check_name_case(right_location, right, Named::Discard);\n                    }\n                };\n\n                Pattern::StringPrefix {\n                    location,\n                    left_location,\n                    right_location,\n                    left_side_string,\n                    left_side_assignment,\n                    right_side_assignment,\n                }\n            }\n\n            Pattern::Assign {\n                name,\n                pattern,\n                location,\n            } => {\n                let pattern = self.unify(*pattern, type_, subject_variable);\n\n                if pattern.is_discard() {\n                    self.problems.warning(Warning::UnusedDiscardPattern {\n                        location,\n                        name: name.clone(),\n                    });\n                }\n                self.insert_variable(\n                    &name,\n                    pattern.type_().clone(),\n                    location,\n                    VariableOrigin {\n                        syntax: VariableSyntax::AssignmentPattern,\n                        declaration: self.position.to_declaration(),\n                    },\n                );\n                Pattern::Assign {\n                    name,\n                    pattern: Box::new(pattern),\n                    location,\n                }\n            }\n\n            Pattern::Int {\n                location,\n                value,\n                int_value,\n            } => {\n                self.unify_types(type_, int(), location);\n\n                if self.environment.target == Target::JavaScript\n                    && !self.current_function.has_javascript_external\n                {\n                    check_javascript_int_safety(&int_value, location, self.problems);\n                }\n\n                Pattern::Int {\n                    location,\n                    value,\n                    int_value,\n                }\n            }\n\n            Pattern::Float {\n                location,\n                value,\n                float_value,\n            } => {\n                self.unify_types(type_, float(), location);\n                check_float_safety(float_value, location, self.problems);\n                Pattern::Float {\n                    location,\n                    value,\n                    float_value,\n                }\n            }\n\n            Pattern::String { location, value } => {\n                self.unify_types(type_, string(), location);\n                Pattern::String { location, value }\n            }\n\n            Pattern::List {\n                location,\n                elements,\n                tail,\n                ..\n            } => match type_.named_type_arguments(\n                Publicity::Public,\n                PRELUDE_PACKAGE_NAME,\n                PRELUDE_MODULE_NAME,\n                \"List\",\n                1,\n                self.environment,\n            ) {\n                Some(arguments) => {\n                    let type_ = arguments\n                        .first()\n                        .expect(\"Failed to get type argument of List\")\n                        .clone();\n                    let elements = elements\n                        .into_iter()\n                        .map(|element| self.unify(element, type_.clone(), None))\n                        .collect();\n                    let type_ = list(type_);\n\n                    let tail = tail.map(|tail| {\n                        Box::new(TailPattern {\n                            location: tail.location,\n                            pattern: self.unify(tail.pattern, type_.clone(), None),\n                        })\n                    });\n\n                    Pattern::List {\n                        location,\n                        elements,\n                        tail,\n                        type_,\n                    }\n                }\n\n                None => {\n                    self.problems.error(Error::CouldNotUnify {\n                        given: list(self.environment.new_unbound_var()),\n                        expected: type_.clone(),\n                        situation: None,\n                        location,\n                    });\n                    self.error_encountered = true;\n\n                    Pattern::Invalid { location, type_ }\n                }\n            },\n\n            Pattern::Tuple { elements, location } => match collapse_links(type_.clone()).deref() {\n                Type::Tuple {\n                    elements: type_elements,\n                } => {\n                    if elements.len() != type_elements.len() {\n                        self.error(Error::IncorrectArity {\n                            labels: vec![],\n                            location,\n                            context: IncorrectArityContext::Pattern,\n                            expected: type_elements.len(),\n                            given: elements.len(),\n                        });\n                        return Pattern::Invalid { location, type_ };\n                    }\n\n                    let elements = elements\n                        .into_iter()\n                        .zip(type_elements)\n                        .map(|(pattern, type_)| self.unify(pattern, type_.clone(), None))\n                        .collect();\n                    Pattern::Tuple { elements, location }\n                }\n\n                Type::Var { .. } => {\n                    let elements_types: Vec<_> = (0..(elements.len()))\n                        .map(|_| self.environment.new_unbound_var())\n                        .collect();\n                    self.unify_types(tuple(elements_types.clone()), type_, location);\n                    let elements = elements\n                        .into_iter()\n                        .zip(elements_types)\n                        .map(|(pattern, type_)| self.unify(pattern, type_, None))\n                        .collect();\n                    Pattern::Tuple { elements, location }\n                }\n\n                Type::Named { .. } | Type::Fn { .. } => {\n                    let elements_types = (0..(elements.len()))\n                        .map(|_| self.environment.new_unbound_var())\n                        .collect();\n\n                    self.error(Error::CouldNotUnify {\n                        given: tuple(elements_types),\n                        expected: type_.clone(),\n                        situation: None,\n                        location,\n                    });\n                    Pattern::Invalid { location, type_ }\n                }\n            },\n\n            Pattern::BitArray { location, segments } => {\n                self.unify_types(type_, bit_array(), location);\n                self.infer_pattern_bit_array(segments, location)\n            }\n\n            Pattern::Constructor {\n                location,\n                module,\n                name_location,\n                name,\n                arguments: mut pattern_arguments,\n                spread,\n                ..\n            } => {\n                // Register the value as seen for detection of unused values\n                self.environment.increment_usage(&name);\n\n                let constructor = self\n                    .environment\n                    .get_value_constructor(module.as_ref().map(|(module, _)| module), &name);\n\n                let constructor = match constructor {\n                    Ok(constructor) => constructor,\n                    Err(error) => {\n                        self.error(convert_get_value_constructor_error(\n                            error,\n                            location,\n                            module.as_ref().map(|(_, location)| *location),\n                        ));\n\n                        // If there's no constructor we still try and infer all\n                        // the pattern arguments and produce an unknown constructor.\n                        return Pattern::Constructor {\n                            location,\n                            name_location,\n                            name,\n                            arguments: self.infer_pattern_call_arguments(\n                                pattern_arguments,\n                                &[],\n                                None,\n                            ),\n                            module,\n                            constructor: Inferred::Unknown,\n                            spread,\n                            type_,\n                        };\n                    }\n                };\n\n                let mut incorrect_arity_error = false;\n                match constructor.field_map() {\n                    // The fun has a field map so labelled arguments may be present and need to be reordered.\n                    Some(field_map) => {\n                        if let Some(spread_location) = spread {\n                            // Using the spread operator when you have already provided variables for all of the\n                            // record's fields throws an error\n                            if pattern_arguments.len() == field_map.arity as usize {\n                                {\n                                    self.problems.error(Error::UnnecessarySpreadOperator {\n                                        location: spread_location,\n                                        arity: field_map.arity as usize,\n                                    });\n                                    self.error_encountered = true;\n                                };\n                            }\n\n                            // Insert discard variables to match the unspecified fields\n                            // In order to support both positional and labelled arguments we have to insert\n                            // them after all positional variables and before the labelled ones. This means\n                            // we have calculate that index and then insert() the discards. It would be faster\n                            // if we could put the discards anywhere which would let us use push().\n                            // Potential future optimisation.\n                            let index_of_first_labelled_arg = pattern_arguments\n                                .iter()\n                                .position(|argument| argument.label.is_some())\n                                .unwrap_or(pattern_arguments.len());\n\n                            // In Gleam we can pass in positional unlabelled args to a constructor\n                            // even if the field was defined as labelled\n                            //\n                            //     pub type Wibble {\n                            //       Wibble(Int, two: Int, three: Int, four: Int)\n                            //     }\n                            //     Wibble(1, 2, 3, 4)\n                            //\n                            // When using `..` to ignore some fields the compiler needs to add a\n                            // placeholder implicit discard pattern for each one of the ignored\n                            // arguments. To give those discards the proper missing label we need to\n                            // know how many of the labelled fields were provided as unlabelled.\n                            //\n                            // That's why we want to keep track of the number of unlabelled argument\n                            // that have been supplied to the pattern and all the labels that have\n                            // been explicitly supplied.\n                            //\n                            //     Wibble(a, b, four: c, ..)\n                            //            ┬───  ┬──────\n                            //            │     ╰ We supplied 1 labelled arg\n                            //            ╰ We supplied 2 unlabelled args\n                            //\n                            let supplied_unlabelled_arguments = index_of_first_labelled_arg;\n                            let supplied_labelled_arguments = pattern_arguments\n                                .iter()\n                                .filter_map(|argument| argument.label.clone())\n                                .collect::<HashSet<_>>();\n                            let constructor_unlabelled_arguments =\n                                field_map.arity - field_map.fields.len() as u32;\n                            let labelled_arguments_supplied_as_unlabelled =\n                                supplied_unlabelled_arguments\n                                    .saturating_sub(constructor_unlabelled_arguments as usize);\n\n                            let mut missing_labels = field_map\n                                .fields\n                                .iter()\n                                // We take the labels in order of definition in the constructor...\n                                .sorted_by_key(|(_, position)| *position)\n                                .map(|(label, _)| label.clone())\n                                // ...and then remove the ones that were supplied as unlabelled\n                                // positional arguments...\n                                .skip(labelled_arguments_supplied_as_unlabelled)\n                                // ... lastly we still need to remove all those labels that\n                                // were explicitly supplied in the pattern.\n                                .filter(|label| !supplied_labelled_arguments.contains(label));\n\n                            while pattern_arguments.len() < field_map.arity as usize {\n                                let new_call_arg = CallArg {\n                                    value: Pattern::Discard {\n                                        name: \"_\".into(),\n                                        location: spread_location,\n                                        type_: (),\n                                    },\n                                    location: spread_location,\n                                    label: missing_labels.next(),\n                                    implicit: Some(ImplicitCallArgOrigin::PatternFieldSpread),\n                                };\n\n                                pattern_arguments.insert(index_of_first_labelled_arg, new_call_arg);\n                            }\n                        }\n\n                        if let Err(error) = field_map.reorder(\n                            &mut pattern_arguments,\n                            location,\n                            IncorrectArityContext::Pattern,\n                        ) {\n                            incorrect_arity_error = true;\n                            self.problems.error(error);\n                            self.error_encountered = true;\n                        }\n                    }\n\n                    None => {\n                        // The constructor has no field map and so we\n                        // error if arguments have been labelled\n                        match assert_no_labelled_arguments(\n                            &pattern_arguments,\n                            UnexpectedLabelledArgKind::RecordConstructorArgument,\n                        ) {\n                            Ok(()) => {}\n                            Err(error) => {\n                                self.problems.error(error);\n                                self.error_encountered = true;\n                            }\n                        }\n\n                        if let Some(spread_location) = spread\n                            && let ValueConstructorVariant::Record { arity, .. } =\n                                &constructor.variant\n                        {\n                            while pattern_arguments.len() < usize::from(*arity) {\n                                pattern_arguments.push(CallArg {\n                                    value: Pattern::Discard {\n                                        name: \"_\".into(),\n                                        location: spread_location,\n                                        type_: (),\n                                    },\n                                    location: spread_location,\n                                    label: None,\n                                    implicit: Some(ImplicitCallArgOrigin::PatternFieldSpread),\n                                });\n                            }\n                        };\n                    }\n                }\n\n                let constructor_type = constructor.type_.clone();\n                let constructor_deprecation = constructor.deprecation.clone();\n                let constructor_field_map = constructor.field_map().cloned();\n                let pattern_constructor = match &constructor.variant {\n                    ValueConstructorVariant::Record {\n                        name,\n                        documentation,\n                        module,\n                        location,\n                        variant_index: constructor_index,\n                        ..\n                    } => {\n                        let constructor_index = *constructor_index;\n                        let constructor = PatternConstructor {\n                            documentation: documentation.clone(),\n                            name: name.clone(),\n                            field_map: constructor.field_map().cloned(),\n                            module: module.clone(),\n                            location: *location,\n                            constructor_index,\n                        };\n\n                        if let Some(ref variable_name) = subject_variable {\n                            self.set_subject_variable_variant(\n                                variable_name.clone(),\n                                constructor_index,\n                            );\n                        }\n\n                        constructor\n                    }\n                    ValueConstructorVariant::LocalVariable { .. }\n                    | ValueConstructorVariant::ModuleConstant { .. }\n                    | ValueConstructorVariant::ModuleFn { .. } => {\n                        panic!(\"Unexpected value constructor type for a constructor pattern.\")\n                    }\n                };\n\n                match constructor_deprecation {\n                    Deprecation::NotDeprecated => {}\n                    Deprecation::Deprecated { message } => {\n                        self.problems.warning(Warning::DeprecatedItem {\n                            location,\n                            message: message.clone(),\n                            layer: Layer::Value,\n                        })\n                    }\n                }\n\n                self.environment.references.register_value_reference(\n                    pattern_constructor.module.clone(),\n                    pattern_constructor.name.clone(),\n                    &name,\n                    name_location,\n                    if module.is_some() {\n                        ReferenceKind::Qualified\n                    } else {\n                        ReferenceKind::Unqualified\n                    },\n                );\n\n                let instantiated_constructor_type =\n                    self.environment\n                        .instantiate(constructor_type, &mut hashmap![], self.hydrator);\n                match instantiated_constructor_type.deref() {\n                    Type::Fn { arguments, return_ } => {\n                        self.unify_types(type_.clone(), return_.clone(), location);\n\n                        if let Some((variable_to_infer, inferred_variant)) =\n                            subject_variable.zip(return_.custom_type_inferred_variant())\n                        {\n                            self.set_subject_variable_variant(variable_to_infer, inferred_variant);\n                        }\n\n                        // We're emitting the incorrect arity error only if we haven't emitted\n                        // one already. This might happen when we can't reorder the field map\n                        // of a constructor because there's not enough labels.\n                        if arguments.len() != pattern_arguments.len() && !incorrect_arity_error {\n                            self.error(Error::IncorrectArity {\n                                labels: vec![],\n                                location,\n                                context: IncorrectArityContext::Pattern,\n                                expected: arguments.len(),\n                                given: pattern_arguments.len(),\n                            });\n                        }\n\n                        let pattern_arguments = self.infer_pattern_call_arguments(\n                            pattern_arguments,\n                            arguments,\n                            constructor_field_map,\n                        );\n\n                        Pattern::Constructor {\n                            location,\n                            name_location,\n                            name,\n                            module,\n                            constructor: Inferred::Known(pattern_constructor),\n                            arguments: pattern_arguments,\n                            spread,\n                            type_: return_.clone(),\n                        }\n                    }\n\n                    Type::Named {\n                        inferred_variant, ..\n                    } => {\n                        self.unify_types(type_, instantiated_constructor_type.clone(), location);\n\n                        if let Some((variable_to_infer, inferred_variant)) =\n                            subject_variable.zip(*inferred_variant)\n                        {\n                            self.set_subject_variable_variant(variable_to_infer, inferred_variant);\n                        }\n\n                        if !pattern_arguments.is_empty() {\n                            self.error(Error::IncorrectArity {\n                                labels: vec![],\n                                location,\n                                context: IncorrectArityContext::Pattern,\n                                expected: 0,\n                                given: pattern_arguments.len(),\n                            });\n                        }\n                        Pattern::Constructor {\n                            location,\n                            name_location,\n                            module,\n                            name,\n                            arguments: vec![],\n                            constructor: Inferred::Known(pattern_constructor),\n                            spread,\n                            type_: instantiated_constructor_type,\n                        }\n                    }\n\n                    Type::Var { .. } | Type::Tuple { .. } => {\n                        panic!(\"Unexpected constructor type for a constructor pattern.\")\n                    }\n                }\n            }\n        }\n    }\n\n    fn infer_pattern_call_arguments(\n        &mut self,\n        pattern_arguments: Vec<CallArg<UntypedPattern>>,\n        expected_types: &[Arc<Type>],\n        field_map: Option<FieldMap>,\n    ) -> Vec<CallArg<TypedPattern>> {\n        pattern_arguments\n            .into_iter()\n            .enumerate()\n            .map(|(index, arg)| {\n                let mut index = index;\n                if !arg.is_implicit() && arg.uses_label_shorthand() {\n                    self.track_feature_usage(FeatureKind::LabelShorthandSyntax, arg.location);\n\n                    if let Some(field_map) = &field_map\n                        && let Some(label) = &arg.label\n                        && let Some(field) = field_map.fields.get(label)\n                    {\n                        index = *field as usize\n                    }\n                }\n\n                let CallArg {\n                    value,\n                    location,\n                    implicit,\n                    label,\n                } = arg;\n\n                let type_ = expected_types\n                    .get(index)\n                    .cloned()\n                    .unwrap_or_else(|| self.environment.new_unbound_var());\n\n                let value = self.unify(value, type_, None);\n                CallArg {\n                    value,\n                    location,\n                    implicit,\n                    label,\n                }\n            })\n            .collect()\n    }\n\n    fn bit_array_size(\n        &mut self,\n        size: BitArraySize<()>,\n        type_: Arc<Type>,\n    ) -> Result<TypedBitArraySize, Error> {\n        let typed_size = match size {\n            BitArraySize::Int {\n                location,\n                value,\n                int_value,\n            } => {\n                self.unify_types(type_, int(), location);\n\n                if self.environment.target == Target::JavaScript\n                    && !self.current_function.has_javascript_external\n                {\n                    check_javascript_int_safety(&int_value, location, self.problems);\n                }\n\n                BitArraySize::Int {\n                    location,\n                    value,\n                    int_value,\n                }\n            }\n            BitArraySize::Variable { name, location, .. } => {\n                let constructor = match self.variables.get_mut(&name) {\n                    // If we've bound a variable in the current bit array pattern,\n                    // we want to use that.\n                    Some(variable) if variable.in_scope() => {\n                        variable.usage = Usage::UsedInPattern;\n                        ValueConstructor::local_variable(\n                            variable.location,\n                            variable.origin.clone(),\n                            variable.type_.clone(),\n                        )\n                    }\n                    // Otherwise, we check the local scope.\n                    Some(_) | None => match self.environment.get_variable(&name) {\n                        Some(constructor) => constructor.clone(),\n                        None => {\n                            return Err(Error::UnknownVariable {\n                                location,\n                                name: name.clone(),\n                                variables: self.environment.local_value_names(),\n                                discarded_location: self\n                                    .environment\n                                    .discarded_names\n                                    .get(&eco_format!(\"_{name}\"))\n                                    .cloned(),\n                                type_with_name_in_scope: self\n                                    .environment\n                                    .module_types\n                                    .keys()\n                                    .any(|type_| type_ == &name),\n                            });\n                        }\n                    },\n                };\n\n                self.environment.increment_usage(&name);\n                let type_ = self.environment.instantiate(\n                    constructor.type_.clone(),\n                    &mut hashmap![],\n                    self.hydrator,\n                );\n                self.unify_types(int(), type_.clone(), location);\n\n                BitArraySize::Variable {\n                    name,\n                    location,\n                    constructor: Some(Box::new(constructor)),\n                    type_,\n                }\n            }\n            BitArraySize::BinaryOperator {\n                location,\n                operator,\n                left,\n                right,\n            } => BitArraySize::BinaryOperator {\n                location,\n                operator,\n                left: Box::new(self.bit_array_size(*left, type_.clone())?),\n                right: Box::new(self.bit_array_size(*right, type_)?),\n            },\n            BitArraySize::Block { location, inner } => BitArraySize::Block {\n                location,\n                inner: Box::new(self.bit_array_size(*inner, type_)?),\n            },\n        };\n\n        Ok(typed_size)\n    }\n\n    fn check_name_case(&mut self, location: SrcSpan, name: &EcoString, kind: Named) {\n        if let Err(error) = check_name_case(location, name, kind) {\n            self.problems.error(error);\n        }\n    }\n\n    fn unify_types(&mut self, first: Arc<Type>, second: Arc<Type>, location: SrcSpan) {\n        match unify(first, second) {\n            Ok(()) => {}\n            Err(error) => self.error(convert_unify_error(error, location)),\n        }\n    }\n\n    fn error(&mut self, error: Error) {\n        self.problems.error(error);\n        self.error_encountered = true;\n    }\n\n    fn track_feature_usage(&mut self, feature_kind: FeatureKind, location: SrcSpan) {\n        let minimum_required_version = feature_kind.required_version();\n\n        // Then if the required version is not in the specified version for the\n        // range we emit a warning highlighting the usage of the feature.\n        if let Some(gleam_version) = &self.environment.gleam_version\n            && let Some(lowest_allowed_version) = gleam_version.lowest_version()\n        {\n            // There is a version in the specified range that is lower than\n            // the one required by this feature! This means that the\n            // specified range is wrong and would allow someone to run a\n            // compiler that is too old to know of this feature.\n            if minimum_required_version > lowest_allowed_version {\n                self.problems\n                    .warning(Warning::FeatureRequiresHigherGleamVersion {\n                        location,\n                        feature_kind,\n                        minimum_required_version: minimum_required_version.clone(),\n                        wrongfully_allowed_version: lowest_allowed_version,\n                    })\n            }\n        }\n\n        if minimum_required_version > self.minimum_required_version {\n            self.minimum_required_version = minimum_required_version;\n        }\n    }\n\n    /// Checks if one of the options is a size option using an expression.\n    /// This needs to be tracked as it was introduced in Gleam 1.12.0.\n    fn check_pattern_segment_size_expression(&mut self, options: &[BitArrayOption<TypedPattern>]) {\n        let Some(size_value) = options.iter().find_map(|option| match option {\n            BitArrayOption::Size { value, .. } => Some(value),\n\n            BitArrayOption::Bytes { .. }\n            | BitArrayOption::Int { .. }\n            | BitArrayOption::Float { .. }\n            | BitArrayOption::Bits { .. }\n            | BitArrayOption::Utf8 { .. }\n            | BitArrayOption::Utf16 { .. }\n            | BitArrayOption::Utf32 { .. }\n            | BitArrayOption::Utf8Codepoint { .. }\n            | BitArrayOption::Utf16Codepoint { .. }\n            | BitArrayOption::Utf32Codepoint { .. }\n            | BitArrayOption::Signed { .. }\n            | BitArrayOption::Unsigned { .. }\n            | BitArrayOption::Big { .. }\n            | BitArrayOption::Little { .. }\n            | BitArrayOption::Native { .. }\n            | BitArrayOption::Unit { .. } => None,\n        }) else {\n            return;\n        };\n\n        let Pattern::BitArraySize(size) = size_value.as_ref() else {\n            return;\n        };\n        match size {\n            BitArraySize::Int { .. } | BitArraySize::Variable { .. } => (),\n            BitArraySize::BinaryOperator { location, .. }\n            | BitArraySize::Block { location, .. } => {\n                self.track_feature_usage(FeatureKind::ExpressionInSegmentSize, *location)\n            }\n        }\n    }\n}\n\n/// Unifies the variants of two variables declared in alternative patterns.\n///\n/// This ensures that constructor variant information is only stored if\n/// all alternate pattern variables have the same variant. For example:\n///\n/// ```gleam\n/// type Wibble {\n///   Wibble(wibble: Int, wobble: Float)\n///   Wobble(wubble: String, wooble, Bool)\n/// }\n///\n/// case some_value {\n///   Wibble(..) as wibble | Wobble(..) as wibble ->\n///     Wibble(..wibble, wobble: 1.3)\n/// }\n/// ```\n///\n/// The `wibble` variable will not have the constructor variant stored,\n/// since it can be one of two possible variants.\n///\nfn unify_constructor_variants(into: &mut Type, from: &Type) {\n    match (into, from) {\n        (\n            Type::Named {\n                inferred_variant: into_index,\n                ..\n            },\n            Type::Named {\n                inferred_variant: from_index,\n                ..\n            },\n        ) if from_index != into_index => *into_index = None,\n        // If the variants are the same, or they aren't both named types,\n        // no modifications are needed\n        _ => {}\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/type_/pipe.rs",
    "content": "use self::expression::CallKind;\n\nuse super::*;\nuse crate::ast::{\n    FunctionLiteralKind, ImplicitCallArgOrigin, PIPE_VARIABLE, PipelineAssignmentKind, Statement,\n    TypedPipelineAssignment, UntypedExpr,\n};\nuse vec1::Vec1;\n\n#[derive(Debug)]\npub(crate) struct PipeTyper<'a, 'b, 'c> {\n    size: usize,\n    argument_type: Arc<Type>,\n    argument_location: SrcSpan,\n    location: SrcSpan,\n    first_value: TypedPipelineAssignment,\n    assignments: Vec<(TypedPipelineAssignment, PipelineAssignmentKind)>,\n    expr_typer: &'a mut ExprTyper<'b, 'c>,\n}\n\nimpl<'a, 'b, 'c> PipeTyper<'a, 'b, 'c> {\n    fn new(expr_typer: &'a mut ExprTyper<'b, 'c>, size: usize, first: TypedExpr, end: u32) -> Self {\n        let first_type = first.type_();\n        let first_location = first.location();\n        let first_value = new_pipeline_assignment(expr_typer, first);\n        Self {\n            size,\n            expr_typer,\n            argument_type: first_type,\n            argument_location: first_location,\n            location: SrcSpan {\n                start: first_location.start,\n                end,\n            },\n            assignments: Vec::with_capacity(size),\n            first_value,\n        }\n    }\n\n    pub fn infer(\n        expr_typer: &'a mut ExprTyper<'b, 'c>,\n        expressions: Vec1<UntypedExpr>,\n    ) -> TypedExpr {\n        // The scope is reset as pipelines are rewritten into a series of\n        // assignments, and we don't want these variables to leak out of the\n        // pipeline.\n        let scope = expr_typer.environment.scope.clone();\n        let result = PipeTyper::run(expr_typer, expressions);\n        expr_typer.environment.scope = scope;\n        result\n    }\n\n    fn run(expr_typer: &'a mut ExprTyper<'b, 'c>, expressions: Vec1<UntypedExpr>) -> TypedExpr {\n        let size = expressions.len();\n        let end = expressions.last().location().end;\n        let mut expressions = expressions.into_iter();\n        let first = expressions.next().expect(\"Empty pipeline in typer\");\n        let first = expr_typer.infer(first);\n\n        Self::new(expr_typer, size, first, end).infer_expressions(expressions)\n    }\n\n    fn infer_expressions(\n        mut self,\n        expressions: impl IntoIterator<Item = UntypedExpr>,\n    ) -> TypedExpr {\n        let (finally, finally_kind) = self.infer_each_expression(expressions);\n        let assignments = std::mem::take(&mut self.assignments);\n        TypedExpr::Pipeline {\n            location: self.location,\n            first_value: self.first_value,\n            assignments,\n            finally: Box::new(finally),\n            finally_kind,\n        }\n    }\n\n    fn infer_each_expression(\n        &mut self,\n        expressions: impl IntoIterator<Item = UntypedExpr>,\n    ) -> (TypedExpr, PipelineAssignmentKind) {\n        let mut finally = None;\n\n        for (i, call) in expressions.into_iter().enumerate() {\n            if self.expr_typer.previous_panics {\n                self.expr_typer\n                    .warn_for_unreachable_code(call.location(), PanicPosition::PreviousExpression);\n            }\n\n            self.warn_if_call_first_argument_is_hole(&call);\n\n            let (kind, call) = match call {\n                func @ UntypedExpr::Fn { location, kind, .. } => {\n                    let (func, arguments, return_type) = self.expr_typer.do_infer_call(\n                        func,\n                        vec![self.untyped_left_hand_value_variable_call_argument()],\n                        location,\n                        CallKind::Function,\n                    );\n\n                    self.expr_typer.purity =\n                        self.expr_typer.purity.merge(func.called_function_purity());\n\n                    let kind = match kind {\n                        FunctionLiteralKind::Capture { hole } => {\n                            PipelineAssignmentKind::Hole { hole }\n                        }\n                        FunctionLiteralKind::Anonymous { .. } | FunctionLiteralKind::Use { .. } => {\n                            PipelineAssignmentKind::FunctionCall\n                        }\n                    };\n\n                    (\n                        kind,\n                        TypedExpr::Call {\n                            location,\n                            arguments,\n                            type_: return_type,\n                            fun: Box::new(func),\n                        },\n                    )\n                }\n\n                // left |> right(..args)\n                //         ^^^^^ This is `fun`\n                UntypedExpr::Call {\n                    fun,\n                    arguments,\n                    location,\n                    ..\n                } => {\n                    let fun = self.expr_typer.infer(*fun);\n\n                    match fun.type_().fn_types() {\n                        // Rewrite as right(..args)(left)\n                        Some((fn_arguments, _)) if fn_arguments.len() == arguments.len() => {\n                            // We are calling the return value of another function.\n                            // Without lifting purity tracking into the type system,\n                            // we have no idea whether it's pure or not!\n                            self.expr_typer.purity = self.expr_typer.purity.merge(Purity::Unknown);\n                            (\n                                PipelineAssignmentKind::FunctionCall,\n                                self.infer_apply_to_call_pipe(fun, arguments, location),\n                            )\n                        }\n\n                        // Rewrite as right(left, ..args)\n                        _ => {\n                            self.expr_typer.purity =\n                                self.expr_typer.purity.merge(fun.called_function_purity());\n                            (\n                                PipelineAssignmentKind::FirstArgument {\n                                    second_argument: arguments.first().map(|arg| arg.location),\n                                },\n                                self.infer_insert_pipe(fun, arguments, location),\n                            )\n                        }\n                    }\n                }\n\n                UntypedExpr::Echo {\n                    location,\n                    keyword_end: _,\n                    expression: None,\n                    message,\n                } => {\n                    self.expr_typer.environment.echo_found = true;\n                    self.expr_typer.purity = Purity::Impure;\n                    // An echo that is not followed by an expression that is\n                    // used as a pipeline's step is just like the identity\n                    // function.\n                    // So it gets the type of the value coming from the previous\n                    // step of the pipeline.\n                    (\n                        PipelineAssignmentKind::Echo,\n                        TypedExpr::Echo {\n                            location,\n                            expression: None,\n                            type_: self.argument_type.clone(),\n                            message: message.map(|message| {\n                                Box::new(self.expr_typer.infer_and_unify(*message, string()))\n                            }),\n                        },\n                    )\n                }\n\n                // right(left)\n                UntypedExpr::Int { .. }\n                | UntypedExpr::Float { .. }\n                | UntypedExpr::String { .. }\n                | UntypedExpr::Block { .. }\n                | UntypedExpr::Var { .. }\n                | UntypedExpr::List { .. }\n                | UntypedExpr::BinOp { .. }\n                | UntypedExpr::PipeLine { .. }\n                | UntypedExpr::Case { .. }\n                | UntypedExpr::FieldAccess { .. }\n                | UntypedExpr::Tuple { .. }\n                | UntypedExpr::TupleIndex { .. }\n                | UntypedExpr::Todo { .. }\n                | UntypedExpr::Panic { .. }\n                | UntypedExpr::Echo { .. }\n                | UntypedExpr::BitArray { .. }\n                | UntypedExpr::RecordUpdate { .. }\n                | UntypedExpr::NegateBool { .. }\n                | UntypedExpr::NegateInt { .. } => (\n                    PipelineAssignmentKind::FunctionCall,\n                    self.infer_apply_pipe(call),\n                ),\n            };\n\n            if i + 2 == self.size {\n                finally = Some((call, kind));\n            } else {\n                self.push_assignment(call, kind);\n            }\n        }\n\n        finally.expect(\"Empty pipeline in typer\")\n    }\n\n    /// Create a call argument that can be used to refer to the value on the\n    /// left hand side of the pipe\n    fn typed_left_hand_value_variable_call_argument(&self) -> CallArg<TypedExpr> {\n        CallArg {\n            label: None,\n            location: self.argument_location,\n            value: self.typed_left_hand_value_variable(),\n            // This argument is given implicitly by the pipe, not explicitly by\n            // the programmer.\n            implicit: Some(ImplicitCallArgOrigin::Pipe),\n        }\n    }\n\n    /// Create a call argument that can be used to refer to the value on the\n    /// left hand side of the pipe\n    fn untyped_left_hand_value_variable_call_argument(&self) -> CallArg<UntypedExpr> {\n        CallArg {\n            label: None,\n            location: self.argument_location,\n            value: self.untyped_left_hand_value_variable(),\n            // This argument is given implicitly by the pipe, not explicitly by\n            // the programmer.\n            implicit: Some(ImplicitCallArgOrigin::Pipe),\n        }\n    }\n\n    /// Create a variable that can be used to refer to the value on the left\n    /// hand side of the pipe\n    fn typed_left_hand_value_variable(&self) -> TypedExpr {\n        TypedExpr::Var {\n            location: self.argument_location,\n            name: PIPE_VARIABLE.into(),\n            constructor: ValueConstructor::local_variable(\n                self.argument_location,\n                VariableOrigin::generated(),\n                self.argument_type.clone(),\n            ),\n        }\n    }\n\n    /// Create a variable that can be used to refer to the value on the left\n    /// hand side of the pipe\n    fn untyped_left_hand_value_variable(&self) -> UntypedExpr {\n        UntypedExpr::Var {\n            location: self.argument_location,\n            name: PIPE_VARIABLE.into(),\n        }\n    }\n\n    /// Push an assignment for the value on the left hand side of the pipe\n    fn push_assignment(&mut self, expression: TypedExpr, kind: PipelineAssignmentKind) {\n        self.argument_type = expression.type_();\n        self.argument_location = expression.location();\n        let assignment = new_pipeline_assignment(self.expr_typer, expression);\n        self.assignments.push((assignment, kind));\n    }\n\n    /// Attempt to infer a |> b(..c) as b(..c)(a)\n    fn infer_apply_to_call_pipe(\n        &mut self,\n        function: TypedExpr,\n        arguments: Vec<CallArg<UntypedExpr>>,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        let (function, arguments, type_) = self.expr_typer.do_infer_call_with_known_fun(\n            function,\n            arguments,\n            location,\n            CallKind::Function,\n        );\n        let function = TypedExpr::Call {\n            location,\n            type_,\n            arguments,\n            fun: Box::new(function),\n        };\n        let arguments = vec![self.untyped_left_hand_value_variable_call_argument()];\n        // TODO: use `.with_unify_error_situation(UnifyErrorSituation::PipeTypeMismatch)`\n        // This will require the typing of the arguments to be lifted up out of\n        // the function below. If it is not we don't know if the error comes\n        // from incorrect usage of the pipe or if it originates from the\n        // argument expressions.\n        let (function, arguments, type_) = self.expr_typer.do_infer_call_with_known_fun(\n            function,\n            arguments,\n            location,\n            CallKind::Function,\n        );\n        TypedExpr::Call {\n            location,\n            type_,\n            arguments,\n            fun: Box::new(function),\n        }\n    }\n\n    /// Attempt to infer a |> b(c) as b(a, c)\n    fn infer_insert_pipe(\n        &mut self,\n        function: TypedExpr,\n        mut arguments: Vec<CallArg<UntypedExpr>>,\n        location: SrcSpan,\n    ) -> TypedExpr {\n        arguments.insert(0, self.untyped_left_hand_value_variable_call_argument());\n        // TODO: use `.with_unify_error_situation(UnifyErrorSituation::PipeTypeMismatch)`\n        // This will require the typing of the arguments to be lifted up out of\n        // the function below. If it is not we don't know if the error comes\n        // from incorrect usage of the pipe or if it originates from the\n        // argument expressions.\n        let (fun, arguments, type_) = self.expr_typer.do_infer_call_with_known_fun(\n            function,\n            arguments,\n            location,\n            CallKind::Function,\n        );\n        TypedExpr::Call {\n            location,\n            type_,\n            arguments,\n            fun: Box::new(fun),\n        }\n    }\n\n    /// Attempt to infer a |> b as b(a)\n    /// b is the `function` argument.\n    fn infer_apply_pipe(&mut self, function: UntypedExpr) -> TypedExpr {\n        let function_location = function.location();\n        let function = Box::new(self.expr_typer.infer(function));\n\n        self.expr_typer.purity = self\n            .expr_typer\n            .purity\n            .merge(function.called_function_purity());\n\n        let return_type = self.expr_typer.new_unbound_var();\n        // Ensure that the function accepts one argument of the correct type\n        let unification_result = unify(\n            function.type_(),\n            fn_(vec![self.argument_type.clone()], return_type.clone()),\n        );\n        match unification_result {\n            Ok(_) => (),\n            Err(error) => {\n                let error = if self.check_if_pipe_type_mismatch(&error) {\n                    convert_unify_error(error, function.location())\n                        .with_unify_error_situation(UnifyErrorSituation::PipeTypeMismatch)\n                } else {\n                    convert_unify_error(flip_unify_error(error), function.location())\n                };\n                self.expr_typer.problems.error(error);\n            }\n        };\n\n        TypedExpr::Call {\n            location: function_location,\n            type_: return_type,\n            fun: function,\n            arguments: vec![self.typed_left_hand_value_variable_call_argument()],\n        }\n    }\n\n    fn check_if_pipe_type_mismatch(&mut self, error: &UnifyError) -> bool {\n        let types = match error {\n            UnifyError::CouldNotUnify {\n                expected, given, ..\n            } => (expected.as_ref(), given.as_ref()),\n            UnifyError::ExtraVarInAlternativePattern { .. }\n            | UnifyError::MissingVarInAlternativePattern { .. }\n            | UnifyError::DuplicateVarInPattern { .. }\n            | UnifyError::RecursiveType => return false,\n        };\n\n        match types {\n            (Type::Fn { arguments: a, .. }, Type::Fn { arguments: b, .. })\n                if a.len() == b.len() =>\n            {\n                match (a.first(), b.first()) {\n                    (Some(a), Some(b)) => unify(a.clone(), b.clone()).is_err(),\n                    _ => false,\n                }\n            }\n            _ => false,\n        }\n    }\n\n    fn warn_if_call_first_argument_is_hole(&mut self, call: &UntypedExpr) {\n        if let UntypedExpr::Fn { kind, body, .. } = &call\n            && kind.is_capture()\n            && let Statement::Expression(UntypedExpr::Call { arguments, .. }) = body.first()\n        {\n            match arguments.as_slice() {\n                // If the first argument is labelled, we don't warn the user\n                // as they might be intentionally adding it to provide more\n                // information about exactly which argument is being piped into.\n                [first] | [first, ..] if first.is_capture_hole() && first.label.is_none() => self\n                    .expr_typer\n                    .problems\n                    .warning(Warning::RedundantPipeFunctionCapture {\n                        location: first.location,\n                    }),\n                _ => (),\n            }\n        }\n    }\n}\n\nfn new_pipeline_assignment(\n    expr_typer: &mut ExprTyper<'_, '_>,\n    expression: TypedExpr,\n) -> TypedPipelineAssignment {\n    let location = expression.location();\n    // Insert the variable for use in type checking the rest of the pipeline\n    expr_typer.environment.insert_local_variable(\n        PIPE_VARIABLE.into(),\n        location,\n        VariableOrigin::generated(),\n        expression.type_(),\n    );\n    TypedPipelineAssignment {\n        location,\n        name: PIPE_VARIABLE.into(),\n        value: Box::new(expression),\n    }\n}\n"
  },
  {
    "path": "compiler-core/src/type_/prelude.rs",
    "content": "use hexpm::version::Version;\nuse strum::{EnumIter, IntoEnumIterator};\n\nuse crate::{\n    ast::{Publicity, SrcSpan},\n    build::Origin,\n    line_numbers::LineNumbers,\n    uid::UniqueIdGenerator,\n};\n\nuse super::{\n    ModuleInterface, Opaque, References, Type, TypeConstructor, TypeValueConstructor,\n    TypeValueConstructorField, TypeVar, TypeVariantConstructors, ValueConstructor,\n    ValueConstructorVariant,\n};\nuse crate::type_::Deprecation::NotDeprecated;\nuse std::{cell::RefCell, collections::HashMap, sync::Arc};\n\nconst BIT_ARRAY: &str = \"BitArray\";\nconst BOOL: &str = \"Bool\";\nconst FLOAT: &str = \"Float\";\nconst INT: &str = \"Int\";\npub const LIST: &str = \"List\";\nconst NIL: &str = \"Nil\";\nconst RESULT: &str = \"Result\";\nconst STRING: &str = \"String\";\nconst UTF_CODEPOINT: &str = \"UtfCodepoint\";\n\npub const PRELUDE_PACKAGE_NAME: &str = \"\";\npub const PRELUDE_MODULE_NAME: &str = \"gleam\";\n\npub fn is_prelude_module(module: &str) -> bool {\n    module == PRELUDE_MODULE_NAME\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter)]\npub enum PreludeType {\n    BitArray,\n    Bool,\n    Float,\n    Int,\n    List,\n    Nil,\n    Result,\n    String,\n    UtfCodepoint,\n}\n\nimpl PreludeType {\n    pub fn name(self) -> &'static str {\n        match self {\n            PreludeType::BitArray => BIT_ARRAY,\n            PreludeType::Bool => BOOL,\n            PreludeType::Float => FLOAT,\n            PreludeType::Int => INT,\n            PreludeType::List => LIST,\n            PreludeType::Nil => NIL,\n            PreludeType::Result => RESULT,\n            PreludeType::String => STRING,\n            PreludeType::UtfCodepoint => UTF_CODEPOINT,\n        }\n    }\n}\n\npub fn int() -> Arc<Type> {\n    Arc::new(Type::Named {\n        publicity: Publicity::Public,\n        name: INT.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        arguments: vec![],\n        inferred_variant: None,\n    })\n}\n\npub fn float() -> Arc<Type> {\n    Arc::new(Type::Named {\n        arguments: vec![],\n        publicity: Publicity::Public,\n        name: FLOAT.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        inferred_variant: None,\n    })\n}\n\npub fn bool() -> Arc<Type> {\n    bool_with_variant(None)\n}\n\npub fn bool_with_variant(variant: Option<bool>) -> Arc<Type> {\n    let variant = match variant {\n        Some(true) => Some(0),\n        Some(false) => Some(1),\n        None => None,\n    };\n\n    Arc::new(Type::Named {\n        arguments: vec![],\n        publicity: Publicity::Public,\n        name: BOOL.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        inferred_variant: variant,\n    })\n}\n\npub fn string() -> Arc<Type> {\n    Arc::new(Type::Named {\n        arguments: vec![],\n        publicity: Publicity::Public,\n        name: STRING.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        inferred_variant: None,\n    })\n}\n\npub fn nil() -> Arc<Type> {\n    Arc::new(Type::Named {\n        arguments: vec![],\n        publicity: Publicity::Public,\n        name: NIL.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        inferred_variant: None,\n    })\n}\n\npub fn list(t: Arc<Type>) -> Arc<Type> {\n    Arc::new(Type::Named {\n        publicity: Publicity::Public,\n        name: LIST.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        arguments: vec![t],\n        inferred_variant: None,\n    })\n}\n\npub fn result(a: Arc<Type>, e: Arc<Type>) -> Arc<Type> {\n    result_with_variant(a, e, None)\n}\n\nfn result_with_variant(a: Arc<Type>, e: Arc<Type>, variant_index: Option<u16>) -> Arc<Type> {\n    Arc::new(Type::Named {\n        publicity: Publicity::Public,\n        name: RESULT.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        arguments: vec![a, e],\n        inferred_variant: variant_index,\n    })\n}\n\npub fn tuple(elements: Vec<Arc<Type>>) -> Arc<Type> {\n    Arc::new(Type::Tuple { elements })\n}\n\npub fn fn_(arguments: Vec<Arc<Type>>, return_: Arc<Type>) -> Arc<Type> {\n    Arc::new(Type::Fn { return_, arguments })\n}\n\npub fn named(\n    package: &str,\n    module: &str,\n    name: &str,\n    publicity: Publicity,\n    arguments: Vec<Arc<Type>>,\n) -> Arc<Type> {\n    Arc::new(Type::Named {\n        publicity,\n        package: package.into(),\n        module: module.into(),\n        name: name.into(),\n        arguments,\n        inferred_variant: None,\n    })\n}\n\npub fn bit_array() -> Arc<Type> {\n    Arc::new(Type::Named {\n        arguments: vec![],\n        publicity: Publicity::Public,\n        name: BIT_ARRAY.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        inferred_variant: None,\n    })\n}\n\npub fn utf_codepoint() -> Arc<Type> {\n    Arc::new(Type::Named {\n        arguments: vec![],\n        publicity: Publicity::Public,\n        name: UTF_CODEPOINT.into(),\n        module: PRELUDE_MODULE_NAME.into(),\n        package: PRELUDE_PACKAGE_NAME.into(),\n        inferred_variant: None,\n    })\n}\n\npub fn generic_var(id: u64) -> Arc<Type> {\n    Arc::new(Type::Var {\n        type_: Arc::new(RefCell::new(TypeVar::Generic { id })),\n    })\n}\n\npub fn unbound_var(id: u64) -> Arc<Type> {\n    Arc::new(Type::Var {\n        type_: Arc::new(RefCell::new(TypeVar::Unbound { id })),\n    })\n}\n\n#[cfg(test)]\npub fn link(type_: Arc<Type>) -> Arc<Type> {\n    Arc::new(Type::Var {\n        type_: Arc::new(RefCell::new(TypeVar::Link { type_ })),\n    })\n}\n\npub fn build_prelude(ids: &UniqueIdGenerator) -> ModuleInterface {\n    let value = |variant, type_| ValueConstructor {\n        publicity: Publicity::Public,\n        deprecation: NotDeprecated,\n        variant,\n        type_,\n    };\n\n    let mut prelude = ModuleInterface {\n        name: PRELUDE_MODULE_NAME.into(),\n        package: \"\".into(),\n        origin: Origin::Src,\n        types: HashMap::new(),\n        types_value_constructors: HashMap::new(),\n        values: HashMap::new(),\n        accessors: HashMap::new(),\n        is_internal: false,\n        warnings: vec![],\n        // prelude doesn't have real src\n        src_path: \"\".into(),\n        // prelude doesn't have real line numbers\n        line_numbers: LineNumbers::new(\"\"),\n        minimum_required_version: Version::new(0, 1, 0),\n        type_aliases: HashMap::new(),\n        documentation: Vec::new(),\n        contains_echo: false,\n        references: References::default(),\n        inline_functions: HashMap::new(),\n    };\n\n    for t in PreludeType::iter() {\n        match t {\n            PreludeType::BitArray => {\n                let v = TypeConstructor {\n                    origin: Default::default(),\n                    parameters: vec![],\n                    type_: bit_array(),\n                    module: PRELUDE_MODULE_NAME.into(),\n                    publicity: Publicity::Public,\n                    deprecation: NotDeprecated,\n                    documentation: None,\n                };\n                let _ = prelude.types.insert(BIT_ARRAY.into(), v.clone());\n            }\n\n            PreludeType::Bool => {\n                let _ = prelude.types_value_constructors.insert(\n                    BOOL.into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![],\n                        variants: vec![\n                            TypeValueConstructor {\n                                name: \"True\".into(),\n                                parameters: vec![],\n                                documentation: None,\n                            },\n                            TypeValueConstructor {\n                                name: \"False\".into(),\n                                parameters: vec![],\n                                documentation: None,\n                            },\n                        ],\n                        opaque: Opaque::NotOpaque,\n                    },\n                );\n                let _ = prelude.values.insert(\n                    \"True\".into(),\n                    value(\n                        ValueConstructorVariant::Record {\n                            documentation: None,\n                            module: PRELUDE_MODULE_NAME.into(),\n                            name: \"True\".into(),\n                            field_map: None,\n                            arity: 0,\n                            location: SrcSpan::default(),\n                            variants_count: 2,\n                            variant_index: 0,\n                        },\n                        bool_with_variant(Some(true)),\n                    ),\n                );\n                let _ = prelude.values.insert(\n                    \"False\".into(),\n                    value(\n                        ValueConstructorVariant::Record {\n                            documentation: None,\n                            module: PRELUDE_MODULE_NAME.into(),\n                            name: \"False\".into(),\n                            field_map: None,\n                            arity: 0,\n                            location: SrcSpan::default(),\n                            variants_count: 2,\n                            variant_index: 1,\n                        },\n                        bool_with_variant(Some(false)),\n                    ),\n                );\n                let _ = prelude.types.insert(\n                    BOOL.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![],\n                        type_: bool(),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n            }\n\n            PreludeType::Float => {\n                let _ = prelude.types.insert(\n                    FLOAT.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![],\n                        type_: float(),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n            }\n\n            PreludeType::Int => {\n                let _ = prelude.types.insert(\n                    INT.into(),\n                    TypeConstructor {\n                        parameters: vec![],\n                        type_: int(),\n                        origin: Default::default(),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n            }\n\n            PreludeType::List => {\n                let list_parameter = generic_var(ids.next());\n                let _ = prelude.types.insert(\n                    LIST.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![list_parameter.clone()],\n                        type_: list(list_parameter),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n            }\n\n            PreludeType::Nil => {\n                let _ = prelude.values.insert(\n                    NIL.into(),\n                    value(\n                        ValueConstructorVariant::Record {\n                            documentation: None,\n                            module: PRELUDE_MODULE_NAME.into(),\n                            name: NIL.into(),\n                            arity: 0,\n                            field_map: None,\n                            location: SrcSpan::default(),\n                            variants_count: 1,\n                            variant_index: 0,\n                        },\n                        nil(),\n                    ),\n                );\n                let _ = prelude.types.insert(\n                    NIL.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![],\n                        type_: nil(),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n                let _ = prelude.types_value_constructors.insert(\n                    NIL.into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![],\n                        variants: vec![TypeValueConstructor {\n                            name: \"Nil\".into(),\n                            parameters: vec![],\n                            documentation: None,\n                        }],\n                        opaque: Opaque::NotOpaque,\n                    },\n                );\n            }\n\n            PreludeType::Result => {\n                let result_value_id = ids.next();\n                let result_error_id = ids.next();\n                let result_value = generic_var(result_value_id);\n                let result_error = generic_var(result_error_id);\n                let _ = prelude.types.insert(\n                    RESULT.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![result_value.clone(), result_error.clone()],\n                        type_: result(result_value.clone(), result_error.clone()),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n                let _ = prelude.types_value_constructors.insert(\n                    RESULT.into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![result_value_id, result_error_id],\n                        variants: vec![\n                            TypeValueConstructor {\n                                name: \"Ok\".into(),\n                                parameters: vec![TypeValueConstructorField {\n                                    type_: result_value,\n                                    label: None,\n                                    documentation: None,\n                                }],\n                                documentation: None,\n                            },\n                            TypeValueConstructor {\n                                name: \"Error\".into(),\n                                parameters: vec![TypeValueConstructorField {\n                                    type_: result_error,\n                                    label: None,\n                                    documentation: None,\n                                }],\n                                documentation: None,\n                            },\n                        ],\n                        opaque: Opaque::NotOpaque,\n                    },\n                );\n                let ok = generic_var(ids.next());\n                let error = generic_var(ids.next());\n                let _ = prelude.values.insert(\n                    \"Ok\".into(),\n                    value(\n                        ValueConstructorVariant::Record {\n                            documentation: None,\n                            module: PRELUDE_MODULE_NAME.into(),\n                            name: \"Ok\".into(),\n                            field_map: None,\n                            arity: 1,\n                            location: SrcSpan::default(),\n                            variants_count: 2,\n                            variant_index: 0,\n                        },\n                        fn_(vec![ok.clone()], result_with_variant(ok, error, Some(0))),\n                    ),\n                );\n                let ok = generic_var(ids.next());\n                let error = generic_var(ids.next());\n                let _ = prelude.values.insert(\n                    \"Error\".into(),\n                    value(\n                        ValueConstructorVariant::Record {\n                            documentation: None,\n                            module: PRELUDE_MODULE_NAME.into(),\n                            name: \"Error\".into(),\n                            field_map: None,\n                            arity: 1,\n                            location: SrcSpan::default(),\n                            variants_count: 2,\n                            variant_index: 1,\n                        },\n                        fn_(vec![error.clone()], result_with_variant(ok, error, Some(1))),\n                    ),\n                );\n            }\n\n            PreludeType::String => {\n                let _ = prelude.types.insert(\n                    STRING.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![],\n                        type_: string(),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n            }\n\n            PreludeType::UtfCodepoint => {\n                let _ = prelude.types.insert(\n                    UTF_CODEPOINT.into(),\n                    TypeConstructor {\n                        origin: Default::default(),\n                        parameters: vec![],\n                        type_: utf_codepoint(),\n                        module: PRELUDE_MODULE_NAME.into(),\n                        publicity: Publicity::Public,\n                        deprecation: NotDeprecated,\n                        documentation: None,\n                    },\n                );\n                let _ = prelude.types_value_constructors.insert(\n                    UTF_CODEPOINT.into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![],\n                        variants: vec![],\n                        opaque: Opaque::NotOpaque,\n                    },\n                );\n            }\n        }\n    }\n\n    prelude\n}\n"
  },
  {
    "path": "compiler-core/src/type_/pretty.rs",
    "content": "use super::{Type, TypeVar};\nuse crate::{\n    docvec,\n    pretty::{nil, *},\n};\nuse ecow::EcoString;\nuse std::sync::Arc;\n\n#[cfg(test)]\nuse super::*;\n#[cfg(test)]\nuse std::cell::RefCell;\n\n#[cfg(test)]\nuse pretty_assertions::assert_eq;\n\nconst INDENT: isize = 2;\n\n#[derive(Debug, Default)]\npub struct Printer {\n    names: im::HashMap<u64, EcoString>,\n    uid: u64,\n    // A mapping of printd type names to the module that they are defined in.\n    printed_types: im::HashMap<EcoString, EcoString>,\n}\n\nimpl Printer {\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    pub fn with_names(&mut self, names: im::HashMap<u64, EcoString>) {\n        self.names = names;\n    }\n\n    /// Render a Type as a well formatted string.\n    ///\n    pub fn pretty_print(&mut self, type_: &Type, initial_indent: usize) -> String {\n        let mut buffer = String::with_capacity(initial_indent);\n        for _ in 0..initial_indent {\n            buffer.push(' ');\n        }\n        buffer\n            .to_doc()\n            .append(self.print(type_))\n            .nest(initial_indent as isize)\n            .to_pretty_string(80)\n    }\n\n    // TODO: have this function return a Document that borrows from the Type.\n    // Is this possible? The lifetime would have to go through the Arc<Refcell<Type>>\n    // for TypeVar::Link'd types.\n    pub fn print<'a>(&mut self, type_: &Type) -> Document<'a> {\n        match type_ {\n            Type::Named {\n                name,\n                arguments,\n                module,\n                ..\n            } => {\n                let doc = if self.name_clashes_if_unqualified(name, module) {\n                    qualify_type_name(module, name)\n                } else {\n                    let _ = self.printed_types.insert(name.clone(), module.clone());\n                    name.to_doc()\n                };\n                if arguments.is_empty() {\n                    doc\n                } else {\n                    doc.append(\"(\")\n                        .append(self.arguments_to_gleam_doc(arguments))\n                        .append(\")\")\n                }\n            }\n\n            Type::Fn { arguments, return_ } => \"fn(\"\n                .to_doc()\n                .append(self.arguments_to_gleam_doc(arguments))\n                .append(\") ->\")\n                .append(\n                    break_(\"\", \" \")\n                        .append(self.print(return_))\n                        .nest(INDENT)\n                        .group(),\n                ),\n\n            Type::Var { type_, .. } => self.type_var_doc(&type_.borrow()),\n\n            Type::Tuple { elements, .. } => {\n                self.arguments_to_gleam_doc(elements).surround(\"#(\", \")\")\n            }\n        }\n    }\n\n    fn name_clashes_if_unqualified(&mut self, type_: &EcoString, module: &str) -> bool {\n        match self.printed_types.get(type_) {\n            None => false,\n            Some(previous_module) if module == previous_module => false,\n            Some(_different_module) => true,\n        }\n    }\n\n    fn type_var_doc<'a>(&mut self, type_: &TypeVar) -> Document<'a> {\n        match type_ {\n            TypeVar::Link { type_, .. } => self.print(type_),\n            TypeVar::Unbound { id, .. } | TypeVar::Generic { id, .. } => self.generic_type_var(*id),\n        }\n    }\n\n    pub fn generic_type_var<'a>(&mut self, id: u64) -> Document<'a> {\n        match self.names.get(&id) {\n            Some(n) => {\n                let _ = self.printed_types.insert(n.clone(), \"\".into());\n                n.to_doc()\n            }\n            None => {\n                let n = self.next_letter();\n                let _ = self.names.insert(id, n.clone());\n                let _ = self.printed_types.insert(n.clone(), \"\".into());\n                n.to_doc()\n            }\n        }\n    }\n\n    fn next_letter(&mut self) -> EcoString {\n        let alphabet_length = 26;\n        let char_offset = 97;\n        let mut chars = vec![];\n        let mut n;\n        let mut rest = self.uid;\n\n        loop {\n            n = rest % alphabet_length;\n            rest /= alphabet_length;\n            chars.push((n as u8 + char_offset) as char);\n\n            if rest == 0 {\n                break;\n            }\n            rest -= 1\n        }\n\n        self.uid += 1;\n        chars.into_iter().rev().collect()\n    }\n\n    fn arguments_to_gleam_doc(&mut self, arguments: &[Arc<Type>]) -> Document<'static> {\n        if arguments.is_empty() {\n            return nil();\n        }\n\n        let arguments = join(\n            arguments.iter().map(|type_| self.print(type_).group()),\n            break_(\",\", \", \"),\n        );\n        break_(\"\", \"\")\n            .append(arguments)\n            .nest(INDENT)\n            .append(break_(\",\", \"\"))\n            .group()\n    }\n}\n\nfn qualify_type_name(module: &str, type_name: &str) -> Document<'static> {\n    docvec![EcoString::from(module), \".\", EcoString::from(type_name)]\n}\n\n#[test]\nfn next_letter_test() {\n    let mut printer = Printer::new();\n    assert_eq!(printer.next_letter().as_str(), \"a\");\n    assert_eq!(printer.next_letter().as_str(), \"b\");\n    assert_eq!(printer.next_letter().as_str(), \"c\");\n    assert_eq!(printer.next_letter().as_str(), \"d\");\n    assert_eq!(printer.next_letter().as_str(), \"e\");\n    assert_eq!(printer.next_letter().as_str(), \"f\");\n    assert_eq!(printer.next_letter().as_str(), \"g\");\n    assert_eq!(printer.next_letter().as_str(), \"h\");\n    assert_eq!(printer.next_letter().as_str(), \"i\");\n    assert_eq!(printer.next_letter().as_str(), \"j\");\n    assert_eq!(printer.next_letter().as_str(), \"k\");\n    assert_eq!(printer.next_letter().as_str(), \"l\");\n    assert_eq!(printer.next_letter().as_str(), \"m\");\n    assert_eq!(printer.next_letter().as_str(), \"n\");\n    assert_eq!(printer.next_letter().as_str(), \"o\");\n    assert_eq!(printer.next_letter().as_str(), \"p\");\n    assert_eq!(printer.next_letter().as_str(), \"q\");\n    assert_eq!(printer.next_letter().as_str(), \"r\");\n    assert_eq!(printer.next_letter().as_str(), \"s\");\n    assert_eq!(printer.next_letter().as_str(), \"t\");\n    assert_eq!(printer.next_letter().as_str(), \"u\");\n    assert_eq!(printer.next_letter().as_str(), \"v\");\n    assert_eq!(printer.next_letter().as_str(), \"w\");\n    assert_eq!(printer.next_letter().as_str(), \"x\");\n    assert_eq!(printer.next_letter().as_str(), \"y\");\n    assert_eq!(printer.next_letter().as_str(), \"z\");\n    assert_eq!(printer.next_letter().as_str(), \"aa\");\n    assert_eq!(printer.next_letter().as_str(), \"ab\");\n    assert_eq!(printer.next_letter().as_str(), \"ac\");\n    assert_eq!(printer.next_letter().as_str(), \"ad\");\n    assert_eq!(printer.next_letter().as_str(), \"ae\");\n    assert_eq!(printer.next_letter().as_str(), \"af\");\n    assert_eq!(printer.next_letter().as_str(), \"ag\");\n    assert_eq!(printer.next_letter().as_str(), \"ah\");\n    assert_eq!(printer.next_letter().as_str(), \"ai\");\n    assert_eq!(printer.next_letter().as_str(), \"aj\");\n    assert_eq!(printer.next_letter().as_str(), \"ak\");\n    assert_eq!(printer.next_letter().as_str(), \"al\");\n    assert_eq!(printer.next_letter().as_str(), \"am\");\n    assert_eq!(printer.next_letter().as_str(), \"an\");\n    assert_eq!(printer.next_letter().as_str(), \"ao\");\n    assert_eq!(printer.next_letter().as_str(), \"ap\");\n    assert_eq!(printer.next_letter().as_str(), \"aq\");\n    assert_eq!(printer.next_letter().as_str(), \"ar\");\n    assert_eq!(printer.next_letter().as_str(), \"as\");\n    assert_eq!(printer.next_letter().as_str(), \"at\");\n    assert_eq!(printer.next_letter().as_str(), \"au\");\n    assert_eq!(printer.next_letter().as_str(), \"av\");\n    assert_eq!(printer.next_letter().as_str(), \"aw\");\n    assert_eq!(printer.next_letter().as_str(), \"ax\");\n    assert_eq!(printer.next_letter().as_str(), \"ay\");\n    assert_eq!(printer.next_letter().as_str(), \"az\");\n    assert_eq!(printer.next_letter().as_str(), \"ba\");\n    assert_eq!(printer.next_letter().as_str(), \"bb\");\n    assert_eq!(printer.next_letter().as_str(), \"bc\");\n    assert_eq!(printer.next_letter().as_str(), \"bd\");\n    assert_eq!(printer.next_letter().as_str(), \"be\");\n    assert_eq!(printer.next_letter().as_str(), \"bf\");\n    assert_eq!(printer.next_letter().as_str(), \"bg\");\n    assert_eq!(printer.next_letter().as_str(), \"bh\");\n    assert_eq!(printer.next_letter().as_str(), \"bi\");\n    assert_eq!(printer.next_letter().as_str(), \"bj\");\n    assert_eq!(printer.next_letter().as_str(), \"bk\");\n    assert_eq!(printer.next_letter().as_str(), \"bl\");\n    assert_eq!(printer.next_letter().as_str(), \"bm\");\n    assert_eq!(printer.next_letter().as_str(), \"bn\");\n    assert_eq!(printer.next_letter().as_str(), \"bo\");\n    assert_eq!(printer.next_letter().as_str(), \"bp\");\n    assert_eq!(printer.next_letter().as_str(), \"bq\");\n    assert_eq!(printer.next_letter().as_str(), \"br\");\n    assert_eq!(printer.next_letter().as_str(), \"bs\");\n    assert_eq!(printer.next_letter().as_str(), \"bt\");\n    assert_eq!(printer.next_letter().as_str(), \"bu\");\n    assert_eq!(printer.next_letter().as_str(), \"bv\");\n    assert_eq!(printer.next_letter().as_str(), \"bw\");\n    assert_eq!(printer.next_letter().as_str(), \"bx\");\n    assert_eq!(printer.next_letter().as_str(), \"by\");\n    assert_eq!(printer.next_letter().as_str(), \"bz\");\n}\n\n#[test]\nfn pretty_print_test() {\n    macro_rules! assert_string {\n        ($src:expr, $type_:expr $(,)?) => {\n            let mut printer = Printer::new();\n            assert_eq!($type_.to_string(), printer.pretty_print(&$src, 0),);\n        };\n    }\n\n    assert_string!(\n        Type::Named {\n            module: \"whatever\".into(),\n            package: \"whatever\".into(),\n            name: \"Int\".into(),\n            publicity: Publicity::Public,\n            arguments: vec![],\n            inferred_variant: None,\n        },\n        \"Int\",\n    );\n    assert_string!(\n        Type::Named {\n            module: \"themodule\".into(),\n            package: \"whatever\".into(),\n            name: \"Pair\".into(),\n            publicity: Publicity::Public,\n            arguments: vec![\n                Arc::new(Type::Named {\n                    module: \"whatever\".into(),\n                    package: \"whatever\".into(),\n                    name: \"Int\".into(),\n                    publicity: Publicity::Public,\n                    arguments: vec![],\n                    inferred_variant: None,\n                }),\n                Arc::new(Type::Named {\n                    module: \"whatever\".into(),\n                    package: \"whatever\".into(),\n                    name: \"Bool\".into(),\n                    publicity: Publicity::Public,\n                    arguments: vec![],\n                    inferred_variant: None,\n                }),\n            ],\n            inferred_variant: None,\n        },\n        \"Pair(Int, Bool)\",\n    );\n    assert_string!(\n        Type::Fn {\n            arguments: vec![\n                Arc::new(Type::Named {\n                    arguments: vec![],\n                    module: \"whatever\".into(),\n                    package: \"whatever\".into(),\n                    name: \"Int\".into(),\n                    publicity: Publicity::Public,\n                    inferred_variant: None,\n                }),\n                Arc::new(Type::Named {\n                    arguments: vec![],\n                    module: \"whatever\".into(),\n                    package: \"whatever\".into(),\n                    name: \"Bool\".into(),\n                    publicity: Publicity::Public,\n                    inferred_variant: None,\n                }),\n            ],\n            return_: Arc::new(Type::Named {\n                arguments: vec![],\n                module: \"whatever\".into(),\n                package: \"whatever\".into(),\n                name: \"Bool\".into(),\n                publicity: Publicity::Public,\n                inferred_variant: None,\n            }),\n        },\n        \"fn(Int, Bool) -> Bool\",\n    );\n    assert_string!(\n        Type::Var {\n            type_: Arc::new(RefCell::new(TypeVar::Link {\n                type_: Arc::new(Type::Named {\n                    arguments: vec![],\n                    module: \"whatever\".into(),\n                    package: \"whatever\".into(),\n                    name: \"Int\".into(),\n                    publicity: Publicity::Public,\n                    inferred_variant: None,\n                }),\n            })),\n        },\n        \"Int\",\n    );\n    assert_string!(\n        Type::Var {\n            type_: Arc::new(RefCell::new(TypeVar::Unbound { id: 2231 })),\n        },\n        \"a\",\n    );\n    assert_string!(\n        fn_(\n            vec![Arc::new(Type::Var {\n                type_: Arc::new(RefCell::new(TypeVar::Unbound { id: 78 })),\n            })],\n            Arc::new(Type::Var {\n                type_: Arc::new(RefCell::new(TypeVar::Unbound { id: 2 })),\n            }),\n        ),\n        \"fn(a) -> b\",\n    );\n    assert_string!(\n        fn_(\n            vec![Arc::new(Type::Var {\n                type_: Arc::new(RefCell::new(TypeVar::Generic { id: 78 })),\n            })],\n            Arc::new(Type::Var {\n                type_: Arc::new(RefCell::new(TypeVar::Generic { id: 2 })),\n            }),\n        ),\n        \"fn(a) -> b\",\n    );\n}\n\n#[test]\nfn function_test() {\n    assert_eq!(pretty_print(fn_(vec![], int())), \"fn() -> Int\");\n\n    assert_eq!(\n        pretty_print(fn_(vec![int(), int(), int()], int())),\n        \"fn(Int, Int, Int) -> Int\"\n    );\n\n    assert_eq!(\n        pretty_print(fn_(\n            vec![\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float()\n            ],\n            float()\n        )),\n        \"fn(\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n) -> Float\"\n    );\n\n    assert_eq!(\n        pretty_print(fn_(\n            vec![\n                tuple(vec![float(), float(), float(), float(), float(), float()]),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float()\n            ],\n            float()\n        )),\n        \"fn(\n  #(Float, Float, Float, Float, Float, Float),\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n  Float,\n) -> Float\"\n    );\n\n    assert_eq!(\n        pretty_print(fn_(\n            vec![tuple(vec![\n                float(),\n                float(),\n                float(),\n                float(),\n                float(),\n                float()\n            ]),],\n            tuple(vec![\n                tuple(vec![float(), float(), float(), float(), float(), float()]),\n                tuple(vec![float(), float(), float(), float(), float(), float()]),\n            ]),\n        )),\n        \"fn(#(Float, Float, Float, Float, Float, Float)) ->\n  #(\n    #(Float, Float, Float, Float, Float, Float),\n    #(Float, Float, Float, Float, Float, Float),\n  )\"\n    );\n}\n\n#[cfg(test)]\nfn pretty_print(type_: Arc<Type>) -> String {\n    Printer::new().pretty_print(&type_, 0)\n}\n"
  },
  {
    "path": "compiler-core/src/type_/printer.rs",
    "content": "use bimap::BiMap;\nuse ecow::{EcoString, eco_format};\nuse im::HashMap;\nuse std::{collections::HashSet, sync::Arc};\n\nuse crate::{\n    ast::SrcSpan,\n    type_::{Type, TypeAliasConstructor, TypeVar},\n};\n\n/// This class keeps track of what names are used for modules in the current\n/// scope, so they can be printed in errors, etc.\n///\n#[derive(Debug, Clone, PartialEq, Eq, Default)]\npub struct Names {\n    /// Types that exist in the current module, either defined or imported in an\n    /// unqualified fashion.\n    ///\n    /// key:   (Defining module name, type name)\n    /// value: Alias name\n    ///\n    /// # Example 1\n    ///\n    /// ```gleam\n    /// type Wibble = wobble.Woo\n    /// ```\n    /// would result in\n    /// - key:   `(\"wibble\", \"Woo\")`\n    /// - value: `\"Wibble\"`\n    ///\n    /// # Example 2\n    ///\n    /// ```gleam\n    /// import some/module.{type Wibble}\n    /// ```\n    /// would result in\n    /// - key:   `(\"some/module\", \"Wibble\")`\n    /// - value: `\"Wibble\"`\n    ///\n    /// # Example 3\n    ///\n    /// ```gleam\n    /// import some/module.{type Wibble as Wobble}\n    /// ```\n    /// would result in\n    /// - key:   `(\"some/module\", \"Wibble\")`\n    /// - value: `\"Wobble\"`\n    ///\n    local_types: BiMap<(EcoString, EcoString), EcoString>,\n\n    /// Mapping of imported modules to their locally used named\n    ///\n    /// key:   The name of the module\n    /// value: The name the module is aliased to\n    ///\n    /// # Example 1\n    ///\n    /// ```gleam\n    /// import mod1 as my_mod\n    /// ```\n    /// would result in:\n    /// - key:   \"mod1\"\n    /// - value: \"my_mod\"\n    ///\n    /// # Example 2\n    ///\n    /// ```gleam\n    /// import mod1\n    /// ```\n    /// would result in:\n    /// - key:   \"mod1\"\n    /// - value: \"mod1\"\n    ///\n    imported_modules: HashMap<EcoString, (EcoString, SrcSpan)>,\n\n    /// Generic type parameters that have been annotated in the current\n    /// function.\n    ///\n    /// key:   The id of generic type that was annotated\n    /// value: The name that is used for the generic type in the annotation.\n    ///\n    /// # Example 1\n    ///\n    /// ```gleam\n    /// fn equal(x: something, y: something) -> Bool {\n    ///   arg1 == arg2\n    /// }\n    /// ```\n    ///\n    /// key:   <some id int>\n    /// value: `\"something\"`\n    ///\n    type_variables: HashMap<u64, EcoString>,\n\n    /// Constructors which are imported in the current module in an\n    /// unqualified fashion.\n    ///\n    /// key:   (Defining module name, type name)\n    /// value: Alias name\n    ///\n    /// # Example 1\n    ///\n    /// ```gleam\n    /// import wibble.{Wobble}\n    /// ```\n    /// would result in\n    /// - key:   `(\"wibble\", \"Wobble\")`\n    /// - value: `\"Wobble\"`\n    ///\n    /// # Example 2\n    ///\n    /// ```gleam\n    /// import wibble.{Wobble as Woo}\n    /// ```\n    /// would result in\n    /// - key:   `(\"wibble\", \"Wobble\")`\n    /// - value: `\"Woo\"`\n    ///\n    local_value_constructors: BiMap<(EcoString, EcoString), EcoString>,\n\n    /// A map containing information about public alias of internal types in\n    /// other packages. This is a common pattern in Gleam, in order to reexport\n    /// an internal type, without exposing its implementation details. Because\n    /// of this, we want to be able to properly handle this case, and use the\n    /// public alias rather than the internal underlying type. Since Gleam type\n    /// aliases are not part of the type system, we have to track them manually\n    /// here.\n    ///\n    /// This is a mapping of internal types to their public aliases that we want\n    /// to favour over the internal types.\n    ///\n    /// For example, if we had the following code:\n    ///\n    /// ```gleam\n    /// // lustre/element.gleam\n    /// import lustre/internal\n    ///\n    /// pub type Element(a) = internal.Element(a)\n    /// ```\n    ///\n    /// This map would contain a key of `(\"lustre/internal\", \"Element\")` with a\n    /// value of `(\"lustre/element\", \"Element\")`. This can then be used to look\n    /// up the alias we want to print based on the type we are printing.\n    ///\n    reexport_aliases: HashMap<(EcoString, EcoString), (EcoString, EcoString)>,\n}\n\n/// The `PartialEq` implementation for `Type` doesn't account for `TypeVar::Link`,\n/// so we implement an equality check that does account for it here.\nfn compare_arguments(arguments: &[Arc<Type>], parameters: &[Arc<Type>]) -> bool {\n    if arguments.len() != parameters.len() {\n        return false;\n    }\n\n    arguments\n        .iter()\n        .zip(parameters)\n        .all(|(argument, parameter)| argument.same_as(parameter))\n}\n\nimpl Names {\n    pub fn new() -> Self {\n        Self {\n            local_types: Default::default(),\n            imported_modules: Default::default(),\n            type_variables: Default::default(),\n            local_value_constructors: Default::default(),\n            reexport_aliases: Default::default(),\n        }\n    }\n\n    /// Record a named type in this module.\n    pub fn named_type_in_scope(\n        &mut self,\n        module_name: EcoString,\n        type_name: EcoString,\n        local_alias: EcoString,\n    ) {\n        _ = self.local_types.remove_by_right(&local_alias);\n        _ = self\n            .local_types\n            .insert((module_name, type_name), local_alias);\n    }\n\n    pub fn type_in_scope(\n        &mut self,\n        local_alias: EcoString,\n        type_: &Type,\n        parameters: &[Arc<Type>],\n    ) {\n        match type_ {\n            Type::Named {\n                module,\n                name,\n                arguments,\n                ..\n            } if compare_arguments(arguments, parameters) => {\n                self.named_type_in_scope(module.clone(), name.clone(), local_alias);\n            }\n            Type::Named { .. } | Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => {\n                _ = self.local_types.remove_by_right(&local_alias);\n            }\n        }\n    }\n\n    /// Record a type variable in this module.\n    pub fn type_variable_in_scope(&mut self, id: u64, local_alias: EcoString) {\n        _ = self.type_variables.insert(id, local_alias.clone());\n    }\n\n    /// Record an imported module in this module.\n    ///\n    /// Returns the location of the previous time this module was imported, if there was one.\n    pub fn imported_module(\n        &mut self,\n        module_name: EcoString,\n        module_alias: EcoString,\n        location: SrcSpan,\n    ) -> Option<SrcSpan> {\n        self.imported_modules\n            .insert(module_name, (module_alias, location))\n            .map(|(_, location)| location)\n    }\n\n    /// Check whether a particular type alias is reexporting an internal type,\n    /// and if so register it so we can print it correctly.\n    pub fn maybe_register_reexport_alias(\n        &mut self,\n        package: &EcoString,\n        alias_name: &EcoString,\n        alias: &TypeAliasConstructor,\n    ) {\n        match alias.type_.as_ref() {\n            Type::Named {\n                publicity,\n                package: type_package,\n                module,\n                name,\n                arguments,\n                ..\n            } => {\n                // We only count this alias as a reexport if it is:\n                // - aliasing a type in the same package\n                // - the type is internal\n                // - the alias exposes the same type parameters as the internal type\n                if type_package == package\n                    && publicity.is_internal()\n                    && compare_arguments(arguments, &alias.parameters)\n                {\n                    _ = self.reexport_aliases.insert(\n                        (module.clone(), name.clone()),\n                        (alias.module.clone(), alias_name.clone()),\n                    );\n                }\n            }\n            Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => {}\n        }\n    }\n\n    /// Get the name and optional module qualifier for a named type.\n    fn named_type<'a>(\n        &'a self,\n        module: &'a EcoString,\n        name: &'a EcoString,\n        print_mode: PrintMode,\n    ) -> NameContextInformation<'a> {\n        if print_mode == PrintMode::ExpandAliases {\n            if let Some((module, _)) = self.imported_modules.get(module) {\n                return NameContextInformation::Qualified(module, name.as_str());\n            };\n\n            return NameContextInformation::Unimported(module, name);\n        }\n\n        let key = (module.clone(), name.clone());\n\n        // Only check for local aliases if we want to print aliases\n        // There is a local name for this type, use that.\n        if let Some(name) = self.local_types.get_by_left(&key) {\n            return NameContextInformation::Unqualified(name.as_str());\n        }\n\n        if let Some((module, alias)) = self.reexport_aliases.get(&key) {\n            if let Some((module, _)) = self.imported_modules.get(module) {\n                return NameContextInformation::Qualified(module, alias);\n            } else {\n                return NameContextInformation::Unimported(module, alias);\n            }\n        }\n\n        // This type is from a module that has been imported\n        if let Some((module, _)) = self.imported_modules.get(module) {\n            return NameContextInformation::Qualified(module, name.as_str());\n        };\n\n        NameContextInformation::Unimported(module, name)\n    }\n\n    /// Record a named value in this module.\n    pub fn named_constructor_in_scope(\n        &mut self,\n        module_name: EcoString,\n        value_name: EcoString,\n        local_alias: EcoString,\n    ) {\n        _ = self.local_value_constructors.remove_by_right(&local_alias);\n        _ = self\n            .local_value_constructors\n            .insert((module_name.clone(), value_name), local_alias.clone());\n    }\n\n    /// Get the name and optional module qualifier for a named constructor.\n    pub fn named_constructor<'a>(\n        &'a self,\n        module: &'a EcoString,\n        name: &'a EcoString,\n    ) -> NameContextInformation<'a> {\n        let key = (module.clone(), name.clone());\n\n        // There is a local name for this value, use that.\n        if let Some(name) = self.local_value_constructors.get_by_left(&key) {\n            return NameContextInformation::Unqualified(name.as_str());\n        }\n\n        // This value is from a module that has been imported\n        if let Some((module, _)) = self.imported_modules.get(module) {\n            return NameContextInformation::Qualified(module, name.as_str());\n        };\n\n        NameContextInformation::Unimported(module, name)\n    }\n\n    pub fn is_imported(&self, module: &str) -> bool {\n        self.imported_modules.contains_key(module)\n    }\n\n    pub fn get_type_variable(&self, id: u64) -> Option<&EcoString> {\n        self.type_variables.get(&id)\n    }\n\n    pub fn reexport_alias(\n        &self,\n        module: EcoString,\n        name: EcoString,\n    ) -> Option<&(EcoString, EcoString)> {\n        self.reexport_aliases.get(&(module, name))\n    }\n}\n\n#[derive(Debug)]\npub enum NameContextInformation<'a> {\n    /// This type is from a module that has not been imported in this module.\n    Unimported(&'a str, &'a str),\n    /// This type has been imported in an unqualifid fashion in this module.\n    Unqualified(&'a str),\n    /// This type is from a module that has been imported.\n    Qualified(&'a str, &'a str),\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum PrintMode {\n    /// Prints the context-specific representation of a type.\n    Normal,\n    /// Prints full detail of the given type, always qualified.\n    /// Useful for providing more detail to the user.\n    ///\n    /// For example, with this code:\n    /// ```gleam\n    /// type A = Int\n    /// ```\n    /// If the type `gleam.Int` were printed using the `Normal` mode,\n    /// we would print `A`, since that is the local alias for the `Int` type.\n    ///\n    /// However, if the user were hovering over the type `A` itself, it wouldn't be\n    /// particularly helpful to print `A`.\n    /// So with `ExpandAliases`, it would print `gleam.Int`,\n    /// which tells the user exactly what type `A` represents.\n    ///\n    ExpandAliases,\n}\n\n/// A type printer that does not wrap and indent, but does take into account the\n/// names that types and modules have been aliased with in the current module.\n#[derive(Debug)]\npub struct Printer<'a> {\n    names: &'a Names,\n    uid: u64,\n\n    /// Some type variables aren't bound to names, so when trying to print those,\n    /// we need to create our own names which don't overlap with existing type variables.\n    /// These two data structures store a mapping of IDs to created type-variable names,\n    /// to ensure consistent printing, and the set of all printed names so that we don't\n    /// create a type variable name which matches an existing one.\n    ///\n    /// Note: These are stored per printer, not per TypeNames struct, because:\n    /// - It doesn't really matter what these are, as long as they are consistent.\n    /// - We would need mutable access to the names struct, which isn't really possible\n    ///   in many contexts.\n    ///\n    printed_type_variables: HashMap<u64, EcoString>,\n    printed_type_variable_names: HashSet<EcoString>,\n}\n\nimpl<'a> Printer<'a> {\n    pub fn new(names: &'a Names) -> Self {\n        Printer {\n            names,\n            uid: Default::default(),\n            printed_type_variables: Default::default(),\n            printed_type_variable_names: names.type_variables.values().cloned().collect(),\n        }\n    }\n\n    /// In the AST, type variables are represented by their IDs, not their names.\n    /// This means that when we are printing a type variable, we either need to\n    /// find its name that was given by the programmer, or generate a new one.\n    /// Type variable names are local to functions, meaning there can be one\n    /// named `a` in one function, and a different one named `a` in another\n    /// function. However, there can't be two named `a` in the same function.\n    ///\n    /// By default, the printer avoids duplicating type variable names entirely.\n    /// This is because we don't have easy access to information about which type\n    /// variables belong to this function. In order to ensure no accidental,\n    /// collisions, we treat all type variables from the module as in scope, even\n    /// though this isn't the case.\n    ///\n    /// When sufficient information is present to ensure type variables are not\n    /// duplicated, `new_without_type_variables` can be used, in combination with\n    /// `register_type_variables` in order to precisely control which variables\n    /// are in scope.\n    ///\n    pub fn new_without_type_variables(names: &'a Names) -> Self {\n        Printer {\n            names,\n            uid: Default::default(),\n            printed_type_variables: Default::default(),\n            printed_type_variable_names: Default::default(),\n        }\n    }\n\n    /// Clear the registered type variable names. This allows the same `Printer`\n    /// to be used in multiple different scopes, which have different sets of\n    /// type variables. After clearing, the correct variables from the desired\n    /// scope can be registered using `register_type_variable`.\n    pub fn clear_type_variables(&mut self) {\n        self.printed_type_variable_names.clear();\n    }\n\n    /// As explained in the documentation for `new_without_type_variables`, it\n    /// it not always possible to determine which type variables are in scope.\n    /// However, when it is possible, this function can be used to manually\n    /// register which type variable names are in scope and cannot be used.\n    pub fn register_type_variable(&mut self, name: EcoString) {\n        _ = self.printed_type_variable_names.insert(name);\n    }\n\n    pub fn print_type(&mut self, type_: &Type) -> EcoString {\n        let mut buffer = EcoString::new();\n        self.print(type_, &mut buffer, PrintMode::Normal);\n        buffer\n    }\n\n    pub fn print_module(&self, module: &str) -> EcoString {\n        match self.names.imported_modules.get(module) {\n            Some((module, _)) => module.clone(),\n            _ => module.split(\"/\").last().unwrap_or(module).into(),\n        }\n    }\n\n    pub fn print_type_without_aliases(&mut self, type_: &Type) -> EcoString {\n        let mut buffer = EcoString::new();\n        self.print(type_, &mut buffer, PrintMode::ExpandAliases);\n        buffer\n    }\n\n    fn print(&mut self, type_: &Type, buffer: &mut EcoString, print_mode: PrintMode) {\n        match type_ {\n            Type::Named {\n                name,\n                arguments,\n                module,\n                ..\n            } => {\n                let (module, name) = match self.names.named_type(module, name, print_mode) {\n                    NameContextInformation::Qualified(module, name) => (Some(module), name),\n                    NameContextInformation::Unqualified(name) => (None, name),\n                    // TODO: indicate that the module is not import and as such\n                    // needs to be, as well as how.\n                    NameContextInformation::Unimported(module, name) => {\n                        (module.split('/').next_back(), name)\n                    }\n                };\n\n                if let Some(module) = module {\n                    buffer.push_str(module);\n                    buffer.push('.');\n                }\n                buffer.push_str(name);\n\n                if !arguments.is_empty() {\n                    buffer.push('(');\n                    self.print_arguments(arguments, buffer, print_mode);\n                    buffer.push(')');\n                }\n            }\n\n            Type::Fn { arguments, return_ } => {\n                buffer.push_str(\"fn(\");\n                self.print_arguments(arguments, buffer, print_mode);\n                buffer.push_str(\") -> \");\n                self.print(return_, buffer, print_mode);\n            }\n\n            Type::Var { type_, .. } => match *type_.borrow() {\n                TypeVar::Link { ref type_, .. } => self.print(type_, buffer, print_mode),\n                TypeVar::Unbound { id, .. } | TypeVar::Generic { id, .. } => {\n                    buffer.push_str(&self.type_variable(id))\n                }\n            },\n\n            Type::Tuple { elements, .. } => {\n                buffer.push_str(\"#(\");\n                self.print_arguments(elements, buffer, print_mode);\n                buffer.push(')');\n            }\n        }\n    }\n\n    pub fn print_constructor(&mut self, module: &EcoString, name: &EcoString) -> EcoString {\n        let (module, name) = match self.names.named_constructor(module, name) {\n            NameContextInformation::Qualified(module, name) => (Some(module), name),\n            NameContextInformation::Unqualified(name) => (None, name),\n            NameContextInformation::Unimported(module, name) => {\n                (module.split('/').next_back(), name)\n            }\n        };\n\n        match module {\n            Some(module) => eco_format!(\"{module}.{name}\"),\n            None => name.into(),\n        }\n    }\n\n    fn print_arguments(\n        &mut self,\n        arguments: &[Arc<Type>],\n        type_str: &mut EcoString,\n        print_mode: PrintMode,\n    ) {\n        for (i, argument) in arguments.iter().enumerate() {\n            self.print(argument, type_str, print_mode);\n            if i < arguments.len() - 1 {\n                type_str.push_str(\", \");\n            }\n        }\n    }\n\n    /// A suitable name of a type variable.\n    pub fn type_variable(&mut self, id: u64) -> EcoString {\n        if let Some(name) = self.names.type_variables.get(&id) {\n            return name.clone();\n        }\n\n        if let Some(name) = self.printed_type_variables.get(&id) {\n            return name.clone();\n        }\n\n        loop {\n            let name = self.next_letter();\n            if !self.printed_type_variable_names.contains(&name) {\n                _ = self.printed_type_variable_names.insert(name.clone());\n                _ = self.printed_type_variables.insert(id, name.clone());\n                return name;\n            }\n        }\n    }\n\n    fn next_letter(&mut self) -> EcoString {\n        let alphabet_length = 26;\n        let char_offset = 97;\n        let mut chars = vec![];\n        let mut n;\n        let mut rest = self.uid;\n\n        loop {\n            n = rest % alphabet_length;\n            rest /= alphabet_length;\n            chars.push((n as u8 + char_offset) as char);\n\n            if rest == 0 {\n                break;\n            }\n            rest -= 1\n        }\n\n        self.uid += 1;\n        chars.into_iter().rev().collect()\n    }\n}\n\n#[test]\nfn test_local_type() {\n    let mut names = Names::new();\n    names.named_type_in_scope(\"mod\".into(), \"Tiger\".into(), \"Cat\".into());\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Tiger\".into(),\n        arguments: vec![],\n        module: \"mod\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"Cat\");\n}\n\n#[test]\nfn test_prelude_type() {\n    let mut names = Names::new();\n    names.named_type_in_scope(\"gleam\".into(), \"Int\".into(), \"Int\".into());\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Int\".into(),\n        arguments: vec![],\n        module: \"gleam\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"Int\");\n}\n\n#[test]\nfn test_shadowed_prelude_type() {\n    let mut names = Names::new();\n\n    names.named_type_in_scope(\"gleam\".into(), \"Int\".into(), \"Int\".into());\n    names.named_type_in_scope(\"mod\".into(), \"Int\".into(), \"Int\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Int\".into(),\n        arguments: vec![],\n        module: \"gleam\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"gleam.Int\");\n}\n\n#[test]\nfn test_generic_type_annotation() {\n    let mut names = Names::new();\n    names.type_variable_in_scope(0, \"one\".into());\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Var {\n        type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id: 0 })),\n    };\n\n    assert_eq!(printer.print_type(&type_), \"one\");\n}\n\n#[test]\nfn test_generic_type_var() {\n    let names = Names::new();\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Var {\n        type_: Arc::new(std::cell::RefCell::new(TypeVar::Unbound { id: 0 })),\n    };\n\n    let typ2 = Type::Var {\n        type_: Arc::new(std::cell::RefCell::new(TypeVar::Unbound { id: 1 })),\n    };\n\n    assert_eq!(printer.print_type(&type_), \"a\");\n    assert_eq!(printer.print_type(&typ2), \"b\");\n}\n\n#[test]\nfn test_tuple_type() {\n    let names = Names::new();\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Tuple {\n        elements: vec![\n            Arc::new(Type::Named {\n                name: \"Int\".into(),\n                arguments: vec![],\n                module: \"gleam\".into(),\n                publicity: crate::ast::Publicity::Public,\n                package: \"\".into(),\n                inferred_variant: None,\n            }),\n            Arc::new(Type::Named {\n                name: \"String\".into(),\n                arguments: vec![],\n                module: \"gleam\".into(),\n                publicity: crate::ast::Publicity::Public,\n                package: \"\".into(),\n                inferred_variant: None,\n            }),\n        ],\n    };\n\n    assert_eq!(printer.print_type(&type_), \"#(gleam.Int, gleam.String)\");\n}\n\n#[test]\nfn test_fn_type() {\n    let mut names = Names::new();\n    names.named_type_in_scope(\"gleam\".into(), \"Int\".into(), \"Int\".into());\n    names.named_type_in_scope(\"gleam\".into(), \"Bool\".into(), \"Bool\".into());\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Fn {\n        arguments: vec![\n            Arc::new(Type::Named {\n                name: \"Int\".into(),\n                arguments: vec![],\n                module: \"gleam\".into(),\n                publicity: crate::ast::Publicity::Public,\n                package: \"\".into(),\n                inferred_variant: None,\n            }),\n            Arc::new(Type::Named {\n                name: \"String\".into(),\n                arguments: vec![],\n                module: \"gleam\".into(),\n                publicity: crate::ast::Publicity::Public,\n                package: \"\".into(),\n                inferred_variant: None,\n            }),\n        ],\n        return_: Arc::new(Type::Named {\n            name: \"Bool\".into(),\n            arguments: vec![],\n            module: \"gleam\".into(),\n            publicity: crate::ast::Publicity::Public,\n            package: \"\".into(),\n            inferred_variant: None,\n        }),\n    };\n\n    assert_eq!(printer.print_type(&type_), \"fn(Int, gleam.String) -> Bool\");\n}\n\n#[test]\nfn test_module_alias() {\n    let mut names = Names::new();\n\n    assert!(\n        names\n            .imported_module(\"mod1\".into(), \"animals\".into(), SrcSpan::new(50, 63))\n            .is_none()\n    );\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Cat\".into(),\n        arguments: vec![],\n        module: \"mod1\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"animals.Cat\");\n}\n\n#[test]\nfn test_type_alias_and_generics() {\n    let mut names = Names::new();\n\n    names.named_type_in_scope(\"mod\".into(), \"Tiger\".into(), \"Cat\".into());\n\n    names.type_variable_in_scope(0, \"one\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Tiger\".into(),\n        arguments: vec![Arc::new(Type::Var {\n            type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id: 0 })),\n        })],\n        module: \"mod\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"Cat(one)\");\n}\n\n#[test]\nfn test_unqualified_import_and_generic() {\n    let mut names = Names::new();\n\n    names.named_type_in_scope(\"mod\".into(), \"Cat\".into(), \"C\".into());\n\n    names.type_variable_in_scope(0, \"one\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Cat\".into(),\n        arguments: vec![Arc::new(Type::Var {\n            type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id: 0 })),\n        })],\n        module: \"mod\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"C(one)\");\n}\n\n#[test]\nfn nested_module() {\n    let names = Names::new();\n    let mut printer = Printer::new(&names);\n    let type_ = Type::Named {\n        name: \"Cat\".into(),\n        arguments: vec![],\n        module: \"one/two/three\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"three.Cat\");\n}\n\n#[test]\nfn test_unqualified_import_and_module_alias() {\n    let mut names = Names::new();\n\n    assert!(\n        names\n            .imported_module(\"mod1\".into(), \"animals\".into(), SrcSpan::new(76, 93))\n            .is_none()\n    );\n\n    let _ = names\n        .local_types\n        .insert((\"mod1\".into(), \"Cat\".into()), \"C\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Cat\".into(),\n        arguments: vec![],\n        module: \"mod1\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"C\");\n}\n\n#[test]\nfn test_module_imports() {\n    let mut names = Names::new();\n\n    assert!(\n        names\n            .imported_module(\"mod\".into(), \"animals\".into(), SrcSpan::new(76, 93))\n            .is_none()\n    );\n\n    let _ = names\n        .local_types\n        .insert((\"mod2\".into(), \"Cat\".into()), \"Cat\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Cat\".into(),\n        arguments: vec![],\n        module: \"mod\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    let typ1 = Type::Named {\n        name: \"Cat\".into(),\n        arguments: vec![],\n        module: \"mod2\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    assert_eq!(printer.print_type(&type_), \"animals.Cat\");\n    assert_eq!(printer.print_type(&typ1), \"Cat\");\n}\n\n#[test]\nfn test_multiple_generic_annotations() {\n    let mut names = Names::new();\n\n    names.type_variable_in_scope(0, \"one\".into());\n    names.type_variable_in_scope(1, \"two\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = Type::Named {\n        name: \"Tiger\".into(),\n        arguments: vec![\n            Arc::new(Type::Var {\n                type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id: 0 })),\n            }),\n            Arc::new(Type::Var {\n                type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id: 1 })),\n            }),\n        ],\n        module: \"tigermodule\".into(),\n        publicity: crate::ast::Publicity::Public,\n        package: \"\".into(),\n        inferred_variant: None,\n    };\n\n    let typ1 = Type::Var {\n        type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id: 2 })),\n    };\n\n    assert_eq!(printer.print_type(&type_), \"tigermodule.Tiger(one, two)\");\n    assert_eq!(printer.print_type(&typ1), \"a\");\n}\n\n#[test]\nfn test_variable_name_already_in_scope() {\n    let mut names = Names::new();\n\n    names.type_variable_in_scope(1, \"a\".into());\n    names.type_variable_in_scope(2, \"b\".into());\n\n    let mut printer = Printer::new(&names);\n\n    let type_ = |id| Type::Var {\n        type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id })),\n    };\n\n    assert_eq!(printer.print_type(&type_(0)), \"c\");\n    assert_eq!(printer.print_type(&type_(1)), \"a\");\n    assert_eq!(printer.print_type(&type_(2)), \"b\");\n    assert_eq!(printer.print_type(&type_(3)), \"d\");\n}\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_all_fields.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Person { Person(name: String, age: Int, city: String) }\\n\\n        pub const base = Person(\\\"Alice\\\", 30, \\\"London\\\")\\n        pub const updated = Person(..base, name: \\\"Bob\\\", age: 25, city: \\\"Paris\\\")\"\n---\n----- SOURCE CODE\npub type Person { Person(name: String, age: Int, city: String) }\n\n        pub const base = Person(\"Alice\", 30, \"London\")\n        pub const updated = Person(..base, name: \"Bob\", age: 25, city: \"Paris\")\n\n----- WARNING\nwarning: Redundant record update\n  ┌─ /src/warning/wrn.gleam:4:29\n  │\n4 │         pub const updated = Person(..base, name: \"Bob\", age: 25, city: \"Paris\")\n  │                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This record update specifies all fields\n\nHint: It is better style to use the record creation syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_field_type_mismatch_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Person { Person(name: String, age: Int) }\\n\\n        pub const alice = Person(\\\"Alice\\\", 30)\\n        pub const bob = Person(..alice, age: \\\"not a number\\\")\"\n---\n----- SOURCE CODE\npub type Person { Person(name: String, age: Int) }\n\n        pub const alice = Person(\"Alice\", 30)\n        pub const bob = Person(..alice, age: \"not a number\")\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:46\n  │\n4 │         pub const bob = Person(..alice, age: \"not a number\")\n  │                                              ^^^^^^^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_fieldless_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Animal { Animal(species: String) }\\n\\n        pub const alice = Animal(\\\"Cat\\\")\\n        pub const dog = Animal(..alice)\"\n---\n----- SOURCE CODE\npub type Animal { Animal(species: String) }\n\n        pub const alice = Animal(\"Cat\")\n        pub const dog = Animal(..alice)\n\n----- WARNING\nwarning: Fieldless record update\n  ┌─ /src/warning/wrn.gleam:4:25\n  │\n4 │         pub const dog = Animal(..alice)\n  │                         ^^^^^^^^^^^^^^^ This record update doesn't change any fields\n\nHint: Add some fields to change or replace it with the record itself.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_non_record.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Person { Person(name: String, age: Int) }\\n\\n        pub const number = 42\\n        pub const bob = Person(..number, name: \\\"Bob\\\")\"\n---\n----- SOURCE CODE\npub type Person { Person(name: String, age: Int) }\n\n        pub const number = 42\n        pub const bob = Person(..number, name: \"Bob\")\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:34\n  │\n4 │         pub const bob = Person(..number, name: \"Bob\")\n  │                                  ^^^^^^\n\nExpected type:\n\n    Person\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_nonexistent_field.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Person { Person(name: String, age: Int) }\\n\\n        pub const alice = Person(\\\"Alice\\\", 30)\\n        pub const bob = Person(..alice, nonexistent: \\\"value\\\")\"\n---\n----- SOURCE CODE\npub type Person { Person(name: String, age: Int) }\n\n        pub const alice = Person(\"Alice\", 30)\n        pub const bob = Person(..alice, nonexistent: \"value\")\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:4:41\n  │\n4 │         pub const bob = Person(..alice, nonexistent: \"value\")\n  │                                         ^^^^^^^^^^^^^^^^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .age\n    .name\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_type_mismatch_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Person { Person(name: String, age: Int) }\\n        pub type Animal { Animal(species: String) }\\n\\n        pub const alice = Person(\\\"Alice\\\", 30)\\n        pub const dog = Animal(..alice)\"\n---\n----- SOURCE CODE\npub type Person { Person(name: String, age: Int) }\n        pub type Animal { Animal(species: String) }\n\n        pub const alice = Person(\"Alice\", 30)\n        pub const dog = Animal(..alice)\n\n----- ERROR\nerror: Incorrect record update\n  ┌─ /src/one/two.gleam:5:34\n  │\n5 │         pub const dog = Animal(..alice)\n  │                                  ^^^^^ This is a `Person`\n\nThis value is a `Person` so it cannot be used to build a `Animal`, even if\nthey share some fields.\n\nNote: If you want to change one variant of a type into another, you should\nspecify all fields explicitly instead of using the record update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_unlabelled_fields.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Point { Point(Int, Int) }\\n\\n        pub const origin = Point(0, 0)\\n        pub const point = Point(..origin)\"\n---\n----- SOURCE CODE\npub type Point { Point(Int, Int) }\n\n        pub const origin = Point(0, 0)\n        pub const point = Point(..origin)\n\n----- ERROR\nerror: Invalid record constructor\n  ┌─ /src/one/two.gleam:4:27\n  │\n4 │         pub const point = Point(..origin)\n  │                           ^^^^^ This is not a record constructor\n\nOnly record constructors can be used with the update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_variant_mismatch_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Subject {\\n            Person(name: String, age: Int)\\n            Animal(species: String)\\n        }\\n\\n        pub const alice = Person(\\\"Alice\\\", 30)\\n        pub const dog = Animal(..alice)\"\n---\n----- SOURCE CODE\npub type Subject {\n            Person(name: String, age: Int)\n            Animal(species: String)\n        }\n\n        pub const alice = Person(\"Alice\", 30)\n        pub const dog = Animal(..alice)\n\n----- ERROR\nerror: Incorrect record update\n  ┌─ /src/one/two.gleam:7:34\n  │\n7 │         pub const dog = Animal(..alice)\n  │                                  ^^^^^ This is a `Person`\n\nThis value is a `Person` so it cannot be used to build a `Animal`, even if\nthey share some fields.\n\nNote: If you want to change one variant of a type into another, you should\nspecify all fields explicitly instead of using the record update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__const_record_update_variant_without_args.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Status { Active Inactive }\\n        pub const status1 = Active\\n        pub const status2 = Active(..status1)\"\n---\n----- SOURCE CODE\npub type Status { Active Inactive }\n        pub const status1 = Active\n        pub const status2 = Active(..status1)\n\n----- ERROR\nerror: Invalid record constructor\n  ┌─ /src/one/two.gleam:3:29\n  │\n3 │         pub const status2 = Active(..status1)\n  │                             ^^^^^^ This is not a record constructor\n\nOnly record constructors can be used with the update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__correct_type_check_for_multiple_mutually_recursive_functions.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub fn wibble(id) {\\n  wobble(id, True)\\n}\\n\\npub fn wobble(id, bool) {\\n  case bool {\\n    True -> wibble(id)\\n    False -> wubble(id, bool)\\n  }\\n}\\n\\npub fn wubble(id, bool) {\\n  case bool {\\n    True -> final(id)\\n    False -> wobble(id, bool)\\n  }\\n}\\n\\npub fn final(id) {\\n  let #(a, b) = id\\n  echo #(a, b)\\n}\\n\\npub fn main() {\\n  wibble(#(\\\"a\\\", \\\"b\\\"))\\n  wibble(2)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn wibble(id) {\n  wobble(id, True)\n}\n\npub fn wobble(id, bool) {\n  case bool {\n    True -> wibble(id)\n    False -> wubble(id, bool)\n  }\n}\n\npub fn wubble(id, bool) {\n  case bool {\n    True -> final(id)\n    False -> wobble(id, bool)\n  }\n}\n\npub fn final(id) {\n  let #(a, b) = id\n  echo #(a, b)\n}\n\npub fn main() {\n  wibble(#(\"a\", \"b\"))\n  wibble(2)\n}\n\n\n----- ERROR\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:27:10\n   │\n27 │   wibble(2)\n   │          ^\n\nExpected type:\n\n    #(a, b)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__function_parameter_errors_do_not_stop_inference.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub fn wibble(x: NonExistent) {\\n  1 + False\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn wibble(x: NonExistent) {\n  1 + False\n}\n\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:2:18\n  │\n2 │ pub fn wibble(x: NonExistent) {\n  │                  ^^^^^^^^^^^\n\nThe type `NonExistent` is not defined or imported in this module.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   1 + False\n  │       ^^^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Bool\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__generic_unlabelled_field_in_updated_const_record_wrong_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"pub type Wibble(a) {\\n            Wibble(a, b: Int, c: a)\\n        }\\n\\n        const w = Wibble(1, 2, 3)\\n        const w2 = Wibble(..w, c: False)\"\n---\n----- SOURCE CODE\npub type Wibble(a) {\n            Wibble(a, b: Int, c: a)\n        }\n\n        const w = Wibble(1, 2, 3)\n        const w2 = Wibble(..w, c: False)\n\n----- ERROR\nerror: Incomplete record update\n  ┌─ /src/one/two.gleam:6:29\n  │\n6 │         const w2 = Wibble(..w, c: False)\n  │                             ^ This is a `Wibble(Int)`\n\nThe 1st field of this value is a `Int`, but the arguments given to the\nrecord update indicate that it should be a `Bool`.\n\nNote: Unlabelled fields cannot be updated in a record update, so either add\na label or use a record constructor.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__pipe_with_annonymous_unannotated_functions_wrong_arity1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n     |> fn (x) { #(x, x + 1) }\\n     |> fn (x, y) { x.0 }\\n     |> fn (x) { x }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x, y) { x.0 }\n     |> fn (x) { x }\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:5:9\n  │\n5 │      |> fn (x, y) { x.0 }\n  │         ^^^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:21\n  │\n5 │      |> fn (x, y) { x.0 }\n  │                     ^ What type is this?\n\nTo index into a tuple we need to know its size, but we don't know anything\nabout this type yet. Please add some type annotations so we can continue.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__pipe_with_annonymous_unannotated_functions_wrong_arity2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n     |> fn (x) { #(x, x + 1) }\\n     |> fn (x) { x.0 }\\n     |> fn (x, y) { x }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x) { x.0 }\n     |> fn (x, y) { x }\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:6:9\n  │\n6 │      |> fn (x, y) { x }\n  │         ^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__pipe_with_annonymous_unannotated_functions_wrong_arity3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n     |> fn (x) { #(x, x + 1) }\\n     |> fn (x) { x.0 }\\n     |> fn () { x }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x) { x.0 }\n     |> fn () { x }\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:6:9\n  │\n6 │      |> fn () { x }\n  │         ^^^^^^^^^^^ Expected no arguments, got 1\n\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:6:17\n  │\n6 │      |> fn () { x }\n  │                 ^\n\nThe name `x` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__prepend_constant_list_wrong_element_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\nconst list = [3, 4, 5]\\npub const full_list = [1.0, 2.0, ..list]\\n\"\n---\n----- SOURCE CODE\n\nconst list = [3, 4, 5]\npub const full_list = [1.0, 2.0, ..list]\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:36\n  │\n3 │ pub const full_list = [1.0, 2.0, ..list]\n  │                                    ^^^^\n\nExpected type:\n\n    List(Float)\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__prepend_constant_list_wrong_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\nconst pi = 3.14\\npub const full_list = [1.0, 2.0, ..pi]\\n\"\n---\n----- SOURCE CODE\n\nconst pi = 3.14\npub const full_list = [1.0, 2.0, ..pi]\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:36\n  │\n3 │ pub const full_list = [1.0, 2.0, ..pi]\n  │                                    ^^\n\nExpected type:\n\n    List(Float)\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__private_types_not_available_in_other_modules.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\nimport wibble\\n\\ntype Wibble {\\n  Wibble(wibble.Wibble)\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\ntype Wibble\n\n-- main.gleam\n\nimport wibble\n\ntype Wibble {\n  Wibble(wibble.Wibble)\n}\n\n\n----- ERROR\nerror: Unknown module type\n  ┌─ /src/one/two.gleam:5:10\n  │\n5 │   Wibble(wibble.Wibble)\n  │          ^^^^^^^^^^^^^\n\nThe module `wibble` does not have a `Wibble` type.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__record_update_variant_inference_fails_for_several_possible_variants.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Vector {\\n  Vector2(x: Float, y: Float)\\n  Vector3(x: Float, y: Float, z: Float)\\n}\\n\\npub fn increase_y(vector, by increase) {\\n  case vector {\\n    Vector2(y:, ..) as vector | Vector3(y:, ..) as vector ->\\n      Vector2(..vector, y: y +. increase)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Vector {\n  Vector2(x: Float, y: Float)\n  Vector3(x: Float, y: Float, z: Float)\n}\n\npub fn increase_y(vector, by increase) {\n  case vector {\n    Vector2(y:, ..) as vector | Vector3(y:, ..) as vector ->\n      Vector2(..vector, y: y +. increase)\n  }\n}\n\n\n----- ERROR\nerror: Unsafe record update\n   ┌─ /src/one/two.gleam:10:17\n   │\n10 │       Vector2(..vector, y: y +. increase)\n   │                 ^^^^^^ I'm not sure this is always a `Vector2`\n\nThis value cannot be used to build an updated `Vector2` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__record_update_variant_inference_fails_for_several_possible_variants_on_subject_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n  Wobble(a: Int, c: String)\\n}\\n\\npub fn update(wibble: Wibble) -> Wibble {\\n  case wibble {\\n    Wibble(..) | Wobble(..) -> Wibble(..wibble, a: 1)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn update(wibble: Wibble) -> Wibble {\n  case wibble {\n    Wibble(..) | Wobble(..) -> Wibble(..wibble, a: 1)\n  }\n}\n\n\n----- ERROR\nerror: Unsafe record update\n  ┌─ /src/one/two.gleam:9:41\n  │\n9 │     Wibble(..) | Wobble(..) -> Wibble(..wibble, a: 1)\n  │                                         ^^^^^^ I'm not sure this is always a `Wibble`\n\nThis value cannot be used to build an updated `Wibble` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__string_concat_ko_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \" \\\"1\\\" <> 2 \"\n---\n----- SOURCE CODE\n \"1\" <> 2 \n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:9\n  │\n1 │  \"1\" <> 2 \n  │         ^\n\nThe <> operator expects arguments of this type:\n\n    String\n\nBut this argument has this type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__string_concat_ko_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \" 1 <> \\\"2\\\" \"\n---\n----- SOURCE CODE\n 1 <> \"2\" \n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:2\n  │\n1 │  1 <> \"2\" \n  │  ^\n\nThe <> operator expects arguments of this type:\n\n    String\n\nBut this argument has this type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__type_unification_does_not_allow_different_variants_to_be_treated_as_safe.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n  Wobble(a: Int, c: String)\\n}\\n\\npub fn main() {\\n  let a = case todo {\\n    Wibble(..) as b -> Wibble(..b, b: 1)\\n    Wobble(..) as b -> Wobble(..b, c: \\\"a\\\")\\n  }\\n\\n  a.b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn main() {\n  let a = case todo {\n    Wibble(..) as b -> Wibble(..b, b: 1)\n    Wobble(..) as b -> Wobble(..b, c: \"a\")\n  }\n\n  a.b\n}\n\n\n----- ERROR\nerror: Unknown record field\n   ┌─ /src/one/two.gleam:13:5\n   │\n13 │   a.b\n   │     ^ Did you mean `a`?\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt has these accessible fields:\n\n    .a\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__type_unification_does_not_allow_lowercase_bools_in_match_clause.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub fn main() {\\n  case 42 > 42 {\\n    true -> 1\\n    false -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case 42 > 42 {\n    true -> 1\n    false -> 2\n  }\n}\n\n\n----- ERROR\nerror: Lowercase bool pattern\n  ┌─ /src/one/two.gleam:4:5\n  │\n4 │     true -> 1\n  │     ^^^^ This is not a bool\n\nSee: https://tour.gleam.run/basics/bools/\nHint: In Gleam bool literals are `True` and `False`.\n\nerror: Lowercase bool pattern\n  ┌─ /src/one/two.gleam:5:5\n  │\n5 │     false -> 2\n  │     ^^^^^ This is not a bool\n\nSee: https://tour.gleam.run/basics/bools/\nHint: In Gleam bool literals are `True` and `False`.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__type_unification_does_not_cause_false_positives_for_variant_matching.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n  Wobble(a: Int, c: String)\\n}\\n\\npub fn wibbler() { todo }\\n\\npub fn main() {\\n  let c = wibbler()\\n\\n  case todo {\\n    Wibble(..) -> Wibble(..c, b: 1)\\n    _ -> todo\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn wibbler() { todo }\n\npub fn main() {\n  let c = wibbler()\n\n  case todo {\n    Wibble(..) -> Wibble(..c, b: 1)\n    _ -> todo\n  }\n}\n\n\n----- ERROR\nerror: Unsafe record update\n   ┌─ /src/one/two.gleam:13:28\n   │\n13 │     Wibble(..) -> Wibble(..c, b: 1)\n   │                            ^ I'm not sure this is always a `Wibble`\n\nThis value cannot be used to build an updated `Wibble` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__type_unification_removes_inferred_variant_in_functions.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Either(a, b) {\\n  Left(value: a)\\n  Right(value: b)\\n}\\n\\nfn a_or_b(_first: value, second: value) -> value {\\n  second\\n}\\n\\npub fn main() {\\n  let func = a_or_b(fn() { Left(1) }, fn() { Right(\\\"hello\\\") })\\n  Left(..func(), value: 10)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Either(a, b) {\n  Left(value: a)\n  Right(value: b)\n}\n\nfn a_or_b(_first: value, second: value) -> value {\n  second\n}\n\npub fn main() {\n  let func = a_or_b(fn() { Left(1) }, fn() { Right(\"hello\") })\n  Left(..func(), value: 10)\n}\n\n\n----- ERROR\nerror: Unsafe record update\n   ┌─ /src/one/two.gleam:13:10\n   │\n13 │   Left(..func(), value: 10)\n   │          ^^^^^^ I'm not sure this is always a `Left`\n\nThis value cannot be used to build an updated `Left` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__type_unification_removes_inferred_variant_in_nested_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Box(a) {\\n  Box(inner: a)\\n}\\n\\npub type Either(a, b) {\\n  Left(value: a)\\n  Right(value: b)\\n}\\n\\nfn a_or_b(_first: value, second: value) -> value {\\n  second\\n}\\n\\npub fn main() {\\n  let Box(inner) = a_or_b(Box(Left(1)), Box(Right(\\\"hello\\\")))\\n  Left(..inner, value: 10)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Box(a) {\n  Box(inner: a)\n}\n\npub type Either(a, b) {\n  Left(value: a)\n  Right(value: b)\n}\n\nfn a_or_b(_first: value, second: value) -> value {\n  second\n}\n\npub fn main() {\n  let Box(inner) = a_or_b(Box(Left(1)), Box(Right(\"hello\")))\n  Left(..inner, value: 10)\n}\n\n\n----- ERROR\nerror: Unsafe record update\n   ┌─ /src/one/two.gleam:17:10\n   │\n17 │   Left(..inner, value: 10)\n   │          ^^^^^ I'm not sure this is always a `Left`\n\nThis value cannot be used to build an updated `Left` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__type_unification_removes_inferred_variant_in_tuples.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Either(a, b) {\\n  Left(value: a)\\n  Right(value: b)\\n}\\n\\nfn a_or_b(_first: value, second: value) -> value {\\n  second\\n}\\n\\npub fn main() {\\n  let #(right) = a_or_b(#(Left(5)), #(Right(\\\"hello\\\")))\\n  Left(..right, value: 10)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Either(a, b) {\n  Left(value: a)\n  Right(value: b)\n}\n\nfn a_or_b(_first: value, second: value) -> value {\n  second\n}\n\npub fn main() {\n  let #(right) = a_or_b(#(Left(5)), #(Right(\"hello\")))\n  Left(..right, value: 10)\n}\n\n\n----- ERROR\nerror: Unsafe record update\n   ┌─ /src/one/two.gleam:13:10\n   │\n13 │   Left(..right, value: 10)\n   │          ^^^^^ I'm not sure this is always a `Left`\n\nThis value cannot be used to build an updated `Left` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__unlabelled_argument_not_allowed_after_labelled_argument.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Bad {\\n  Bad(labelled: Int, Float)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Bad {\n  Bad(labelled: Int, Float)\n}\n\n\n----- ERROR\nerror: Unlabelled argument after labelled argument\n  ┌─ /src/one/two.gleam:3:22\n  │\n3 │   Bad(labelled: Int, Float)\n  │                      ^^^^^\n\nAll unlabelled arguments must come before any labelled arguments.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__variant_inference_does_not_escape_clause_scope.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Thingy {\\n  A(a: Int)\\n  B(x: Int, b: Int)\\n}\\n\\npub fn fun(x) {\\n  case x {\\n    A(..) -> x.a\\n    B(..) -> x.b\\n  }\\n  x.b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thingy {\n  A(a: Int)\n  B(x: Int, b: Int)\n}\n\npub fn fun(x) {\n  case x {\n    A(..) -> x.a\n    B(..) -> x.b\n  }\n  x.b\n}\n\n\n----- ERROR\nerror: Unknown record field\n   ┌─ /src/one/two.gleam:12:5\n   │\n12 │   x.b\n   │     ^ This field does not exist\n\nThe value being accessed has this type:\n\n    Thingy\n\nIt does not have fields that are common across all variants.\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/snapshots/gleam_core__type___tests__variant_inference_on_literal_record.snap",
    "content": "---\nsource: compiler-core/src/type_/tests.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\npub fn main() {\\n  case Wibble, Wobble {\\n    Wibble, Wibble -> todo\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  case Wibble, Wobble {\n    Wibble, Wibble -> todo\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n   ┌─ /src/one/two.gleam:8:3\n   │  \n 8 │ ╭   case Wibble, Wobble {\n 9 │ │     Wibble, Wibble -> todo\n10 │ │   }\n   │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Wibble, Wobble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/accessors.rs",
    "content": "use crate::assert_module_infer;\n\n#[test]\nfn bug_3629() {\n    assert_module_infer!(\n        (\"imported\", \"pub type Wibble\"),\n        r#\"\nimport imported\n\npub type Exp {\n  One(field: imported.Wibble)\n  Two(field: imported.Wibble)\n}\n\npub fn main() {\n  let exp = One(todo)\n  exp.field\n}\n        \"#,\n        vec![\n            (\"One\", \"fn(Wibble) -> Exp\"),\n            (\"Two\", \"fn(Wibble) -> Exp\"),\n            (\"main\", \"fn() -> Wibble\")\n        ],\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/assert.rs",
    "content": "use crate::{assert_error, assert_infer, assert_module_infer, assert_warning};\n\n#[test]\nfn bool_value() {\n    assert_infer!(\n        \"\nlet value = True\nassert value\n\",\n        \"Nil\"\n    );\n}\n\n#[test]\nfn equality_check() {\n    assert_infer!(\n        \"\nlet value = 10\nassert value == 10\n\",\n        \"Nil\"\n    );\n}\n\n#[test]\nfn comparison() {\n    assert_infer!(\n        \"\nlet value = 4\nassert value < 5\n\",\n        \"Nil\"\n    );\n}\n\n#[test]\nfn function_call() {\n    assert_module_infer!(\n        \"\nfn bool() {\n  True\n}\n\npub fn main() {\n  assert bool()\n}\n\",\n        vec![(\"main\", \"fn() -> Nil\")]\n    );\n}\n\n#[test]\nfn bool_literal() {\n    assert_warning!(\n        \"\npub fn main() {\n  assert True\n}\n\"\n    );\n}\n\n#[test]\nfn negation_of_bool_literal() {\n    assert_warning!(\n        \"\npub fn main() {\n  assert !False\n}\n\"\n    );\n}\n\n#[test]\nfn equality_check_on_literals() {\n    assert_warning!(\n        \"\npub fn main() {\n  assert 1 == 2\n}\n\"\n    );\n}\n\n#[test]\nfn comparison_on_literals() {\n    assert_warning!(\n        \"\npub fn main() {\n  assert 1 < 2\n}\n\"\n    );\n}\n\n#[test]\nfn with_message() {\n    assert_infer!(r#\"assert True as \"This should never panic\"\"#, \"Nil\");\n}\n\n#[test]\nfn compound_message() {\n    assert_infer!(\n        r#\"assert 1 == 2 as { \"one\" <> \" is never equal to \" <> \"two\" }\"#,\n        \"Nil\"\n    );\n}\n\n#[test]\nfn mismatched_types() {\n    assert_error!(\"assert 10\");\n}\n\n#[test]\nfn wrong_message_type() {\n    assert_error!(\"assert True as 10\");\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/assignments.rs",
    "content": "use crate::assert_infer;\n\n#[test]\nfn let_() {\n    assert_infer!(\"let x = 1 2\", \"Int\");\n}\n\n#[test]\nfn let_1() {\n    assert_infer!(\"let x = 1 x\", \"Int\");\n}\n\n#[test]\nfn let_2() {\n    assert_infer!(\"let x = 2.0 x\", \"Float\");\n}\n\n#[test]\nfn let_3() {\n    assert_infer!(\"let x = 2 let y = x y\", \"Int\");\n}\n\n#[test]\nfn let_4() {\n    assert_infer!(\n        \"let #(#(_, _) as x, _) = #(#(0, 1.0), []) x\",\n        \"#(Int, Float)\"\n    );\n}\n\n#[test]\nfn let_5() {\n    assert_infer!(\"let x: String = \\\"\\\" x\", \"String\");\n}\n\n#[test]\nfn let_6() {\n    assert_infer!(\"let x: #(Int, Int) = #(5, 5) x\", \"#(Int, Int)\",);\n}\n\n#[test]\nfn let_7() {\n    assert_infer!(\"let x: #(Int, Float) = #(5, 5.0) x\", \"#(Int, Float)\",);\n}\n\n#[test]\nfn let_8() {\n    assert_infer!(\"let assert [1, 2, ..x]: List(Int) = [1,2,3] x\", \"List(Int)\",);\n}\n\n#[test]\nfn let_9() {\n    assert_infer!(\n        \"let assert #(5, [..x]): #(Int, List(Int)) = #(5, [1,2,3]) x\",\n        \"List(Int)\",\n    );\n}\n\n#[test]\nfn let_10() {\n    assert_infer!(\n        \"let assert #(5.0, [..x]): #(Float, List(Int)) = #(5.0, [1,2,3]) x\",\n        \"List(Int)\",\n    );\n}\n\n#[test]\nfn let_11() {\n    assert_infer!(\"let x: List(_) = [] x\", \"List(a)\");\n}\n\n#[test]\nfn let_12() {\n    assert_infer!(\"let x: List(_) = [1] x\", \"List(Int)\");\n}\n\n#[test]\nfn let_13() {\n    assert_infer!(\"let assert [a] = [1] a\", \"Int\");\n}\n\n#[test]\nfn let_14() {\n    assert_infer!(\"let assert [a, 2] = [1] a\", \"Int\");\n}\n\n#[test]\nfn let_15() {\n    assert_infer!(\"let assert [a, .. b] = [1] a\", \"Int\");\n}\n\n#[test]\nfn let_16() {\n    assert_infer!(\"let assert [a, .. _] = [1] a\", \"Int\");\n}\n\n#[test]\nfn let_17() {\n    assert_infer!(\"fn(x) { let assert [a] = x a }\", \"fn(List(a)) -> a\");\n}\n\n#[test]\nfn let_18() {\n    assert_infer!(\"fn(x) { let assert [a] = x a + 1 }\", \"fn(List(Int)) -> Int\");\n}\n\n#[test]\nfn let_19() {\n    assert_infer!(\"let _x = 1 2.0\", \"Float\");\n}\n\n#[test]\nfn let_20() {\n    assert_infer!(\"let _ = 1 2.0\", \"Float\");\n}\n\n#[test]\nfn let_21() {\n    assert_infer!(\"let #(tag, x) = #(1.0, 1) x\", \"Int\");\n}\n\n#[test]\nfn let_22() {\n    assert_infer!(\"fn(x) { let #(a, b) = x a }\", \"fn(#(a, b)) -> a\");\n}\n\n#[test]\nfn let_23() {\n    assert_infer!(\"let assert [] = [] 1\", \"Int\");\n}\n\n#[test]\nfn let_24() {\n    assert_infer!(\"let assert Ok(..) = Ok(10)\", \"Result(Int, a)\");\n}\n\n#[test]\nfn let_25() {\n    assert_infer!(\"let assert \\\"hello\\\" as a <> _ = \\\"\\\" a\", \"String\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/1991\n#[test]\nfn no_scoped_var_collision() {\n    assert_infer!(\"let x = 1 { let x = 1.0 } x\", \"Int\");\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/conditional_compilation.rs",
    "content": "use crate::assert_module_infer;\n\n#[test]\nfn excluded_error() {\n    assert_module_infer!(\n        \"@target(javascript)\npub type X = Y\n\npub const x = 1\n\",\n        vec![(\"x\", \"Int\")],\n    );\n}\n\n#[test]\nfn alias() {\n    assert_module_infer!(\n        \"@target(erlang)\npub type X = Int\n\npub const x: X = 1\n\",\n        vec![(\"x\", \"Int\")],\n    );\n}\n\n#[test]\nfn alias_in_block() {\n    assert_module_infer!(\n        \"@target(erlang)\npub type X = Int \n\n@target(erlang)\npub const x: X = 1\n\",\n        vec![(\"x\", \"Int\")],\n    );\n}\n\n#[test]\nfn generalising() {\n    assert_module_infer!(\n        \"\n@target(erlang)\npub fn id(x) { x }\n\n@target(erlang)\npub fn x() { id(1) }\n\",\n        vec![(\"id\", \"fn(a) -> a\"), (\"x\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn excluded_generalising() {\n    assert_module_infer!(\n        \"\n@target(javascript)\npub fn id(x) { x }\n\n@target(javascript)\npub fn x() { id(1) }\n\npub const y = 1\n\",\n        vec![(\"y\", \"Int\")],\n    );\n}\n\n#[test]\nfn included_const_ref_earlier() {\n    assert_module_infer!(\n        \"\n@target(erlang)\nconst x = 1\n\npub fn main() { x }\n\",\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn included_const_ref_later() {\n    assert_module_infer!(\n        \"pub fn main() { x }\n\n@target(erlang)\nconst x = 1\n\",\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn target_does_not_need_to_be_the_first_attribute() {\n    // In previous versions of Gleam the `@target` attribute had to be the\n    // first attribute.\n    assert_module_infer!(\n        r#\"\n@external(erlang, \"blah\", \"wub\")\n@target(erlang)\npub fn main() -> Int\n\"#,\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/custom_types.rs",
    "content": "use crate::{assert_module_error, assert_module_infer, assert_warning};\n\n// https://github.com/gleam-lang/gleam/issues/2215\n#[test]\nfn generic_phantom() {\n    assert_module_infer!(\n        r#\"\npub type Test(a) {\n  MakeTest(field: Test(Int))\n}\n\"#,\n        vec![(\"MakeTest\", \"fn(Test(Int)) -> Test(a)\")]\n    );\n}\n\n#[test]\nfn deprecated_type() {\n    assert_warning!(\n        r#\"\n@deprecated(\"Dont use this!\")\npub type Cat {\n  Cat(name: String, cuteness: Int)\n}\n\npub fn name() -> String {\n  let c = Cat(\"Numi\", 20)\n  c.name\n}\n        \"#\n    );\n}\n\n#[test]\nfn deprecated_all_varients_type() {\n    assert_module_error!(\n        r#\"\npub type Numbers {\n  @deprecated(\"1\")\n  One\n  @deprecated(\"2\")\n  Two\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_varients_type() {\n    assert_warning!(\n        r#\"\npub type Numbers {\n  @deprecated(\"1\")\n  One\n  Two\n}\n\npub fn num() {\n  let _one = One\n  let _two = Two\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn depreacted_type_deprecate_varient_err() {\n    assert_module_error!(\n        r#\"\n@deprecated(\"2\")\npub type Numbers {\n  @deprecated(\"1\")\n  One\n  Two\n}\n\npub fn num() {\n  let _two = Two\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn fault_tolerance() {\n    // An error in a custom type does not stop analysis\n    assert_module_error!(\n        r#\"\npub type Cat {\n  Cat(UnknownType)\n}\n\npub type Kitten = AnotherUnknownType\n        \"#\n    );\n}\n\n#[test]\nfn duplicate_variable_error_does_not_stop_analysis() {\n    // Both these aliases have errors! We do not stop on the first one.\n    assert_module_error!(\n        r#\"\ntype Two(a, a) {\n  Two(a, a)\n}\n\ntype Three(a, a) {\n  Three\n}\n\"#\n    );\n}\n\n#[test]\nfn conflict_with_import() {\n    // We cannot declare a type with the same name as an imported type\n    assert_module_error!(\n        (\"wibble\", \"pub type A { B }\"),\n        \"import wibble.{type A} type A { C }\",\n    );\n}\n\n#[test]\nfn generic_record_update1() {\n    // A record update on polymorphic types with a field of different type\n    assert_module_infer!(\n        \"\npub type Box(a) {\n  Box(value: a, i: Int)\n}\n\npub fn update_box(box: Box(Int), value: String) {\n  Box(..box, value: value)\n}\",\n        vec![\n            (\"Box\", \"fn(a, Int) -> Box(a)\"),\n            (\"update_box\", \"fn(Box(Int), String) -> Box(String)\")\n        ]\n    );\n}\n\n#[test]\nfn generic_record_update2() {\n    // A record update on polymorphic types with generic fields of a different type\n    assert_module_infer!(\n        \"\npub type Box(a) {\n  Box(value: a, i: Int)\n}\npub fn update_box(box: Box(a), value: b) {\n  Box(..box, value: value)\n}\",\n        vec![\n            (\"Box\", \"fn(a, Int) -> Box(a)\"),\n            (\"update_box\", \"fn(Box(a), b) -> Box(b)\")\n        ]\n    );\n}\n\n#[test]\nfn inferred_variant_record_update_change_type_parameter() {\n    assert_module_infer!(\n        r#\"\npub type Box(a) {\n  Locked(password: String, value: a)\n  Unlocked(password: String, value: a)\n}\n\npub fn main() {\n  let box = Locked(\"ungu€$$4bLe\", 11)\n  case box {\n    Locked(..) as box -> Locked(..box, value: True)\n    Unlocked(..) as box -> Unlocked(..box, value: False)\n  }\n}\n\"#,\n        vec![\n            (\"Locked\", \"fn(String, a) -> Box(a)\"),\n            (\"Unlocked\", \"fn(String, a) -> Box(a)\"),\n            (\"main\", \"fn() -> Box(Bool)\")\n        ]\n    );\n}\n\n#[test]\nfn pattern_match_correct_labeled_field() {\n    assert_module_error!(\n        r#\"\ntype Fish {\n  Starfish()\n  Jellyfish(name: String, jiggly: Bool)\n}\n\nfn handle_fish(fish: Fish) {\n  case fish {\n    Starfish() -> False\n    Jellyfish(jiggly:) -> jiggly  // <- error is here\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_match_correct_pos_field() {\n    assert_module_error!(\n        r#\"\ntype Fish {\n  Starfish()\n  Jellyfish(String, Bool)\n}\n\nfn handle_fish(fish: Fish) {\n  case fish {\n    Starfish() -> False\n    Jellyfish(jiggly) -> jiggly\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/dead_code_detection.rs",
    "content": "use crate::{assert_no_warnings, assert_warning};\n\n#[test]\nfn unused_recursive_function() {\n    assert_warning!(\n        \"\nfn unused(value: Int) -> Int {\n  case value {\n    0 -> 0\n    _ -> unused(value - 1)\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unused_mutually_recursive_functions() {\n    assert_warning!(\n        \"\nfn wibble(value: Int) -> Int {\n  wobble(value)\n}\n\nfn wobble(value: Int) -> Int {\n  wibble(value)\n}\n\"\n    );\n}\n\n#[test]\nfn constant_only_referenced_by_unused_function() {\n    assert_warning!(\n        \"\nconst value = 10\n\nfn unused() {\n  value\n}\n\"\n    );\n}\n\n#[test]\nfn constant_only_referenced_by_unused_constant() {\n    assert_warning!(\n        \"\nconst value = 10\n\nconst value_twice = #(value, value)\n\"\n    );\n}\n\n#[test]\nfn constant_referenced_by_public_constant() {\n    assert_no_warnings!(\n        \"\nconst value = 10\n\npub const value_twice = #(value, value)\n\"\n    );\n}\n\n#[test]\nfn type_variant_only_referenced_by_unused_function() {\n    assert_warning!(\n        \"\ntype Wibble {\n  Wibble\n  Wobble\n}\n\nfn unused() {\n  Wibble\n}\n\npub fn used() {\n  let _ = Wobble\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn type_marked_as_used_if_variant_used() {\n    assert_no_warnings!(\n        \"\ntype PrivateType {\n  PrivateConstructor\n}\n\npub fn public_function() {\n  let _constructor = PrivateConstructor\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn type_and_variant_unused() {\n    assert_warning!(\n        \"\ntype PrivateType {\n  PrivateConstructor\n}\n\"\n    );\n}\n\n#[test]\nfn type_used_by_public_alias() {\n    assert_no_warnings!(\n        \"\ntype PrivateType\n\npub type PublicAlias = PrivateType\n\"\n    );\n}\n\n#[test]\nfn imported_module_only_referenced_by_unused_function() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble\n\nfn unused() {\n  wibble.Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_module_alias_only_referenced_by_unused_function() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble as wobble\n\nfn unused() {\n  wobble.Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_module_alias_only_referenced_by_unused_function_with_unqualified() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble.{type Wibble} as wobble\n\nfn unused() {\n  wobble.Wibble\n}\n\npub fn main() -> Wibble {\n  panic\n}\n\"\n    );\n}\n\n#[test]\nfn imported_module_used_by_public_function() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble\n\npub fn main() {\n  wibble.Wibble(4)\n}\n\"\n    );\n}\n\n#[test]\nfn imported_module_used_in_type() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble\n\npub fn main() -> wibble.Wibble {\n  panic\n}\n\"\n    );\n}\n\n#[test]\nfn imported_module_used_by_public_constant() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble\n\npub const value = wibble.Wibble(42)\n\"\n    );\n}\n\n#[test]\nfn imported_module_used_in_type_variant() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble\n\npub type Wobble {\n  Wobble(w: wibble.Wibble)\n}\n\"\n    );\n}\n\n#[test]\nfn imported_module_used_in_type_alias() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble\n\npub type Wobble = wibble.Wibble\n\"\n    );\n}\n\n#[test]\nfn imported_value_only_referenced_by_unused_function() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(Int)\n}\n\"\n        ),\n        \"\nimport wibble.{Wibble}\n\nfn unused() {\n  Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_type_only_referenced_by_unused_function() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble\n\"\n        ),\n        \"\nimport wibble.{type Wibble}\n\nfn unused() -> Wibble {\n  panic\n}\n\"\n    );\n}\n\n#[test]\nfn imported_value_used_by_public_function() {\n    assert_no_warnings!(\n        (\"thepackage\", \"wibble\", \"pub type Wibble { Wibble }\"),\n        \"\nimport wibble.{Wibble}\n\npub fn main() {\n  Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_type_used_by_public_function() {\n    assert_no_warnings!(\n        (\"thepackage\", \"wibble\", \"pub type Wibble { Wibble }\"),\n        \"\nimport wibble.{type Wibble}\n\npub fn main() -> Wibble {\n  wibble.Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_type_used_by_public_function_parameter() {\n    assert_no_warnings!(\n        (\"thepackage\", \"wibble\", \"pub type Wibble { Wibble }\"),\n        \"\nimport wibble.{type Wibble}\n\npub fn main(a: Wibble) {\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn unused_type_alias() {\n    assert_warning!(\n        \"\ntype Wibble = Int\n\"\n    );\n}\n\n#[test]\nfn private_type_alias_only_referenced_by_unused_function() {\n    assert_warning!(\n        \"\ntype Wibble = Int\n\nfn unused() -> Wibble {\n  10\n}\n\"\n    );\n}\n\n#[test]\nfn private_type_alias_underlying_type_referenced_by_public_function() {\n    assert_warning!(\n        \"\ntype Wibble = Int\n\npub fn used() -> Int {\n  10\n}\n\"\n    );\n}\n\n#[test]\nfn private_type_alias_referenced_by_public_function() {\n    assert_no_warnings!(\n        \"\ntype Wibble = Int\n\npub fn used() -> Wibble {\n  10\n}\n\"\n    );\n}\n\n#[test]\nfn shadowed_imported_value_marked_unused() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub const wibble = 1\n\"\n        ),\n        \"\nimport wibble.{wibble}\n\npub const wibble = 2\n\"\n    );\n}\n\n#[test]\nfn used_shadowed_imported_value() {\n    assert_warning!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub const wibble = 1\n\"\n        ),\n        \"\nimport wibble.{wibble}\n\npub const wibble = wibble\n\"\n    );\n}\n\n#[test]\nfn imported_module_marked_unused_when_shadowed_in_record_access() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub const wibble = 1\n\"\n        ),\n        \"\nimport wibble\n\ntype Wibble {\n  Wibble(wobble: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(10)\n  // This does not reference the `wibble` module!\n  wibble.wobble\n}\n\"\n    );\n}\n\n#[test]\nfn local_variable_marked_unused_when_shadowed_in_module_access() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub const wibble = 1\n\"\n        ),\n        \"\nimport wibble\n\npub fn main() {\n  let wibble = 10\n  // This does not reference the `wibble` variable!\n  wibble.wibble\n}\n\"\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3552\nfn constructor_used_if_type_alias_shadows_it() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(String)\n}\n\"\n        ),\n        r#\"\nimport wibble.{Wibble}\n\ntype Wibble =\n  wibble.Wibble\n\npub fn main() {\n  Wibble(\"hello\")\n}\n\"#\n    );\n}\n\n#[test]\nfn imported_type_and_constructor_with_same_name() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble\n}\n\"\n        ),\n        \"\nimport wibble.{type Wibble, Wibble}\n\npub fn main() {\n  Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_type_and_constructor_with_same_name2() {\n    assert_warning!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble\n}\n\"\n        ),\n        \"\nimport wibble.{type Wibble, Wibble}\n\npub fn main() -> Wibble {\n  wibble.Wibble\n}\n\"\n    );\n}\n\n#[test]\nfn imported_type_and_constructor_with_same_name3() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble\n}\n\"\n        ),\n        \"\nimport wibble.{type Wibble, Wibble}\n\npub fn main() -> Wibble {\n  Wibble\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/echo.rs",
    "content": "use crate::assert_module_infer;\n\n#[test]\npub fn echo_has_same_type_as_printed_expression() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  echo 1\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\npub fn echo_has_same_type_as_printed_expression_2() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  let wibble = todo\n  echo wibble\n}\n\"#,\n        vec![(\"main\", \"fn() -> a\")]\n    );\n}\n\n#[test]\npub fn echo_in_pipeline_acts_as_the_identity_function() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo\n}\n\"#,\n        vec![(\"main\", \"fn() -> List(Int)\")]\n    );\n}\n\n#[test]\npub fn echo_in_pipeline_acts_as_the_identity_function_2() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  1\n  |> echo\n  |> fn(_: Int) { True }\n}\n\"#,\n        vec![(\"main\", \"fn() -> Bool\")]\n    );\n}\n\n#[test]\npub fn echo_in_pipeline_acts_as_the_identity_function_3() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> echo\n  |> wibble\n}\n\nfn wibble(_: List(Int)) -> List(String) { todo }\n\"#,\n        vec![(\"main\", \"fn() -> List(String)\")]\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/errors.rs",
    "content": "use crate::{\n    assert_error, assert_internal_module_error, assert_js_module_error, assert_module_error,\n    assert_module_syntax_error,\n};\n\n#[test]\nfn bit_array_invalid_type() {\n    assert_module_error!(\n        \"fn x() { \\\"test\\\" }\n\nfn main() {\n    let a = <<1:size(x())>>\n    a\n}\"\n    );\n}\n\n#[test]\nfn bit_arrays2() {\n    assert_error!(\"let <<x:utf8>> = <<1>>\");\n}\n\n#[test]\nfn bit_arrays3() {\n    assert_error!(\"let <<x:utf16>> = <<1>>\");\n}\n\n#[test]\nfn bit_arrays4() {\n    assert_error!(\"let <<x:utf32>> = <<1>>\");\n}\n\n#[test]\nfn bit_array_float() {\n    assert_error!(\"case <<1>> { <<a:float>> if a > 1 -> 1 _ -> 2 }\");\n}\n\n#[test]\nfn bit_array_binary() {\n    assert_error!(\"case <<1>> { <<a:bytes>> if a > 1 -> 1 _ -> 2 }\");\n}\n\n#[test]\nfn bit_array_guard() {\n    assert_error!(\"case <<1>> { <<a:utf16_codepoint>> if a == \\\"test\\\" -> 1 _ -> 2 }\");\n}\n\n#[test]\nfn bit_array_segment_nosize() {\n    assert_error!(\"case <<1>> { <<_:bytes, _:bytes>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_nosize2() {\n    assert_error!(\"case <<1>> { <<_:bits, _:bytes>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_nosize3() {\n    assert_error!(\"case <<1>> { <<_:bytes, _:bits>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_conflicting_options_int() {\n    assert_error!(\"let x = <<1:int-bytes>> x\");\n}\n\n#[test]\nfn bit_array_segment_conflicting_options_bit_array() {\n    assert_error!(\"case <<1>> { <<1:bits-bytes>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_conflicting_signedness1() {\n    assert_error!(\"let x = <<1:signed-unsigned>> x\");\n}\n\n#[test]\nfn bit_array_segment_conflicting_signedness2() {\n    assert_error!(\"case <<1>> { <<1:unsigned-signed>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_conflicting_endianness1() {\n    assert_error!(\"let x = <<1:big-little>> x\");\n}\n\n#[test]\nfn bit_array_segment_conflicting_endianness2() {\n    assert_error!(\"case <<1>> { <<1:native-big>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_size() {\n    assert_error!(\"let x = <<1:8-size(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_size2() {\n    assert_error!(\"case <<1>> { <<1:size(2)-size(8)>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_unit_unit() {\n    assert_error!(\"let x = <<1:unit(2)-unit(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_codepoint_utf8() {\n    assert_error!(\"let x = <<1:utf8_codepoint-unit(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_codepoint_utf16() {\n    assert_error!(\"let x = <<1:utf16_codepoint-unit(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_codepoint_utf32() {\n    assert_error!(\"case <<1>> { <<1:utf32_codepoint-unit(2)>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_codepoint_utf8_2() {\n    assert_error!(\"let x = <<1:utf8_codepoint-size(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_codepoint_utf16_2() {\n    assert_error!(\"let x = <<1:utf16_codepoint-size(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_codepoint_utf32_2() {\n    assert_error!(\"case <<1>> { <<1:utf32_codepoint-size(5)>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_utf8_2() {\n    assert_error!(\"let x = <<1:utf8-unit(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_utf16() {\n    assert_error!(\"let x = <<1:utf16-unit(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_unit_utf32() {\n    assert_error!(\"case <<1>> { <<1:utf32-unit(2)>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_size_utf8() {\n    assert_error!(\"let x = <<1:utf8-size(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_size_utf16() {\n    assert_error!(\"let x = <<1:utf16-size(5)>> x\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_size_utf32() {\n    assert_error!(\"case <<1>> { <<1:utf32-size(5)>> -> 1 }\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_variable_string() {\n    assert_error!(\"case <<>> { <<a:utf8>> -> 1 _ -> 2 }\");\n}\n\n#[test]\nfn bit_array_segment_type_does_not_allow_aliased_variable_string() {\n    assert_error!(\"case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }\");\n}\n\n#[test]\nfn bit_array_segment_unit_no_size() {\n    assert_error!(\"let x = <<1:unit(5)>> x\");\n}\n\n#[test]\nfn bit_array_size_not_int() {\n    assert_error!(\"let x = <<1:size(\\\"1\\\")>> x\");\n}\n\n#[test]\nfn bit_array_size_not_int_variable() {\n    assert_error!(\"let a = 2.0 case <<1>> { <<1:size(a)>> -> a }\");\n}\n\n#[test]\nfn bit_array_float_size() {\n    // float given invalid size\n    assert_error!(\"let x = <<1:8-float>> x\");\n}\n\n#[test]\nfn bit_array_bits_option_in_value() {\n    assert_error!(\"let x = <<<<1:1>>:bytes>> x\");\n}\n\n#[test]\nfn bit_array_utf8_and_size() {\n    assert_error!(r#\"let x = <<\"test\":size(1)>> x\"#);\n}\n\n#[test]\nfn bit_array_utf8_and_unit() {\n    assert_error!(r#\"let x = <<\"test\":unit(5)>> x\"#);\n}\n\n#[test]\nfn add_int_float() {\n    assert_error!(\"1 + 1.0\");\n}\n\n#[test]\nfn add_f_int_float() {\n    assert_error!(\"1 +. 1.0\");\n}\n\n#[test]\nfn int_eq_float() {\n    assert_error!(\"1 == 1.0\");\n}\n\n#[test]\nfn int_gt_float() {\n    assert_error!(\"1 > 1.0\");\n}\n\n#[test]\nfn float_gtf_int() {\n    assert_error!(\"1.0 >. 1\");\n}\n\n#[test]\nfn fn0_eq_fn1() {\n    assert_error!(\"fn() { 1 } == fn(x) { x + 1 }\");\n}\n\n#[test]\nfn unknown_variable() {\n    assert_error!(\"x\");\n}\n\n#[test]\nfn unknown_variable_type() {\n    assert_error!(\"Int\");\n}\n\n#[test]\nfn unknown_module() {\n    assert_module_error!(\"import xpto\");\n}\n\n#[test]\nfn unknown_variable_2() {\n    assert_error!(\"case 1 { x -> 1 1 -> x }\");\n}\n\n#[test]\nfn unknown_variable_3() {\n    assert_error!(\"let add = fn(x, y) { x + y } 1 |> add(unknown)\");\n}\n\n#[test]\nfn incorrect_arity_error() {\n    assert_error!(\"let id = fn(x) { x } id()\");\n}\n\n#[test]\nfn incorrect_arity_error_2() {\n    assert_error!(\"let id = fn(x) { x } id(1, 2)\");\n}\n\n#[test]\nfn case_clause_mismatch() {\n    assert_error!(\"case 1 { a -> 1 b -> 2.0 }\");\n}\n\n#[test]\nfn case_subject_pattern_unify() {\n    assert_error!(\"case 1.0 { 1 -> 1 }\");\n}\n\n#[test]\nfn case_subject_pattern_unify_2() {\n    assert_error!(\"case 1 { 1.0 -> 1 }\");\n}\n\n#[test]\nfn case_operator_unify_situation() {\n    assert_error!(\"case 1, 2.0 { a, b -> a + b }\");\n}\n\n#[test]\nfn case_could_not_unify() {\n    assert_error!(\"case 1, 2.0 { a, b -> a 1, 2 -> 0 }\");\n}\n\n#[test]\nfn assigned_function_annotation() {\n    assert_error!(\"let f = fn(x: Int) { x } f(1.0)\");\n}\n\n#[test]\nfn function_return_annotation() {\n    assert_error!(\"fn() -> Int { 2.0 }\");\n}\n\n#[test]\nfn function_arg_and_return_annotation() {\n    assert_error!(\"fn(x: Int) -> Float { x }\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/1378\n#[test]\nfn function_return_annotation_mismatch_with_pipe() {\n    assert_module_error!(\n        \"pub fn main() -> String {\n            1\n            |> add_two\n         }\n\n         fn add_two(i: Int) -> Int {\n            i + 2\n         }\"\n    );\n}\n\n#[test]\nfn functions_called_outside_module() {\n    assert_module_syntax_error!(\"const first = list.at([1], 0)\");\n}\n\n#[test]\nfn pipe_mismatch_error() {\n    assert_module_error!(\n        \"pub fn main() -> String {\n            Orange\n            |> eat_veggie\n         }\n\n         type Fruit{ Orange }\n         type Veg{ Lettuce }\n\n         fn eat_veggie(v: Veg) -> String {\n            \\\"Ok\\\"\n         }\"\n    );\n}\n\n#[test]\nfn pipe_value_type_mismatch_error() {\n    assert_module_error!(\n        \"pub fn main() -> String {\n            eat_veggie\n            |> Orange\n         }\n\n         type Fruit{ Orange }\n         type Veg{ Lettuce }\n\n         fn eat_veggie(v: Veg) -> String {\n            \\\"Ok\\\"\n         }\"\n    );\n}\n\n#[test]\nfn case_tuple_guard() {\n    assert_error!(\"case #(1, 2, 3) { x if x == #(1, 1.0) -> 1 }\");\n}\n\n#[test]\nfn case_list_guard() {\n    assert_error!(\"case [1] { x if x == [1, 2.0] -> 1 _ -> 2 }\");\n}\n\n#[test]\nfn case_tuple_guard_2() {\n    assert_error!(\"case #(1, 2) { x if x == #(1, 1.0) -> 1 }\");\n}\n\n#[test]\nfn case_int_tuple_guard() {\n    assert_error!(\"case 1 { x if x == #() -> 1 }\");\n}\n\n#[test]\nfn wrong_number_of_subjects() {\n    assert_error!(\"case 1 { _, _ -> 1 }\");\n}\n\n#[test]\nfn wrong_number_of_subjects_alternative_patterns() {\n    assert_error!(\"case 1 { _, _ | _ | _, _, _ -> 1 }\");\n}\n\n#[test]\nfn recursive_var() {\n    assert_error!(\"let id = fn(x) { x(x) } 1\");\n}\n\n#[test]\nfn true_fn() {\n    assert_error!(\"let True(x) = 1\");\n}\n\n#[test]\nfn ok_2_args() {\n    assert_error!(\"let Ok(1, x) = 1\");\n}\n\n#[test]\nfn access_int() {\n    assert_error!(\"let x = 1 x.whatever\");\n}\n\n#[test]\nfn tuple_2_3() {\n    assert_error!(\"#(1, 2) == #(1, 2, 3)\");\n}\n\n#[test]\nfn tuple_int_float() {\n    assert_error!(\"#(1.0, 2, 3) == #(1, 2, 3)\");\n}\n\n#[test]\nfn tuple_int() {\n    assert_error!(\"let #(a, b) = 1\");\n}\n\n#[test]\nfn int_float_list() {\n    assert_error!(\"[1.0] == [1]\");\n}\n\n#[test]\nfn guard_int_float_eq_vars() {\n    assert_error!(\"let x = 1 let y = 1.0 case x { _ if x == y -> 1 }\");\n}\n\n#[test]\nfn guard_float_int_eq_vars() {\n    assert_error!(\"let x = 1.0 let y = 1 case x { _ if x == y -> 1 }\");\n}\n\n#[test]\nfn guard_if_float() {\n    assert_error!(\"let x = 1.0 case x { _ if x -> 1 }\");\n}\n\n#[test]\nfn case() {\n    assert_error!(\"case #(1, 1.0) { #(x, _) | #(_, x) -> 1 }\");\n}\n\n#[test]\nfn case2() {\n    assert_error!(\"case [3.33], 1 { x, y if x > y -> 1 }\");\n}\n\n#[test]\nfn case3() {\n    assert_error!(\"case 1, 2.22, \\\"three\\\" { x, _, y if x > y -> 1 }\");\n}\n\n#[test]\nfn case4() {\n    assert_error!(\"case [3.33], 1 { x, y if x >= y -> 1 }\");\n}\n\n#[test]\nfn case5() {\n    assert_error!(\"case 1, 2.22, \\\"three\\\" { x, _, y if x >= y -> 1 }\");\n}\n\n#[test]\nfn case6() {\n    assert_error!(\"case [3.33], 1 { x, y if x < y -> 1 }\");\n}\n\n#[test]\nfn case7() {\n    assert_error!(\"case 1, 2.22, \\\"three\\\" { x, _, y if x < y -> 1 }\");\n}\n\n#[test]\nfn case8() {\n    assert_error!(\"case [3.33], 1 { x, y if x <= y -> 1 }\");\n}\n\n#[test]\nfn case9() {\n    assert_error!(\"case 1, 2.22, \\\"three\\\" { x, _, y if x <= y -> 1 }\");\n}\n\n#[test]\nfn case10() {\n    assert_error!(\"case [3], 1.1 { x, y if x >. y -> 1 }\");\n}\n\n#[test]\nfn case11() {\n    assert_error!(\"case 2.22, 1, \\\"three\\\" { x, _, y if x >. y -> 1 }\");\n}\n\n#[test]\nfn case12() {\n    assert_error!(\"case [3], 1.1 { x, y if x >=. y -> 1 }\");\n}\n\n#[test]\nfn case13() {\n    assert_error!(\"case 2.22, 1, \\\"three\\\" { x, _, y if x >=. y -> 1 }\");\n}\n\n#[test]\nfn case14() {\n    assert_error!(\"case [3], 1.1 { x, y if x <. y -> 1 }\");\n}\n\n#[test]\nfn case15() {\n    assert_error!(\"case 2.22, 1, \\\"three\\\" { x, _, y if x <. y -> 1 }\");\n}\n\n#[test]\nfn case16() {\n    assert_error!(\"case [3], 1.1 { x, y if x <=. y -> 1 }\");\n}\n\n#[test]\nfn case17() {\n    assert_error!(\"case 2.22, 1, \\\"three\\\" { x, _, y if x <=. y -> 1 }\");\n}\n\n#[test]\nfn int_operator_on_floats_in_case_guard() {\n    assert_error!(\"case 3.0 { x if x > 2.0 -> \\\"a\\\" _ -> \\\"b\\\" }\");\n}\n\n#[test]\nfn float_operator_on_ints_in_case_guard() {\n    assert_error!(\"case 3 { x if x +. 2 == 5.0 -> \\\"a\\\" _ -> \\\"b\\\" }\");\n}\n\n#[test]\nfn case18() {\n    assert_error!(\"case 1 { x if x == \\\"x\\\" -> 1 }\");\n}\n\n#[test]\nfn case19() {\n    assert_error!(\"case [1] { [x] | x -> 1 }\");\n}\n\n#[test]\nfn case20() {\n    assert_error!(\"case [1] { [x] | [] as x -> 1 }\");\n}\n\n#[test]\nfn extra_var_inalternative() {\n    assert_error!(\"case [1] { [x] | [x, y] -> 1 }\");\n}\n\n#[test]\nfn extra_var_inalternative2() {\n    assert_error!(\"case #(1, 2) { #(1, y) | #(x, y) -> 1 }\");\n}\n\n#[test]\nfn extra_var_inalternative3() {\n    assert_error!(\"let x = 1 case #(1, 2) { #(1, y) | #(x, y) -> 1 }\");\n}\n\n#[test]\nfn tuple_arity() {\n    // https://github.com/gleam-lang/gleam/issues/714\n    assert_error!(\"case #(1, 2) { #(1, _, _, _) -> 1 }\");\n}\n\n#[test]\nfn duplicate_vars() {\n    assert_error!(\"case #(1, 2) { #(x, x) -> 1 }\");\n}\n\n#[test]\nfn duplicate_vars_2() {\n    assert_error!(\"case [3.33], 1 { x, x -> 1 }\");\n}\n\n#[test]\nfn duplicate_vars_3() {\n    assert_error!(\"case [1, 2, 3] { [x, x, y] -> 1 }\");\n}\n\n#[test]\nfn tuple_index_out_of_bounds() {\n    assert_error!(\"#(0, 1).2\");\n}\n\n#[test]\nfn tuple_index_not_a_tuple() {\n    assert_error!(\"Nil.2\");\n}\n\n#[test]\nfn tuple_index_not_a_tuple_unbound() {\n    assert_error!(\"fn(a) { a.2 }\");\n}\n\n#[test]\nfn unknown_accessed_type() {\n    assert_error!(\"fn(a) { a.field }\");\n}\n\n#[test]\nfn unknown_field() {\n    assert_error!(\"fn(a: a) { a.field }\");\n}\n\n#[test]\nfn field_not_in_all_variants() {\n    assert_module_error!(\n        \"\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_title(person: Person) { person.title }\"\n    );\n}\n\n#[test]\nfn field_not_in_any_variant() {\n    assert_module_error!(\n        \"\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_height(person: Person) { person.height }\"\n    );\n}\n\n#[test]\nfn field_type_different_between_variants() {\n    assert_module_error!(\n        \"\npub type Shape {\n    Square(x: Int, y: Int)\n    Rectangle(x: String, y: String)\n}\npub fn get_x(shape: Shape) { shape.x }\n\"\n    );\n}\n\n#[test]\nfn accessor_multiple_variants_multiple_positions() {\n    // We cannot access fields on custom types with multiple variants where they are in different positions e.g. 2nd and 3rd\n    assert_module_error!(\n        \"\npub type Person {\n    Teacher(name: String, title: String, age: Int)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn accessor_multiple_variants_multiple_positions2() {\n    // We cannot access fields on custom types with multiple variants where they are in different positions e.g. 1st and 3rd\n    assert_module_error!(\n        \"\npub type Person {\n    Teacher(title: String, age: Int, name: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\"\n    );\n}\n\n#[test]\nfn record_access_on_inferred_variant_when_field_is_in_other_variants() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(wibble: Int)\n  Wobble(wobble: Int)\n}\n\npub fn main() {\n  let always_wibble = Wibble(10)\n  always_wibble.wobble\n}\n\"\n    );\n}\n\n#[test]\nfn module_could_not_unify() {\n    assert_module_error!(\"fn go() { 1 + 2.0 }\");\n}\n\n#[test]\nfn module_could_not_unify2() {\n    assert_module_error!(\"fn go() { 1 + 2.0 }\");\n}\n\n#[test]\nfn module_could_not_unify3() {\n    assert_module_error!(\n        \"\nfn id(x: a, y: a) { x }\npub fn x() { id(1, 1.0) }\"\n    );\n}\n\n#[test]\nfn module_could_not_unify4() {\n    assert_module_error!(\n        \"\nfn wobble() -> Int {\n    5\n}\n\nfn run(one: fn() -> String) {\n    one()\n}\n\nfn demo() {\n    run(wobble)\n}\"\n    );\n}\n\n#[test]\nfn module_could_not_unify5() {\n    assert_module_error!(\n        \"\nfn wobble(x: Int) -> Int {\n    x * 5\n}\n\nfn run(one: fn(String) -> Int) {\n    one(\\\"one.\\\")\n}\n\nfn demo() {\n    run(wobble)\n}\"\n    );\n}\n\n#[test]\nfn module_could_not_unify6() {\n    assert_module_error!(\"fn main() { let x: String = 5 x }\");\n}\n\n#[test]\nfn module_could_not_unify7() {\n    assert_module_error!(\"fn main() { let assert 5 = \\\"\\\" }\");\n}\n\n#[test]\nfn module_could_not_unify8() {\n    assert_module_error!(\"fn main() { let x: #(x, x) = #(5, 5.0) x }\");\n}\n\n#[test]\nfn module_could_not_unify9() {\n    assert_module_error!(\"fn main() { let assert [1, 2, ..x]: List(String) = [1,2,3] x }\");\n}\n\n#[test]\nfn module_could_not_unify10() {\n    assert_module_error!(\n        \"fn main() {\n            let #(y, [..x]): #(x, List(x)) = #(\\\"one\\\", [1,2,3])\n            x\n        }\"\n    );\n}\n\n#[test]\nfn module_could_not_unify11() {\n    assert_module_error!(\n        \"\n        pub type Box(inner) {\n            Box(inner)\n        }\n\n        pub fn create_int_box(value: Int) {\n            let x: Box(Float) = Box(value)\n            x\n        }\"\n    );\n}\n\n#[test]\nfn module_could_not_unify12() {\n    assert_module_error!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n\n        pub fn create_person(age: Float) {\n            let x: Person = Person(name: \\\"Quinn\\\", age: age)\n            x\n        }\"\n    );\n}\n\n#[test]\nfn module_arity_error() {\n    assert_module_error!(\"fn go(x: List(a, b)) -> Int { 1 }\");\n}\n\n#[test]\nfn module_private_type_leak_1() {\n    assert_module_error!(\n        r#\"type PrivateType\n\n@external(erlang, \"a\", \"b\")\npub fn leak_type() -> PrivateType\n\"#\n    );\n}\n\n#[test]\nfn module_private_type_leak_2() {\n    assert_module_error!(\n        r#\"type PrivateType\n\n@external(erlang, \"a\", \"b\")\nfn go() -> PrivateType\n\npub fn leak_type() { go() }\"#\n    );\n}\n\n#[test]\nfn module_private_type_leak_3() {\n    assert_module_error!(\n        r#\"type PrivateType\n@external(erlang, \"a\", \"b\")\nfn go() -> PrivateType\npub fn leak_type() { [go()] }\"#\n    );\n}\n\n#[test]\nfn module_private_type_leak_4() {\n    assert_module_error!(\n        r#\"type PrivateType\n@external(erlang, \"a\", \"b\")\npub fn go(x: PrivateType) -> Int\"#\n    );\n}\n\n#[test]\nfn module_private_type_leak_5() {\n    assert_module_error!(\n        r#\"type PrivateType\npub type LeakType { Variant(PrivateType) }\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3387\n// Private types should not leak even in internal modules\n#[test]\nfn module_private_type_leak_6() {\n    assert_internal_module_error!(\n        r#\"type PrivateType\npub type LeakType { Variant(PrivateType) }\"#\n    );\n}\n\n#[test]\nfn unexpected_labelled_arg() {\n    assert_module_error!(r#\"fn id(x) { x } fn y() { id(x: 4) }\"#);\n}\n\n#[test]\nfn unexpected_labelled_arg_record_constructor() {\n    assert_module_error!(r#\"type X { X(Int) } fn y() { X(a: 0) }\"#);\n}\n\n#[test]\nfn unexpected_arg_with_label_shorthand() {\n    assert_module_error!(\n        r#\"\n    fn id(x) { x }\n    fn y() {\n        let x = 4\n        id(x:)\n    }\n\"#\n    );\n}\n\n#[test]\nfn positional_argument_after_labelled() {\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Int, c: Int) }\nfn x() { X(b: 1, a: 1, 1) }\"#\n    );\n}\n\n#[test]\nfn positional_argument_after_one_using_label_shorthand() {\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Int, c: Int) }\nfn x() {\n  let b = 1\n  let a = 1\n  X(b:, a:, 1)\n}\"#\n    );\n}\n\n#[test]\nfn unknown_type() {\n    assert_module_error!(r#\"type Thing { Thing(unknown: x) }\"#);\n}\n\n#[test]\nfn unknown_type_in_alias() {\n    // We cannot refer to unknown types in an alias\n    assert_module_error!(\"type IntMap = IllMap(Int, Int)\");\n}\n\n#[test]\nfn unknown_type_in_alias2() {\n    // We cannot refer to unknown types in an alias\n    assert_module_error!(\"type IntMap = Map(Inf, Int)\");\n}\n\n#[test]\nfn unknown_type_var_in_alias2() {\n    // We cannot use undeclared type vars in a type alias\n    assert_module_error!(\"type X = List(a)\");\n}\n\n#[test]\nfn module_non_local_gaurd_var() {\n    assert_module_error!(\n        r#\"fn one() { 1 }\nfn main() { case 1 { _ if one -> 1 } }\"#\n    );\n}\n\n#[test]\nfn unknown_record_field() {\n    // An unknown field should report the possible fields' labels\n    assert_module_error!(\n        \"\npub type Box(a) { Box(inner: a) }\npub fn main(box: Box(Int)) { box.unknown }\n\"\n    );\n}\n\n#[test]\nfn unknown_record_field_2() {\n    // An unknown field should report the possible fields' labels\n    assert_module_error!(\n        \"\npub type Box(a) { Box(inner: a) }\npub fn main(box: Box(Box(Int))) { box.inner.unknown }\"\n    );\n}\n\n#[test]\nfn unnecessary_spread_operator() {\n    assert_module_error!(\n        \"\ntype Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\nfn main() {\n  let triple = Triple(1,2,3)\n  let Triple(a, b, c, ..) = triple\n}\"\n    );\n}\n\n#[test]\nfn duplicate_var_in_record_pattern() {\n    // Duplicate var in record\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Int, c: Int) }\nfn x() {\n  case X(1,2,3) { X(x, y, x) -> 1 }\n}\"#\n    );\n}\n\n#[test]\nfn duplicate_label_shorthands_in_record_pattern() {\n    // Duplicate var in record\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Int, c: Int) }\nfn x() {\n  case X(1,2,3) { X(a:, b:, c: a) -> 1 }\n}\"#\n    );\n}\n\n#[test]\nfn guard_record_wrong_arity() {\n    // Constructor in guard clause errors\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Float) }\nfn x() {\n  case X(1, 2.0) { x if x == X(1) -> 1 _ -> 2 }\n}\"#\n    );\n}\n\n#[test]\nfn subject_int_float_guard_tuple() {\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Float) }\nfn x() { case X(1, 2.0) { x if x == X(2.0, 1) -> 1 _ -> 2 } }\"#\n    );\n}\n\n#[test]\nfn type_variables_in_body() {\n    // Type variables are shared between function annotations and let annotations within their body\n    assert_module_error!(\n        \"\npub type Box(a) {\n  Box(value: a)\n}\npub fn go(box1: Box(a), box2: Box(b)) {\n  let _: Box(a) = box2\n  let _: Box(b) = box1\n  5\n}\"\n    );\n}\n\n#[test]\nfn duplicate_function_names() {\n    // We cannot declare two functions with the same name in a module\n    assert_module_error!(\n        \"fn dupe() { 1 }\nfn dupe() { 2 }\"\n    );\n}\n\n#[test]\nfn duplicate_function_names_2() {\n    // Different types to force a unify error if we don't detect the\n    // duplicate during refactoring.\n    assert_module_error!(\n        \"fn dupe() { 1 }\nfn dupe() { 2.0 }\"\n    );\n}\n\n#[test]\nfn duplicate_function_names_3() {\n    assert_module_error!(\n        \"fn dupe() { 1 }\nfn dupe(x) { x }\"\n    );\n}\n\n#[test]\nfn duplicate_function_names_4() {\n    assert_module_error!(\n        r#\"fn dupe() { 1 }\n@external(erlang, \"a\", \"b\")\nfn dupe(x) -> x\n\"#\n    );\n}\n\n#[test]\nfn duplicate_function_names_5() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"a\", \"b\")\nfn dupe(x) -> x\nfn dupe() { 1 }\n\"#\n    );\n}\n\n#[test]\nfn duplicate_constructors() {\n    // We cannot declare two type constructors with the same name in a module\n    assert_module_error!(\n        \"type Box { Box(x: Int) }\ntype Boxy { Box(Int) }\"\n    );\n}\n\n#[test]\nfn duplicate_constructors2() {\n    // We cannot declare two type constructors with the same name in a module\n    assert_module_error!(\n        \"type Boxy { Box(Int) }\ntype Box { Box(x: Int) }\"\n    );\n}\n\n#[test]\nfn duplicate_constructors3() {\n    // We cannot declare two type constructors with the same name in a module\n    assert_module_error!(\"type Boxy { Box(Int) Box(Float) }\");\n}\n\n#[test]\nfn duplicate_alias_names() {\n    // We cannot reuse an alias name in the same module\n    assert_module_error!(\"type X = Int type X = Int\");\n}\n\n#[test]\nfn duplicate_custom_type_names() {\n    // We cannot declare two types with the same name in a module\n    assert_module_error!(\"type DupType { A } type DupType { B }\");\n}\n\n#[test]\nfn duplicate_const_names() {\n    // We cannot declare two const with the same name in a module\n    assert_module_error!(\n        \"const duplicate = 1\npub const duplicate = 1\"\n    );\n}\n\n#[test]\nfn duplicate_const_and_function_names_const_fn() {\n    // We cannot declare const and functions with the same name in a module\n    // https://github.com/gleam-lang/gleam/issues/2069\n    assert_module_error!(\n        \"const duplicate = 1\nfn duplicate() { 2 }\"\n    );\n}\n\n#[test]\nfn duplicate_const_const() {\n    assert_module_error!(\n        \"const wibble = 1\nconst wibble = 2\"\n    );\n}\n\n#[test]\nfn duplicate_fn_fn() {\n    assert_module_error!(\n        \"fn wibble() { 1 }\nfn wibble() { 2 }\"\n    );\n}\n\n#[test]\nfn duplicate_extfn_extfn() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"module1\", \"function1\")\nfn wibble() -> Float\n@external(erlang, \"module2\", \"function2\")\nfn wibble() -> Float\n\"#\n    );\n}\n\n#[test]\nfn duplicate_extfn_fn() {\n    assert_module_error!(\n        \"\n@external(erlang, \\\"module1\\\", \\\"function1\\\")\nfn wibble() -> Float\n\nfn wibble() { 2 }\"\n    );\n}\n\n#[test]\nfn duplicate_fn_extfn() {\n    assert_module_error!(\n        \"fn wibble() { 1 }\n\n@external(erlang, \\\"module2\\\", \\\"function2\\\")\nfn wibble() -> Float\n\"\n    );\n}\n\n#[test]\nfn duplicate_const_extfn() {\n    assert_module_error!(\n        \"const wibble = 1\n\n@external(erlang, \\\"module2\\\", \\\"function2\\\")\nfn wibble() -> Float\n\"\n    );\n}\n\n#[test]\nfn duplicate_extfn_const() {\n    assert_module_error!(\n        \"\n@external(erlang, \\\"module1\\\", \\\"function1\\\")\nfn wibble() -> Float\n\nconst wibble = 2\"\n    );\n}\n\n#[test]\nfn duplicate_const_fn() {\n    assert_module_error!(\n        \"const wibble = 1\nfn wibble() { 2 }\"\n    );\n}\n\n#[test]\nfn duplicate_fn_const() {\n    assert_module_error!(\n        \"fn wibble() { 1 }\nconst wibble = 2\"\n    );\n}\n\n#[test]\nfn invalid_const_name() {\n    assert_module_error!(\"const myInvalid_Constant = 42\");\n}\n\n#[test]\nfn invalid_parameter_name() {\n    assert_module_error!(\"fn add(numA: Int, num_b: Int) { numA + num_b }\");\n}\n\n#[test]\nfn invalid_parameter_name2() {\n    assert_module_error!(\"fn pass(label paramName: Bool) { paramName }\");\n}\n\n#[test]\nfn invalid_parameter_name3() {\n    assert_error!(\"let add = fn(numA: Int, num_b: Int) { numA + num_b }\");\n}\n\n#[test]\nfn invalid_parameter_discard_name() {\n    assert_module_error!(\"fn ignore(_ignoreMe: Bool) { 98 }\");\n}\n\n#[test]\nfn invalid_parameter_discard_name2() {\n    assert_module_error!(\"fn ignore(labelled_discard _ignoreMe: Bool) { 98 }\");\n}\n\n#[test]\nfn invalid_parameter_discard_name3() {\n    assert_error!(\"let ignore = fn(_ignoreMe: Bool) { 98 }\");\n}\n\n#[test]\nfn invalid_parameter_label() {\n    assert_module_error!(\"fn func(thisIsALabel param: Int) { param }\");\n}\n\n#[test]\nfn invalid_parameter_label2() {\n    assert_module_error!(\"fn ignore(thisIsALabel _ignore: Int) { 25 }\");\n}\n\n#[test]\nfn invalid_constructor_name() {\n    assert_module_error!(\"type MyType { Int_Value(Int) }\");\n}\n\n#[test]\nfn invalid_constructor_arg_name() {\n    assert_module_error!(\"type IntWrapper { IntWrapper(innerInt: Int) }\");\n}\n\n#[test]\nfn invalid_custom_type_name() {\n    assert_module_error!(\"type Boxed_value { Box(Int) }\");\n}\n\n#[test]\nfn invalid_type_alias_name() {\n    assert_module_error!(\"type Fancy_Bool = Bool\");\n}\n\n#[test]\nfn invalid_function_name() {\n    assert_module_error!(\"fn doStuff() {}\");\n}\n\n#[test]\nfn invalid_variable_name() {\n    assert_error!(\"let theAnswer = 42\");\n}\n\n#[test]\nfn invalid_variable_discard_name() {\n    assert_error!(\"let _boringNumber = 72\");\n}\n\n#[test]\nfn invalid_use_name() {\n    assert_module_error!(\n        \"fn use_test(f) { f(Nil) }\npub fn main() { use useVar <- use_test() }\"\n    );\n}\n\n#[test]\nfn invalid_use_discard_name() {\n    assert_module_error!(\n        \"fn use_test(f) { f(Nil) }\npub fn main() { use _discardVar <- use_test() }\"\n    );\n}\n\n#[test]\nfn invalid_pattern_assignment_name() {\n    assert_error!(\"let assert 42 as theAnswer = 42\");\n}\n\n#[test]\nfn invalid_list_pattern_name() {\n    assert_error!(\"let assert [theElement] = [9.4]\");\n}\n\n#[test]\nfn invalid_list_pattern_discard_name() {\n    assert_error!(\"let assert [_elemOne] = [False]\");\n}\n\n#[test]\nfn invalid_constructor_pattern_name() {\n    assert_module_error!(\n        \"pub type Box { Box(Int) } pub fn main() { let Box(innerValue) = Box(203) }\"\n    );\n}\n\n#[test]\nfn invalid_constructor_pattern_discard_name() {\n    assert_module_error!(\n        \"pub type Box { Box(Int) } pub fn main() { let Box(_ignoredInner) = Box(203)}\"\n    );\n}\n\n#[test]\nfn invalid_tuple_pattern_name() {\n    assert_error!(\"let #(a, secondValue) = #(1, 2)\");\n}\n\n#[test]\nfn invalid_tuple_pattern_discard_name() {\n    assert_error!(\"let #(a, _secondValue) = #(1, 2)\");\n}\n\n#[test]\nfn invalid_bit_array_pattern_name() {\n    assert_error!(\"let assert <<bitValue>> = <<73>>\");\n}\n\n#[test]\nfn invalid_bit_array_pattern_discard_name() {\n    assert_error!(\"let assert <<_iDontCare>> = <<97>>\");\n}\n\n#[test]\nfn invalid_string_prefix_pattern_name() {\n    assert_error!(r#\"let assert \"prefix\" <> coolSuffix = \"prefix-suffix\"\"#);\n}\n\n#[test]\nfn invalid_string_prefix_pattern_discard_name() {\n    assert_error!(r#\"let assert \"prefix\" <> _boringSuffix = \"prefix-suffix\"\"#);\n}\n\n#[test]\nfn invalid_string_prefix_pattern_alias() {\n    assert_error!(r#\"let assert \"prefix\" as thePrefix <> _suffix = \"prefix-suffix\"\"#);\n}\n\n#[test]\nfn invalid_case_variable_name() {\n    assert_error!(\"case 21 { twentyOne -> {Nil} }\");\n}\n\n#[test]\nfn invalid_case_variable_discard_name() {\n    assert_error!(\"case 21 { _twentyOne -> {Nil} }\");\n}\n\n#[test]\nfn invalid_type_parameter_name() {\n    assert_module_error!(\"type Wrapper(innerType) {}\");\n}\n\n#[test]\nfn invalid_type_alias_parameter_name() {\n    assert_module_error!(\"type GleamOption(okType) = Result(okType, Nil)\");\n}\n\n#[test]\nfn invalid_function_type_parameter_name() {\n    assert_module_error!(\"fn identity(value: someType) { value }\");\n}\n\n#[test]\nfn correct_pipe_arity_error_location() {\n    // https://github.com/gleam-lang/gleam/issues/672\n    assert_module_error!(\n        \"fn x(x, y) { x }\nfn main() { 1 |> x() }\"\n    );\n}\n\n#[test]\nfn const_annotation_wrong() {\n    assert_module_error!(\"pub const group_id: Int = \\\"42\\\"\");\n}\n\n#[test]\nfn const_annotation_wrong_2() {\n    assert_module_error!(\"pub const numbers: List(Int) = [1, 2, 2.3]\");\n}\n\n#[test]\nfn const_annotation_wrong_3() {\n    assert_module_error!(\"pub const numbers: List(Int) = [1.1, 2.2, 3.3]\");\n}\n\n#[test]\nfn const_annotation_wrong_4() {\n    assert_module_error!(\"pub const pair: #(Int, Float) = #(4.1, 1)\");\n}\n\n#[test]\nfn const_multiple_errors_mismatched_types() {\n    assert_module_error!(\n        \"const mismatched_types: String = 7\nconst invalid_annotation: MyInvalidType = \\\"str\\\"\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_invalid_annotation() {\n    assert_module_error!(\n        \"const invalid_annotation: MyInvalidType = \\\"str\\\"\nconst invalid_value: String = MyInvalidValue\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_invalid_value() {\n    assert_module_error!(\n        \"const invalid_value: String = MyInvalidValue\nconst invalid_unannotated_value = [1, 2.0]\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_invalid_unannotated_value() {\n    assert_module_error!(\n        \"const invalid_unannotated_value = [1, 2.0]\nconst invalid_everything: MyInvalidType = MyInvalidValue\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_invalid_annotation_and_value() {\n    assert_module_error!(\n        \"const invalid_everything: MyInvalidType = MyInvalidValue\nconst mismatched_types: String = 7\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_are_local_with_annotation() {\n    assert_module_error!(\n        \"const num: String = 7\nconst tpl: String = #(Ok(1), MyInvalidType, 3)\nconst assignment1: String = num\nconst assignment2: String = tpl\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_are_local_with_inferred_value() {\n    assert_module_error!(\n        \"const str: MyInvalidType = \\\"str\\\"\nconst assignment: String = str\"\n    );\n}\n\n#[test]\nfn const_multiple_errors_are_local_with_unbound_value() {\n    assert_module_error!(\n        \"const lst = [1, 2.0]\nconst unbound: MyInvalidType = MyInvalidType\nconst assignment1: String = lst\nconst assignment2: String = unbound\"\n    );\n}\n\n#[test]\nfn const_usage_wrong() {\n    assert_module_error!(\n        \"const pair = #(1, 2.0)\nfn main() { 1 == pair }\"\n    );\n}\n\n#[test]\nfn const_heterogenus_list() {\n    assert_module_error!(\"const pair = [1, 1.0]\");\n}\n\n#[test]\nfn custom_type_module_constants() {\n    assert_module_error!(\n        r#\"type X { X }\nconst x = unknown.X\"#\n    );\n}\n\n#[test]\nfn unknown_label() {\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Float) }\nfn x() {\n  let x = X(a: 1, c: 2.0)\n  x\n}\"#\n    );\n}\n\n#[test]\nfn unknown_label_shorthand() {\n    assert_module_error!(\n        r#\"type X { X(a: Int, b: Float) }\nfn x() {\n  let c = 2.0\n  let x = X(a: 1, c:)\n  x\n}\"#\n    );\n}\n\n#[test]\nfn wrong_type_var() {\n    // A unification error should show the type var as named by user\n    // See https://github.com/gleam-lang/gleam/issues/1256\n    assert_module_error!(\n        r#\"fn wibble(x: String) { x }\nfn multi_result(x: some_name) {\n  wibble(x)\n}\"#\n    );\n}\n\n#[test]\nfn wrong_type_arg() {\n    assert_module_error!(\n        r#\"\nfn wibble(x: List(Int)) { x }\nfn main(y: List(something)) {\n  wibble(y)\n}\"#\n    );\n}\n\n#[test]\nfn wrong_type_ret() {\n    // See https://github.com/gleam-lang/gleam/pull/1407#issuecomment-1001162876\n    assert_module_error!(\n        r#\"pub fn main(x: something) -> Int {\n  let y = x\n  y\n}\"#\n    );\n}\n\n#[test]\nfn wrong_type_update() {\n    // A variable of the wrong type given to a record update\n    assert_module_error!(\n        \"\n pub type Person {\n   Person(name: String, age: Int)\n }\n pub type Box(a) {\n   Box(a)\n }\n pub fn update_person(person: Person, box: Box(a)) {\n   Person(..box)\n }\"\n    );\n}\n\n#[test]\nfn unknown_variable_update() {\n    // An undefined variable given to a record update\n    assert_module_error!(\n        \"\npub type Person {\n  Person(name: String, age: Int)\n}\npub fn update_person() {\n  Person(..person)\n}\"\n    );\n}\n\n#[test]\nfn unknown_field_update() {\n    // An unknown field given to a record update\n    assert_module_error!(\n        \"\n pub type Person {\n   Person(name: String)\n }\n pub fn update_person(person: Person) {\n   Person(..person, one: 5)\n }\"\n    );\n}\n\n#[test]\nfn unknown_field_update2() {\n    // An unknown field given to a record update\n    assert_module_error!(\n        \"\n pub type Person {\n   Person(name: String, age: Int, size: Int)\n }\n pub fn update_person(person: Person) {\n   Person(..person, size: 66, one: 5, age: 3)\n }\"\n    );\n}\n\n#[test]\nfn unknown_constructor_update() {\n    // An unknown record constructor being used in a record update\n    assert_module_error!(\n        \"\npub type Person {\n   Person(name: String, age: Int)\n}\npub fn update_person(person: Person) {\n   NotAPerson(..person)\n}\"\n    );\n}\n\n#[test]\nfn not_a_constructor_update() {\n    // Something other than a record constructor being used in a record update\n    assert_module_error!(\n        \"\npub type Person {\n  Person(name: String, age: Int)\n}\npub fn identity(a) { a }\npub fn update_person(person: Person) {\n  identity(..person)\n}\"\n    );\n}\n\n#[test]\nfn expression_constructor_update() {\n    // A record update with a constructor returned from an expression\n    assert_module_error!(\n        \"\npub type Person {\n  Person(name: String, age: Int)\n}\npub fn update_person(person: Person) {\n  let constructor = Person\n  constructor(..person)\n}\"\n    );\n}\n\n#[test]\nfn type_vars_must_be_declared() {\n    // https://github.com/gleam-lang/gleam/issues/734\n    assert_module_error!(\n        r#\"type A(a) { A }\ntype B = a\"#\n    );\n}\n\n#[test]\nfn type_holes1() {\n    // Type holes cannot be used when decaring types or external functions\n    assert_module_error!(r#\"type A { A(_) }\"#);\n}\n\n#[test]\nfn type_holes2() {\n    // Type holes cannot be used when decaring types or external functions\n    assert_module_error!(\n        r#\"\n@external(erlang, \"a\", \"b\")\nfn main() -> List(_)\n\"#\n    );\n}\n\n#[test]\nfn type_holes3() {\n    // Type holes cannot be used when decaring types or external functions\n    assert_module_error!(\n        r#\"\n@external(erlang, \"a\", \"b\")\nfn main(x: List(_)) -> Nil\n\"#\n    );\n}\n\n#[test]\nfn type_holes4() {\n    // Type holes cannot be used when decaring types or external functions\n    assert_module_error!(r#\"type X = List(_)\"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1263\n#[test]\nfn missing_variable_in_alternative_pattern() {\n    assert_error!(\"case [] { [x] | [] -> x _ -> 0 }\");\n}\n\n#[test]\nfn type_annotations() {\n    assert_module_error!(\"fn inc(x: a) { x + 1 }\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/892\n#[test]\nfn case_clause_pipe_diagnostic() {\n    assert_module_error!(\n        r#\"\npub fn change(x: String) -> String {\n  \"\"\n}\n\npub fn parse(input: BitArray) -> String {\n  case input {\n    <<>> -> 1\n    <<\"(\":utf8, b:bytes>> ->\n      parse(input)\n      |> change\n    _ -> 3\n  }\n}\"#\n    );\n}\n\n#[test]\nfn pipe_arity_error() {\n    assert_module_error!(\n        r#\"\nfn go(x, y) {\n  x + y\n}\n\nfn main(x) {\n  1\n  |> go\n}\n\"#\n    );\n}\n\n#[test]\nfn negate_string() {\n    assert_error!(r#\"!\"Hello Gleam\"\"#);\n}\n\n#[test]\nfn ambiguous_type_error() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Thing { Thing }\"),\n        \"import wibble pub type Thing { Thing }\n        pub fn main() {\n            [Thing] == [wibble.Thing]\n        }\",\n    );\n}\n\n#[test]\nfn ambiguous_import_error_no_unqualified() {\n    assert_module_error!(\n        (\"wibble/sub\", \"pub fn wobble() { 1 }\"),\n        (\"wibble2/sub\", \"pub fn wobble() { 1 }\"),\n        \"\n        import wibble/sub\n        import wibble2/sub\n        pub fn main() {\n            sub.wobble()\n        }\n        \",\n    );\n}\n\n#[test]\nfn ambiguous_import_error_with_unqualified() {\n    assert_module_error!(\n        (\"wibble/sub\", \"pub fn wobble() { 1 }\"),\n        (\"wibble2/sub\", \"pub fn wobble() { 1 }\"),\n        \"\n        import wibble/sub\n        import wibble2/sub.{wobble}\n        pub fn main() {\n            sub.wobble()\n        }\n        \",\n    );\n}\n\n#[test]\nfn same_imports_multiple_times() {\n    assert_module_error!(\n        (\n            \"gleam/wibble\",\n            \"\n            pub fn wobble() { 1 }\n            pub fn zoo() { 1 }\n            \"\n        ),\n        \"\n        import gleam/wibble.{wobble}\n        import gleam/wibble.{zoo}\n        pub fn go() { wobble() + zoo() }\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_1() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one\n        import two as one\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_2() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one as two\n        import two\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_3() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one as x\n        import two as x\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_4() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one.{fn1}\n        import two.{fn2} as one\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_5() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one.{fn1} as two\n        import two.{fn2}\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_6() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one.{fn1} as x\n        import two.{fn2} as x\n        \"\n    );\n}\n\n#[test]\nfn same_imports_multiple_times_7() {\n    assert_module_error!(\n        (\n            \"one\",\n            \"\n            pub fn fn1() { 1 }\n            \"\n        ),\n        (\n            \"two\",\n            \"\n            pub fn fn2() { 1 }\n            \"\n        ),\n        \"\n        import one.{\n          fn1\n        } as x\n        import two.{\n          fn2\n        } as x\n        \"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1705\n#[test]\nfn update_multi_variant_record() {\n    assert_module_error!(\n        \"\npub type Point {\n  Point2(a: Int, b: Int)\n  Point3(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  Point3(..Point2(a: 1, b: 2))\n}\"\n    );\n}\n\n#[test]\nfn hint_for_method_call() {\n    assert_module_error!(\n        \"\npub type User {\n  User(id: Int, name: String)\n}\n\npub fn main(user: User) {\n  user.login()\n}\n\"\n    );\n}\n\n#[test]\nfn no_hint_for_non_method_call() {\n    assert_module_error!(\n        \"\npub type User {\n  User(id: Int, name: String)\n}\n\nfn login(user: User) {\n  user\n}\n\npub fn main(user: User) {\n  login(user.wibble)\n}\n\"\n    );\n}\n\n#[test]\nfn unknown_imported_module_type() {\n    assert_module_error!(\n        (\"one/two\", \"\"),\n        \"\nimport one/two\n\npub fn main(_x: two.Thing) {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn value_imported_as_type() {\n    assert_module_error!(\n        (\n            \"gleam/wibble\",\n            \"pub type Wibble {\n               Wobble\n             }\"\n        ),\n        \"import gleam/wibble.{type Wobble}\"\n    );\n}\n\n#[test]\nfn type_imported_as_value() {\n    assert_module_error!(\n        (\n            \"gleam/wibble\",\n            \"pub type Wibble {\n               Wobble\n             }\"\n        ),\n        \"import gleam/wibble.{Wibble}\"\n    );\n}\n\n#[test]\nfn duplicate_module_function_arguments() {\n    assert_module_error!(\n        \"\npub fn main(x, x) {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn duplicate_anon_function_arguments() {\n    assert_error!(\n        \"\nfn(x, x) {\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn negate_boolean_as_integer() {\n    assert_error!(\n        \"\nfn() {\n  let a = True\n  let b = -a\n}\n\"\n    );\n}\n\n#[test]\nfn negate_float_as_integer() {\n    assert_error!(\n        \"\nfn() {\n  let a = 3.0\n  let b = -a\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2371\n#[test]\nfn list() {\n    assert_error!(\"[1, 2.0]\");\n}\n\n#[test]\nfn mismatched_list_tail() {\n    assert_error!(\"[\\\"wibble\\\", ..[1, 2]]\");\n}\n\n#[test]\nfn leak_multiple_private_types() {\n    assert_module_error!(\n        \"\n        type Private {\n            Private\n        }\n\n        pub fn ret_private() -> Private {\n            Private\n        }\n\n        pub fn ret_private2() -> Private {\n            Private\n        }\n\n        pub fn main() {\n            ret_private()\n        }\n        \"\n    );\n}\n\n#[test]\nfn const_string_concat_invalid_type() {\n    assert_module_error!(\n        \"\nconst some_int = 5\nconst invalid_concat = some_int <> \\\"with_string\\\"\n\"\n    );\n}\n\n#[test]\nfn invalid_pattern_label_shorthand() {\n    assert_module_error!(\n        \"\npub type Wibble { Wibble(arg: Int) }\npub fn main() {\n  let Wibble(not_a_label:) = Wibble(1)\n}\n\"\n    );\n}\n\n#[test]\nfn no_crash_on_duplicate_definition() {\n    // This previous caused the compiler to crash\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wobble\n  Wobble\n}\n\npub fn main() {\n  let wibble = Wobble\n  case wibble {\n    Wobble -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn no_crash_on_duplicate_definition2() {\n    // This also caused a compiler crash, separate to the above test\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble\n  Wobble\n  Wobble\n  Wubble\n}\n\npub fn main() {\n  let wibble = Wobble\n  case wibble {\n    Wibble -> Nil\n    Wobble -> Nil\n    Wubble -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unknown_module_suggest_import() {\n    assert_module_error!(\n        (\"utils\", \"pub fn helpful() {}\"),\n        \"\npub fn main() {\n  utils.helpful()\n}\n\",\n    );\n}\n\n#[test]\nfn unknown_module_suggest_typo_for_imported_module() {\n    assert_module_error!(\n        (\"wibble\", \"pub fn wobble() {}\"),\n        \"\nimport wibble\npub fn main() {\n  wible.wobble()\n}\n\",\n    );\n}\n\n#[test]\nfn unknown_module_suggest_typo_for_unimported_module() {\n    assert_module_error!(\n        (\"wibble/wobble\", \"pub fn wubble() {}\"),\n        \"\npub fn main() {\n  woble.wubble()\n}\n\",\n    );\n}\n\n#[test]\nfn qualified_type_mismatched_type_error() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Wobble\"),\n        \"\nimport wibble\nconst my_wobble: wibble.Wobble = Nil\n\"\n    );\n}\n\n#[test]\nfn qualified_type_similar_type_name() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Int\"),\n        \"\nimport wibble\nconst value: wibble.Int = 20\n\"\n    );\n}\n\n#[test]\nfn qualified_type_not_a_function() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Function { Function(fn() -> Nil) }\"),\n        \"\nimport wibble.{type Function as FuncWrapper}\npub fn main(f: FuncWrapper) {\n  f()\n}\n\"\n    );\n}\n\n#[test]\nfn qualified_type_unknown_field() {\n    assert_module_error!(\n        \"\nimport gleam\ntype Int {\n  Int(bit_size: gleam.Int, bits: BitArray)\n}\n\npub fn main(not_a_record: gleam.Int) {\n  not_a_record.bits\n}\n\"\n    );\n}\n\n#[test]\nfn qualified_type_invalid_operands() {\n    assert_module_error!(\n        (\"maths\", \"pub type Vector { Vector(x: Float, y: Float) }\"),\n        \"\nimport maths as math\npub fn add_two_vectors(a: math.Vector, b: math.Vector) {\n  a + b\n}\n\"\n    );\n}\n\n#[test]\nfn qualified_type_invalid_pipe_argument() {\n    assert_module_error!(\n        (\n            \"mod\",\n            \"pub type Wibble pub fn takes_wibble(value: Wibble) { value }\"\n        ),\n        \"\nimport mod\npub fn main() {\n  Nil |> mod.takes_wibble\n}\n\"\n    );\n}\n\n#[test]\nfn qualified_type_unification_error() {\n    assert_module_error!(\n        \"\nimport gleam\n\ntype Bool {\n  True\n  False\n}\n\nconst list_of_bools = [True, False, gleam.False]\n\"\n    );\n}\n\n#[test]\nfn qualified_type_not_a_tuple() {\n    assert_module_error!(\n        (\"mod\", \"pub type Pair(a, b) { Pair(a, b) }\"),\n        \"\nimport mod.{type Pair as Duo}\npub fn first(pair: Duo(a, b)) {\n  pair.0\n}\n\"\n    );\n}\n\n#[test]\nfn qualified_type_not_fn_in_use() {\n    assert_module_error!(\n        (\"some_mod\", \"pub type Function(param1, param2, return)\"),\n        \"\nimport some_mod as sm\npub fn main(func: sm.Function(Int, String, Float)) {\n  use <- func()\n}\n\"\n    );\n}\n\n#[test]\nfn qualified_type_use_fn_without_callback() {\n    assert_module_error!(\n        (\n            \"some_mod\",\n            \"pub type NotACallback pub fn do_a_thing(a: Int, _b: NotACallback) { a }\"\n        ),\n        \"\nimport some_mod\npub fn main() {\n  use value <- some_mod.do_a_thing(10)\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_unwrapping_a_result_when_types_match() {\n    assert_module_error!(\n        \"\npub fn main() {\n  let value = Ok(1)\n  add_1(value)\n}\n\nfn add_1(to x) { x + 1 }\n\"\n    );\n}\n\n#[test]\nfn unknown_field_that_appears_in_an_imported_variant_has_note() {\n    assert_module_error!(\n        (\n            \"some_mod\",\n            \"pub type Wibble {\n              Wibble(field: Int)\n              Wobble(not_field: String, field: Int)\n            }\"\n        ),\n        \"\nimport some_mod\npub fn main(wibble: some_mod.Wibble) {\n  wibble.field\n}\n\"\n    );\n}\n\n#[test]\nfn unknown_field_that_appears_in_a_variant_has_note() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(field: Int)\n  Wobble(not_field: String, field: Int)\n}\n\npub fn main(wibble: Wibble) {\n  wibble.field\n}\n\"\n    );\n}\n\n#[test]\nfn unknown_field_that_does_not_appear_in_variant_has_no_note() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(field: Int)\n  Wobble(not_field: String, field: Int)\n}\n\npub fn main(wibble: Wibble) {\n  wibble.wibble\n}\n\"\n    );\n}\n\n#[test]\nfn no_note_about_reliable_access_if_the_accessed_type_has_a_single_variant() {\n    assert_module_error!(\n        \"\npub type User {\n  User(name: String)\n}\n\npub fn main() {\n  User(\\\"Jak\\\").nam\n}\n\"\n    );\n}\n\n#[test]\nfn no_crash_on_duplicate_record_fields() {\n    // https://github.com/gleam-lang/gleam/issues/3713\n    assert_module_error!(\n        \"\npub type X {\n  A\n  B(e0: Int, e0: Int)\n}\n\nfn compiler_crash(x: X) {\n  case x {\n    A -> todo\n    _ -> todo\n  }\n}\n  \"\n    );\n}\n\n#[test]\nfn record_update_unknown_variant() {\n    assert_module_error!(\n        r#\"\npub type Wibble {\n  Wibble(wibble: Int, wubble: Bool)\n  Wobble(wobble: Int, wubble: Bool)\n}\n\npub fn wibble(value: Wibble) {\n  Wibble(..value, wubble: True)\n}\n\"#\n    );\n}\n\n#[test]\nfn record_update_wrong_variant() {\n    assert_module_error!(\n        r#\"\npub type MyRecord {\n  A(common: Int, other: String)\n  B(common: Int, different: Float)\n}\n\npub fn b_to_a(value: MyRecord) {\n  case value {\n    A(..) -> value\n    B(..) as b -> A(..b, other: \"Hi\")\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn record_update_wrong_variant_imported_type() {\n    assert_module_error!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int)\n  Wobble(wobble: Int, wubble: Int)\n}\"\n        ),\n        \"\nimport wibble\n\npub fn main(wibble: wibble.Wibble) {\n  case wibble {\n    wibble.Wibble(..) as w -> wibble.Wobble(..w, wubble: 10)\n    _ -> panic\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inferred_variant_record_update_change_type_parameter_different_branches() {\n    assert_module_error!(\n        r#\"\npub type Box(a) {\n  Locked(password: String, value: a)\n  Unlocked(password: String, value: a)\n}\n\npub fn main() {\n  let box = Locked(\"ungu€$$4bLe\", 11)\n  case box {\n    Locked(..) as box -> Locked(..box, value: True)\n    Unlocked(..) as box -> Unlocked(..box, password: \"pwd\")\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3783\n#[test]\nfn duplicate_fields_in_record_update_reports_error() {\n    assert_module_error!(\n        \"\npub type Wibble { Wibble(thing: Int, other: Int) }\n\npub fn main() {\n  let wibble = Wibble(1, 2)\n  let wobble = Wibble(..wibble, thing: 1, thing: 2)\n}\n\"\n    );\n}\n\n#[test]\nfn record_update_compatible_fields_wrong_variant() {\n    assert_module_error!(\n        r#\"\npub type Wibble {\n  A(a: Int, b: Int)\n  B(a: Int, b: Int)\n}\n\npub fn b_to_a(value: Wibble) {\n  case value {\n    A(..) -> value\n    B(..) as b -> A(..b, b: 3)\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn record_update_compatible_fields_wrong_type() {\n    assert_module_error!(\n        r#\"\npub type A {\n  A(a: Int, b: Int)\n}\n\npub type B {\n  B(a: Int, b: Int)\n}\n\npub fn b_to_a(value: B) {\n  A(..value, b: 5)\n}\n\"#\n    );\n}\n\n#[test]\nfn record_update_incompatible_but_linked_generics() {\n    assert_module_error!(\n        r#\"\npub type Wibble(a) {\n  Wibble(a: a, b: a)\n}\n\npub fn b_to_a(value: Wibble(a)) -> Wibble(Int) {\n  Wibble(..value, a: 5)\n}\n\"#\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3879\nfn inexhaustive_use_reports_error() {\n    assert_error!(\n        r#\"\nuse [1, 2, 3] <- todo\ntodo\n\"#\n    );\n}\n\n#[test]\nfn out_of_range_erlang_float() {\n    assert_error!(r#\"1.8e308\"#);\n}\n\n#[test]\nfn out_of_range_erlang_float_in_pattern() {\n    assert_error!(r#\"let assert [1.8e308, b] = [x, y]\"#);\n}\n\n#[test]\nfn out_of_range_erlang_float_in_const() {\n    assert_module_error!(r#\"const x = 1.8e308\"#);\n}\n\n#[test]\nfn negative_out_of_range_erlang_float() {\n    assert_error!(r#\"-1.8e308\"#);\n}\n\n#[test]\nfn negative_out_of_range_erlang_float_in_pattern() {\n    assert_error!(r#\"let assert [-1.8e308, b] = [x, y]\"#);\n}\n\n#[test]\nfn negative_out_of_range_erlang_float_in_const() {\n    assert_module_error!(r#\"const x = -1.8e308\"#);\n}\n\n#[test]\nfn missing_case_body() {\n    assert_error!(\"case True\");\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_ok_if_types_match() {\n    assert_module_error!(\n        \"\npub fn main() {\n  case todo {\n    1 -> Ok(2)\n    _ -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_ok_if_types_match_2() {\n    assert_module_error!(\n        \"\npub fn main() {\n  wibble(1)\n}\n\nfn wibble(arg: Result(Int, String)) { todo }\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_ok_if_types_match_with_block() {\n    assert_module_error!(\n        \"\npub fn main() {\n  case todo {\n    1 -> Ok(2)\n    _ -> {\n      todo\n      1\n    }\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_ok_with_generic_type() {\n    assert_module_error!(\n        \"\npub fn first(list: List(a)) -> Result(a, Nil) {\n  case list {\n    [] -> Error(Nil)\n    [first, ..rest] -> first\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_ok_if_types_match_with_multiline_result_in_block() {\n    assert_module_error!(\n        \"\npub fn main() {\n  case todo {\n    1 -> Ok(2)\n    _ -> {\n      todo\n      1\n      |> add_1\n    }\n  }\n}\n\nfn add_1(n: Int) { n + 1 }\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_error_if_types_match() {\n    assert_module_error!(\n        \"\npub fn main() {\n  case todo {\n    1 -> Error(1)\n    _ -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_value_into_error_if_types_match_2() {\n    assert_module_error!(\n        \"\npub fn main() {\n    wibble(\\\"a\\\")\n}\n\nfn wibble(arg: Result(Int, String)) { todo }\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_function_return_value_in_ok() {\n    assert_module_error!(\n        \"\npub fn main() -> Result(Int, Bool) {\n  1\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_function_return_value_in_error() {\n    assert_module_error!(\n        \"\npub fn main() -> Result(Int, Bool) {\n  True\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_use_returned_value_in_ok() {\n    assert_module_error!(\n        \"\npub fn main() -> Result(Int, Bool) {\n  use <- want_result\n  1\n}\n\npub fn want_result(wibble: fn() -> Result(Int, Bool)) {\n  todo\n}\n\"\n    );\n}\n\n#[test]\nfn suggest_wrapping_a_use_returned_value_in_error() {\n    assert_module_error!(\n        \"\npub fn main() -> Result(Int, Bool) {\n  use <- want_result\n  False\n}\n\npub fn want_result(wibble: fn() -> Result(Int, Bool)) {\n  todo\n}\n\"\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/4195\nfn let_assert_binding_cannot_be_used_in_panic_message() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let assert Ok(message) = Error(\"Not Message\") as { \"Uh oh: \" <> message }\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression() {\n    assert_error!(\"echo\");\n}\n\n#[test]\nfn echo_followed_by_no_expression_and_message() {\n    assert_error!(\"echo as \\\"wibble\\\"\");\n}\n\n#[test]\nfn echo_followed_by_no_expression_and_invalid_message() {\n    assert_error!(\"echo as 1\");\n}\n\n#[test]\nfn echo_followed_by_invalid_message() {\n    assert_error!(\"echo 11 as { True || False }\");\n}\n\n#[test]\nfn echo_followed_by_no_expression_2() {\n    assert_module_error!(\n        r#\"\n  pub fn wibble(a) { a }\n\n  pub fn main() {\n    wibble(echo)\n  }\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_3() {\n    assert_module_error!(\n        r#\"\n  pub fn main() {\n    echo + 1\n  }\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_4() {\n    assert_module_error!(\n        r#\"\n  pub fn main() {\n    \"wibble\" <> echo\n  }\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_5() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  panic as echo\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_6() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  [echo, 1, 2]\n}\n\"#\n    );\n}\n#[test]\nfn echo_followed_by_no_expression_7() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  #(1, echo)\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_8() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  todo\n  |> fn(_) { echo }\n  |> todo\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_9() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  todo\n  |> { echo }\n  |> todo\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_no_expression_10() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  echo\n  |> todo\n}\n\"#\n    );\n}\n\n#[test]\nfn function_that_does_not_exist_does_not_produce_error_for_labelled_args() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  // We only want to error on `wibble` since it doesn't exist, we don't want\n  // an error on the label at this point!\n  wibble(label: 1)\n}\n\"#\n    );\n}\n\n#[test]\nfn constructor_that_does_not_exist_does_not_produce_error_for_labelled_args() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  // We only want to error on `Wibble` since it doesn't exist, we don't want\n  // an error on the label at this point!\n  Wibble(label: 1)\n}\n\"#\n    );\n}\n\n#[test]\nfn float_operator_on_ints() {\n    assert_error!(\"1 +. 2\");\n}\n\n#[test]\nfn float_operator_on_ints_2() {\n    assert_error!(\"1 <. 2\");\n}\n\n#[test]\nfn int_operator_on_floats() {\n    assert_error!(\"1.1 + 2.0\");\n}\n\n#[test]\nfn int_operator_on_floats_2() {\n    assert_error!(\"1.1 > 2.0\");\n}\n\n#[test]\nfn add_on_strings() {\n    assert_error!(r#\"\"Hello, \" + \"Jak\"\"#);\n}\n\n#[test]\nfn fault_tolerant_list() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  [1, \"a\", 1.0, \"a\" + 1]\n}\n\"#\n    );\n}\n\n#[test]\nfn fault_tolerant_list_tail() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  [1, \"a\", ..[\"a\", \"b\"]]\n}\n\"#\n    );\n}\n\n#[test]\nfn fault_tolerant_negate_bool() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  !!{ True || a }\n}\n\"#\n    );\n}\n\n#[test]\nfn fault_tolerant_negate_int() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  --{ 1 + a }\n}\n\"#\n    );\n}\n\n#[test]\nfn fault_tolerant_tuple() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  #(1, 1 + \"a\", not_in_scope)\n}\n\"#\n    );\n}\n\n#[test]\nfn error_for_missing_type_parameters() {\n    assert_module_error!(\n        r#\"\ntype Wibble(a)\n\ntype Wobble {\n  Wobble(Wibble)\n}\n\"#\n    );\n}\n\n#[test]\nfn double_assignment_in_bit_array() {\n    assert_error!(\"let assert <<a as b>> = <<>>\");\n}\n\n#[test]\nfn negative_size_pattern() {\n    assert_error!(\"let assert <<1:size(-1)>> = <<>>\");\n}\n\n#[test]\nfn zero_size_pattern() {\n    assert_error!(\"let assert <<1:size(0)>> = <<>>\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/3253\n#[test]\nfn bit_array_using_pattern_variables() {\n    assert_error!(\"let assert #(a, <<b:size(a)>>) = #(2, <<2:2>>)\");\n}\n\n#[test]\nfn bit_array_using_pattern_variables_from_other_bit_array() {\n    assert_error!(\"let assert #(<<a>>, <<b:size(a)>>) = #(<<2>>, <<2:2>>)\");\n}\n\n#[test]\nfn non_utf8_string_assignment() {\n    assert_error!(r#\"let assert <<\"Hello\" as message:utf16>> = <<>>\"#);\n}\n\n#[test]\nfn shadowed_function_argument() {\n    assert_module_error!(\n        \"\npub fn go(_x) {\n  x + 1\n}\n\"\n    );\n}\n\n#[test]\nfn shadowed_fn_argument() {\n    assert_module_error!(\n        \"\npub fn go(x) {\n  fn(_y) {\n    y + x\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn shadowed_let_variable() {\n    assert_module_error!(\n        \"\npub fn go() {\n  let _x = 1\n  x + 1\n}\n\"\n    );\n}\n\n#[test]\nfn shadowed_pattern_variable() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn go(x) {\n  case x {\n    Wibble(_y) -> y + 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn do_not_suggest_ignored_variable_outside_of_current_scope() {\n    assert_module_error!(\n        \"\npub fn go() {\n  let _ = {\n    let _y = 1 // <- this shouldn't be highlighted!\n  }\n  y\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4693\n#[test]\nfn pattern_with_incorrect_arity() {\n    assert_module_error!(\n        \"\npub type Pokemon { Pokemon(name: String, id: Int) }\n\npub fn main() {\n  case todo {\n    Pokemon(name:) -> todo\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3884\n#[test]\nfn show_only_missing_labels() {\n    assert_module_error!(\n        \"\nfn wibble(a a: Int, b b: Float, c c: String) {\n    todo\n}\n\npub fn wobble() {\n    wibble(1, 2.0)\n}\n\"\n    );\n}\n#[test]\nfn native_endianness_javascript_target() {\n    assert_js_module_error!(\n        \"\npub fn main() {\n  let assert <<a:native>> = <<10>>\n}\n\"\n    );\n}\n\n#[test]\nfn utf8_codepoint_javascript_target() {\n    assert_js_module_error!(\n        \"\npub fn main() {\n  let assert <<a:utf8_codepoint>> = <<10>>\n}\n\"\n    );\n}\n\n#[test]\nfn utf16_codepoint_javascript_target() {\n    assert_js_module_error!(\n        \"\npub fn main() {\n  let assert <<a:utf16_codepoint>> = <<10>>\n}\n\"\n    );\n}\n\n#[test]\nfn utf32_codepoint_javascript_target() {\n    assert_js_module_error!(\n        \"\npub fn main() {\n  let assert <<a:utf32_codepoint>> = <<10>>\n}\n\"\n    );\n}\n\n#[test]\nfn private_opaque_type() {\n    assert_module_error!(\n        \"\nopaque type Wibble {\n  Wobble\n}\n\"\n    );\n}\n\n#[test]\nfn src_importing_dev_dependency() {\n    assert_module_error!(\n        (\"dev_dependency\", \"some_module\", \"pub fn main() { Nil }\"),\n        \"\nimport some_module\n\npub fn main() {\n  some_module.main()\n}\n\"\n    );\n}\n\n#[test]\nfn missing_type_constructor_arguments_in_type_annotation_1() {\n    assert_module_error!(\"pub fn main() -> Result() {}\");\n}\n\n#[test]\nfn missing_type_constructor_arguments_in_type_annotation_2() {\n    assert_module_error!(\n        \"pub fn main() {\n  let a: Result() = todo\n}\"\n    );\n}\n\n#[test]\nfn type_used_as_a_constructor_1() {\n    assert_module_error!(\"pub fn main() -> Int() {}\");\n}\n\n#[test]\nfn type_used_as_a_constructor_2() {\n    assert_module_error!(\n        \"pub fn main() {\n  let a: Int() = todo\n}\"\n    );\n}\n\n#[test]\nfn type_used_as_a_constructor_with_more_arguments() {\n    assert_module_error!(\n        \"pub fn main() {\n  let a: Int(Int, String) = todo\n}\"\n    );\n}\n\n#[test]\nfn remembering_record_field_when_type_checking_fails() {\n    assert_module_error!(\n        r#\"pub type Wibble {\n  Wibble(x: Int, f: fn(Wobble) -> Int)\n}\n\npub fn wibble() {\n  Wibble(1, fn(_) { 2 })\n}\n\npub fn wobble(wibble: Wibble) {\n  wibble.f\n}\n\npub fn woo(wibble: Wibble) {\n  Wibble(..wibble, x: 1)\n}\"#\n    );\n}\n\n#[test]\nfn external_annotation_on_custom_type_with_constructors() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"gleam_stdlib\", \"dict\")\npub type Dict(key, value) {\n  Dict(pairs: List(#(key, value)))\n}\n\"#\n    );\n}\n\n#[test]\nfn generic_unlabelled_field_in_updated_record_wrong_type() {\n    assert_module_error!(\n        \"\npub type Wibble(a) {\n  Wibble(a, b: Int, c: a)\n}\n\npub fn main() {\n  let w = Wibble(1, 2, 3)\n  Wibble(..w, c: False)\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5296\n#[test]\nfn no_crash_on_record_update_when_constructor_definition_is_invalid() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Int, Bool)\n}\n\npub fn main() {\n  let one = Wibble(False, a: 5, b: 6)\n  let two = Wibble(..one, b: 1)\n}\n        \"\n    );\n}\n\n#[test]\nfn incomplete_pattern_does_not_show_structure_of_internal_type_outside_of_its_module() {\n    assert_module_error!(\n        (\n            \"wibble\",\n            \"@internal\n            pub type Wibble { Wibble Wobble Woo }\"\n        ),\n        \"import wibble.{type Wibble}\n\npub fn go(wibble: Wibble) {\n  case wibble {}\n}\"\n    );\n}\n\n#[test]\nfn incomplete_pattern_does_not_show_structure_of_internal_type_outside_of_its_module_2() {\n    assert_module_error!(\n        (\n            \"wibble\",\n            \"@internal\n            pub type Wibble { Wibble Wobble Woo }\"\n        ),\n        \"import wibble.{type Wibble}\n\npub type Type {\n  Type(wibble: Wibble, list: List(Int))\n}\n\npub fn go(value: Type) {\n  case value {}\n}\"\n    );\n}\n\n#[test]\nfn record_update_does_not_stop_at_first_invalid_field_1() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, c: 1, a: 1.0)\n}\"\n    );\n}\n\n#[test]\nfn record_update_does_not_stop_at_first_invalid_field_2() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: 1.0, a: 2, c: 2)\n}\"\n    );\n}\n\n#[test]\nfn record_update_does_not_stop_at_first_invalid_field_3() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: 1.0, a: 2)\n}\"\n    );\n}\n\n#[test]\nfn record_update_does_not_stop_at_first_invalid_field_4() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: 2, a: 3, b: 1)\n}\"\n    );\n}\n\n#[test]\nfn record_update_does_not_stop_at_first_invalid_field_5() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, b: 1, a: True, c: 2)\n}\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/exhaustiveness.rs",
    "content": "use crate::{assert_error, assert_module_error, assert_no_warnings, assert_warning};\n\n#[test]\nfn whatever() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    _ -> 0\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn nil() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    Nil -> 0\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn bool() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    True -> 1\n    False -> 0\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn bool_true() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    True -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn bool_false() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    False -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(_) -> 1\n    Error(_) -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_ok() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(_) -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_error() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Error(_) -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_nil() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(Nil) -> 1\n    Error(Nil) -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_nil_ok() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(Nil) -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_nil_error() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Error(Nil) -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 3\n    Error(True) -> 2\n    Error(False) -> 4\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_1() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(False) -> 1\n    Error(True) -> 2\n    Error(False) -> 3\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_2() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Error(True) -> 2\n    Error(False) -> 3\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_3() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 2\n    Error(False) -> 3\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_4() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 2\n    Error(True) -> 3\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_5() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_6() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Error(True) -> 1\n    Error(False) -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_7() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Error(True) -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn result_bool_8() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    Ok(False) -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    [_, ..] -> 1\n    [] -> 2\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_empty() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    [] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_non_empty() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    [_, ..] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_one() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    [_] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_one_two() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    [_] -> 1\n    [_, _] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_zero_one_two() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    [] -> 1\n    [_] -> 1\n    [_, _] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_zero_one_two_any() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  case x {\n    [] -> 1\n    [_] -> 1\n    [_, _] -> 1\n    [_, _, ..] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn list_zero_two_any() {\n    assert_module_error!(\n        \"\npub fn main(x) {\n  case x {\n    [] -> 1\n    [_, _] -> 1\n    [_, _, ..] -> 1\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn string() {\n    assert_no_warnings!(\n        r#\"\npub fn main(x) {\n  case x {\n    \"\" -> 1\n    \"a\" -> 1\n    \"b\" -> 1\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn string_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    \"\" -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn string_2() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    \"a\" -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn string_3() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    \"a\" -> 1\n    \"b\" -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array() {\n    assert_no_warnings!(\n        r#\"\npub fn main(x) {\n  case x {\n    <<>> -> 1\n    <<1>> -> 1\n    <<2>> -> 1\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    <<>> -> 1\n    <<1>> -> 1\n    <<2>> -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_2() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    <<>> -> 1\n    <<1>> -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn int() {\n    assert_no_warnings!(\n        r#\"\npub fn main(x) {\n  case x {\n    0 -> 1\n    1 -> 1\n    2 -> 1\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn int_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    0 -> 1\n    1 -> 1\n    2 -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn int_2() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    0 -> 1\n    1 -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn float() {\n    assert_no_warnings!(\n        r#\"\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    1.1 -> 1\n    2.2 -> 1\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn float_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    1.1 -> 1\n    2.2 -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn float_2() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    1.1 -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn list_bool_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    [] -> 1\n    [True] -> 2\n    [_, _, ..] -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn list_bool_2() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  case x {\n    [] -> 1\n    [True] -> 2\n    [_, False] -> 2\n    [_, _, _, ..] -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_all_fields() {\n    assert_no_warnings!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_1() {\n    assert_no_warnings!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: True, ..) -> 1\n    Thing(a: False, ..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_2() {\n    assert_module_error!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: True, ..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_3() {\n    assert_module_error!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: False, ..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_4() {\n    assert_module_error!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: True, ..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_5() {\n    assert_module_error!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: False, ..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn discard_6() {\n    assert_module_error!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(False, ..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn label_1() {\n    assert_module_error!(\n        r#\"\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: False, b: True) -> 1\n    Thing(b: False, a: True) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn guard() {\n    assert_module_error!(\n        r#\"\npub fn main(x, y) {\n  case x {\n    _ if y -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn guard_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x, y) {\n  case x {\n    True if y -> 1\n    False -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn custom_1() {\n    assert_module_error!(\n        r#\"\npub type Type {\n  One\n  Two\n}\n\npub fn main(x) {\n  case x {\n    One -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn custom_2() {\n    assert_module_error!(\n        r#\"\npub type Type {\n  One\n  Two\n  Three(Type)\n}\n\npub fn main(x) {\n  case x {\n    One -> 1\n    Two -> 2\n    Three(One) -> 4\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_1() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    _ -> 1\n    _ -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_2() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    True -> 1\n    False -> 2\n    True -> 3\n  }\n}\n\"#\n    );\n}\n\n//https://github.com/gleam-lang/gleam/issues/2651\n#[test]\nfn redundant_3() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\ncase x {\n59 -> \"gleew\"\n14 -> \"glabber\"\n1 -> \"\"\n_ -> \"glooper\"\n2 -> \"\"\n3 -> \"glen\"\n4 -> \"glew\"\n}\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_4() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\ncase x {\n\"P\" -> 4\n_ -> 3\n\"geeper!\" -> 5\n}\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_5() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\ncase x {\n\"P\" -> 4\n\"\" -> 65\n\"P\" -> 19\n_ -> 3\n}\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_int_with_underscores() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    10 -> \"ten\"\n    1_0 -> \"also ten\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_int_with_multiple_underscores() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    1_000_000 -> \"one million\"\n    1000000 -> \"also one million\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_float_with_different_formatting() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    1.0 -> \"one\"\n    1.00 -> \"also one\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_float_with_no_trailing_decimal() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    1.0 -> \"one\"\n    1. -> \"another one\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_float_with_underscore() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    10.0 -> \"ten\"\n    1_0.0 -> \"also ten\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_float_scientific_notation() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    10.0 -> \"ten\"\n    1.0e1 -> \"also ten\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn redundant_float_scientific_notation_and_underscore() {\n    assert_warning!(\n        r#\"\npub fn main(x) {\n  case x {\n    1.0e2 -> \"one hundred\"\n    1_0_0.0 -> \"one hundred again\"\n    _ -> \"other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn let_1() {\n    assert_module_error!(\n        r#\"\npub fn main(x) {\n  let True = x\n  0\n}\n\"#\n    );\n}\n\n#[test]\nfn tuple_0() {\n    assert_module_error!(\n        r#\"\npub fn main(x, y) {\n  case #(x, y) {\n    #(True, _) -> 1\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2577\n#[test]\nfn nested_type_parameter_usage() {\n    assert_module_error!(\n        r#\"\npub type Returned(a) {\n  Returned(List(a))\n}\n\nfn wibble(user: Returned(#())) -> Int {\n  let Returned([#()]) = user\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn empty_case_of_external() {\n    // This external type has no known constructors, and we want to make sure\n    // that an empty case expression is not valid for it.\n    assert_module_error!(\n        r#\"\npub type Thingy\n\npub fn main(x: Thingy) {\n  case x {\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn empty_case_of_generic() {\n    // This generic type has no known constructors, and we want to make sure\n    // that an empty case expression is not valid for it.\n    assert_module_error!(\n        r#\"\npub fn main(x: something) {\n  case x {\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn reference_absent_type() {\n    // This test is here because this code previously caused the compiler\n    // to crash, and we want to make sure that it doesn't break again\n    assert_module_error!(\n        \"\ntype Wibble {\n    One(Int)\n    Two(Absent)\n}\n\npub fn main(wibble) {\n    case wibble {\n        One(x) -> x\n    }\n}\n\"\n    );\n}\n\n#[test]\nfn case_error_prints_module_names() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport wibble\npub type Things { Thing1 Thing2(Int) }\npub fn main(wobble_thing) {\n    case wobble_thing {\n        #(wibble.Wibble, Thing1) -> Nil\n    }\n}\n\",\n    );\n}\n\n#[test]\nfn case_error_prints_module_alias() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport wibble as wobble\npub fn main(wibble) {\n    case wibble {\n        wobble.Wibble -> Nil\n    }\n}\n\",\n    );\n}\n\n#[test]\nfn case_error_prints_unqualified_value() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport wibble.{Wibble, Wobble}\npub fn main(wibble) {\n    case wibble {\n        Wibble -> Nil\n    }\n}\n\",\n    );\n}\n\n#[test]\nfn case_error_prints_aliased_unqualified_value() {\n    assert_module_error!(\n        (\"wibble\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport wibble.{Wibble, Wobble as Wubble}\npub fn main(wibble) {\n    case wibble {\n        Wibble -> Nil\n    }\n}\n\",\n    );\n}\n\n#[test]\nfn case_error_prints_prelude_module_unqualified() {\n    assert_module_error!(\n        \"\npub fn main(result: Result(Nil, Nil)) {\n  case result {\n    Ok(Nil) -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn case_error_prints_prelude_module_when_shadowed() {\n    assert_module_error!(\n        \"\nimport gleam\ntype MyResult { Ok Error }\npub fn main(res: Result(Int, Nil)) {\n  case res {\n    gleam.Ok(n) -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn case_error_prints_module_when_shadowed() {\n    assert_module_error!(\n        (\"mod\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport mod.{Wibble}\ntype Wibble { Wibble Wobble }\npub fn main() {\n  let wibble = mod.Wibble\n  case wibble {\n    mod.Wobble -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn case_error_prints_module_when_aliased_and_shadowed() {\n    assert_module_error!(\n        (\"mod\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport mod.{Wibble as Wobble}\ntype Wibble { Wobble Wubble }\npub fn main() {\n  let wibble = mod.Wibble\n  case wibble {\n    mod.Wobble -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn case_error_prints_unqualifed_when_aliased() {\n    assert_module_error!(\n        (\"mod\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport mod.{Wibble as Wobble}\ntype Wibble { Wibble Wubble }\npub fn main() {\n  let wibble = mod.Wibble\n  case wibble {\n    mod.Wobble -> Nil\n  }\n}\n\"\n    );\n}\n\n// The following few tests all verify that the compiler provides useful errors\n// when there are no case arms, instead of just suggesting `_` as it did previously.\n#[test]\nfn empty_case_of_bool() {\n    assert_module_error!(\n        \"\npub fn main(b: Bool) {\n  case b {}\n}\n\"\n    );\n}\n\n#[test]\nfn empty_case_of_custom_type() {\n    assert_module_error!(\n        \"\npub type Wibble { Wibble Wobble Wubble }\npub fn main(wibble: Wibble) {\n  case wibble {}\n}\n\"\n    );\n}\n\n#[test]\nfn empty_case_of_list() {\n    assert_error!(\n        \"\nlet list = []\ncase list {}\n\"\n    );\n}\n\n#[test]\nfn empty_case_of_int() {\n    assert_error!(\n        \"\nlet num = 24\ncase num {}\n\"\n    );\n}\n\n#[test]\nfn empty_case_of_float() {\n    assert_error!(\n        \"\nlet age = 10.6\ncase age {}\n\"\n    );\n}\n\n#[test]\nfn empty_case_of_string() {\n    assert_error!(\n        r#\"\nlet name = \"John Doe\"\ncase name {}\n\"#\n    );\n}\n\n#[test]\nfn empty_case_of_multi_pattern() {\n    assert_module_error!(\n        \"\npub fn main(a: Result(a, b), b: Bool) {\n  case a, b {}\n}\n\"\n    );\n}\n\n#[test]\nfn inexhaustive_multi_pattern() {\n    assert_error!(\n        \"\nlet a = Ok(1)\nlet b = True\ncase a, b {\n  Error(_), _ -> Nil\n}\n\"\n    );\n}\n\n#[test]\nfn inexhaustive_multi_pattern2() {\n    assert_module_error!(\n        \"\npub fn main(a: Result(Int, Nil), b: Bool) {\n  case a, b {\n    Ok(1), True -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inexhaustive_multi_pattern3() {\n    assert_error!(\n        \"\nlet a = Ok(1)\nlet b = True\ncase a, b {\n  _, False -> Nil\n}\n\"\n    );\n}\n\n#[test]\nfn inexhaustive_multi_pattern4() {\n    assert_module_error!(\n        \"\npub fn main(c: Bool) {\n  let a = 12\n  let b = 3.14\n  case a, b, c {\n    1, 2.0, True -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inexhaustive_multi_pattern5() {\n    assert_module_error!(\n        \"\npub fn main(c: Bool) {\n  let a = 12\n  let b = 3.14\n  case a, b, c {\n    12, _, False -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn inferred_variant() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble(Bool)\n  Wobble(Int)\n}\n\npub fn main() {\n  let wibble = Wibble(False)\n  case wibble {\n    Wibble(True) -> 1\n    Wibble(False) -> 0\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn inferred_variant2() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main(b: Bool) {\n  let wibble = Wibble\n  case wibble, b {\n    Wibble, True -> True\n    Wibble, False -> False\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn inferred_variant3() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble(Int, Float, Bool)\n  Wobble(String)\n}\n\npub fn main() {\n  let wibble = Wibble(1, 3.14, False)\n  let Wibble(_int, _float, _bool) = wibble\n}\n\",\n    );\n}\n\n#[test]\nfn other_variant_unreachable_when_inferred() {\n    assert_warning!(\n        \"\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  let always_wobble = Wobble\n  case always_wobble {\n    Wibble -> panic\n    Wobble -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn other_variant_unreachable_when_inferred2() {\n    assert_warning!(\n        \"\npub type Wibble {\n  Wibble\n  Wobble\n  Wubble\n}\n\npub fn main() {\n  let always_wobble = Wobble\n  case always_wobble {\n    Wibble | Wubble -> panic\n    Wobble -> Nil\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unreachable_string_pattern_after_prefix() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest -> rest\n    \"wibble\" -> \"a\"\n    _ -> \"b\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn reachable_string_pattern_after_prefix() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest if True -> rest\n    \"wibble\" -> \"a\"\n    _ -> \"b\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn reachable_string_pattern_after_prefix_1() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wibble\" <> rest -> rest\n    \"wib\" -> \"a\"\n    _ -> \"b\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn unreachable_prefix_pattern_after_prefix() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest -> rest\n    \"wibble\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn reachable_prefix_pattern_after_prefix() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest if True -> rest\n    \"wibble\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn reachable_prefix_pattern_after_prefix_1() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wibble\" <> rest -> rest\n    \"wib\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn multiple_unreachable_prefix_patterns() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest -> rest\n    \"wibble\" <> rest -> rest\n    \"wibblest\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn multiple_unreachable_prefix_patterns_1() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest if True -> rest\n    \"wibble\" <> rest -> rest\n    \"wibblest\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_bits_catches_everything() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_:bits>> -> 1\n    <<1>> -> 2\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_bytes_needs_catch_all() {\n    assert_module_error!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_:bytes>> -> 1\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_overlapping_patterns_are_redundant() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<1, a:size(16)>> -> a\n    <<1, b:size(8)-unit(2)>> -> b\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_similar_overlapping_patterns_are_not_redundant() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<1, a:size(16)>> -> a\n    <<2, b:size(8)-unit(2)>> -> b\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_overlapping_redundant_patterns_with_variable_size() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  let len = 3\n  case bit_array {\n    <<a:size(len), _:size(16)>> -> a\n    <<_:size(len), b:size(8)-unit(2)>> -> b\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_overlapping_redundant_patterns_with_variable_size_2() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<len, _:size(len)-unit(3)>> -> 1\n    <<len, _:size(len)-unit(2), 1:size(len)>> -> 2\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_overlapping_patterns_with_variable_size_not_redundant() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<len, 1:size(len)-unit(3)>> -> 1\n    <<len, _:size(len)-unit(2), 1:size(len)>> -> 2\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_patterns_with_different_length_with_same_name_are_not_redundant() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  let len = 10\n  case bit_array {\n    <<_, _:size(len)-unit(3)>> -> 1\n    // Down here len is not the same as the len above, so the branch below is\n    // not redundant!\n    <<len, _:size(len)-unit(3)>> -> 2\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_patterns_with_different_length_with_same_name_are_not_redundant_1() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  let len = 10\n  case bit_array {\n    <<len, _:size(len)-unit(3)>> -> 1\n    // Down here len is not the same as the len above, so the branch below is\n    // not redundant!\n    <<_, _:size(len)-unit(3)>> -> 2\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn bit_array_patterns_with_different_length_with_same_name_are_not_redundant_2() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_, len, _:size(len)>> -> 1\n    // Down here len is not the same as the len above, so the branch below is\n    // not redundant!\n    <<len, _, _:size(len)>> -> 2\n    _ -> 2\n  }\n}\"#\n    );\n}\n\n#[test]\nfn same_catch_all_bytes_are_redundant() {\n    assert_warning!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_:bytes>> -> <<>>\n    <<a:bytes>> -> a\n    _ -> <<>>\n  }\n}\"#\n    );\n}\n\n#[test]\nfn different_catch_all_bytes_are_not_redundant() {\n    assert_no_warnings!(\n        r#\"pub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_, _:bytes>> -> <<>>\n    <<_:bytes>> -> <<>>\n    _ -> <<>>\n  }\n}\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2616\n#[test]\nfn duplicated_alternative_patterns() {\n    assert_warning!(\n        \"\npub fn main() {\n  let x = 1\n  case x {\n    2 | 2 -> 2\n    _ -> panic\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2616\n#[test]\nfn duplicated_pattern_in_alternative() {\n    assert_warning!(\n        \"\npub fn main() {\n  let x = 1\n  case x {\n    2 -> x\n    1 | 2 -> x - 4\n    _ -> panic\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2616\n#[test]\nfn duplicated_pattern_with_multiple_alternatives() {\n    assert_warning!(\n        \"\npub fn main() {\n  let x = 1\n  case x {\n    1 -> 1\n    3 -> 3\n    5 -> 5\n    1 | 2 | 3 | 4 | 5 -> x - 1\n    _ -> panic\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unreachable_multi_pattern() {\n    assert_warning!(\n        \"\npub fn main() {\n  let x = 1\n  let y = 2\n  case x, y {\n    1, 2 -> True\n    1, 2 -> False\n    _, _ -> panic\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unreachable_alternative_multi_pattern() {\n    assert_warning!(\n        \"\npub fn main() {\n  let x = 1\n  let y = 2\n  case x, y {\n    1, 2 -> True\n    3, 4 | 1, 2 -> False\n    _, _ -> panic\n  }\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4586\n#[test]\nfn compiler_does_not_crash_when_defining_duplicate_alternative_variables() {\n    assert_error!(\n        \"\ncase todo {\n  #(a, b) | #(a, a as b) -> todo\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4626\n#[test]\nfn correct_missing_patterns_for_opaque_type() {\n    assert_module_error!(\n        (\n            \"mod\",\n            \"pub opaque type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        \"\nimport mod\n\npub fn main(w: mod.Wibble) {\n  case w {}\n}\n\"\n    );\n}\n\n#[test]\nfn correct_missing_patterns_for_opaque_type_in_definition_module() {\n    assert_module_error!(\n        \"\npub opaque type Wibble { Wibble(Int) Wobble(String) }\n\npub fn main(w: Wibble) {\n  case w {}\n}\n\"\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/4278\nfn redundant_missing_patterns() {\n    assert_module_error!(\n        r#\"\nfn wibble(b: Bool, i: Int) {\n  case b, i {\n    False, 1 -> todo\n    True, 2 -> todo\n  }\n}\n\npub fn main() { wibble(False, 1) }\"#\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/5262\nfn compiler_does_not_crash_when_matching_on_utfcodepoint() {\n    assert_module_error!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/string\",\n            r#\"\n@external(erlang, \"gleam_stdlib\", \"identity\")\nfn unsafe_int_to_utf_codepoint(a: Int) -> UtfCodepoint\n\npub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) {\n  case value {\n    i if i > 1_114_111 -> Error(Nil)\n    i if i >= 55_296 && i <= 57_343 -> Error(Nil)\n    i if i < 0 -> Error(Nil)\n    i -> Ok(unsafe_int_to_utf_codepoint(i))\n  }\n}\n            \"#\n        ),\n        r#\"\nimport gleam/string\n\npub fn main() {\n  let assert Ok(wibble) = string.utf_codepoint(71)\n  case wibble {\n  }\n}        \"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5286\n#[test]\nfn reachable_bit_array_pattern() {\n    assert_no_warnings!(\n        r#\"\npub fn main(x) {\n  case x {\n    <<_, \"==\">> -> 1\n    <<_, _, \"=\">> -> 2\n    // ^^^ This should be reachable\n    _ -> 3\n  }\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/externals.rs",
    "content": "use crate::{\n    assert_js_module_error, assert_js_module_infer, assert_module_error, assert_module_infer,\n};\n\n// https://github.com/gleam-lang/gleam/issues/2324\n#[test]\nfn javascript_only_function_used_by_erlang_module() {\n    let module = r#\"@external(javascript, \"one\", \"two\")\nfn js_only() -> Int\n\npub fn main() {\n  js_only()\n}\n\"#;\n    assert_module_error!(module);\n    assert_js_module_infer!(module, vec![(\"main\", \"fn() -> Int\")]);\n}\n\n#[test]\nfn erlang_only_function_used_by_javascript_module() {\n    let module = r#\"@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n\npub fn main() {\n  erlang_only()\n}\n\"#;\n    assert_js_module_error!(module);\n    assert_module_infer!(module, vec![(\"main\", \"fn() -> Int\")]);\n}\n\n#[test]\nfn unused_javascript_only_function_is_not_rejected_on_erlang_target() {\n    assert_module_infer!(\n        r#\"@external(javascript, \"one\", \"two\")\nfn js_only() -> Int\n\npub fn main() {\n  10\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn unused_erlang_only_function_is_not_rejected_on_javascript_target() {\n    assert_js_module_infer!(\n        r#\"@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n\npub fn main() {\n  10\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn erlang_only_function_with_javascript_external() {\n    let module = r#\"\n@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n\n@external(javascript, \"one\", \"two\")\nfn all_targets() -> Int {\n  erlang_only()\n}\n\npub fn main() {\n  all_targets()\n}\n    \"#;\n\n    let expected = vec![(\"main\", \"fn() -> Int\")];\n\n    assert_module_infer!(module, expected.clone());\n    assert_js_module_infer!(module, expected);\n}\n\n#[test]\nfn javascript_only_function_with_erlang_external() {\n    let module = r#\"\n@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\n\n@external(erlang, \"one\", \"two\")\nfn all_targets() -> Int {\n  javascript_only()\n}\n\npub fn main() {\n  all_targets()\n}\n    \"#;\n\n    let expected = vec![(\"main\", \"fn() -> Int\")];\n\n    assert_module_infer!(module, expected.clone());\n    assert_js_module_infer!(module, expected);\n}\n\n#[test]\nfn javascript_only_function_with_javascript_external() {\n    let module = r#\"@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\n\n@external(javascript, \"one\", \"two\")\npub fn uh_oh() -> Int {\n  javascript_only()\n}\n\"#;\n    assert_js_module_infer!(module, vec![(\"uh_oh\", \"fn() -> Int\")]);\n    assert_module_error!(module);\n}\n\n#[test]\nfn erlang_only_function_with_erlang_external() {\n    let module = r#\"@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n\n@external(erlang, \"one\", \"two\")\npub fn uh_oh() -> Int {\n  erlang_only()\n}\n\"#;\n    assert_js_module_error!(module);\n    assert_module_infer!(module, vec![(\"uh_oh\", \"fn() -> Int\")]);\n}\n\n#[test]\nfn erlang_targeted_function_cant_contain_javascript_only_function() {\n    let module = r#\"@target(erlang)\npub fn erlang_only() -> Int {\n  javascript_only()\n}\n\n@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\n    \"#;\n    assert_js_module_infer!(module, vec![]);\n    assert_module_error!(module);\n}\n\n#[test]\nfn javascript_targeted_function_cant_contain_erlang_only_function() {\n    let module = r#\"@target(javascript)\npub fn javascript_only() -> Int {\n  erlang_only()\n}\n\n@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n    \"#;\n    assert_module_infer!(module, vec![]);\n    assert_js_module_error!(module);\n}\n\n#[test]\nfn imported_javascript_only_function() {\n    assert_module_error!(\n        (\n            \"module\",\n            r#\"@external(javascript, \"one\", \"two\")\npub fn javascript_only() -> Int\"#\n        ),\n        \"import module\npub fn main() {\n  module.javascript_only()\n}\",\n    );\n}\n\n#[test]\nfn javascript_only_constant() {\n    assert_module_error!(\n        (\n            \"module\",\n            r#\"@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\nconst constant = javascript_only\npub const javascript_only_constant = constant\n\"#\n        ),\n        \"import module\npub fn main() {\n  module.javascript_only_constant()\n}\",\n    );\n}\n\n#[test]\nfn public_javascript_external() {\n    let module = r#\"@external(javascript, \"one\", \"two\")\npub fn main() -> Int\n\"#;\n    assert_module_error!(module);\n    assert_js_module_infer!(module, vec![(\"main\", \"fn() -> Int\")]);\n}\n\n#[test]\nfn public_erlang_external() {\n    let module = r#\"@external(erlang, \"one\", \"two\")\npub fn main() -> Int\n\"#;\n    assert_module_infer!(module, vec![(\"main\", \"fn() -> Int\")]);\n    assert_js_module_error!(module);\n}\n\n#[test]\nfn unsupported_target_for_unused_import() {\n    // If we import a function which doesn't support the current target,\n    // even if we don't use it, the compiler should error\n    assert_module_error!(\n        (\n            \"mod\",\n            r#\"@external(javascript, \"wibble\", \"wobble\") pub fn wobble()\"#\n        ),\n        \"import mod.{wobble}\"\n    );\n}\n\n#[test]\nfn supported_target_for_imported_value() {\n    assert_module_infer!(\n        (\n            \"mod\",\n            r#\"@external(erlang, \"wibble\", \"wobble\") pub fn wobble() -> Int\"#\n        ),\n        \"import mod.{wobble}\npub const wobble = wobble\",\n        vec![(\"wobble\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn javascript_mjs() {\n    assert_js_module_infer!(\n        r#\"@external(javascript, \"one.mjs\", \"two\")\npub fn main() -> Int\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn javascript_cjs() {\n    assert_js_module_infer!(\n        r#\"@external(javascript, \"one.cjs\", \"two\")\npub fn main() -> Int\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/functions.rs",
    "content": "use crate::{assert_module_error, assert_module_infer};\n\n// https://github.com/gleam-lang/gleam/issues/1860\n#[test]\nfn unlabelled_after_labelled() {\n    assert_module_error!(\n        \"fn main(wibble wibber, wobber) {\n  Nil\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1860\n#[test]\nfn unlabelled_after_labelled_with_type() {\n    assert_module_error!(\n        \"fn main(wibble wibber, wobber: Int) {\n  Nil\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1860\n#[test]\nfn unlabelled_after_labelled_external() {\n    assert_module_error!(\n        r#\"\n@external(erlang, \"\", \"\")\nfn main(wibble x: Int, y: Int) -> Int\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1860\n#[test]\nfn all_labelled() {\n    assert_module_infer!(\n        r#\"pub fn prepend(to list: List(a), this item: a) -> List(a) {\n  [item, ..list]\n}\n\"#,\n        vec![(r#\"prepend\"#, r#\"fn(List(a), a) -> List(a)\"#)]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1814\n#[test]\nfn out_of_order_generalisation() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  call(fn() {\n    \"Hello\"\n  })\n}\n\nfn call(f: fn() -> a) {\n  f()\n}\n\"#,\n        vec![(r#\"main\"#, r#\"fn() -> String\"#)]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2275\n#[test]\nfn bug_2275() {\n    assert_module_infer!(\n        r#\"\npub fn zero() {\n  one()\n}\n\nfn one() {\n  one()\n  two()\n}\n\nfn two() {\n  two\n  Nil\n}\n\"#,\n        vec![(r#\"zero\"#, r#\"fn() -> Nil\"#)]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2275\n#[test]\nfn bug_2275_2_self_references() {\n    assert_module_infer!(\n        r#\"\npub fn zero() {\n  one()\n}\n\nfn one() {\n  one()\n  two()\n}\n\nfn two() {\n  two\n  two\n  Nil\n}\n\"#,\n        vec![(r#\"zero\"#, r#\"fn() -> Nil\"#)]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2275\n#[test]\nfn bug_2275_again() {\n    assert_module_infer!(\n        r#\"\npub fn aaa(input) {\n  case [] {\n    [] -> input\n\n    _ -> {\n      let input2 = bbb()\n      aaa(input2)\n    }\n  }\n}\n\npub fn bbb() {\n  ccc() + bbb()\n}\n\npub fn ccc() {\n  ccc() + bbb()\n}\n\"#,\n        vec![\n            (r#\"aaa\"#, r#\"fn(Int) -> Int\"#),\n            (r#\"bbb\"#, r#\"fn() -> Int\"#),\n            (r#\"ccc\"#, r#\"fn() -> Int\"#),\n        ]\n    );\n}\n\n#[test]\nfn deprecated_function() {\n    assert_module_infer!(\n        r#\"\n@deprecated(\"use wibble instead\")\npub fn main() {\n  Nil\n}\"#,\n        vec![(r#\"main\"#, r#\"fn() -> Nil\"#)]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2303\n#[test]\nfn recursive_type() {\n    assert_module_error!(\n        r#\"\npub fn one(x) {\n  two([x])\n}\n\npub fn two(x) {\n  one(x)\n}\n\"#\n    );\n}\n\n#[test]\nfn no_impl_function_fault_tolerance() {\n    // A function not having an implementation does not stop analysis.\n    assert_module_error!(\n        r#\"\npub fn no_impl() -> Nil\n\npub type X = UnknownType\n\"#\n    );\n}\n\n#[test]\nfn bad_body_function_fault_tolerance() {\n    // A function having an invalid body does not stop analysis.\n    assert_module_error!(\n        r#\"\npub fn bad(x: Int) -> Float {\n  // Invalid body.\n  \"\" + \"\"\n}\n\npub fn user() -> Float {\n  // This checks that the bad function is still usable, the types coming from\n  // its annotations. This function is valid.\n  bad(1)\n}\n\n// Another bad function to make sure that analysis has not stopped. This error\n// should also be emitted.\npub fn bad_2() {\n  bad(Nil)\n}\n\"#\n    );\n}\n\n#[test]\nfn annotation_mismatch_function_fault_tolerance() {\n    // A function having an invalid body does not stop analysis.\n    assert_module_error!(\n        r#\"\npub fn bad(x: Int) -> Float {\n  // This does not match the return annotation\n  1\n}\n\npub fn user() -> Float {\n  // This checks that the bad function is still usable, the types coming from\n  // its annotations. This function is valid.\n  bad(1)\n}\n\n// Another bad function to make sure that analysis has not stopped. This error\n// should also be emitted.\npub fn bad_2() {\n  bad(Nil)\n}\n\"#\n    );\n}\n\n#[test]\nfn invalid_javascript_external_do_not_stop_analysis() {\n    // Both these have errors! We do not stop on the first one.\n    assert_module_error!(\n        r#\"\n@external(javascript, \"somemodule\", \"() => 123\")\npub fn one() -> Nil {\n  Nil\n}\n\npub fn two() -> Nil {\n  \"\"\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_bad_statement_assignment_fault_tolerance() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let a = 1 + 2.0\n  let b = 3 + 4.0\n  let c = a + b\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_bad_statement_assignment_with_annotation_fault_tolerance() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let a: Int = \"not an int\"\n  let b: String = 1\n  let c = a + 2\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_bad_statement_assignment_with_annotation_fault_tolerance2() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  // Since the value is invalid the type is the annotation\n  let a: Int = Junk\n  let b: String = 1\n  let c = a + 2\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_bad_statement_assignment_with_pattern_fault_tolerance2() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  // Since the pattern is invalid no variable is created\n  let Junk(a) = 7\n  // Pattern is valid but does not type check\n  let Ok(b) = 1\n  let c = a + b\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_bad_statement_expression_fault_tolerance() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  1 + 2.0\n  3 + 4.0\n  let c = 1 + 2\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_incorrect_arg_types_fault_tolerance() {\n    assert_module_error!(\n        r#\"\nfn add(x: Int, y: Int) {\n  x + y\n}\n\npub fn main() {\n  add(1.0, 1.0)\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_incorrect_arity_fault_tolerance() {\n    assert_module_error!(\n        r#\"\nfn add(x: Int, y: Int) {\n  x + y\n}\n\npub fn main() {\n  add(1.0)\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_incorrect_arity_with_labels_fault_tolerance() {\n    assert_module_error!(\n        r#\"\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int) -> Int {\n  arg1() + arg2\n}\n\npub fn main() {\n  wibble(wobble: \"\")\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_incorrect_arity_with_label_shorthand_fault_tolerance() {\n    assert_module_error!(\n        r#\"\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int) -> Int {\n  arg1() + arg2\n}\n\npub fn main() {\n  let wobble = \"\"\n  wibble(wobble:)\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_incorrect_arity_with_labels_fault_tolerance2() {\n    assert_module_error!(\n        r#\"\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int, wabble arg3: Int) -> Int {\n  arg1() + arg2 + arg3\n}\n\npub fn main() {\n  wibble(fn() {\"\"}, wobble: \"\")\n}\n\"#\n    );\n}\n\n#[test]\nfn function_call_incorrect_arity_with_label_shorthand_fault_tolerance2() {\n    assert_module_error!(\n        r#\"\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int, wabble arg3: Int) -> Int {\n  arg1() + arg2 + arg3\n}\n\npub fn main() {\n  let wobble = \"\"\n  wibble(fn() {\"\"}, wobble:)\n}\n\"#\n    );\n}\n\n#[test]\nfn case_clause_pattern_fault_tolerance() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let wibble = True\n  case wibble {\n    True -> 0\n    Wibble -> 1\n    Wibble2 -> 2\n    _ -> 3\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn case_clause_guard_fault_tolerance() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let wibble = True\n  case wibble {\n    a if a == Wibble -> 0\n    b if b == Wibble -> 0\n    _ -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn case_clause_then_fault_tolerance() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let wibble = True\n  case wibble {\n    True -> {\n      1.0 + 1.0\n    }\n    _ -> {\n      1.0 + 1.0\n    }\n  }\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2504\n#[test]\nfn provide_arg_type_to_fn_implicit_ok() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n   let z = #(1,2)\n   fn(x) { x.0 }(z)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn provide_arg_type_to_fn_explicit_ok() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n   let z = #(1,2)\n   fn(x: #(Int, Int)) { x.0 }(z)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn provide_arg_type_to_fn_implicit_error() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n   let z = #(1,2)\n   fn(x) { x.2 }(z)\n}\n\"#\n    );\n}\n\n#[test]\nfn provide_arg_type_to_fn_explicit_error() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n   let z = #(1,2)\n   fn(x: #(Int, Int)) { x.2 }(z)\n}\n\"#\n    );\n}\n\n#[test]\nfn provide_arg_type_to_fn_arg_infer_error() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n   fn(x) { x.2 }(z)\n}\n\"#\n    );\n}\n\n#[test]\nfn provide_arg_type_to_fn_not_a_tuple() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n   let z = \"not a tuple\"\n   fn(x) { x.2 }(z)\n}\n\"#\n    );\n}\n\n#[test]\nfn provide_two_args_type_to_fn() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n   let a = #(1,2)\n   let b = #(1,2)\n   fn(x, y) { x.0 + y.1 }(a, b)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn provide_one_arg_type_to_two_args_fn() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n   let a = #(1,2)\n   fn(x, y) { x.0 + y.1 }(a)\n}\n\"#\n    );\n}\n\n#[test]\nfn provide_two_args_type_to_fn_wrong_types() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n   let a = 1\n   let b = \"not an int\"\n   fn(x, y) { x + y }(a, b)\n}\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/guards.rs",
    "content": "use crate::{assert_module_error, assert_module_infer};\n\n#[test]\nfn nested_record_access() {\n    assert_module_infer!(\n        r#\"\npub type A {\n  A(b: B)\n}\n\npub type B {\n  B(c: C)\n}\n\npub type C {\n  C(d: Bool)\n}\n\npub fn a(a: A) {\n  case a {\n    _ if a.b.c.d -> 1\n    _ -> 0\n  }\n}\n\"#,\n        vec![\n            (\"A\", \"fn(B) -> A\"),\n            (\"B\", \"fn(C) -> B\"),\n            (\"C\", \"fn(Bool) -> C\"),\n            (\"a\", \"fn(A) -> Int\"),\n        ],\n    );\n}\n\n#[test]\nfn string_variable_access() {\n    assert_module_error!(\n        r#\"\npub fn a(a: String) {\n  case a {\n    _ if a.b -> 1\n    _ -> 0\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn qualified_record() {\n    assert_module_infer!(\n        (\"wibble\", \"pub type Wibble { Wibble Wobble }\"),\n        \"\nimport wibble\n\npub fn main(wibble: wibble.Wibble) {\n  case wibble {\n    w if w == wibble.Wobble -> True\n    _ -> False\n  }\n}\n\",\n        vec![(\"main\", \"fn(Wibble) -> Bool\")]\n    );\n}\n\n#[test]\nfn qualified_record_with_arguments() {\n    assert_module_infer!(\n        (\n            \"wibble\",\n            \"pub type Wibble { Wibble(Int) Wobble(Int, Float) }\"\n        ),\n        \"\nimport wibble\n\npub fn main(wibble: wibble.Wibble) {\n  case wibble {\n    w if w == wibble.Wobble(1, 3.8) -> True\n    _ -> False\n  }\n}\n\",\n        vec![(\"main\", \"fn(Wibble) -> Bool\")]\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/imports.rs",
    "content": "use crate::{assert_module_error, assert_module_infer};\n\n// https://github.com/gleam-lang/gleam/issues/1760\n#[test]\nfn import_value_with_same_name_as_imported_module() {\n    assert_module_infer!(\n        (\"other\", \"pub const other = 1\"),\n        \"\nimport other.{other}\npub const a = other\n\",\n        vec![(\"a\", \"Int\")],\n    );\n}\n\n#[test]\nfn imported_constant_record() {\n    assert_module_infer!(\n        (\"one/two\", \"pub type Thing { Thing(Int) }\"),\n        \"\nimport one/two\n\npub const a = two.Thing(1)\n\",\n        vec![(\"a\", \"Thing\")],\n    );\n}\n\n#[test]\nfn using_private_constructor() {\n    assert_module_error!(\n        (\"one\", \"type Two { Two }\"),\n        \"import one\n\npub fn main() {\n  one.Two\n}\",\n    );\n}\n\n#[test]\nfn using_private_constructor_pattern() {\n    assert_module_error!(\n        (\"one\", \"type Two { Two }\"),\n        \"import one\n\npub fn main(x) {\n  let one.Two = x\n}\",\n    );\n}\n\n#[test]\nfn using_opaque_constructor() {\n    assert_module_error!(\n        (\"one\", \"pub opaque type Two { Two }\"),\n        \"import one\n\npub fn main() {\n  one.Two\n}\",\n    );\n}\n\n#[test]\nfn using_private_function() {\n    assert_module_error!(\n        (\"one\", \"fn two() { 2 }\"),\n        \"import one\n\npub fn main() {\n  one.two\n}\",\n    );\n}\n\n#[test]\nfn using_private_type_alias() {\n    assert_module_error!(\n        (\"one\", \"type X = Int\"),\n        \"import one\n\npub fn main() {\n  one.X\n}\",\n    );\n}\n\n#[test]\nfn using_private_unqualified_type_alias() {\n    assert_module_error!(\n        (\"one\", \"type X = Int\"),\n        \"import one.{X}\n\npub fn main() {\n  X\n}\",\n    );\n}\n\n#[test]\nfn using_private_external_type() {\n    assert_module_error!(\n        (\"one\", \"type X\"),\n        \"import one\n\npub fn main() {\n  one.X\n}\",\n    );\n}\n\n#[test]\nfn using_private_unqualified_external_type() {\n    assert_module_error!(\n        (\"one\", \"type X\"),\n        \"import one.{X}\n\npub fn main() {\n  X\n}\",\n    );\n}\n\n#[test]\nfn using_private_custom_type() {\n    assert_module_error!(\n        (\"one\", \"type X { Y }\"),\n        \"import one\n\npub fn main() {\n  one.X\n}\",\n    );\n}\n\n#[test]\nfn using_private_unqualified_custom_type() {\n    assert_module_error!(\n        (\"one\", \"type X { Y }\"),\n        \"import one.{X}\n\npub fn main() {\n  X\n}\",\n    );\n}\n\n#[test]\nfn unqualified_using_private_constructor() {\n    assert_module_error!(\n        (\"one\", \"type Two { Two }\"),\n        \"import one.{Two}\n\npub fn main() {\n  Two\n}\",\n    );\n}\n\n#[test]\nfn unqualified_using_private_constructor_pattern() {\n    assert_module_error!(\n        (\"one\", \"type Two { Two }\"),\n        \"import one.{Two}\n\npub fn main(x) {\n  let Two = x\n}\",\n    );\n}\n\n#[test]\nfn unqualified_using_opaque_constructor() {\n    assert_module_error!(\n        (\"one\", \"pub opaque type Two { Two }\"),\n        \"import one.{Two}\n\npub fn main() {\n  Two\n}\",\n    );\n}\n\n#[test]\nfn unqualified_using_private_function() {\n    assert_module_error!(\n        (\"one\", \"fn two() { 2 }\"),\n        \"import one.{two}\n\npub fn main() {\n  two\n}\",\n    );\n}\n\n#[test]\nfn import_type() {\n    assert_module_infer!(\n        (\"one\", \"pub type One = Int\"),\n        \"import one.{type One}\n\npub fn main() -> One {\n  todo\n}\n\",\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn import_type_duplicate() {\n    assert_module_error!(\n        (\"one\", \"pub type One = Int\"),\n        \"import one.{One, type One}\n\npub fn main() -> One {\n  todo\n}\n\",\n    );\n}\n\n#[test]\nfn import_type_duplicate_with_as() {\n    assert_module_error!(\n        (\"one\", \"pub type One = Int\"),\n        \"import one.{type One as MyOne, type One as MyOne}\n\npub type X = One\n\",\n    );\n}\n\n#[test]\nfn import_type_duplicate_with_as_multiline() {\n    assert_module_error!(\n        (\"one\", \"pub type One = Int\"),\n        \"import one.{\n          type One as MyOne,\n          type One as MyOne\n        }\n\npub type X = One\n\",\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2379\n#[test]\nfn deprecated_type_import_conflict() {\n    assert_module_infer!(\n        (\"one\", \"pub type X { X }\"),\n        \"import one.{X, type X}\",\n        vec![]\n    );\n}\n\n#[test]\nfn aliased_unqualified_type_and_value() {\n    assert_module_infer!(\n        (\"one\", \"pub type X { X }\"),\n        \"import one.{X as XX, type X as XX}\",\n        vec![]\n    );\n}\n\n#[test]\nfn deprecated_type_import_conflict_two_modules() {\n    assert_module_infer!(\n        (\"one\", \"pub type X { X }\"),\n        (\"two\", \"pub type X { X }\"),\n        \"\n        import one.{type X as Y}\n        import two.{X}\n        \",\n        vec![]\n    );\n}\n\n#[test]\nfn imported_constructor_instead_of_type() {\n    assert_module_error!(\n        (\"module\", \"pub type Wibble { Wibble }\"),\n        \"import module.{Wibble}\n\npub fn main(x: Wibble) {\n  todo\n}\",\n    );\n}\n\n#[test]\nfn import_errors_do_not_block_analysis() {\n    // An error in an import doesn't stop the rest of the module being analysed\n    assert_module_error!(\n        \"import unknown_module\n\npub fn main() {\n  1 + Nil\n}\"\n    );\n}\n\n#[test]\nfn unqualified_import_errors_do_not_block_later_unqualified() {\n    assert_module_error!(\n        \"import gleam.{Unknown, type Int as Integer}\n\npub fn main() -> Integer {\n  Nil\n}\"\n    );\n}\n\n#[test]\nfn module_alias_used_as_a_name() {\n    assert_module_error!(\n        (\"one/two\", \"\"),\n        \"\nimport one/two\n\npub fn main() {\n  two\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/let_assert.rs",
    "content": "use crate::{assert_error, assert_infer};\n\n#[test]\nfn empty_list() {\n    assert_infer!(\"let assert [] = [] 1\", \"Int\");\n}\n\n#[test]\nfn list_one() {\n    assert_infer!(\"let assert [a] = [1] a\", \"Int\");\n}\n\n#[test]\nfn list_two() {\n    assert_infer!(\"let assert [a, 2] = [1] a\", \"Int\");\n}\n\n#[test]\nfn list_spread() {\n    assert_infer!(\"let assert [a, ..] = [1] a\", \"Int\");\n}\n\n#[test]\nfn list_spread_discard() {\n    assert_infer!(\"let assert [a, .._] = [1] a\", \"Int\");\n}\n\n#[test]\nfn list_spread_discard_comma_after() {\n    assert_infer!(\"let assert [a, .._,] = [1] a\", \"Int\");\n}\n\n#[test]\nfn in_fn() {\n    assert_infer!(\"fn(x) { let assert [a] = x a }\", \"fn(List(a)) -> a\");\n}\n\n#[test]\nfn in_fn_list_int() {\n    assert_infer!(\"fn(x) { let assert [a] = x a + 1 }\", \"fn(List(Int)) -> Int\");\n}\n\n#[test]\nfn discard_named() {\n    assert_infer!(\"let assert _x = 1 2.0\", \"Float\");\n}\n\n#[test]\nfn discard() {\n    assert_infer!(\"let assert _ = 1 2.0\", \"Float\");\n}\n\n#[test]\nfn tuple() {\n    assert_infer!(\"let assert #(tag, x) = #(1.0, 1) x\", \"Int\");\n}\n\n#[test]\nfn tuple_in_fn() {\n    assert_infer!(\"fn(x) { let assert #(a, b) = x a }\", \"fn(#(a, b)) -> a\");\n}\n\n#[test]\nfn annotation() {\n    assert_infer!(\"let assert 5: Int = 5 5\", \"Int\");\n}\n\n#[test]\nfn new_syntax() {\n    assert_infer!(\"let assert Ok(x) = Error(1)\", \"Result(a, Int)\");\n}\n\n#[test]\nfn expression() {\n    assert_infer!(\"let assert x = 1\", \"Int\");\n}\n\n#[test]\nfn expression1() {\n    assert_infer!(\"let assert x = { let assert x = 1 }\", \"Int\");\n}\n\n#[test]\nfn expression2() {\n    assert_infer!(\"let assert x = { let assert x = 1. }\", \"Float\");\n}\n\n#[test]\nfn expression3() {\n    assert_infer!(\"let assert 1 = 1\", \"Int\");\n}\n\n#[test]\nfn message() {\n    assert_infer!(\n        r#\"\nlet assert Ok(inner) = Ok(10) as \"This clearly never fails\"\ninner\n\"#,\n        \"Int\"\n    );\n}\n\n#[test]\nfn non_string_message() {\n    assert_error!(\"let assert 1 = 2 as 3\");\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/pipes.rs",
    "content": "use crate::{assert_module_error, assert_module_infer, assert_no_warnings};\n\n// https://github.com/gleam-lang/gleam/issues/2392\n#[test]\nfn empty_list() {\n    assert_module_infer!(\n        \"\npub fn a() {\n  fn(_) { Nil }\n}\n\npub fn b(_) {\n  fn(_) { Nil }\n}\n\npub fn c() {\n  Nil\n  |> b(\n    Nil\n    |> a(),\n  )\n}\",\n        vec![\n            (\"a\", \"fn() -> fn(a) -> Nil\"),\n            (\"b\", \"fn(a) -> fn(b) -> Nil\"),\n            (\"c\", \"fn() -> Nil\"),\n        ]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/pull/3406#discussion_r1683068647\n#[test]\nfn pipe_rewrite_with_missing_argument() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  let f = fn(a, b) { fn(c) { a + b + c } }\n  1 |> f(2)\n}\n\"#,\n        vec![(\"main\", \"fn() -> fn(Int) -> Int\")]\n    );\n}\n\n#[test]\nfn pipe_regression_gh3515() {\n    // https://github.com/gleam-lang/gleam/issues/3515\n    assert_module_infer!(\n        r#\"\nfn relu(t) {\n  fn(theta: String) {\n    // use t and theta and return a Float\n    0.0\n  }\n}\n\npub fn k_relu(k: Int) {\n  fn(t: Float) {\n    fn(theta: String) {\n      case k {\n        0 -> t\n        _ -> {\n          // following code is OK on gleam 1.3.2,\n          // but raised error on gleam 1.4.1\n          // The key here is that it is not a direct function call,\n          // but a \"var\" call, which points to the same function.\n          let next_layer = theta |> relu(t) |> k_relu(k - 1)\n          theta |> next_layer\n        }\n      }\n    }\n  }\n}\"#,\n        vec![(\"k_relu\", \"fn(Int) -> fn(Float) -> fn(String) -> Float\")],\n    );\n}\n\n#[test]\nfn pipe_callback_var_function1() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  let f = fn(a) { fn(b) { #(a, b) } }\n  let x = 1 |> f()\n}\n\"#,\n        vec![(\"main\", \"fn() -> fn(a) -> #(Int, a)\")],\n    );\n}\n\n#[test]\nfn pipe_callback_var_function2() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  let f = fn(a) { fn(b) { #(a, b) } }\n  let x = 1 |> f(1)\n}\n\"#,\n        vec![(\"main\", \"fn() -> #(Int, Int)\")],\n    );\n}\n\n#[test]\nfn pipe_callback_correct_arity1() {\n    assert_module_infer!(\n        r#\"\nfn callback(a: Int) {\n  fn() -> String {\n    \"Called\"\n  }\n}\n\npub fn main() {\n  let x = 1 |> callback()\n}\n\"#,\n        vec![(\"main\", \"fn() -> fn() -> String\")],\n    );\n}\n\n#[test]\nfn pipe_callback_correct_arity2() {\n    assert_module_infer!(\n        r#\"\nfn callback(a: Float) {\n  fn(b: Int) -> String {\n    \"Called\"\n  }\n}\n\npub fn main() {\n  let x = 1 |> callback(2.5)\n}\n\"#,\n        vec![(\"main\", \"fn() -> String\")],\n    );\n}\n\n#[test]\nfn pipe_callback_wrong_arity() {\n    assert_module_error!(\n        r#\"\nfn callback(a: Int) {\n  fn() -> String {\n    \"Called\"\n  }\n}\n\npub fn main() {\n  let x = 1 |> callback(2)\n}\n\"#\n    );\n}\n\n#[test]\nfn no_warnings_when_piping_into_labelled_capture_as_first_argument() {\n    assert_no_warnings!(\n        \"\nfn wibble(label1 a, label2 b, lots c, of d, labels e) {\n  a + b * c - d / e\n}\n\npub fn main() {\n  1 |> wibble(label1: _, label2: 2, lots: 3, of: 4, labels: 5)\n}\n\"\n    );\n}\n\n#[test]\nfn no_warnings_when_piping_into_labelled_capture_as_only_argument() {\n    assert_no_warnings!(\n        \"\nfn wibble(descriptive_label value) {\n  value\n}\n\npub fn main() {\n  42 |> wibble(descriptive_label: _)\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/pretty.rs",
    "content": "use std::sync::Arc;\n\nuse crate::type_::{\n    Type,\n    prelude::{bool, int, tuple},\n    pretty::Printer,\n};\n\nuse super::Publicity;\n\nfn print(type_: Arc<Type>) -> String {\n    Printer::new().pretty_print(&type_, 0)\n}\n\nfn custom_bool() -> Arc<Type> {\n    Arc::new(Type::Named {\n        publicity: Publicity::Public,\n        package: \"wibble\".into(),\n        module: \"one/two\".into(),\n        name: \"Bool\".into(),\n        arguments: vec![],\n        inferred_variant: None,\n    })\n}\n\n#[test]\nfn repeated_prelude_type() {\n    insta::assert_snapshot!(print(tuple(vec![int(), int(), int()])));\n}\n\n#[test]\nfn prelude_type_clash_prelude_first() {\n    insta::assert_snapshot!(print(tuple(vec![bool(), custom_bool()])));\n}\n\n#[test]\nfn prelude_type_clash_custom_first() {\n    insta::assert_snapshot!(print(tuple(vec![custom_bool(), bool()])));\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__assert__bool_literal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert True\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert True\n}\n\n\n----- WARNING\nwarning: Assertion of a literal value\n  ┌─ /src/warning/wrn.gleam:3:10\n  │\n3 │   assert True\n  │          ^^^^\n\nAsserting on a literal bool is redundant since you can already tell whether\nit will be `True` or `False`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__assert__comparison_on_literals.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert 1 < 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert 1 < 2\n}\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:3:10\n  │\n3 │   assert 1 < 2\n  │          ^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__assert__equality_check_on_literals.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert 1 == 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert 1 == 2\n}\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:3:10\n  │\n3 │   assert 1 == 2\n  │          ^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__assert__mismatched_types.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/assert.rs\nexpression: assert 10\n---\n----- SOURCE CODE\nassert 10\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:8\n  │\n1 │ assert 10\n  │        ^^\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__assert__negation_of_bool_literal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/assert.rs\nexpression: \"\\npub fn main() {\\n  assert !False\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  assert !False\n}\n\n\n----- WARNING\nwarning: Assertion of a literal value\n  ┌─ /src/warning/wrn.gleam:3:10\n  │\n3 │   assert !False\n  │          ^^^^^^\n\nAsserting on a literal bool is redundant since you can already tell whether\nit will be `True` or `False`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__assert__wrong_message_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/assert.rs\nexpression: assert True as 10\n---\n----- SOURCE CODE\nassert True as 10\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:16\n  │\n1 │ assert True as 10\n  │                ^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__conflict_with_import.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"import wibble.{type A} type A { C }\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type A { B }\n\n-- main.gleam\nimport wibble.{type A} type A { C }\n\n----- ERROR\nerror: Duplicate type definition\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ import wibble.{type A} type A { C }\n  │                ------  ^^^^^^ Redefined here\n  │                │        \n  │                First defined here\n\nThe type `A` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\n@deprecated(\\\"2\\\")\\npub type Numbers {\\n  @deprecated(\\\"1\\\")\\n  One\\n  Two\\n}\\n\\npub fn num() {\\n  let _two = Two\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\n@deprecated(\"2\")\npub type Numbers {\n  @deprecated(\"1\")\n  One\n  Two\n}\n\npub fn num() {\n  let _two = Two\n  Nil\n}\n\n\n----- ERROR\nerror: Custom type already deprecated\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   One\n  │   ^^^\n\nThis custom type has already been deprecated, so deprecating one of its\nvariants does nothing.\nConsider removing the deprecation attribute on the variant.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\npub type Numbers {\\n  @deprecated(\\\"1\\\")\\n  One\\n  @deprecated(\\\"2\\\")\\n  Two\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Numbers {\n  @deprecated(\"1\")\n  One\n  @deprecated(\"2\")\n  Two\n}\n\n\n----- ERROR\nerror: All variants of custom type deprecated.\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ pub type Numbers {\n  │ ^^^^^^^^^^^^^^^^\n\nConsider deprecating the type as a whole.\n\n  @deprecated(\"message\")\n  type Wibble {\n    Wobble1\n    Wobble2\n  }\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\n@deprecated(\\\"Dont use this!\\\")\\npub type Cat {\\n  Cat(name: String, cuteness: Int)\\n}\\n\\npub fn name() -> String {\\n  let c = Cat(\\\"Numi\\\", 20)\\n  c.name\\n}\\n        \"\n---\n----- SOURCE CODE\n\n@deprecated(\"Dont use this!\")\npub type Cat {\n  Cat(name: String, cuteness: Int)\n}\n\npub fn name() -> String {\n  let c = Cat(\"Numi\", 20)\n  c.name\n}\n        \n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:8:11\n  │\n8 │   let c = Cat(\"Numi\", 20)\n  │           ^^^ This value has been deprecated\n\nIt was deprecated with this message: Dont use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\npub type Numbers {\\n  @deprecated(\\\"1\\\")\\n  One\\n  Two\\n}\\n\\npub fn num() {\\n  let _one = One\\n  let _two = Two\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Numbers {\n  @deprecated(\"1\")\n  One\n  Two\n}\n\npub fn num() {\n  let _one = One\n  let _two = Two\n  Nil\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:9:14\n  │\n9 │   let _one = One\n  │              ^^^ This value has been deprecated\n\nIt was deprecated with this message: 1\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__duplicate_variable_error_does_not_stop_analysis.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\ntype Two(a, a) {\\n  Two(a, a)\\n}\\n\\ntype Three(a, a) {\\n  Three\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Two(a, a) {\n  Two(a, a)\n}\n\ntype Three(a, a) {\n  Three\n}\n\n\n----- ERROR\nerror: Duplicate type parameter\n  ┌─ /src/one/two.gleam:2:13\n  │\n2 │ type Two(a, a) {\n  │             ^\n\nThis definition has multiple type parameters named `a`.\nRename or remove one of them.\n\nerror: Duplicate type parameter\n  ┌─ /src/one/two.gleam:6:15\n  │\n6 │ type Three(a, a) {\n  │               ^\n\nThis definition has multiple type parameters named `a`.\nRename or remove one of them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\npub type Cat {\\n  Cat(UnknownType)\\n}\\n\\npub type Kitten = AnotherUnknownType\\n        \"\n---\n----- SOURCE CODE\n\npub type Cat {\n  Cat(UnknownType)\n}\n\npub type Kitten = AnotherUnknownType\n        \n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   Cat(UnknownType)\n  │       ^^^^^^^^^^^\n\nThe type `UnknownType` is not defined or imported in this module.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:6:19\n  │\n6 │ pub type Kitten = AnotherUnknownType\n  │                   ^^^^^^^^^^^^^^^^^^\n\nThe type `AnotherUnknownType` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__pattern_match_correct_labeled_field.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\ntype Fish {\\n  Starfish()\\n  Jellyfish(name: String, jiggly: Bool)\\n}\\n\\nfn handle_fish(fish: Fish) {\\n  case fish {\\n    Starfish() -> False\\n    Jellyfish(jiggly:) -> jiggly  // <- error is here\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Fish {\n  Starfish()\n  Jellyfish(name: String, jiggly: Bool)\n}\n\nfn handle_fish(fish: Fish) {\n  case fish {\n    Starfish() -> False\n    Jellyfish(jiggly:) -> jiggly  // <- error is here\n  }\n}\n\n\n----- ERROR\nerror: Incorrect arity\n   ┌─ /src/one/two.gleam:10:5\n   │\n10 │     Jellyfish(jiggly:) -> jiggly  // <- error is here\n   │     ^^^^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\nThis pattern accepts these additional labelled arguments:\n\n  - name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__pattern_match_correct_pos_field.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/custom_types.rs\nexpression: \"\\ntype Fish {\\n  Starfish()\\n  Jellyfish(String, Bool)\\n}\\n\\nfn handle_fish(fish: Fish) {\\n  case fish {\\n    Starfish() -> False\\n    Jellyfish(jiggly) -> jiggly\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Fish {\n  Starfish()\n  Jellyfish(String, Bool)\n}\n\nfn handle_fish(fish: Fish) {\n  case fish {\n    Starfish() -> False\n    Jellyfish(jiggly) -> jiggly\n  }\n}\n\n\n----- ERROR\nerror: Incorrect arity\n   ┌─ /src/one/two.gleam:10:5\n   │\n10 │     Jellyfish(jiggly) -> jiggly\n   │     ^^^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\n\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:10:5\n   │\n10 │     Jellyfish(jiggly) -> jiggly\n   │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__constant_only_referenced_by_unused_constant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nconst value = 10\\n\\nconst value_twice = #(value, value)\\n\"\n---\n----- SOURCE CODE\n\nconst value = 10\n\nconst value_twice = #(value, value)\n\n\n----- WARNING\nwarning: Unused private constant\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ const value = 10\n  │ ^^^^^^^^^^^ This private constant is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private constant\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ const value_twice = #(value, value)\n  │ ^^^^^^^^^^^^^^^^^ This private constant is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__constant_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nconst value = 10\\n\\nfn unused() {\\n  value\\n}\\n\"\n---\n----- SOURCE CODE\n\nconst value = 10\n\nfn unused() {\n  value\n}\n\n\n----- WARNING\nwarning: Unused private constant\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ const value = 10\n  │ ^^^^^^^^^^^ This private constant is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__constructor_used_if_type_alias_shadows_it.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{Wibble}\\n\\ntype Wibble =\\n  wibble.Wibble\\n\\npub fn main() {\\n  Wibble(\\\"hello\\\")\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble(String)\n}\n\n\n-- main.gleam\n\nimport wibble.{Wibble}\n\ntype Wibble =\n  wibble.Wibble\n\npub fn main() {\n  Wibble(\"hello\")\n}\n\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:4:1\n  │  \n4 │ ╭ type Wibble =\n5 │ │   wibble.Wibble\n  │ ╰───────────────^ This private type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_alias_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble as wobble\\n\\nfn unused() {\\n  wobble.Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble(Int)\n}\n\n\n-- main.gleam\n\nimport wibble as wobble\n\nfn unused() {\n  wobble.Wibble\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_alias_only_referenced_by_unused_function_with_unqualified.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{type Wibble} as wobble\\n\\nfn unused() {\\n  wobble.Wibble\\n}\\n\\npub fn main() -> Wibble {\\n  panic\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble(Int)\n}\n\n\n-- main.gleam\n\nimport wibble.{type Wibble} as wobble\n\nfn unused() {\n  wobble.Wibble\n}\n\npub fn main() -> Wibble {\n  panic\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_marked_unused_when_shadowed_in_record_access.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble\\n\\ntype Wibble {\\n  Wibble(wobble: Int)\\n}\\n\\npub fn main() {\\n  let wibble = Wibble(10)\\n  // This does not reference the `wibble` module!\\n  wibble.wobble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub const wibble = 1\n\n\n-- main.gleam\n\nimport wibble\n\ntype Wibble {\n  Wibble(wobble: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(10)\n  // This does not reference the `wibble` module!\n  wibble.wobble\n}\n\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import wibble\n  │ ^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble\\n\\nfn unused() {\\n  wibble.Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble(Int)\n}\n\n\n-- main.gleam\n\nimport wibble\n\nfn unused() {\n  wibble.Wibble\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_type_and_constructor_with_same_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{type Wibble, Wibble}\\n\\npub fn main() {\\n  Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble\n}\n\n\n-- main.gleam\n\nimport wibble.{type Wibble, Wibble}\n\npub fn main() {\n  Wibble\n}\n\n\n----- WARNING\nwarning: Unused imported type\n  ┌─ /src/warning/wrn.gleam:2:16\n  │\n2 │ import wibble.{type Wibble, Wibble}\n  │                ^^^^^^^^^^^ This imported type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_type_and_constructor_with_same_name2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{type Wibble, Wibble}\\n\\npub fn main() -> Wibble {\\n  wibble.Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble\n}\n\n\n-- main.gleam\n\nimport wibble.{type Wibble, Wibble}\n\npub fn main() -> Wibble {\n  wibble.Wibble\n}\n\n\n----- WARNING\nwarning: Unused imported item\n  ┌─ /src/warning/wrn.gleam:2:29\n  │\n2 │ import wibble.{type Wibble, Wibble}\n  │                             ^^^^^^ This imported constructor is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_type_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{type Wibble}\\n\\nfn unused() -> Wibble {\\n  panic\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble\n\n\n-- main.gleam\n\nimport wibble.{type Wibble}\n\nfn unused() -> Wibble {\n  panic\n}\n\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import wibble.{type Wibble}\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() -> Wibble {\n  │ ^^^^^^^^^^^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_value_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{Wibble}\\n\\nfn unused() {\\n  Wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble(Int)\n}\n\n\n-- main.gleam\n\nimport wibble.{Wibble}\n\nfn unused() {\n  Wibble\n}\n\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import wibble.{Wibble}\n  │ ^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__local_variable_marked_unused_when_shadowed_in_module_access.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  let wibble = 10\\n  // This does not reference the `wibble` variable!\\n  wibble.wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub const wibble = 1\n\n\n-- main.gleam\n\nimport wibble\n\npub fn main() {\n  let wibble = 10\n  // This does not reference the `wibble` variable!\n  wibble.wibble\n}\n\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:5:7\n  │\n5 │   let wibble = 10\n  │       ^^^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `_wibble`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__private_type_alias_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\ntype Wibble = Int\\n\\nfn unused() -> Wibble {\\n  10\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble = Int\n\nfn unused() -> Wibble {\n  10\n}\n\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ type Wibble = Int\n  │ ^^^^^^^^^^^^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ fn unused() -> Wibble {\n  │ ^^^^^^^^^^^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__private_type_alias_underlying_type_referenced_by_public_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\ntype Wibble = Int\\n\\npub fn used() -> Int {\\n  10\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble = Int\n\npub fn used() -> Int {\n  10\n}\n\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ type Wibble = Int\n  │ ^^^^^^^^^^^^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__shadowed_imported_value_marked_unused.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{wibble}\\n\\npub const wibble = 2\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub const wibble = 1\n\n\n-- main.gleam\n\nimport wibble.{wibble}\n\npub const wibble = 2\n\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import wibble.{wibble}\n  │ ^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n\nwarning: Shadowed Import\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ pub const wibble = 2\n  │ ^^^^^^^^^^^^^^^^ `wibble` is defined here\n\nDefinition of wibble shadows an imported value.\nThe imported value could not be used in this module anyway.\nHint: Either rename the definition or remove the import.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__type_and_variant_unused.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\ntype PrivateType {\\n  PrivateConstructor\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype PrivateType {\n  PrivateConstructor\n}\n\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ type PrivateType {\n  │ ^^^^^^^^^^^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private constructor\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   PrivateConstructor\n  │   ^^^^^^^^^^^^^^^^^^ This private constructor is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__type_variant_only_referenced_by_unused_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\ntype Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\nfn unused() {\\n  Wibble\\n}\\n\\npub fn used() {\\n  let _ = Wobble\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble\n  Wobble\n}\n\nfn unused() {\n  Wibble\n}\n\npub fn used() {\n  let _ = Wobble\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused private constructor\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   Wibble\n  │   ^^^^^^ This private constructor is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:7:1\n  │\n7 │ fn unused() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__unused_mutually_recursive_functions.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nfn wibble(value: Int) -> Int {\\n  wobble(value)\\n}\\n\\nfn wobble(value: Int) -> Int {\\n  wibble(value)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(value: Int) -> Int {\n  wobble(value)\n}\n\nfn wobble(value: Int) -> Int {\n  wibble(value)\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ fn wibble(value: Int) -> Int {\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:6:1\n  │\n6 │ fn wobble(value: Int) -> Int {\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__unused_recursive_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nfn unused(value: Int) -> Int {\\n  case value {\\n    0 -> 0\\n    _ -> unused(value - 1)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn unused(value: Int) -> Int {\n  case value {\n    0 -> 0\n    _ -> unused(value - 1)\n  }\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ fn unused(value: Int) -> Int {\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__unused_type_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\ntype Wibble = Int\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble = Int\n\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ type Wibble = Int\n  │ ^^^^^^^^^^^^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__used_shadowed_imported_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/dead_code_detection.rs\nexpression: \"\\nimport wibble.{wibble}\\n\\npub const wibble = wibble\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub const wibble = 1\n\n\n-- main.gleam\n\nimport wibble.{wibble}\n\npub const wibble = wibble\n\n\n----- WARNING\nwarning: Shadowed Import\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ pub const wibble = wibble\n  │ ^^^^^^^^^^^^^^^^ `wibble` is defined here\n\nDefinition of wibble shadows an imported value.\nThe imported value could not be used in this module anyway.\nHint: Either rename the definition or remove the import.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__access_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let x = 1 x.whatever\n---\n----- SOURCE CODE\nlet x = 1 x.whatever\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let x = 1 x.whatever\n  │             ^^^^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Int\n\nIt does not have any fields.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__accessor_multiple_variants_multiple_positions.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: String, title: String, age: Int)\\n    Student(name: String, age: Int)\\n}\\npub fn get_name(person: Person) { person.name }\\npub fn get_age(person: Person) { person.age }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, title: String, age: Int)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:7:41\n  │\n7 │ pub fn get_age(person: Person) { person.age }\n  │                                         ^^^ Did you mean `name`?\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .name\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__accessor_multiple_variants_multiple_positions2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n    Teacher(title: String, age: Int, name: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_name(person: Person) { person.name }\\npub fn get_age(person: Person) { person.age }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(title: String, age: Int, name: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:6:42\n  │\n6 │ pub fn get_name(person: Person) { person.name }\n  │                                          ^^^^ Did you mean `age`?\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .age\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__add_f_int_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1 +. 1.0\n---\n----- SOURCE CODE\n1 +. 1.0\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ 1 +. 1.0\n  │ ^\n\nThe +. operator expects arguments of this type:\n\n    Float\n\nBut this argument has this type:\n\n    Int\n\nHint: the + operator can be used with Ints\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__add_int_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1 + 1.0\n---\n----- SOURCE CODE\n1 + 1.0\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ 1 + 1.0\n  │     ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__add_on_strings.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\\"Hello, \\\" + \\\"Jak\\\"\"\n---\n----- SOURCE CODE\n\"Hello, \" + \"Jak\"\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ \"Hello, \" + \"Jak\"\n  │           ^ Use <> instead\n\nThe + operator can only be used on Ints.\nTo join two strings together you can use the <> operator.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__ambiguous_import_error_no_unqualified.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import wibble/sub\\n        import wibble2/sub\\n        pub fn main() {\\n            sub.wobble()\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- wibble/sub.gleam\npub fn wobble() { 1 }\n\n-- wibble2/sub.gleam\npub fn wobble() { 1 }\n\n-- main.gleam\n\n        import wibble/sub\n        import wibble2/sub\n        pub fn main() {\n            sub.wobble()\n        }\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import wibble/sub\n  │         ----------------- First imported here\n3 │         import wibble2/sub\n  │         ^^^^^^^^^^^^^^^^^^ Reimported here\n\n`sub` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__ambiguous_import_error_with_unqualified.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import wibble/sub\\n        import wibble2/sub.{wobble}\\n        pub fn main() {\\n            sub.wobble()\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- wibble/sub.gleam\npub fn wobble() { 1 }\n\n-- wibble2/sub.gleam\npub fn wobble() { 1 }\n\n-- main.gleam\n\n        import wibble/sub\n        import wibble2/sub.{wobble}\n        pub fn main() {\n            sub.wobble()\n        }\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import wibble/sub\n  │         ----------------- First imported here\n3 │         import wibble2/sub.{wobble}\n  │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Reimported here\n\n`sub` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__ambiguous_type_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"import wibble pub type Thing { Thing }\\n        pub fn main() {\\n            [Thing] == [wibble.Thing]\\n        }\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Thing { Thing }\n\n-- main.gleam\nimport wibble pub type Thing { Thing }\n        pub fn main() {\n            [Thing] == [wibble.Thing]\n        }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:24\n  │\n3 │             [Thing] == [wibble.Thing]\n  │                        ^^^^^^^^^^^^^^\n\nExpected type:\n\n    List(Thing)\n\nFound type:\n\n    List(wibble.Thing)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__assigned_function_annotation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let f = fn(x: Int) { x } f(1.0)\"\n---\n----- SOURCE CODE\nlet f = fn(x: Int) { x } f(1.0)\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ let f = fn(x: Int) { x } f(1.0)\n  │                            ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_binary.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<a:bytes>> if a > 1 -> 1 _ -> 2 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<a:bytes>> if a > 1 -> 1 _ -> 2 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ case <<1>> { <<a:bytes>> if a > 1 -> 1 _ -> 2 }\n  │                             ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    BitArray\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_bits_option_in_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<<<1:1>>:bytes>> x\"\n---\n----- SOURCE CODE\nlet x = <<<<1:1>>:bytes>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:19\n  │\n1 │ let x = <<<<1:1>>:bytes>> x\n  │                   ^^^^^ This option is only allowed in BitArray patterns\n\nHint: This option has no effect in BitArray values.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<a:float>> if a > 1 -> 1 _ -> 2 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<a:float>> if a > 1 -> 1 _ -> 2 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ case <<1>> { <<a:float>> if a > 1 -> 1 _ -> 2 }\n  │                             ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_float_size.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:8-float>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:8-float>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let x = <<1:8-float>> x\n  │             ^ Invalid float size\n\nHint: floats have an exact size of 16/32/64 bits.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<a:utf16_codepoint>> if a == \\\"test\\\" -> 1 _ -> 2 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<a:utf16_codepoint>> if a == \"test\" -> 1 _ -> 2 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:39\n  │\n1 │ case <<1>> { <<a:utf16_codepoint>> if a == \"test\" -> 1 _ -> 2 }\n  │                                       ^^^^^^^^^^^\n\nExpected type:\n\n    UtfCodepoint\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_invalid_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn x() { \\\"test\\\" }\\n\\nfn main() {\\n    let a = <<1:size(x())>>\\n    a\\n}\"\n---\n----- SOURCE CODE\nfn x() { \"test\" }\n\nfn main() {\n    let a = <<1:size(x())>>\n    a\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:22\n  │\n4 │     let a = <<1:size(x())>>\n  │                      ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_conflicting_endianness1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:big-little>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:big-little>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ let x = <<1:big-little>> x\n  │                 ^^^^^^ This is an extra endianness specifier\n\nHint: This segment already has an endianness of big.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_conflicting_endianness2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:native-big>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:native-big>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:25\n  │\n1 │ case <<1>> { <<1:native-big>> -> 1 }\n  │                         ^^^ This is an extra endianness specifier\n\nHint: This segment already has an endianness of native.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_conflicting_options_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:bits-bytes>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:bits-bytes>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:23\n  │\n1 │ case <<1>> { <<1:bits-bytes>> -> 1 }\n  │                       ^^^^^ This is an extra type specifier\n\nHint: This segment already has the type bits.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_conflicting_options_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:int-bytes>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:int-bytes>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ let x = <<1:int-bytes>> x\n  │                 ^^^^^ This is an extra type specifier\n\nHint: This segment already has the type int.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_conflicting_signedness1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:signed-unsigned>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:signed-unsigned>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:20\n  │\n1 │ let x = <<1:signed-unsigned>> x\n  │                    ^^^^^^^^ This is an extra signedness specifier\n\nHint: This segment already has a signedness of signed.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_conflicting_signedness2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:unsigned-signed>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:unsigned-signed>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:27\n  │\n1 │ case <<1>> { <<1:unsigned-signed>> -> 1 }\n  │                           ^^^^^^ This is an extra signedness specifier\n\nHint: This segment already has a signedness of unsigned.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_nosize.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<_:bytes, _:bytes>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<_:bytes, _:bytes>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ case <<1>> { <<_:bytes, _:bytes>> -> 1 }\n  │                  ^^^^^ This segment has no size\n\nHint: Bit array segments without a size are only allowed at the end of a\nbin pattern.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_nosize2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<_:bits, _:bytes>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<_:bits, _:bytes>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ case <<1>> { <<_:bits, _:bytes>> -> 1 }\n  │                  ^^^^ This segment has no size\n\nHint: Bit array segments without a size are only allowed at the end of a\nbin pattern.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_nosize3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<_:bytes, _:bits>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<_:bytes, _:bits>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ case <<1>> { <<_:bytes, _:bits>> -> 1 }\n  │                  ^^^^^ This segment has no size\n\nHint: Bit array segments without a size are only allowed at the end of a\nbin pattern.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_size.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:8-size(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:8-size(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ let x = <<1:8-size(5)>> x\n  │               ^^^^^^^ This is an extra size specifier\n\nHint: This segment already has a size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_size2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:size(2)-size(8)>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:size(2)-size(8)>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ case <<1>> { <<1:size(2)-size(8)>> -> 1 }\n  │                          ^^^^^^^ This is an extra size specifier\n\nHint: This segment already has a size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_aliased_variable_string.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }\"\n---\n----- SOURCE CODE\ncase <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }\n  │               ^^^^^^^^^^^ This cannot be a variable\n\nHint: in patterns utf8, utf16, and utf32  must be an exact string.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_size_utf16.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf16-size(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf16-size(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:19\n  │\n1 │ let x = <<1:utf16-size(5)>> x\n  │                   ^^^^^^^ Size cannot be specified here\n\nHint: utf16 segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_size_utf32.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:utf32-size(5)>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:utf32-size(5)>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ case <<1>> { <<1:utf32-size(5)>> -> 1 }\n  │                        ^^^^^^^ Size cannot be specified here\n\nHint: utf32 segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_size_utf8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf8-size(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf8-size(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ let x = <<1:utf8-size(5)>> x\n  │                  ^^^^^^^ Size cannot be specified here\n\nHint: utf8 segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_codepoint_utf16.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf16_codepoint-unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf16_codepoint-unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ let x = <<1:utf16_codepoint-unit(5)>> x\n  │                             ^^^^^^^ Unit cannot be specified here\n\nHint: utf16_codepoint segments are sized based on their value and cannot\nhave a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_codepoint_utf16_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf16_codepoint-size(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf16_codepoint-size(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ let x = <<1:utf16_codepoint-size(5)>> x\n  │                             ^^^^^^^ Size cannot be specified here\n\nHint: utf16_codepoint segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_codepoint_utf32.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:utf32_codepoint-unit(2)>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:utf32_codepoint-unit(2)>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:34\n  │\n1 │ case <<1>> { <<1:utf32_codepoint-unit(2)>> -> 1 }\n  │                                  ^^^^^^^ Unit cannot be specified here\n\nHint: utf32_codepoint segments are sized based on their value and cannot\nhave a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_codepoint_utf32_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:utf32_codepoint-size(5)>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:utf32_codepoint-size(5)>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:34\n  │\n1 │ case <<1>> { <<1:utf32_codepoint-size(5)>> -> 1 }\n  │                                  ^^^^^^^ Size cannot be specified here\n\nHint: utf32_codepoint segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_codepoint_utf8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf8_codepoint-unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf8_codepoint-unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ let x = <<1:utf8_codepoint-unit(5)>> x\n  │                            ^^^^^^^ Unit cannot be specified here\n\nHint: utf8_codepoint segments are sized based on their value and cannot\nhave a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_codepoint_utf8_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf8_codepoint-size(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf8_codepoint-size(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ let x = <<1:utf8_codepoint-size(5)>> x\n  │                            ^^^^^^^ Size cannot be specified here\n\nHint: utf8_codepoint segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_utf16.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf16-unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf16-unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:19\n  │\n1 │ let x = <<1:utf16-unit(5)>> x\n  │                   ^^^^^^^ Unit cannot be specified here\n\nHint: utf16 segments are sized based on their value and cannot have a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_utf32.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<1>> { <<1:utf32-unit(2)>> -> 1 }\"\n---\n----- SOURCE CODE\ncase <<1>> { <<1:utf32-unit(2)>> -> 1 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ case <<1>> { <<1:utf32-unit(2)>> -> 1 }\n  │                        ^^^^^^^ Unit cannot be specified here\n\nHint: utf32 segments are sized based on their value and cannot have a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_unit_utf8_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:utf8-unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:utf8-unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ let x = <<1:utf8-unit(5)>> x\n  │                  ^^^^^^^ Unit cannot be specified here\n\nHint: utf8 segments are sized based on their value and cannot have a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_type_does_not_allow_variable_string.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case <<>> { <<a:utf8>> -> 1 _ -> 2 }\"\n---\n----- SOURCE CODE\ncase <<>> { <<a:utf8>> -> 1 _ -> 2 }\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ case <<>> { <<a:utf8>> -> 1 _ -> 2 }\n  │               ^^^^^^ This cannot be a variable\n\nHint: in patterns utf8, utf16, and utf32  must be an exact string.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_unit_no_size.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let x = <<1:unit(5)>> x\n  │             ^^^^^^^ This needs an explicit size\n\nHint: If you specify unit() you must also specify size().\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_segment_unit_unit.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:unit(2)-unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:unit(2)-unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ let x = <<1:unit(2)-unit(5)>> x\n  │                     ^^^^^^^ This is an extra unit specifier\n\nHint: A BitArray segment can have at most 1 unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_size_not_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<1:size(\\\"1\\\")>> x\"\n---\n----- SOURCE CODE\nlet x = <<1:size(\"1\")>> x\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ let x = <<1:size(\"1\")>> x\n  │                  ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_size_not_int_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let a = 2.0 case <<1>> { <<1:size(a)>> -> a }\"\n---\n----- SOURCE CODE\nlet a = 2.0 case <<1>> { <<1:size(a)>> -> a }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:35\n  │\n1 │ let a = 2.0 case <<1>> { <<1:size(a)>> -> a }\n  │                                   ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_using_pattern_variables.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert #(a, <<b:size(a)>>) = #(2, <<2:2>>)\"\n---\n----- SOURCE CODE\nlet assert #(a, <<b:size(a)>>) = #(2, <<2:2>>)\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ let assert #(a, <<b:size(a)>>) = #(2, <<2:2>>)\n  │                          ^\n\nThe name `a` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_using_pattern_variables_from_other_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert #(<<a>>, <<b:size(a)>>) = #(<<2>>, <<2:2>>)\"\n---\n----- SOURCE CODE\nlet assert #(<<a>>, <<b:size(a)>>) = #(<<2>>, <<2:2>>)\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:30\n  │\n1 │ let assert #(<<a>>, <<b:size(a)>>) = #(<<2>>, <<2:2>>)\n  │                              ^\n\nThe name `a` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_utf8_and_size.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<\\\"test\\\":size(1)>> x\"\n---\n----- SOURCE CODE\nlet x = <<\"test\":size(1)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ let x = <<\"test\":size(1)>> x\n  │                  ^^^^^^^ Size cannot be specified here\n\nHint: utf8 segments have an automatic size.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_array_utf8_and_unit.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = <<\\\"test\\\":unit(5)>> x\"\n---\n----- SOURCE CODE\nlet x = <<\"test\":unit(5)>> x\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ let x = <<\"test\":unit(5)>> x\n  │                  ^^^^^^^ Unit cannot be specified here\n\nHint: utf8 segments are sized based on their value and cannot have a unit.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_arrays2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let <<x:utf8>> = <<1>>\"\n---\n----- SOURCE CODE\nlet <<x:utf8>> = <<1>>\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:7\n  │\n1 │ let <<x:utf8>> = <<1>>\n  │       ^^^^^^ This cannot be a variable\n\nHint: in patterns utf8, utf16, and utf32  must be an exact string.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_arrays3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let <<x:utf16>> = <<1>>\"\n---\n----- SOURCE CODE\nlet <<x:utf16>> = <<1>>\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:7\n  │\n1 │ let <<x:utf16>> = <<1>>\n  │       ^^^^^^^ This cannot be a variable\n\nHint: in patterns utf8, utf16, and utf32  must be an exact string.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__bit_arrays4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let <<x:utf32>> = <<1>>\"\n---\n----- SOURCE CODE\nlet <<x:utf32>> = <<1>>\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:7\n  │\n1 │ let <<x:utf32>> = <<1>>\n  │       ^^^^^^^ This cannot be a variable\n\nHint: in patterns utf8, utf16, and utf32  must be an exact string.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case #(1, 1.0) { #(x, _) | #(_, x) -> 1 }\"\n---\n----- SOURCE CODE\ncase #(1, 1.0) { #(x, _) | #(_, x) -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:33\n  │\n1 │ case #(1, 1.0) { #(x, _) | #(_, x) -> 1 }\n  │                                 ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case10.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3], 1.1 { x, y if x >. y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3], 1.1 { x, y if x >. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:25\n  │\n1 │ case [3], 1.1 { x, y if x >. y -> 1 }\n  │                         ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case11.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 2.22, 1, \\\"three\\\" { x, _, y if x >. y -> 1 }\"\n---\n----- SOURCE CODE\ncase 2.22, 1, \"three\" { x, _, y if x >. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:41\n  │\n1 │ case 2.22, 1, \"three\" { x, _, y if x >. y -> 1 }\n  │                                         ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case12.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3], 1.1 { x, y if x >=. y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3], 1.1 { x, y if x >=. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:25\n  │\n1 │ case [3], 1.1 { x, y if x >=. y -> 1 }\n  │                         ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case13.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 2.22, 1, \\\"three\\\" { x, _, y if x >=. y -> 1 }\"\n---\n----- SOURCE CODE\ncase 2.22, 1, \"three\" { x, _, y if x >=. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:42\n  │\n1 │ case 2.22, 1, \"three\" { x, _, y if x >=. y -> 1 }\n  │                                          ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case14.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3], 1.1 { x, y if x <. y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3], 1.1 { x, y if x <. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:25\n  │\n1 │ case [3], 1.1 { x, y if x <. y -> 1 }\n  │                         ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case15.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 2.22, 1, \\\"three\\\" { x, _, y if x <. y -> 1 }\"\n---\n----- SOURCE CODE\ncase 2.22, 1, \"three\" { x, _, y if x <. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:41\n  │\n1 │ case 2.22, 1, \"three\" { x, _, y if x <. y -> 1 }\n  │                                         ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case16.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3], 1.1 { x, y if x <=. y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3], 1.1 { x, y if x <=. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:25\n  │\n1 │ case [3], 1.1 { x, y if x <=. y -> 1 }\n  │                         ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case17.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 2.22, 1, \\\"three\\\" { x, _, y if x <=. y -> 1 }\"\n---\n----- SOURCE CODE\ncase 2.22, 1, \"three\" { x, _, y if x <=. y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:42\n  │\n1 │ case 2.22, 1, \"three\" { x, _, y if x <=. y -> 1 }\n  │                                          ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case18.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { x if x == \\\"x\\\" -> 1 }\"\n---\n----- SOURCE CODE\ncase 1 { x if x == \"x\" -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ case 1 { x if x == \"x\" -> 1 }\n  │               ^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case19.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [1] { [x] | x -> 1 }\"\n---\n----- SOURCE CODE\ncase [1] { [x] | x -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ case [1] { [x] | x -> 1 }\n  │                  ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3.33], 1 { x, y if x > y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3.33], 1 { x, y if x > y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ case [3.33], 1 { x, y if x > y -> 1 }\n  │                          ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    List(Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case20.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [1] { [x] | [] as x -> 1 }\"\n---\n----- SOURCE CODE\ncase [1] { [x] | [] as x -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ case [1] { [x] | [] as x -> 1 }\n  │                        ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1, 2.22, \\\"three\\\" { x, _, y if x > y -> 1 }\"\n---\n----- SOURCE CODE\ncase 1, 2.22, \"three\" { x, _, y if x > y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:40\n  │\n1 │ case 1, 2.22, \"three\" { x, _, y if x > y -> 1 }\n  │                                        ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3.33], 1 { x, y if x >= y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3.33], 1 { x, y if x >= y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ case [3.33], 1 { x, y if x >= y -> 1 }\n  │                          ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    List(Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1, 2.22, \\\"three\\\" { x, _, y if x >= y -> 1 }\"\n---\n----- SOURCE CODE\ncase 1, 2.22, \"three\" { x, _, y if x >= y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:41\n  │\n1 │ case 1, 2.22, \"three\" { x, _, y if x >= y -> 1 }\n  │                                         ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3.33], 1 { x, y if x < y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3.33], 1 { x, y if x < y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ case [3.33], 1 { x, y if x < y -> 1 }\n  │                          ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    List(Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1, 2.22, \\\"three\\\" { x, _, y if x < y -> 1 }\"\n---\n----- SOURCE CODE\ncase 1, 2.22, \"three\" { x, _, y if x < y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:40\n  │\n1 │ case 1, 2.22, \"three\" { x, _, y if x < y -> 1 }\n  │                                        ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3.33], 1 { x, y if x <= y -> 1 }\"\n---\n----- SOURCE CODE\ncase [3.33], 1 { x, y if x <= y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ case [3.33], 1 { x, y if x <= y -> 1 }\n  │                          ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    List(Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case9.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1, 2.22, \\\"three\\\" { x, _, y if x <= y -> 1 }\"\n---\n----- SOURCE CODE\ncase 1, 2.22, \"three\" { x, _, y if x <= y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:41\n  │\n1 │ case 1, 2.22, \"three\" { x, _, y if x <= y -> 1 }\n  │                                         ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_clause_mismatch.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { a -> 1 b -> 2.0 }\"\n---\n----- SOURCE CODE\ncase 1 { a -> 1 b -> 2.0 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ case 1 { a -> 1 b -> 2.0 }\n  │                 ^^^^^^^^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_clause_pipe_diagnostic.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn change(x: String) -> String {\\n  \\\"\\\"\\n}\\n\\npub fn parse(input: BitArray) -> String {\\n  case input {\\n    <<>> -> 1\\n    <<\\\"(\\\":utf8, b:bytes>> ->\\n      parse(input)\\n      |> change\\n    _ -> 3\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn change(x: String) -> String {\n  \"\"\n}\n\npub fn parse(input: BitArray) -> String {\n  case input {\n    <<>> -> 1\n    <<\"(\":utf8, b:bytes>> ->\n      parse(input)\n      |> change\n    _ -> 3\n  }\n}\n\n----- ERROR\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:7:3\n   │  \n 7 │ ╭   case input {\n 8 │ │     <<>> -> 1\n 9 │ │     <<\"(\":utf8, b:bytes>> ->\n10 │ │       parse(input)\n11 │ │       |> change\n12 │ │     _ -> 3\n13 │ │   }\n   │ ╰───^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:9:5\n   │  \n 9 │ ╭     <<\"(\":utf8, b:bytes>> ->\n10 │ │       parse(input)\n11 │ │       |> change\n   │ ╰───────────────^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_could_not_unify.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1, 2.0 { a, b -> a 1, 2 -> 0 }\"\n---\n----- SOURCE CODE\ncase 1, 2.0 { a, b -> a 1, 2 -> 0 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ case 1, 2.0 { a, b -> a 1, 2 -> 0 }\n  │                            ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_int_tuple_guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { x if x == #() -> 1 }\"\n---\n----- SOURCE CODE\ncase 1 { x if x == #() -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ case 1 { x if x == #() -> 1 }\n  │               ^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    #()\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_list_guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [1] { x if x == [1, 2.0] -> 1 _ -> 2 }\"\n---\n----- SOURCE CODE\ncase [1] { x if x == [1, 2.0] -> 1 _ -> 2 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:26\n  │\n1 │ case [1] { x if x == [1, 2.0] -> 1 _ -> 2 }\n  │                          ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_operator_unify_situation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1, 2.0 { a, b -> a + b }\"\n---\n----- SOURCE CODE\ncase 1, 2.0 { a, b -> a + b }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:27\n  │\n1 │ case 1, 2.0 { a, b -> a + b }\n  │                           ^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_subject_pattern_unify.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1.0 { 1 -> 1 }\"\n---\n----- SOURCE CODE\ncase 1.0 { 1 -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:12\n  │\n1 │ case 1.0 { 1 -> 1 }\n  │            ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_subject_pattern_unify_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { 1.0 -> 1 }\"\n---\n----- SOURCE CODE\ncase 1 { 1.0 -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ case 1 { 1.0 -> 1 }\n  │          ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_tuple_guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case #(1, 2, 3) { x if x == #(1, 1.0) -> 1 }\"\n---\n----- SOURCE CODE\ncase #(1, 2, 3) { x if x == #(1, 1.0) -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ case #(1, 2, 3) { x if x == #(1, 1.0) -> 1 }\n  │                        ^^^^^^^^^^^^^^\n\nExpected type:\n\n    #(Int, Int, Int)\n\nFound type:\n\n    #(Int, Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__case_tuple_guard_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case #(1, 2) { x if x == #(1, 1.0) -> 1 }\"\n---\n----- SOURCE CODE\ncase #(1, 2) { x if x == #(1, 1.0) -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ case #(1, 2) { x if x == #(1, 1.0) -> 1 }\n  │                     ^^^^^^^^^^^^^^\n\nExpected type:\n\n    #(Int, Int)\n\nFound type:\n\n    #(Int, Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_annotation_wrong.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub const group_id: Int = \\\"42\\\"\"\n---\n----- SOURCE CODE\npub const group_id: Int = \"42\"\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:27\n  │\n1 │ pub const group_id: Int = \"42\"\n  │                           ^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_annotation_wrong_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub const numbers: List(Int) = [1, 2, 2.3]\"\n---\n----- SOURCE CODE\npub const numbers: List(Int) = [1, 2, 2.3]\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:39\n  │\n1 │ pub const numbers: List(Int) = [1, 2, 2.3]\n  │                                       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_annotation_wrong_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub const numbers: List(Int) = [1.1, 2.2, 3.3]\"\n---\n----- SOURCE CODE\npub const numbers: List(Int) = [1.1, 2.2, 3.3]\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:32\n  │\n1 │ pub const numbers: List(Int) = [1.1, 2.2, 3.3]\n  │                                ^^^^^^^^^^^^^^^\n\nExpected type:\n\n    List(Int)\n\nFound type:\n\n    List(Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_annotation_wrong_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub const pair: #(Int, Float) = #(4.1, 1)\"\n---\n----- SOURCE CODE\npub const pair: #(Int, Float) = #(4.1, 1)\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:33\n  │\n1 │ pub const pair: #(Int, Float) = #(4.1, 1)\n  │                                 ^^^^^^^^^\n\nExpected type:\n\n    #(Int, Float)\n\nFound type:\n\n    #(Float, Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_heterogenus_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const pair = [1, 1.0]\"\n---\n----- SOURCE CODE\nconst pair = [1, 1.0]\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ const pair = [1, 1.0]\n  │                  ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_are_local_with_annotation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const num: String = 7\\nconst tpl: String = #(Ok(1), MyInvalidType, 3)\\nconst assignment1: String = num\\nconst assignment2: String = tpl\"\n---\n----- SOURCE CODE\nconst num: String = 7\nconst tpl: String = #(Ok(1), MyInvalidType, 3)\nconst assignment1: String = num\nconst assignment2: String = tpl\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ const num: String = 7\n  │                     ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:21\n  │\n2 │ const tpl: String = #(Ok(1), MyInvalidType, 3)\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    #(Result(Int, a), b, Int)\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:2:30\n  │\n2 │ const tpl: String = #(Ok(1), MyInvalidType, 3)\n  │                              ^^^^^^^^^^^^^\n\nThe custom type variant constructor `MyInvalidType` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_are_local_with_inferred_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const str: MyInvalidType = \\\"str\\\"\\nconst assignment: String = str\"\n---\n----- SOURCE CODE\nconst str: MyInvalidType = \"str\"\nconst assignment: String = str\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:12\n  │\n1 │ const str: MyInvalidType = \"str\"\n  │            ^^^^^^^^^^^^^\n\nThe type `MyInvalidType` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_are_local_with_unbound_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const lst = [1, 2.0]\\nconst unbound: MyInvalidType = MyInvalidType\\nconst assignment1: String = lst\\nconst assignment2: String = unbound\"\n---\n----- SOURCE CODE\nconst lst = [1, 2.0]\nconst unbound: MyInvalidType = MyInvalidType\nconst assignment1: String = lst\nconst assignment2: String = unbound\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ const lst = [1, 2.0]\n  │                 ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:2:16\n  │\n2 │ const unbound: MyInvalidType = MyInvalidType\n  │                ^^^^^^^^^^^^^\n\nThe type `MyInvalidType` is not defined or imported in this module.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:2:32\n  │\n2 │ const unbound: MyInvalidType = MyInvalidType\n  │                                ^^^^^^^^^^^^^\n\nThe custom type variant constructor `MyInvalidType` is not in scope here.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:29\n  │\n3 │ const assignment1: String = lst\n  │                             ^^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_invalid_annotation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const invalid_annotation: MyInvalidType = \\\"str\\\"\\nconst invalid_value: String = MyInvalidValue\"\n---\n----- SOURCE CODE\nconst invalid_annotation: MyInvalidType = \"str\"\nconst invalid_value: String = MyInvalidValue\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:27\n  │\n1 │ const invalid_annotation: MyInvalidType = \"str\"\n  │                           ^^^^^^^^^^^^^\n\nThe type `MyInvalidType` is not defined or imported in this module.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:2:31\n  │\n2 │ const invalid_value: String = MyInvalidValue\n  │                               ^^^^^^^^^^^^^^\n\nThe custom type variant constructor `MyInvalidValue` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_invalid_annotation_and_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const invalid_everything: MyInvalidType = MyInvalidValue\\nconst mismatched_types: String = 7\"\n---\n----- SOURCE CODE\nconst invalid_everything: MyInvalidType = MyInvalidValue\nconst mismatched_types: String = 7\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:27\n  │\n1 │ const invalid_everything: MyInvalidType = MyInvalidValue\n  │                           ^^^^^^^^^^^^^\n\nThe type `MyInvalidType` is not defined or imported in this module.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:43\n  │\n1 │ const invalid_everything: MyInvalidType = MyInvalidValue\n  │                                           ^^^^^^^^^^^^^^\n\nThe custom type variant constructor `MyInvalidValue` is not in scope here.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:34\n  │\n2 │ const mismatched_types: String = 7\n  │                                  ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_invalid_unannotated_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const invalid_unannotated_value = [1, 2.0]\\nconst invalid_everything: MyInvalidType = MyInvalidValue\"\n---\n----- SOURCE CODE\nconst invalid_unannotated_value = [1, 2.0]\nconst invalid_everything: MyInvalidType = MyInvalidValue\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:39\n  │\n1 │ const invalid_unannotated_value = [1, 2.0]\n  │                                       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:2:27\n  │\n2 │ const invalid_everything: MyInvalidType = MyInvalidValue\n  │                           ^^^^^^^^^^^^^\n\nThe type `MyInvalidType` is not defined or imported in this module.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:2:43\n  │\n2 │ const invalid_everything: MyInvalidType = MyInvalidValue\n  │                                           ^^^^^^^^^^^^^^\n\nThe custom type variant constructor `MyInvalidValue` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_invalid_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const invalid_value: String = MyInvalidValue\\nconst invalid_unannotated_value = [1, 2.0]\"\n---\n----- SOURCE CODE\nconst invalid_value: String = MyInvalidValue\nconst invalid_unannotated_value = [1, 2.0]\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:31\n  │\n1 │ const invalid_value: String = MyInvalidValue\n  │                               ^^^^^^^^^^^^^^\n\nThe custom type variant constructor `MyInvalidValue` is not in scope here.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:39\n  │\n2 │ const invalid_unannotated_value = [1, 2.0]\n  │                                       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_multiple_errors_mismatched_types.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const mismatched_types: String = 7\\nconst invalid_annotation: MyInvalidType = \\\"str\\\"\"\n---\n----- SOURCE CODE\nconst mismatched_types: String = 7\nconst invalid_annotation: MyInvalidType = \"str\"\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:34\n  │\n1 │ const mismatched_types: String = 7\n  │                                  ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:2:27\n  │\n2 │ const invalid_annotation: MyInvalidType = \"str\"\n  │                           ^^^^^^^^^^^^^\n\nThe type `MyInvalidType` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_string_concat_invalid_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nconst some_int = 5\\nconst invalid_concat = some_int <> \\\"with_string\\\"\\n\"\n---\n----- SOURCE CODE\n\nconst some_int = 5\nconst invalid_concat = some_int <> \"with_string\"\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:24\n  │\n3 │ const invalid_concat = some_int <> \"with_string\"\n  │                        ^^^^^^^^\n\nThe <> operator expects arguments of this type:\n\n    String\n\nBut this argument has this type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__const_usage_wrong.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const pair = #(1, 2.0)\\nfn main() { 1 == pair }\"\n---\n----- SOURCE CODE\nconst pair = #(1, 2.0)\nfn main() { 1 == pair }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:18\n  │\n2 │ fn main() { 1 == pair }\n  │                  ^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    #(Int, Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__constructor_that_does_not_exist_does_not_produce_error_for_labelled_args.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  // We only want to error on `Wibble` since it doesn't exist, we don't want\\n  // an error on the label at this point!\\n  Wibble(label: 1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  // We only want to error on `Wibble` since it doesn't exist, we don't want\n  // an error on the label at this point!\n  Wibble(label: 1)\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   Wibble(label: 1)\n  │   ^^^^^^\n\nThe custom type variant constructor `Wibble` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__correct_pipe_arity_error_location.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn x(x, y) { x }\\nfn main() { 1 |> x() }\"\n---\n----- SOURCE CODE\nfn x(x, y) { x }\nfn main() { 1 |> x() }\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:2:18\n  │\n2 │ fn main() { 1 |> x() }\n  │                  ^^^ Expected 2 arguments, got 1\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__custom_type_module_constants.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X }\\nconst x = unknown.X\"\n---\n----- SOURCE CODE\ntype X { X }\nconst x = unknown.X\n\n----- ERROR\nerror: Unknown module\n  ┌─ /src/one/two.gleam:2:11\n  │\n2 │ const x = unknown.X\n  │           ^^^^^^^\n\nNo module has been found with the name `unknown`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__do_not_suggest_ignored_variable_outside_of_current_scope.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn go() {\\n  let _ = {\\n    let _y = 1 // <- this shouldn't be highlighted!\\n  }\\n  y\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let _ = {\n    let _y = 1 // <- this shouldn't be highlighted!\n  }\n  y\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:6:3\n  │\n6 │   y\n  │   ^\n\nThe name `y` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__double_assignment_in_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let assert <<a as b>> = <<>>\n---\n----- SOURCE CODE\nlet assert <<a as b>> = <<>>\n\n----- ERROR\nerror: Double variable assignment\n  ┌─ /src/one/two.gleam:1:19\n  │\n1 │ let assert <<a as b>> = <<>>\n  │                   ^\n\nThis pattern assigns to two different variables at once, which is not\npossible in bit arrays.\nHint: Remove the `as` assignment.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_alias_names.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: type X = Int type X = Int\n---\n----- SOURCE CODE\ntype X = Int type X = Int\n\n----- ERROR\nerror: Duplicate type definition\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ type X = Int type X = Int\n  │ ------------ ^^^^^^^^^^^^ Redefined here\n  │ │             \n  │ First defined here\n\nThe type `X` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_anon_function_arguments.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn(x, x) {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn(x, x) {\n  Nil\n}\n\n\n----- ERROR\nerror: Argument name already used\n  ┌─ /src/one/two.gleam:2:7\n  │\n2 │ fn(x, x) {\n  │       ^\n\nTwo `x` arguments have been defined for this function.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_const_and_function_names_const_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const duplicate = 1\\nfn duplicate() { 2 }\"\n---\n----- SOURCE CODE\nconst duplicate = 1\nfn duplicate() { 2 }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ const duplicate = 1\n  │ --------------- First defined here\n2 │ fn duplicate() { 2 }\n  │ ^^^^^^^^^^^^^^ Redefined here\n\n`duplicate` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_const_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const wibble = 1\\nconst wibble = 2\"\n---\n----- SOURCE CODE\nconst wibble = 1\nconst wibble = 2\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ const wibble = 1\n  │ ------------ First defined here\n2 │ const wibble = 2\n  │ ^^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_const_extfn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const wibble = 1\\n\\n@external(erlang, \\\"module2\\\", \\\"function2\\\")\\nfn wibble() -> Float\\n\"\n---\n----- SOURCE CODE\nconst wibble = 1\n\n@external(erlang, \"module2\", \"function2\")\nfn wibble() -> Float\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:4:1\n  │\n1 │ const wibble = 1\n  │ ------------ First defined here\n  ·\n4 │ fn wibble() -> Float\n  │ ^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_const_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const wibble = 1\\nfn wibble() { 2 }\"\n---\n----- SOURCE CODE\nconst wibble = 1\nfn wibble() { 2 }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ const wibble = 1\n  │ ------------ First defined here\n2 │ fn wibble() { 2 }\n  │ ^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_const_names.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const duplicate = 1\\npub const duplicate = 1\"\n---\n----- SOURCE CODE\nconst duplicate = 1\npub const duplicate = 1\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ const duplicate = 1\n  │ --------------- First defined here\n2 │ pub const duplicate = 1\n  │ ^^^^^^^^^^^^^^^^^^^ Redefined here\n\n`duplicate` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_constructors.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type Box { Box(x: Int) }\\ntype Boxy { Box(Int) }\"\n---\n----- SOURCE CODE\ntype Box { Box(x: Int) }\ntype Boxy { Box(Int) }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:13\n  │\n1 │ type Box { Box(x: Int) }\n  │            ----------- First defined here\n2 │ type Boxy { Box(Int) }\n  │             ^^^^^^^^ Redefined here\n\n`Box` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_constructors2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type Boxy { Box(Int) }\\ntype Box { Box(x: Int) }\"\n---\n----- SOURCE CODE\ntype Boxy { Box(Int) }\ntype Box { Box(x: Int) }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:12\n  │\n1 │ type Boxy { Box(Int) }\n  │             -------- First defined here\n2 │ type Box { Box(x: Int) }\n  │            ^^^^^^^^^^^ Redefined here\n\n`Box` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_constructors3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type Boxy { Box(Int) Box(Float) }\"\n---\n----- SOURCE CODE\ntype Boxy { Box(Int) Box(Float) }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ type Boxy { Box(Int) Box(Float) }\n  │             -------- ^^^^^^^^^^ Redefined here\n  │             │         \n  │             First defined here\n\n`Box` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_custom_type_names.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type DupType { A } type DupType { B }\"\n---\n----- SOURCE CODE\ntype DupType { A } type DupType { B }\n\n----- ERROR\nerror: Duplicate type definition\n  ┌─ /src/one/two.gleam:1:20\n  │\n1 │ type DupType { A } type DupType { B }\n  │ ------------       ^^^^^^^^^^^^ Redefined here\n  │ │                   \n  │ First defined here\n\nThe type `DupType` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_extfn_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"module1\\\", \\\"function1\\\")\\nfn wibble() -> Float\\n\\nconst wibble = 2\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"module1\", \"function1\")\nfn wibble() -> Float\n\nconst wibble = 2\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:5:1\n  │\n3 │ fn wibble() -> Float\n  │ ----------- First defined here\n4 │ \n5 │ const wibble = 2\n  │ ^^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_extfn_extfn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"module1\\\", \\\"function1\\\")\\nfn wibble() -> Float\\n@external(erlang, \\\"module2\\\", \\\"function2\\\")\\nfn wibble() -> Float\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"module1\", \"function1\")\nfn wibble() -> Float\n@external(erlang, \"module2\", \"function2\")\nfn wibble() -> Float\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:5:1\n  │\n3 │ fn wibble() -> Float\n  │ ----------- First defined here\n4 │ @external(erlang, \"module2\", \"function2\")\n5 │ fn wibble() -> Float\n  │ ^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_extfn_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"module1\\\", \\\"function1\\\")\\nfn wibble() -> Float\\n\\nfn wibble() { 2 }\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"module1\", \"function1\")\nfn wibble() -> Float\n\nfn wibble() { 2 }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:5:1\n  │\n3 │ fn wibble() -> Float\n  │ ----------- First defined here\n4 │ \n5 │ fn wibble() { 2 }\n  │ ^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_fields_in_record_update_reports_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble { Wibble(thing: Int, other: Int) }\\n\\npub fn main() {\\n  let wibble = Wibble(1, 2)\\n  let wobble = Wibble(..wibble, thing: 1, thing: 2)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(thing: Int, other: Int) }\n\npub fn main() {\n  let wibble = Wibble(1, 2)\n  let wobble = Wibble(..wibble, thing: 1, thing: 2)\n}\n\n\n----- ERROR\nerror: Duplicate argument\n  ┌─ /src/one/two.gleam:6:43\n  │\n6 │   let wobble = Wibble(..wibble, thing: 1, thing: 2)\n  │                                           ^^^^^^^^\n\nThe labelled argument `thing` has already been supplied.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_fn_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn wibble() { 1 }\\nconst wibble = 2\"\n---\n----- SOURCE CODE\nfn wibble() { 1 }\nconst wibble = 2\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ fn wibble() { 1 }\n  │ ----------- First defined here\n2 │ const wibble = 2\n  │ ^^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_fn_extfn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn wibble() { 1 }\\n\\n@external(erlang, \\\"module2\\\", \\\"function2\\\")\\nfn wibble() -> Float\\n\"\n---\n----- SOURCE CODE\nfn wibble() { 1 }\n\n@external(erlang, \"module2\", \"function2\")\nfn wibble() -> Float\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:4:1\n  │\n1 │ fn wibble() { 1 }\n  │ ----------- First defined here\n  ·\n4 │ fn wibble() -> Float\n  │ ^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_fn_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn wibble() { 1 }\\nfn wibble() { 2 }\"\n---\n----- SOURCE CODE\nfn wibble() { 1 }\nfn wibble() { 2 }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ fn wibble() { 1 }\n  │ ----------- First defined here\n2 │ fn wibble() { 2 }\n  │ ^^^^^^^^^^^ Redefined here\n\n`wibble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_function_names.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn dupe() { 1 }\\nfn dupe() { 2 }\"\n---\n----- SOURCE CODE\nfn dupe() { 1 }\nfn dupe() { 2 }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ fn dupe() { 1 }\n  │ --------- First defined here\n2 │ fn dupe() { 2 }\n  │ ^^^^^^^^^ Redefined here\n\n`dupe` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_function_names_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn dupe() { 1 }\\nfn dupe() { 2.0 }\"\n---\n----- SOURCE CODE\nfn dupe() { 1 }\nfn dupe() { 2.0 }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ fn dupe() { 1 }\n  │ --------- First defined here\n2 │ fn dupe() { 2.0 }\n  │ ^^^^^^^^^ Redefined here\n\n`dupe` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_function_names_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn dupe() { 1 }\\nfn dupe(x) { x }\"\n---\n----- SOURCE CODE\nfn dupe() { 1 }\nfn dupe(x) { x }\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:2:1\n  │\n1 │ fn dupe() { 1 }\n  │ --------- First defined here\n2 │ fn dupe(x) { x }\n  │ ^^^^^^^^^^ Redefined here\n\n`dupe` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_function_names_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn dupe() { 1 }\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\nfn dupe(x) -> x\\n\"\n---\n----- SOURCE CODE\nfn dupe() { 1 }\n@external(erlang, \"a\", \"b\")\nfn dupe(x) -> x\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:3:1\n  │\n1 │ fn dupe() { 1 }\n  │ --------- First defined here\n2 │ @external(erlang, \"a\", \"b\")\n3 │ fn dupe(x) -> x\n  │ ^^^^^^^^^^ Redefined here\n\n`dupe` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_function_names_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\nfn dupe(x) -> x\\nfn dupe() { 1 }\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"a\", \"b\")\nfn dupe(x) -> x\nfn dupe() { 1 }\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:4:1\n  │\n3 │ fn dupe(x) -> x\n  │ ---------- First defined here\n4 │ fn dupe() { 1 }\n  │ ^^^^^^^^^ Redefined here\n\n`dupe` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_label_shorthands_in_record_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Int, c: Int) }\\nfn x() {\\n  case X(1,2,3) { X(a:, b:, c: a) -> 1 }\\n}\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Int, c: Int) }\nfn x() {\n  case X(1,2,3) { X(a:, b:, c: a) -> 1 }\n}\n\n----- ERROR\nerror: Duplicate variable in pattern\n  ┌─ /src/one/two.gleam:3:32\n  │\n3 │   case X(1,2,3) { X(a:, b:, c: a) -> 1 }\n  │                                ^ This has already been used\n\nVariables can only be used once per pattern. This variable `a` appears\nmultiple times.\nIf you used the same variable twice deliberately in order to check for\nequality please use a guard clause instead.\ne.g. (x, y) if x == y -> ...\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_module_function_arguments.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main(x, x) {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x, x) {\n  Nil\n}\n\n\n----- ERROR\nerror: Argument name already used\n  ┌─ /src/one/two.gleam:2:16\n  │\n2 │ pub fn main(x, x) {\n  │                ^\n\nTwo `x` arguments have been defined for this function.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_var_in_record_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Int, c: Int) }\\nfn x() {\\n  case X(1,2,3) { X(x, y, x) -> 1 }\\n}\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Int, c: Int) }\nfn x() {\n  case X(1,2,3) { X(x, y, x) -> 1 }\n}\n\n----- ERROR\nerror: Duplicate variable in pattern\n  ┌─ /src/one/two.gleam:3:27\n  │\n3 │   case X(1,2,3) { X(x, y, x) -> 1 }\n  │                           ^ This has already been used\n\nVariables can only be used once per pattern. This variable `x` appears\nmultiple times.\nIf you used the same variable twice deliberately in order to check for\nequality please use a guard clause instead.\ne.g. (x, y) if x == y -> ...\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_vars.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case #(1, 2) { #(x, x) -> 1 }\"\n---\n----- SOURCE CODE\ncase #(1, 2) { #(x, x) -> 1 }\n\n----- ERROR\nerror: Duplicate variable in pattern\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ case #(1, 2) { #(x, x) -> 1 }\n  │                     ^ This has already been used\n\nVariables can only be used once per pattern. This variable `x` appears\nmultiple times.\nIf you used the same variable twice deliberately in order to check for\nequality please use a guard clause instead.\ne.g. (x, y) if x == y -> ...\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_vars_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [3.33], 1 { x, x -> 1 }\"\n---\n----- SOURCE CODE\ncase [3.33], 1 { x, x -> 1 }\n\n----- ERROR\nerror: Duplicate variable in pattern\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ case [3.33], 1 { x, x -> 1 }\n  │                     ^ This has already been used\n\nVariables can only be used once per pattern. This variable `x` appears\nmultiple times.\nIf you used the same variable twice deliberately in order to check for\nequality please use a guard clause instead.\ne.g. (x, y) if x == y -> ...\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__duplicate_vars_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [1, 2, 3] { [x, x, y] -> 1 }\"\n---\n----- SOURCE CODE\ncase [1, 2, 3] { [x, x, y] -> 1 }\n\n----- ERROR\nerror: Duplicate variable in pattern\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ case [1, 2, 3] { [x, x, y] -> 1 }\n  │                      ^ This has already been used\n\nVariables can only be used once per pattern. This variable `x` appears\nmultiple times.\nIf you used the same variable twice deliberately in order to check for\nequality please use a guard clause instead.\ne.g. (x, y) if x == y -> ...\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_invalid_message.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"echo 11 as { True || False }\"\n---\n----- SOURCE CODE\necho 11 as { True || False }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:12\n  │\n1 │ echo 11 as { True || False }\n  │            ^^^^^^^^^^^^^^^^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Bool\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: echo\n---\n----- SOURCE CODE\necho\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ echo\n  │ ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_10.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  echo\\n  |> todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo\n  |> todo\n}\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   echo\n  │   ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n  pub fn wibble(a) { a }\\n\\n  pub fn main() {\\n    wibble(echo)\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn wibble(a) { a }\n\n  pub fn main() {\n    wibble(echo)\n  }\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:5:12\n  │\n5 │     wibble(echo)\n  │            ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n  pub fn main() {\\n    echo + 1\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn main() {\n    echo + 1\n  }\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:3:5\n  │\n3 │     echo + 1\n  │     ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n  pub fn main() {\\n    \\\"wibble\\\" <> echo\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn main() {\n    \"wibble\" <> echo\n  }\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:3:17\n  │\n3 │     \"wibble\" <> echo\n  │                 ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  panic as echo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  panic as echo\n}\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:3:12\n  │\n3 │   panic as echo\n  │            ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  [echo, 1, 2]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [echo, 1, 2]\n}\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:3:4\n  │\n3 │   [echo, 1, 2]\n  │    ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  #(1, echo)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  #(1, echo)\n}\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │   #(1, echo)\n  │        ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  todo\\n  |> fn(_) { echo }\\n  |> todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  todo\n  |> fn(_) { echo }\n  |> todo\n}\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:4:14\n  │\n4 │   |> fn(_) { echo }\n  │              ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_9.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  todo\\n  |> { echo }\\n  |> todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  todo\n  |> { echo }\n  |> todo\n}\n\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:4:8\n  │\n4 │   |> { echo }\n  │        ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_and_invalid_message.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: echo as 1\n---\n----- SOURCE CODE\necho as 1\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ echo as 1\n  │ ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:9\n  │\n1 │ echo as 1\n  │         ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__echo_followed_by_no_expression_and_message.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"echo as \\\"wibble\\\"\"\n---\n----- SOURCE CODE\necho as \"wibble\"\n\n----- ERROR\nerror: Invalid echo use\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ echo as \"wibble\"\n  │ ^^^^ I was expecting a value after this\n\nThe `echo` keyword should be followed by a value to print.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__error_for_missing_type_parameters.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\ntype Wibble(a)\\n\\ntype Wobble {\\n  Wobble(Wibble)\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble(a)\n\ntype Wobble {\n  Wobble(Wibble)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:5:10\n  │\n5 │   Wobble(Wibble)\n  │          ^^^^^^ Expected 1 type argument, got 0\n\n`Wibble` requires 1 type argument but none where provided.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__expression_constructor_update.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n  Person(name: String, age: Int)\\n}\\npub fn update_person(person: Person) {\\n  let constructor = Person\\n  constructor(..person)\\n}\"\n---\n----- SOURCE CODE\n\npub type Person {\n  Person(name: String, age: Int)\n}\npub fn update_person(person: Person) {\n  let constructor = Person\n  constructor(..person)\n}\n\n----- ERROR\nerror: Invalid record constructor\n  ┌─ /src/one/two.gleam:7:3\n  │\n7 │   constructor(..person)\n  │   ^^^^^^^^^^^ This is not a record constructor\n\nOnly record constructors can be used with the update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__external_annotation_on_custom_type_with_constructors.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"gleam_stdlib\\\", \\\"dict\\\")\\npub type Dict(key, value) {\\n  Dict(pairs: List(#(key, value)))\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"gleam_stdlib\", \"dict\")\npub type Dict(key, value) {\n  Dict(pairs: List(#(key, value)))\n}\n\n\n----- ERROR\nerror: External type with constructors\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub type Dict(key, value) {\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis type is annotated with the `@external` annotation, but it has\nconstructors. The `@external` annotation is only for external types with no\nconstructors.\nHint: Remove the `@external` annotation\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__extra_var_inalternative.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [1] { [x] | [x, y] -> 1 }\"\n---\n----- SOURCE CODE\ncase [1] { [x] | [x, y] -> 1 }\n\n----- ERROR\nerror: Extra alternative pattern variable\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ case [1] { [x] | [x, y] -> 1 }\n  │                      ^ Has not been previously defined\n\nAll alternative patterns must define the same variables as the initial\npattern. This variable `y` has not been previously defined.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__extra_var_inalternative2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case #(1, 2) { #(1, y) | #(x, y) -> 1 }\"\n---\n----- SOURCE CODE\ncase #(1, 2) { #(1, y) | #(x, y) -> 1 }\n\n----- ERROR\nerror: Extra alternative pattern variable\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ case #(1, 2) { #(1, y) | #(x, y) -> 1 }\n  │                            ^ Has not been previously defined\n\nAll alternative patterns must define the same variables as the initial\npattern. This variable `x` has not been previously defined.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__extra_var_inalternative3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = 1 case #(1, 2) { #(1, y) | #(x, y) -> 1 }\"\n---\n----- SOURCE CODE\nlet x = 1 case #(1, 2) { #(1, y) | #(x, y) -> 1 }\n\n----- ERROR\nerror: Extra alternative pattern variable\n  ┌─ /src/one/two.gleam:1:38\n  │\n1 │ let x = 1 case #(1, 2) { #(1, y) | #(x, y) -> 1 }\n  │                                      ^ Has not been previously defined\n\nAll alternative patterns must define the same variables as the initial\npattern. This variable `x` has not been previously defined.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__fault_tolerant_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  [1, \\\"a\\\", 1.0, \\\"a\\\" + 1]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, \"a\", 1.0, \"a\" + 1]\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   [1, \"a\", 1.0, \"a\" + 1]\n  │       ^^^\n\nAll elements of a list must be the same type, but this one doesn't\nmatch the one before it.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:12\n  │\n3 │   [1, \"a\", 1.0, \"a\" + 1]\n  │            ^^^\n\nAll elements of a list must be the same type, but this one doesn't\nmatch the one before it.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:17\n  │\n3 │   [1, \"a\", 1.0, \"a\" + 1]\n  │                 ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    String\n\nHint: Strings can be joined using the `<>` operator.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__fault_tolerant_list_tail.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  [1, \\\"a\\\", ..[\\\"a\\\", \\\"b\\\"]]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  [1, \"a\", ..[\"a\", \"b\"]]\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   [1, \"a\", ..[\"a\", \"b\"]]\n  │       ^^^\n\nAll elements of a list must be the same type, but this one doesn't\nmatch the one before it.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:14\n  │\n3 │   [1, \"a\", ..[\"a\", \"b\"]]\n  │              ^^^^^^^^^^\n\nAll elements in a list must have the same type, but the elements of\nthis list don't match the type of the elements being prepended to it.\n\nExpected type:\n\n    List(Int)\n\nFound type:\n\n    List(String)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__fault_tolerant_negate_bool.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  !!{ True || a }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  !!{ True || a }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:3:15\n  │\n3 │   !!{ True || a }\n  │               ^\n\nThe name `a` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__fault_tolerant_negate_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  --{ 1 + a }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  --{ 1 + a }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:3:11\n  │\n3 │   --{ 1 + a }\n  │           ^\n\nThe name `a` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__fault_tolerant_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  #(1, 1 + \\\"a\\\", not_in_scope)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  #(1, 1 + \"a\", not_in_scope)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:12\n  │\n3 │   #(1, 1 + \"a\", not_in_scope)\n  │            ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    String\n\nHint: Strings can be joined using the `<>` operator.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:3:17\n  │\n3 │   #(1, 1 + \"a\", not_in_scope)\n  │                 ^^^^^^^^^^^^\n\nThe name `not_in_scope` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__field_not_in_all_variants.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: String, age: Int, title: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_title(person: Person) { person.title }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_title(person: Person) { person.title }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:6:43\n  │\n6 │ pub fn get_title(person: Person) { person.title }\n  │                                           ^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .age\n    .name\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__field_not_in_any_variant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n    Teacher(name: String, age: Int, title: String)\\n    Student(name: String, age: Int)\\n}\\npub fn get_height(person: Person) { person.height }\"\n---\n----- SOURCE CODE\n\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_height(person: Person) { person.height }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:6:44\n  │\n6 │ pub fn get_height(person: Person) { person.height }\n  │                                            ^^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .age\n    .name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__field_type_different_between_variants.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Shape {\\n    Square(x: Int, y: Int)\\n    Rectangle(x: String, y: String)\\n}\\npub fn get_x(shape: Shape) { shape.x }\\n\"\n---\n----- SOURCE CODE\n\npub type Shape {\n    Square(x: Int, y: Int)\n    Rectangle(x: String, y: String)\n}\npub fn get_x(shape: Shape) { shape.x }\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:6:36\n  │\n6 │ pub fn get_x(shape: Shape) { shape.x }\n  │                                    ^ This field does not exist\n\nThe value being accessed has this type:\n\n    Shape\n\nIt does not have fields that are common across all variants.\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__float_gtf_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1.0 >. 1\n---\n----- SOURCE CODE\n1.0 >. 1\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:8\n  │\n1 │ 1.0 >. 1\n  │        ^\n\nThe >. operator expects arguments of this type:\n\n    Float\n\nBut this argument has this type:\n\n    Int\n\nHint: the > operator can be used with Ints\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__float_operator_on_ints.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1 +. 2\n---\n----- SOURCE CODE\n1 +. 2\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:3\n  │\n1 │ 1 +. 2\n  │   ^^ Use + instead\n\nThe +. operator can only be used on Floats.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__float_operator_on_ints_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1 <. 2\n---\n----- SOURCE CODE\n1 <. 2\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:3\n  │\n1 │ 1 <. 2\n  │   ^^ Use < instead\n\nThe <. operator can only be used on Floats.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__float_operator_on_ints_in_case_guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 3 { x if x +. 2 == 5.0 -> \\\"a\\\" _ -> \\\"b\\\" }\"\n---\n----- SOURCE CODE\ncase 3 { x if x +. 2 == 5.0 -> \"a\" _ -> \"b\" }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ case 3 { x if x +. 2 == 5.0 -> \"a\" _ -> \"b\" }\n  │               ^^^^^^ Use + instead\n\nThe +. operator can only be used on Floats.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__fn0_eq_fn1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn() { 1 } == fn(x) { x + 1 }\"\n---\n----- SOURCE CODE\nfn() { 1 } == fn(x) { x + 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ fn() { 1 } == fn(x) { x + 1 }\n  │               ^^^^^^^^^^^^^^^\n\nExpected type:\n\n    fn() -> Int\n\nFound type:\n\n    fn(Int) -> Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__function_arg_and_return_annotation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn(x: Int) -> Float { x }\"\n---\n----- SOURCE CODE\nfn(x: Int) -> Float { x }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:23\n  │\n1 │ fn(x: Int) -> Float { x }\n  │                       ^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__function_return_annotation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn() -> Int { 2.0 }\"\n---\n----- SOURCE CODE\nfn() -> Int { 2.0 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ fn() -> Int { 2.0 }\n  │               ^^^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__function_return_annotation_mismatch_with_pipe.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() -> String {\\n            1\\n            |> add_two\\n         }\\n\\n         fn add_two(i: Int) -> Int {\\n            i + 2\\n         }\"\n---\n----- SOURCE CODE\npub fn main() -> String {\n            1\n            |> add_two\n         }\n\n         fn add_two(i: Int) -> Int {\n            i + 2\n         }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:13\n  │  \n2 │ ╭             1\n3 │ │             |> add_two\n  │ ╰──────────────────────^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__function_that_does_not_exist_does_not_produce_error_for_labelled_args.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  // We only want to error on `wibble` since it doesn't exist, we don't want\\n  // an error on the label at this point!\\n  wibble(label: 1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  // We only want to error on `wibble` since it doesn't exist, we don't want\n  // an error on the label at this point!\n  wibble(label: 1)\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   wibble(label: 1)\n  │   ^^^^^^\n\nThe name `wibble` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__functions_called_outside_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"const first = list.at([1], 0)\"\n---\n----- SOURCE CODE\nconst first = list.at([1], 0)\n\n----- ERROR\nerror: Syntax error\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ const first = list.at([1], 0)\n  │               ^^^^^^^^ Functions can only be called within other functions\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__generic_unlabelled_field_in_updated_record_wrong_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble(a) {\\n  Wibble(a, b: Int, c: a)\\n}\\n\\npub fn main() {\\n  let w = Wibble(1, 2, 3)\\n  Wibble(..w, c: False)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble(a) {\n  Wibble(a, b: Int, c: a)\n}\n\npub fn main() {\n  let w = Wibble(1, 2, 3)\n  Wibble(..w, c: False)\n}\n\n\n----- ERROR\nerror: Incomplete record update\n  ┌─ /src/one/two.gleam:8:12\n  │\n8 │   Wibble(..w, c: False)\n  │            ^ This is a `Wibble(Int)`\n\nThe 1st field of this value is a `Int`, but the arguments given to the\nrecord update indicate that it should be a `Bool`.\n\nNote: Unlabelled fields cannot be updated in a record update, so either add\na label or use a record constructor.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__guard_float_int_eq_vars.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = 1.0 let y = 1 case x { _ if x == y -> 1 }\"\n---\n----- SOURCE CODE\nlet x = 1.0 let y = 1 case x { _ if x == y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:37\n  │\n1 │ let x = 1.0 let y = 1 case x { _ if x == y -> 1 }\n  │                                     ^^^^^^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__guard_if_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = 1.0 case x { _ if x -> 1 }\"\n---\n----- SOURCE CODE\nlet x = 1.0 case x { _ if x -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:27\n  │\n1 │ let x = 1.0 case x { _ if x -> 1 }\n  │                           ^\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__guard_int_float_eq_vars.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let x = 1 let y = 1.0 case x { _ if x == y -> 1 }\"\n---\n----- SOURCE CODE\nlet x = 1 let y = 1.0 case x { _ if x == y -> 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:37\n  │\n1 │ let x = 1 let y = 1.0 case x { _ if x == y -> 1 }\n  │                                     ^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__guard_record_wrong_arity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Float) }\\nfn x() {\\n  case X(1, 2.0) { x if x == X(1) -> 1 _ -> 2 }\\n}\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Float) }\nfn x() {\n  case X(1, 2.0) { x if x == X(1) -> 1 _ -> 2 }\n}\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:30\n  │\n3 │   case X(1, 2.0) { x if x == X(1) -> 1 _ -> 2 }\n  │                              ^^^^ Expected 2 arguments, got 1\n\nThis call accepts these additional labelled arguments:\n\n  - b\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__hint_for_method_call.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type User {\\n  User(id: Int, name: String)\\n}\\n\\npub fn main(user: User) {\\n  user.login()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type User {\n  User(id: Int, name: String)\n}\n\npub fn main(user: User) {\n  user.login()\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:7:8\n  │\n7 │   user.login()\n  │        ^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    User\n\nIt has these accessible fields:\n\n    .id\n    .name\n\nGleam is not object oriented, so if you are trying to call a method on this\nvalue you may want to use the function syntax instead.\n\n    login(value)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__incomplete_pattern_does_not_show_structure_of_internal_type_outside_of_its_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"import wibble.{type Wibble}\\n\\npub fn go(wibble: Wibble) {\\n  case wibble {}\\n}\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n@internal\n            pub type Wibble { Wibble Wobble Woo }\n\n-- main.gleam\nimport wibble.{type Wibble}\n\npub fn go(wibble: Wibble) {\n  case wibble {}\n}\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   case wibble {}\n  │   ^^^^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__incomplete_pattern_does_not_show_structure_of_internal_type_outside_of_its_module_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"import wibble.{type Wibble}\\n\\npub type Type {\\n  Type(wibble: Wibble, list: List(Int))\\n}\\n\\npub fn go(value: Type) {\\n  case value {}\\n}\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n@internal\n            pub type Wibble { Wibble Wobble Woo }\n\n-- main.gleam\nimport wibble.{type Wibble}\n\npub type Type {\n  Type(wibble: Wibble, list: List(Int))\n}\n\npub fn go(value: Type) {\n  case value {}\n}\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:8:3\n  │\n8 │   case value {}\n  │   ^^^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Type(wibble:, list:)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__incorrect_arity_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let id = fn(x) { x } id()\"\n---\n----- SOURCE CODE\nlet id = fn(x) { x } id()\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ let id = fn(x) { x } id()\n  │                      ^^^^ Expected 1 argument, got 0\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__incorrect_arity_error_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let id = fn(x) { x } id(1, 2)\"\n---\n----- SOURCE CODE\nlet id = fn(x) { x } id(1, 2)\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ let id = fn(x) { x } id(1, 2)\n  │                      ^^^^^^^^ Expected 1 argument, got 2\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__inexhaustive_use_reports_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nuse [1, 2, 3] <- todo\\ntodo\\n\"\n---\n----- SOURCE CODE\n\nuse [1, 2, 3] <- todo\ntodo\n\n\n----- ERROR\nerror: Inexhaustive pattern\n  ┌─ /src/one/two.gleam:2:5\n  │\n2 │ use [1, 2, 3] <- todo\n  │     ^^^^^^^^^\n\nThis assignment uses a pattern that does not match all possible values. If\none of the other values is used then the assignment will crash.\n\nThe missing patterns are:\n\n    []\n    [_]\n    [_, _]\n    [_, _, _]\n    [_, _, _, _, ..]\n\nHint: Use a more general pattern or use `let assert` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__inferred_variant_record_update_change_type_parameter_different_branches.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Box(a) {\\n  Locked(password: String, value: a)\\n  Unlocked(password: String, value: a)\\n}\\n\\npub fn main() {\\n  let box = Locked(\\\"ungu€$$4bLe\\\", 11)\\n  case box {\\n    Locked(..) as box -> Locked(..box, value: True)\\n    Unlocked(..) as box -> Unlocked(..box, password: \\\"pwd\\\")\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Box(a) {\n  Locked(password: String, value: a)\n  Unlocked(password: String, value: a)\n}\n\npub fn main() {\n  let box = Locked(\"ungu€$$4bLe\", 11)\n  case box {\n    Locked(..) as box -> Locked(..box, value: True)\n    Unlocked(..) as box -> Unlocked(..box, password: \"pwd\")\n  }\n}\n\n\n----- ERROR\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:11:5\n   │\n11 │     Unlocked(..) as box -> Unlocked(..box, password: \"pwd\")\n   │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Box(Bool)\n\nFound type:\n\n    Box(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__int_eq_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1 == 1.0\n---\n----- SOURCE CODE\n1 == 1.0\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:6\n  │\n1 │ 1 == 1.0\n  │      ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__int_float_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"[1.0] == [1]\"\n---\n----- SOURCE CODE\n[1.0] == [1]\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ [1.0] == [1]\n  │          ^^^\n\nExpected type:\n\n    List(Float)\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__int_gt_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1 > 1.0\n---\n----- SOURCE CODE\n1 > 1.0\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ 1 > 1.0\n  │     ^^^\n\nThe > operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the >. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__int_operator_on_floats.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1.1 + 2.0\n---\n----- SOURCE CODE\n1.1 + 2.0\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ 1.1 + 2.0\n  │     ^ Use +. instead\n\nThe + operator can only be used on Ints.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__int_operator_on_floats_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: 1.1 > 2.0\n---\n----- SOURCE CODE\n1.1 > 2.0\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ 1.1 > 2.0\n  │     ^ Use >. instead\n\nThe > operator can only be used on Ints.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__int_operator_on_floats_in_case_guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 3.0 { x if x > 2.0 -> \\\"a\\\" _ -> \\\"b\\\" }\"\n---\n----- SOURCE CODE\ncase 3.0 { x if x > 2.0 -> \"a\" _ -> \"b\" }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ case 3.0 { x if x > 2.0 -> \"a\" _ -> \"b\" }\n  │                 ^^^^^^^ Use >. instead\n\nThe > operator can only be used on Ints.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_bit_array_pattern_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let assert <<_iDontCare>> = <<97>>\n---\n----- SOURCE CODE\nlet assert <<_iDontCare>> = <<97>>\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ let assert <<_iDontCare>> = <<97>>\n  │              ^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _i_dont_care\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_bit_array_pattern_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let assert <<bitValue>> = <<73>>\n---\n----- SOURCE CODE\nlet assert <<bitValue>> = <<73>>\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ let assert <<bitValue>> = <<73>>\n  │              ^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: bit_value\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_case_variable_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 21 { _twentyOne -> {Nil} }\"\n---\n----- SOURCE CODE\ncase 21 { _twentyOne -> {Nil} }\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ case 21 { _twentyOne -> {Nil} }\n  │           ^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _twenty_one\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_case_variable_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 21 { twentyOne -> {Nil} }\"\n---\n----- SOURCE CODE\ncase 21 { twentyOne -> {Nil} }\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ case 21 { twentyOne -> {Nil} }\n  │           ^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: twenty_one\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_const_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: const myInvalid_Constant = 42\n---\n----- SOURCE CODE\nconst myInvalid_Constant = 42\n\n----- ERROR\nerror: Invalid constant name\n  ┌─ /src/one/two.gleam:1:7\n  │\n1 │ const myInvalid_Constant = 42\n  │       ^^^^^^^^^^^^^^^^^^ This is not a valid constant name\n\nHint: Constant names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: my_invalid_constant\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_constructor_arg_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type IntWrapper { IntWrapper(innerInt: Int) }\"\n---\n----- SOURCE CODE\ntype IntWrapper { IntWrapper(innerInt: Int) }\n\n----- ERROR\nerror: Invalid label name\n  ┌─ /src/one/two.gleam:1:30\n  │\n1 │ type IntWrapper { IntWrapper(innerInt: Int) }\n  │                              ^^^^^^^^ This is not a valid label name\n\nHint: Label names start with a lowercase letter and contain a-z, 0-9, or _.\nTry: inner_int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_constructor_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type MyType { Int_Value(Int) }\"\n---\n----- SOURCE CODE\ntype MyType { Int_Value(Int) }\n\n----- ERROR\nerror: Invalid type variant name\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ type MyType { Int_Value(Int) }\n  │               ^^^^^^^^^ This is not a valid type variant name\n\nHint: Type variant names start with an uppercase letter and contain only\nlowercase letters, numbers, and uppercase letters.\nTry: IntValue\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_constructor_pattern_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub type Box { Box(Int) } pub fn main() { let Box(_ignoredInner) = Box(203)}\"\n---\n----- SOURCE CODE\npub type Box { Box(Int) } pub fn main() { let Box(_ignoredInner) = Box(203)}\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:51\n  │\n1 │ pub type Box { Box(Int) } pub fn main() { let Box(_ignoredInner) = Box(203)}\n  │                                                   ^^^^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _ignored_inner\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_constructor_pattern_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub type Box { Box(Int) } pub fn main() { let Box(innerValue) = Box(203) }\"\n---\n----- SOURCE CODE\npub type Box { Box(Int) } pub fn main() { let Box(innerValue) = Box(203) }\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:51\n  │\n1 │ pub type Box { Box(Int) } pub fn main() { let Box(innerValue) = Box(203) }\n  │                                                   ^^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: inner_value\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_custom_type_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type Boxed_value { Box(Int) }\"\n---\n----- SOURCE CODE\ntype Boxed_value { Box(Int) }\n\n----- ERROR\nerror: Invalid type name\n  ┌─ /src/one/two.gleam:1:6\n  │\n1 │ type Boxed_value { Box(Int) }\n  │      ^^^^^^^^^^^ This is not a valid type name\n\nHint: Type names start with an uppercase letter and contain only lowercase\nletters, numbers, and uppercase letters.\nTry: BoxedValue\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_function_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn doStuff() {}\"\n---\n----- SOURCE CODE\nfn doStuff() {}\n\n----- ERROR\nerror: Invalid function name\n  ┌─ /src/one/two.gleam:1:4\n  │\n1 │ fn doStuff() {}\n  │    ^^^^^^^ This is not a valid function name\n\nHint: Function names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: do_stuff\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_function_type_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn identity(value: someType) { value }\"\n---\n----- SOURCE CODE\nfn identity(value: someType) { value }\n\n----- ERROR\nerror: Invalid type variable name\n  ┌─ /src/one/two.gleam:1:20\n  │\n1 │ fn identity(value: someType) { value }\n  │                    ^^^^^^^^ This is not a valid type variable name\n\nHint: Type variable names start with a lowercase letter and contain a-z,\n0-9, or _.\nTry: some_type\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_list_pattern_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert [_elemOne] = [False]\"\n---\n----- SOURCE CODE\nlet assert [_elemOne] = [False]\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let assert [_elemOne] = [False]\n  │             ^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _elem_one\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_list_pattern_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert [theElement] = [9.4]\"\n---\n----- SOURCE CODE\nlet assert [theElement] = [9.4]\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let assert [theElement] = [9.4]\n  │             ^^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: the_element\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn ignore(_ignoreMe: Bool) { 98 }\"\n---\n----- SOURCE CODE\nfn ignore(_ignoreMe: Bool) { 98 }\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ fn ignore(_ignoreMe: Bool) { 98 }\n  │           ^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _ignore_me\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_discard_name2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn ignore(labelled_discard _ignoreMe: Bool) { 98 }\"\n---\n----- SOURCE CODE\nfn ignore(labelled_discard _ignoreMe: Bool) { 98 }\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ fn ignore(labelled_discard _ignoreMe: Bool) { 98 }\n  │                            ^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _ignore_me\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_discard_name3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let ignore = fn(_ignoreMe: Bool) { 98 }\"\n---\n----- SOURCE CODE\nlet ignore = fn(_ignoreMe: Bool) { 98 }\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ let ignore = fn(_ignoreMe: Bool) { 98 }\n  │                 ^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _ignore_me\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_label.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn func(thisIsALabel param: Int) { param }\"\n---\n----- SOURCE CODE\nfn func(thisIsALabel param: Int) { param }\n\n----- ERROR\nerror: Invalid label name\n  ┌─ /src/one/two.gleam:1:9\n  │\n1 │ fn func(thisIsALabel param: Int) { param }\n  │         ^^^^^^^^^^^^ This is not a valid label name\n\nHint: Label names start with a lowercase letter and contain a-z, 0-9, or _.\nTry: this_is_a_label\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_label2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn ignore(thisIsALabel _ignore: Int) { 25 }\"\n---\n----- SOURCE CODE\nfn ignore(thisIsALabel _ignore: Int) { 25 }\n\n----- ERROR\nerror: Invalid label name\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ fn ignore(thisIsALabel _ignore: Int) { 25 }\n  │           ^^^^^^^^^^^^ This is not a valid label name\n\nHint: Label names start with a lowercase letter and contain a-z, 0-9, or _.\nTry: this_is_a_label\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn add(numA: Int, num_b: Int) { numA + num_b }\"\n---\n----- SOURCE CODE\nfn add(numA: Int, num_b: Int) { numA + num_b }\n\n----- ERROR\nerror: Invalid argument name\n  ┌─ /src/one/two.gleam:1:8\n  │\n1 │ fn add(numA: Int, num_b: Int) { numA + num_b }\n  │        ^^^^ This is not a valid argument name\n\nHint: Argument names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: num_a\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_name2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn pass(label paramName: Bool) { paramName }\"\n---\n----- SOURCE CODE\nfn pass(label paramName: Bool) { paramName }\n\n----- ERROR\nerror: Invalid argument name\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ fn pass(label paramName: Bool) { paramName }\n  │               ^^^^^^^^^ This is not a valid argument name\n\nHint: Argument names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: param_name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_parameter_name3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let add = fn(numA: Int, num_b: Int) { numA + num_b }\"\n---\n----- SOURCE CODE\nlet add = fn(numA: Int, num_b: Int) { numA + num_b }\n\n----- ERROR\nerror: Invalid argument name\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ let add = fn(numA: Int, num_b: Int) { numA + num_b }\n  │              ^^^^ This is not a valid argument name\n\nHint: Argument names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: num_a\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_pattern_assignment_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let assert 42 as theAnswer = 42\n---\n----- SOURCE CODE\nlet assert 42 as theAnswer = 42\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ let assert 42 as theAnswer = 42\n  │                  ^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: the_answer\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_pattern_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble { Wibble(arg: Int) }\\npub fn main() {\\n  let Wibble(not_a_label:) = Wibble(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(arg: Int) }\npub fn main() {\n  let Wibble(not_a_label:) = Wibble(1)\n}\n\n\n----- ERROR\nerror: Unknown label\n  ┌─ /src/one/two.gleam:4:14\n  │\n4 │   let Wibble(not_a_label:) = Wibble(1)\n  │              ^^^^^^^^^^^^ Did you mean `arg`?\n\nIt accepts these labels:\n\n    arg\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_string_prefix_pattern_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert \\\"prefix\\\" as thePrefix <> _suffix = \\\"prefix-suffix\\\"\"\n---\n----- SOURCE CODE\nlet assert \"prefix\" as thePrefix <> _suffix = \"prefix-suffix\"\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ let assert \"prefix\" as thePrefix <> _suffix = \"prefix-suffix\"\n  │                        ^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: the_prefix\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_string_prefix_pattern_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert \\\"prefix\\\" <> _boringSuffix = \\\"prefix-suffix\\\"\"\n---\n----- SOURCE CODE\nlet assert \"prefix\" <> _boringSuffix = \"prefix-suffix\"\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ let assert \"prefix\" <> _boringSuffix = \"prefix-suffix\"\n  │                        ^^^^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _boring_suffix\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_string_prefix_pattern_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert \\\"prefix\\\" <> coolSuffix = \\\"prefix-suffix\\\"\"\n---\n----- SOURCE CODE\nlet assert \"prefix\" <> coolSuffix = \"prefix-suffix\"\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ let assert \"prefix\" <> coolSuffix = \"prefix-suffix\"\n  │                        ^^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: cool_suffix\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_tuple_pattern_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let #(a, _secondValue) = #(1, 2)\"\n---\n----- SOURCE CODE\nlet #(a, _secondValue) = #(1, 2)\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ let #(a, _secondValue) = #(1, 2)\n  │          ^^^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _second_value\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_tuple_pattern_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let #(a, secondValue) = #(1, 2)\"\n---\n----- SOURCE CODE\nlet #(a, secondValue) = #(1, 2)\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ let #(a, secondValue) = #(1, 2)\n  │          ^^^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: second_value\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_type_alias_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: type Fancy_Bool = Bool\n---\n----- SOURCE CODE\ntype Fancy_Bool = Bool\n\n----- ERROR\nerror: Invalid type alias name\n  ┌─ /src/one/two.gleam:1:6\n  │\n1 │ type Fancy_Bool = Bool\n  │      ^^^^^^^^^^ This is not a valid type alias name\n\nHint: Type alias names start with an uppercase letter and contain only\nlowercase letters, numbers, and uppercase letters.\nTry: FancyBool\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_type_alias_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type GleamOption(okType) = Result(okType, Nil)\"\n---\n----- SOURCE CODE\ntype GleamOption(okType) = Result(okType, Nil)\n\n----- ERROR\nerror: Invalid type variable name\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ type GleamOption(okType) = Result(okType, Nil)\n  │                  ^^^^^^ This is not a valid type variable name\n\nHint: Type variable names start with a lowercase letter and contain a-z,\n0-9, or _.\nTry: ok_type\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_type_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type Wrapper(innerType) {}\"\n---\n----- SOURCE CODE\ntype Wrapper(innerType) {}\n\n----- ERROR\nerror: Invalid type variable name\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ type Wrapper(innerType) {}\n  │              ^^^^^^^^^ This is not a valid type variable name\n\nHint: Type variable names start with a lowercase letter and contain a-z,\n0-9, or _.\nTry: inner_type\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_use_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn use_test(f) { f(Nil) }\\npub fn main() { use _discardVar <- use_test() }\"\n---\n----- SOURCE CODE\nfn use_test(f) { f(Nil) }\npub fn main() { use _discardVar <- use_test() }\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:2:21\n  │\n2 │ pub fn main() { use _discardVar <- use_test() }\n  │                     ^^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _discard_var\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_use_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn use_test(f) { f(Nil) }\\npub fn main() { use useVar <- use_test() }\"\n---\n----- SOURCE CODE\nfn use_test(f) { f(Nil) }\npub fn main() { use useVar <- use_test() }\n\n----- ERROR\nerror: Invalid argument name\n  ┌─ /src/one/two.gleam:2:21\n  │\n2 │ pub fn main() { use useVar <- use_test() }\n  │                     ^^^^^^ This is not a valid argument name\n\nHint: Argument names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: use_var\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_variable_discard_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let _boringNumber = 72\n---\n----- SOURCE CODE\nlet _boringNumber = 72\n\n----- ERROR\nerror: Invalid discard name\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let _boringNumber = 72\n  │     ^^^^^^^^^^^^^ This is not a valid discard name\n\nHint: Discard names start with _ and contain a-z, 0-9, or _.\nTry: _boring_number\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__invalid_variable_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let theAnswer = 42\n---\n----- SOURCE CODE\nlet theAnswer = 42\n\n----- ERROR\nerror: Invalid variable name\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let theAnswer = 42\n  │     ^^^^^^^^^ This is not a valid variable name\n\nHint: Variable names start with a lowercase letter and contain a-z, 0-9, or\n_.\nTry: the_answer\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__leak_multiple_private_types.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        type Private {\\n            Private\\n        }\\n\\n        pub fn ret_private() -> Private {\\n            Private\\n        }\\n\\n        pub fn ret_private2() -> Private {\\n            Private\\n        }\\n\\n        pub fn main() {\\n            ret_private()\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        type Private {\n            Private\n        }\n\n        pub fn ret_private() -> Private {\n            Private\n        }\n\n        pub fn ret_private2() -> Private {\n            Private\n        }\n\n        pub fn main() {\n            ret_private()\n        }\n        \n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:6:9\n  │\n6 │         pub fn ret_private() -> Private {\n  │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    Private\n\nPrivate types can only be used within the module that defines them.\n\nerror: Private type used in public interface\n   ┌─ /src/one/two.gleam:10:9\n   │\n10 │         pub fn ret_private2() -> Private {\n   │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    Private\n\nPrivate types can only be used within the module that defines them.\n\nerror: Private type used in public interface\n   ┌─ /src/one/two.gleam:14:9\n   │\n14 │         pub fn main() {\n   │         ^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    Private\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__let_assert_binding_cannot_be_used_in_panic_message.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  let assert Ok(message) = Error(\\\"Not Message\\\") as { \\\"Uh oh: \\\" <> message }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert Ok(message) = Error(\"Not Message\") as { \"Uh oh: \" <> message }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:3:67\n  │\n3 │   let assert Ok(message) = Error(\"Not Message\") as { \"Uh oh: \" <> message }\n  │                                                                   ^^^^^^^\n\nThe name `message` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"[1, 2.0]\"\n---\n----- SOURCE CODE\n[1, 2.0]\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ [1, 2.0]\n  │     ^^^\n\nAll elements of a list must be the same type, but this one doesn't\nmatch the one before it.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__mismatched_list_tail.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"[\\\"wibble\\\", ..[1, 2]]\"\n---\n----- SOURCE CODE\n[\"wibble\", ..[1, 2]]\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ [\"wibble\", ..[1, 2]]\n  │              ^^^^^^\n\nAll elements in a list must have the same type, but the elements of\nthis list don't match the type of the elements being prepended to it.\n\nExpected type:\n\n    List(String)\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__missing_case_body.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: case True\n---\n----- SOURCE CODE\ncase True\n\n----- ERROR\nerror: Missing case body\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ case True\n  │ ^^^^^^^^^\n\nThis case expression is missing its body.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__missing_type_constructor_arguments_in_type_annotation_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() -> Result() {}\"\n---\n----- SOURCE CODE\npub fn main() -> Result() {}\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:18\n  │\n1 │ pub fn main() -> Result() {}\n  │                  ^^^^^^^^ Expected 2 type arguments, got 0\n\n`Result` requires 2 type arguments but none where provided.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__missing_type_constructor_arguments_in_type_annotation_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() {\\n  let a: Result() = todo\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a: Result() = todo\n}\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:2:10\n  │\n2 │   let a: Result() = todo\n  │          ^^^^^^^^ Expected 2 type arguments, got 0\n\n`Result` requires 2 type arguments but none where provided.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__missing_variable_in_alternative_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case [] { [x] | [] -> x _ -> 0 }\"\n---\n----- SOURCE CODE\ncase [] { [x] | [] -> x _ -> 0 }\n\n----- ERROR\nerror: Missing alternative pattern variable\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ case [] { [x] | [] -> x _ -> 0 }\n  │           ^^^^^^^^^^^^^ This does not define all required variables\n\nAll alternative patterns must define the same variables as the initial\npattern, but the `x` variable is missing.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_arity_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn go(x: List(a, b)) -> Int { 1 }\"\n---\n----- SOURCE CODE\nfn go(x: List(a, b)) -> Int { 1 }\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ fn go(x: List(a, b)) -> Int { 1 }\n  │          ^^^^^^^^^^ Expected 1 type argument, got 2\n\n`List` requires 1 type argument but 2 where provided.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn go() { 1 + 2.0 }\"\n---\n----- SOURCE CODE\nfn go() { 1 + 2.0 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ fn go() { 1 + 2.0 }\n  │               ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify10.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn main() {\\n            let #(y, [..x]): #(x, List(x)) = #(\\\"one\\\", [1,2,3])\\n            x\\n        }\"\n---\n----- SOURCE CODE\nfn main() {\n            let #(y, [..x]): #(x, List(x)) = #(\"one\", [1,2,3])\n            x\n        }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:46\n  │\n2 │             let #(y, [..x]): #(x, List(x)) = #(\"one\", [1,2,3])\n  │                                              ^^^^^^^^^^^^^^^^^\n\nExpected type:\n\n    #(x, List(x))\n\nFound type:\n\n    #(String, List(Int))\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify11.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        pub type Box(inner) {\\n            Box(inner)\\n        }\\n\\n        pub fn create_int_box(value: Int) {\\n            let x: Box(Float) = Box(value)\\n            x\\n        }\"\n---\n----- SOURCE CODE\n\n        pub type Box(inner) {\n            Box(inner)\n        }\n\n        pub fn create_int_box(value: Int) {\n            let x: Box(Float) = Box(value)\n            x\n        }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:33\n  │\n7 │             let x: Box(Float) = Box(value)\n  │                                 ^^^^^^^^^^\n\nExpected type:\n\n    Box(Float)\n\nFound type:\n\n    Box(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify12.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        pub type Person {\\n            Person(name: String, age: Int)\\n        }\\n\\n        pub fn create_person(age: Float) {\\n            let x: Person = Person(name: \\\"Quinn\\\", age: age)\\n            x\\n        }\"\n---\n----- SOURCE CODE\n\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n\n        pub fn create_person(age: Float) {\n            let x: Person = Person(name: \"Quinn\", age: age)\n            x\n        }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:56\n  │\n7 │             let x: Person = Person(name: \"Quinn\", age: age)\n  │                                                        ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn go() { 1 + 2.0 }\"\n---\n----- SOURCE CODE\nfn go() { 1 + 2.0 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ fn go() { 1 + 2.0 }\n  │               ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn id(x: a, y: a) { x }\\npub fn x() { id(1, 1.0) }\"\n---\n----- SOURCE CODE\n\nfn id(x: a, y: a) { x }\npub fn x() { id(1, 1.0) }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:20\n  │\n3 │ pub fn x() { id(1, 1.0) }\n  │                    ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn wobble() -> Int {\\n    5\\n}\\n\\nfn run(one: fn() -> String) {\\n    one()\\n}\\n\\nfn demo() {\\n    run(wobble)\\n}\"\n---\n----- SOURCE CODE\n\nfn wobble() -> Int {\n    5\n}\n\nfn run(one: fn() -> String) {\n    one()\n}\n\nfn demo() {\n    run(wobble)\n}\n\n----- ERROR\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:11:9\n   │\n11 │     run(wobble)\n   │         ^^^^^^\n\nExpected type:\n\n    fn() -> String\n\nFound type:\n\n    fn() -> Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn wobble(x: Int) -> Int {\\n    x * 5\\n}\\n\\nfn run(one: fn(String) -> Int) {\\n    one(\\\"one.\\\")\\n}\\n\\nfn demo() {\\n    run(wobble)\\n}\"\n---\n----- SOURCE CODE\n\nfn wobble(x: Int) -> Int {\n    x * 5\n}\n\nfn run(one: fn(String) -> Int) {\n    one(\"one.\")\n}\n\nfn demo() {\n    run(wobble)\n}\n\n----- ERROR\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:11:9\n   │\n11 │     run(wobble)\n   │         ^^^^^^\n\nExpected type:\n\n    fn(String) -> Int\n\nFound type:\n\n    fn(Int) -> Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn main() { let x: String = 5 x }\"\n---\n----- SOURCE CODE\nfn main() { let x: String = 5 x }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ fn main() { let x: String = 5 x }\n  │                             ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn main() { let assert 5 = \\\"\\\" }\"\n---\n----- SOURCE CODE\nfn main() { let assert 5 = \"\" }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ fn main() { let assert 5 = \"\" }\n  │                        ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn main() { let x: #(x, x) = #(5, 5.0) x }\"\n---\n----- SOURCE CODE\nfn main() { let x: #(x, x) = #(5, 5.0) x }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:30\n  │\n1 │ fn main() { let x: #(x, x) = #(5, 5.0) x }\n  │                              ^^^^^^^^^\n\nExpected type:\n\n    #(x, x)\n\nFound type:\n\n    #(Int, Float)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_could_not_unify9.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn main() { let assert [1, 2, ..x]: List(String) = [1,2,3] x }\"\n---\n----- SOURCE CODE\nfn main() { let assert [1, 2, ..x]: List(String) = [1,2,3] x }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:52\n  │\n1 │ fn main() { let assert [1, 2, ..x]: List(String) = [1,2,3] x }\n  │                                                    ^^^^^^^\n\nExpected type:\n\n    List(String)\n\nFound type:\n\n    List(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_non_local_gaurd_var.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn one() { 1 }\\nfn main() { case 1 { _ if one -> 1 } }\"\n---\n----- SOURCE CODE\nfn one() { 1 }\nfn main() { case 1 { _ if one -> 1 } }\n\n----- ERROR\nerror: Invalid guard variable\n  ┌─ /src/one/two.gleam:2:27\n  │\n2 │ fn main() { case 1 { _ if one -> 1 } }\n  │                           ^^^ Is not locally defined\n\nVariables used in guards must be either defined in the function, or be an\nargument to the function. The variable `one` is not defined locally.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_private_type_leak_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type PrivateType\\n\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\npub fn leak_type() -> PrivateType\\n\"\n---\n----- SOURCE CODE\ntype PrivateType\n\n@external(erlang, \"a\", \"b\")\npub fn leak_type() -> PrivateType\n\n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:4:1\n  │\n4 │ pub fn leak_type() -> PrivateType\n  │ ^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    PrivateType\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_private_type_leak_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type PrivateType\\n\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\nfn go() -> PrivateType\\n\\npub fn leak_type() { go() }\"\n---\n----- SOURCE CODE\ntype PrivateType\n\n@external(erlang, \"a\", \"b\")\nfn go() -> PrivateType\n\npub fn leak_type() { go() }\n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:6:1\n  │\n6 │ pub fn leak_type() { go() }\n  │ ^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    PrivateType\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_private_type_leak_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type PrivateType\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\nfn go() -> PrivateType\\npub fn leak_type() { [go()] }\"\n---\n----- SOURCE CODE\ntype PrivateType\n@external(erlang, \"a\", \"b\")\nfn go() -> PrivateType\npub fn leak_type() { [go()] }\n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:4:1\n  │\n4 │ pub fn leak_type() { [go()] }\n  │ ^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    PrivateType\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_private_type_leak_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type PrivateType\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\npub fn go(x: PrivateType) -> Int\"\n---\n----- SOURCE CODE\ntype PrivateType\n@external(erlang, \"a\", \"b\")\npub fn go(x: PrivateType) -> Int\n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub fn go(x: PrivateType) -> Int\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    PrivateType\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_private_type_leak_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type PrivateType\\npub type LeakType { Variant(PrivateType) }\"\n---\n----- SOURCE CODE\ntype PrivateType\npub type LeakType { Variant(PrivateType) }\n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:2:21\n  │\n2 │ pub type LeakType { Variant(PrivateType) }\n  │                     ^^^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    PrivateType\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__module_private_type_leak_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type PrivateType\\npub type LeakType { Variant(PrivateType) }\"\n---\n----- SOURCE CODE\ntype PrivateType\npub type LeakType { Variant(PrivateType) }\n\n----- ERROR\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:2:21\n  │\n2 │ pub type LeakType { Variant(PrivateType) }\n  │                     ^^^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    PrivateType\n\nPrivate types can only be used within the module that defines them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__native_endianness_javascript_target.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nassertion_line: 3260\nexpression: \"\\npub fn main() {\\n  let assert <<a:native>> = <<10>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<a:native>> = <<10>>\n}\n\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:3:18\n  │\n3 │   let assert <<a:native>> = <<10>>\n  │                  ^^^^^^ Unsupported endianness\n\nThe JavaScript target does not support the `native` endianness option.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negate_boolean_as_integer.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn() {\\n  let a = True\\n  let b = -a\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn() {\n  let a = True\n  let b = -a\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:12\n  │\n4 │   let b = -a\n  │            ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Bool\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negate_float_as_integer.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn() {\\n  let a = 3.0\\n  let b = -a\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn() {\n  let a = 3.0\n  let b = -a\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:12\n  │\n4 │   let b = -a\n  │            ^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negate_string.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"!\\\"Hello Gleam\\\"\"\n---\n----- SOURCE CODE\n!\"Hello Gleam\"\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:2\n  │\n1 │ !\"Hello Gleam\"\n  │  ^^^^^^^^^^^^^\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negative_out_of_range_erlang_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"-1.8e308\"\n---\n----- SOURCE CODE\n-1.8e308\n\n----- ERROR\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ -1.8e308\n  │ ^^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negative_out_of_range_erlang_float_in_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: const x = -1.8e308\n---\n----- SOURCE CODE\nconst x = -1.8e308\n\n----- ERROR\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ const x = -1.8e308\n  │           ^^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negative_out_of_range_erlang_float_in_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert [-1.8e308, b] = [x, y]\"\n---\n----- SOURCE CODE\nlet assert [-1.8e308, b] = [x, y]\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ let assert [-1.8e308, b] = [x, y]\n  │                             ^\n\nThe name `x` is not in scope here.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:32\n  │\n1 │ let assert [-1.8e308, b] = [x, y]\n  │                                ^\n\nThe name `y` is not in scope here.\n\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let assert [-1.8e308, b] = [x, y]\n  │             ^^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__negative_size_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert <<1:size(-1)>> = <<>>\"\n---\n----- SOURCE CODE\nlet assert <<1:size(-1)>> = <<>>\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:16\n  │\n1 │ let assert <<1:size(-1)>> = <<>>\n  │                ^^^^^^^^ A constant size must be a positive number\n\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_duplicate_definition.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wobble\\n  Wobble\\n}\\n\\npub fn main() {\\n  let wibble = Wobble\\n  case wibble {\\n    Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wobble\n  Wobble\n}\n\npub fn main() {\n  let wibble = Wobble\n  case wibble {\n    Wobble -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:4:3\n  │\n3 │   Wobble\n  │   ------ First defined here\n4 │   Wobble\n  │   ^^^^^^ Redefined here\n\n`Wobble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_duplicate_definition2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n  Wobble\\n  Wubble\\n}\\n\\npub fn main() {\\n  let wibble = Wobble\\n  case wibble {\\n    Wibble -> Nil\\n    Wobble -> Nil\\n    Wubble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n  Wobble\n  Wubble\n}\n\npub fn main() {\n  let wibble = Wobble\n  case wibble {\n    Wibble -> Nil\n    Wobble -> Nil\n    Wubble -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Duplicate definition\n  ┌─ /src/one/two.gleam:5:3\n  │\n4 │   Wobble\n  │   ------ First defined here\n5 │   Wobble\n  │   ^^^^^^ Redefined here\n\n`Wobble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_duplicate_record_fields.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type X {\\n  A\\n  B(e0: Int, e0: Int)\\n}\\n\\nfn compiler_crash(x: X) {\\n  case x {\\n    A -> todo\\n    _ -> todo\\n  }\\n}\\n  \"\n---\n----- SOURCE CODE\n\npub type X {\n  A\n  B(e0: Int, e0: Int)\n}\n\nfn compiler_crash(x: X) {\n  case x {\n    A -> todo\n    _ -> todo\n  }\n}\n  \n\n----- ERROR\nerror: Duplicate label\n  ┌─ /src/one/two.gleam:4:14\n  │\n4 │   B(e0: Int, e0: Int)\n  │              ^^\n\nThe label `e0` has already been defined. Rename this label.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_record_update_when_constructor_definition_is_invalid.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Int, Bool)\\n}\\n\\npub fn main() {\\n  let one = Wibble(False, a: 5, b: 6)\\n  let two = Wibble(..one, b: 1)\\n}\\n        \"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Int, Bool)\n}\n\npub fn main() {\n  let one = Wibble(False, a: 5, b: 6)\n  let two = Wibble(..one, b: 1)\n}\n        \n\n----- ERROR\nerror: Unlabelled argument after labelled argument\n  ┌─ /src/one/two.gleam:3:26\n  │\n3 │   Wibble(a: Int, b: Int, Bool)\n  │                          ^^^^\n\nAll unlabelled arguments must come before any labelled arguments.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_hint_for_non_method_call.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type User {\\n  User(id: Int, name: String)\\n}\\n\\nfn login(user: User) {\\n  user\\n}\\n\\npub fn main(user: User) {\\n  login(user.wibble)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type User {\n  User(id: Int, name: String)\n}\n\nfn login(user: User) {\n  user\n}\n\npub fn main(user: User) {\n  login(user.wibble)\n}\n\n\n----- ERROR\nerror: Unknown record field\n   ┌─ /src/one/two.gleam:11:14\n   │\n11 │   login(user.wibble)\n   │              ^^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    User\n\nIt has these accessible fields:\n\n    .id\n    .name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_note_about_reliable_access_if_the_accessed_type_has_a_single_variant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type User {\\n  User(name: String)\\n}\\n\\npub fn main() {\\n  User(\\\"Jak\\\").nam\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type User {\n  User(name: String)\n}\n\npub fn main() {\n  User(\"Jak\").nam\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:7:15\n  │\n7 │   User(\"Jak\").nam\n  │               ^^^ Did you mean `name`?\n\nThe value being accessed has this type:\n\n    User\n\nIt has these accessible fields:\n\n    .name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__non_utf8_string_assignment.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert <<\\\"Hello\\\" as message:utf16>> = <<>>\"\n---\n----- SOURCE CODE\nlet assert <<\"Hello\" as message:utf16>> = <<>>\n\n----- ERROR\nerror: Non UTF-8 string assignment\n  ┌─ /src/one/two.gleam:1:25\n  │\n1 │ let assert <<\"Hello\" as message:utf16>> = <<>>\n  │                         ^^^^^^^\n\nThis pattern assigns a non UTF-8 string to a variable in a bit array. This\nis planned to be supported in the future, but we are unsure of the desired\nbehaviour. Please go to https://github.com/gleam-lang/gleam/issues/4566 and\nexplain your usecase for this pattern, and how you would expect it to\nbehave.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__not_a_constructor_update.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n  Person(name: String, age: Int)\\n}\\npub fn identity(a) { a }\\npub fn update_person(person: Person) {\\n  identity(..person)\\n}\"\n---\n----- SOURCE CODE\n\npub type Person {\n  Person(name: String, age: Int)\n}\npub fn identity(a) { a }\npub fn update_person(person: Person) {\n  identity(..person)\n}\n\n----- ERROR\nerror: Invalid record constructor\n  ┌─ /src/one/two.gleam:7:3\n  │\n7 │   identity(..person)\n  │   ^^^^^^^^ This is not a record constructor\n\nOnly record constructors can be used with the update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__ok_2_args.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let Ok(1, x) = 1\"\n---\n----- SOURCE CODE\nlet Ok(1, x) = 1\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let Ok(1, x) = 1\n  │     ^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Result(Int, a)\n\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let Ok(1, x) = 1\n  │     ^^^^^^^^ Expected 1 argument, got 2\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__out_of_range_erlang_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"1.8e308\"\n---\n----- SOURCE CODE\n1.8e308\n\n----- ERROR\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ 1.8e308\n  │ ^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__out_of_range_erlang_float_in_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: const x = 1.8e308\n---\n----- SOURCE CODE\nconst x = 1.8e308\n\n----- ERROR\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:1:11\n  │\n1 │ const x = 1.8e308\n  │           ^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__out_of_range_erlang_float_in_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert [1.8e308, b] = [x, y]\"\n---\n----- SOURCE CODE\nlet assert [1.8e308, b] = [x, y]\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ let assert [1.8e308, b] = [x, y]\n  │                            ^\n\nThe name `x` is not in scope here.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:31\n  │\n1 │ let assert [1.8e308, b] = [x, y]\n  │                               ^\n\nThe name `y` is not in scope here.\n\nerror: Float outside of valid range\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ let assert [1.8e308, b] = [x, y]\n  │             ^^^^^^^\n\nThis float value is too large to be represented by a floating point type:\nfloat values must be in the range -1.7976931348623157e308 -\n1.7976931348623157e308.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__pattern_with_incorrect_arity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Pokemon { Pokemon(name: String, id: Int) }\\n\\npub fn main() {\\n  case todo {\\n    Pokemon(name:) -> todo\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Pokemon { Pokemon(name: String, id: Int) }\n\npub fn main() {\n  case todo {\n    Pokemon(name:) -> todo\n  }\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:6:5\n  │\n6 │     Pokemon(name:) -> todo\n  │     ^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\nThis pattern accepts these additional labelled arguments:\n\n  - id\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__pipe_arity_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn go(x, y) {\\n  x + y\\n}\\n\\nfn main(x) {\\n  1\\n  |> go\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn go(x, y) {\n  x + y\n}\n\nfn main(x) {\n  1\n  |> go\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:8:6\n  │\n8 │   |> go\n  │      ^^\n\nExpected type:\n\n    fn(Int) -> a\n\nFound type:\n\n    fn(Int, Int) -> Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__pipe_mismatch_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() -> String {\\n            Orange\\n            |> eat_veggie\\n         }\\n\\n         type Fruit{ Orange }\\n         type Veg{ Lettuce }\\n\\n         fn eat_veggie(v: Veg) -> String {\\n            \\\"Ok\\\"\\n         }\"\n---\n----- SOURCE CODE\npub fn main() -> String {\n            Orange\n            |> eat_veggie\n         }\n\n         type Fruit{ Orange }\n         type Veg{ Lettuce }\n\n         fn eat_veggie(v: Veg) -> String {\n            \"Ok\"\n         }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:16\n  │\n3 │             |> eat_veggie\n  │                ^^^^^^^^^^ This function does not accept the piped type\n\nThe argument is:\n\n    Fruit\n\nBut function expects:\n\n    Veg\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__pipe_value_type_mismatch_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() -> String {\\n            eat_veggie\\n            |> Orange\\n         }\\n\\n         type Fruit{ Orange }\\n         type Veg{ Lettuce }\\n\\n         fn eat_veggie(v: Veg) -> String {\\n            \\\"Ok\\\"\\n         }\"\n---\n----- SOURCE CODE\npub fn main() -> String {\n            eat_veggie\n            |> Orange\n         }\n\n         type Fruit{ Orange }\n         type Veg{ Lettuce }\n\n         fn eat_veggie(v: Veg) -> String {\n            \"Ok\"\n         }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:16\n  │\n3 │             |> Orange\n  │                ^^^^^^\n\nExpected type:\n\n    fn(fn(Veg) -> String) -> String\n\nFound type:\n\n    Fruit\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__positional_argument_after_labelled.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Int, c: Int) }\\nfn x() { X(b: 1, a: 1, 1) }\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Int, c: Int) }\nfn x() { X(b: 1, a: 1, 1) }\n\n----- ERROR\nerror: Unexpected positional argument\n  ┌─ /src/one/two.gleam:2:24\n  │\n2 │ fn x() { X(b: 1, a: 1, 1) }\n  │                        ^\n\nThis unlabeled argument has been supplied after a labelled argument.\nOnce a labelled argument has been supplied all following arguments must\nalso be labelled.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__positional_argument_after_one_using_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Int, c: Int) }\\nfn x() {\\n  let b = 1\\n  let a = 1\\n  X(b:, a:, 1)\\n}\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Int, c: Int) }\nfn x() {\n  let b = 1\n  let a = 1\n  X(b:, a:, 1)\n}\n\n----- ERROR\nerror: Unexpected positional argument\n  ┌─ /src/one/two.gleam:5:13\n  │\n5 │   X(b:, a:, 1)\n  │             ^\n\nThis unlabeled argument has been supplied after a labelled argument.\nOnce a labelled argument has been supplied all following arguments must\nalso be labelled.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__private_opaque_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nopaque type Wibble {\\n  Wobble\\n}\\n\"\n---\n----- SOURCE CODE\n\nopaque type Wibble {\n  Wobble\n}\n\n\n----- ERROR\nerror: Private opaque type\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ opaque type Wibble {\n  │ ^^^^^^ You can safely remove this.\n\nOnly a public type can be opaque.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_invalid_operands.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport maths as math\\npub fn add_two_vectors(a: math.Vector, b: math.Vector) {\\n  a + b\\n}\\n\"\n---\n----- SOURCE CODE\n-- maths.gleam\npub type Vector { Vector(x: Float, y: Float) }\n\n-- main.gleam\n\nimport maths as math\npub fn add_two_vectors(a: math.Vector, b: math.Vector) {\n  a + b\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   a + b\n  │   ^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    math.Vector\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   a + b\n  │       ^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    math.Vector\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_invalid_pipe_argument.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport mod\\npub fn main() {\\n  Nil |> mod.takes_wibble\\n}\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub type Wibble pub fn takes_wibble(value: Wibble) { value }\n\n-- main.gleam\n\nimport mod\npub fn main() {\n  Nil |> mod.takes_wibble\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:10\n  │\n4 │   Nil |> mod.takes_wibble\n  │          ^^^^^^^^^^^^^^^^ This function does not accept the piped type\n\nThe argument is:\n\n    Nil\n\nBut function expects:\n\n    mod.Wibble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_mismatched_type_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport wibble\\nconst my_wobble: wibble.Wobble = Nil\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wobble\n\n-- main.gleam\n\nimport wibble\nconst my_wobble: wibble.Wobble = Nil\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:34\n  │\n3 │ const my_wobble: wibble.Wobble = Nil\n  │                                  ^^^\n\nExpected type:\n\n    wibble.Wobble\n\nFound type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_not_a_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport wibble.{type Function as FuncWrapper}\\npub fn main(f: FuncWrapper) {\\n  f()\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Function { Function(fn() -> Nil) }\n\n-- main.gleam\n\nimport wibble.{type Function as FuncWrapper}\npub fn main(f: FuncWrapper) {\n  f()\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   f()\n  │   ^\n\nThis value is being called as a function but its type is:\n\n    FuncWrapper\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_not_a_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport mod.{type Pair as Duo}\\npub fn first(pair: Duo(a, b)) {\\n  pair.0\\n}\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub type Pair(a, b) { Pair(a, b) }\n\n-- main.gleam\n\nimport mod.{type Pair as Duo}\npub fn first(pair: Duo(a, b)) {\n  pair.0\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   pair.0\n  │   ^^^^ This is not a tuple\n\nTo index into this value it needs to be a tuple, however it has this type:\n\n    Duo(a, b)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_not_fn_in_use.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport some_mod as sm\\npub fn main(func: sm.Function(Int, String, Float)) {\\n  use <- func()\\n}\\n\"\n---\n----- SOURCE CODE\n-- some_mod.gleam\npub type Function(param1, param2, return)\n\n-- main.gleam\n\nimport some_mod as sm\npub fn main(func: sm.Function(Int, String, Float)) {\n  use <- func()\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:10\n  │\n4 │   use <- func()\n  │          ^^^^^^\n\nIn a use expression, there should be a function on the right hand side of\n`<-`, but this value has type:\n\n    sm.Function(Int, String, Float)\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_similar_type_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport wibble\\nconst value: wibble.Int = 20\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Int\n\n-- main.gleam\n\nimport wibble\nconst value: wibble.Int = 20\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:27\n  │\n3 │ const value: wibble.Int = 20\n  │                           ^^\n\nExpected type:\n\n    wibble.Int\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_unification_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport gleam\\n\\ntype Bool {\\n  True\\n  False\\n}\\n\\nconst list_of_bools = [True, False, gleam.False]\\n\"\n---\n----- SOURCE CODE\n\nimport gleam\n\ntype Bool {\n  True\n  False\n}\n\nconst list_of_bools = [True, False, gleam.False]\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:9:37\n  │\n9 │ const list_of_bools = [True, False, gleam.False]\n  │                                     ^^^^^^^^^^^\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    gleam.Bool\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_unknown_field.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport gleam\\ntype Int {\\n  Int(bit_size: gleam.Int, bits: BitArray)\\n}\\n\\npub fn main(not_a_record: gleam.Int) {\\n  not_a_record.bits\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam\ntype Int {\n  Int(bit_size: gleam.Int, bits: BitArray)\n}\n\npub fn main(not_a_record: gleam.Int) {\n  not_a_record.bits\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:8:16\n  │\n8 │   not_a_record.bits\n  │                ^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    gleam.Int\n\nIt does not have any fields.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__qualified_type_use_fn_without_callback.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport some_mod\\npub fn main() {\\n  use value <- some_mod.do_a_thing(10)\\n}\\n\"\n---\n----- SOURCE CODE\n-- some_mod.gleam\npub type NotACallback pub fn do_a_thing(a: Int, _b: NotACallback) { a }\n\n-- main.gleam\n\nimport some_mod\npub fn main() {\n  use value <- some_mod.do_a_thing(10)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:16\n  │\n4 │   use value <- some_mod.do_a_thing(10)\n  │                ^^^^^^^^^^^^^^^^^^^^^^^\n\nThe function on the right hand side of `<-` has to take a callback function\nas its last argument. But the last argument of this function has type:\n\n    some_mod.NotACallback\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_access_on_inferred_variant_when_field_is_in_other_variants.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int)\\n  Wobble(wobble: Int)\\n}\\n\\npub fn main() {\\n  let always_wibble = Wibble(10)\\n  always_wibble.wobble\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(wibble: Int)\n  Wobble(wobble: Int)\n}\n\npub fn main() {\n  let always_wibble = Wibble(10)\n  always_wibble.wobble\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:9:17\n  │\n9 │   always_wibble.wobble\n  │                 ^^^^^^ Did you mean `wibble`?\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt has these accessible fields:\n\n    .wibble\n\nNote: The field exists in this custom type but is not defined for the\ncurrent variant. Ensure that you are accessing the field on a variant where\nit is valid.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_compatible_fields_wrong_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type A {\\n  A(a: Int, b: Int)\\n}\\n\\npub type B {\\n  B(a: Int, b: Int)\\n}\\n\\npub fn b_to_a(value: B) {\\n  A(..value, b: 5)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type A {\n  A(a: Int, b: Int)\n}\n\npub type B {\n  B(a: Int, b: Int)\n}\n\npub fn b_to_a(value: B) {\n  A(..value, b: 5)\n}\n\n\n----- ERROR\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:11:7\n   │\n11 │   A(..value, b: 5)\n   │       ^^^^^\n\nExpected type:\n\n    A\n\nFound type:\n\n    B\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_compatible_fields_wrong_variant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  A(a: Int, b: Int)\\n  B(a: Int, b: Int)\\n}\\n\\npub fn b_to_a(value: Wibble) {\\n  case value {\\n    A(..) -> value\\n    B(..) as b -> A(..b, b: 3)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  A(a: Int, b: Int)\n  B(a: Int, b: Int)\n}\n\npub fn b_to_a(value: Wibble) {\n  case value {\n    A(..) -> value\n    B(..) as b -> A(..b, b: 3)\n  }\n}\n\n\n----- ERROR\nerror: Incorrect record update\n   ┌─ /src/one/two.gleam:10:23\n   │\n10 │     B(..) as b -> A(..b, b: 3)\n   │                       ^ This is a `B`\n\nThis value is a `B` so it cannot be used to build a `A`, even if they share\nsome fields.\n\nNote: If you want to change one variant of a type into another, you should\nspecify all fields explicitly instead of using the record update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_does_not_stop_at_first_invalid_field_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, c: 1, a: 1.0)\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, c: 1, a: 1.0)\n}\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:7:22\n  │\n7 │     Wibble(..wibble, c: 1, a: 1.0)\n  │                      ^^^^ Did you mean `a`?\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt has these accessible fields:\n\n    .a\n    .b\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:28\n  │\n7 │     Wibble(..wibble, c: 1, a: 1.0)\n  │                            ^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_does_not_stop_at_first_invalid_field_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: 1.0, a: 2, c: 2)\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: 1.0, a: 2, c: 2)\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:22\n  │\n7 │     Wibble(..wibble, a: 1.0, a: 2, c: 2)\n  │                      ^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Duplicate argument\n  ┌─ /src/one/two.gleam:7:30\n  │\n7 │     Wibble(..wibble, a: 1.0, a: 2, c: 2)\n  │                              ^^^^\n\nThe labelled argument `a` has already been supplied.\n\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:7:36\n  │\n7 │     Wibble(..wibble, a: 1.0, a: 2, c: 2)\n  │                                    ^^^^ Did you mean `a`?\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt has these accessible fields:\n\n    .a\n    .b\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_does_not_stop_at_first_invalid_field_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: 1.0, a: 2)\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: 1.0, a: 2)\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:22\n  │\n7 │     Wibble(..wibble, a: 1.0, a: 2)\n  │                      ^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Duplicate argument\n  ┌─ /src/one/two.gleam:7:30\n  │\n7 │     Wibble(..wibble, a: 1.0, a: 2)\n  │                              ^^^^\n\nThe labelled argument `a` has already been supplied.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_does_not_stop_at_first_invalid_field_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: 2, a: 3, b: 1)\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: 2, a: 3, b: 1)\n}\n\n----- ERROR\nerror: Duplicate argument\n  ┌─ /src/one/two.gleam:7:28\n  │\n7 │     Wibble(..wibble, a: 2, a: 3, b: 1)\n  │                            ^^^^\n\nThe labelled argument `a` has already been supplied.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:34\n  │\n7 │     Wibble(..wibble, a: 2, a: 3, b: 1)\n  │                                  ^^^^\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_does_not_stop_at_first_invalid_field_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, b: 1, a: True, c: 2)\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, b: 1, a: True, c: 2)\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:22\n  │\n7 │     Wibble(..wibble, b: 1, a: True, c: 2)\n  │                      ^^^^\n\nExpected type:\n\n    Bool\n\nFound type:\n\n    Int\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:28\n  │\n7 │     Wibble(..wibble, b: 1, a: True, c: 2)\n  │                            ^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Bool\n\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:7:37\n  │\n7 │     Wibble(..wibble, b: 1, a: True, c: 2)\n  │                                     ^^^^ Did you mean `a`?\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt has these accessible fields:\n\n    .a\n    .b\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_incompatible_but_linked_generics.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble(a) {\\n  Wibble(a: a, b: a)\\n}\\n\\npub fn b_to_a(value: Wibble(a)) -> Wibble(Int) {\\n  Wibble(..value, a: 5)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble(a) {\n  Wibble(a: a, b: a)\n}\n\npub fn b_to_a(value: Wibble(a)) -> Wibble(Int) {\n  Wibble(..value, a: 5)\n}\n\n\n----- ERROR\nerror: Incomplete record update\n  ┌─ /src/one/two.gleam:7:12\n  │\n7 │   Wibble(..value, a: 5)\n  │            ^^^^^ This is a `Wibble(a)`\n\nThe `b` field of this value is a `a`, but the arguments given to the record\nupdate indicate that it should be a `Int`.\n\nNote: If the same type variable is used for multiple fields, all those\nfields need to be updated at the same time if their type changes.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_unknown_variant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wubble: Bool)\\n  Wobble(wobble: Int, wubble: Bool)\\n}\\n\\npub fn wibble(value: Wibble) {\\n  Wibble(..value, wubble: True)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(wibble: Int, wubble: Bool)\n  Wobble(wobble: Int, wubble: Bool)\n}\n\npub fn wibble(value: Wibble) {\n  Wibble(..value, wubble: True)\n}\n\n\n----- ERROR\nerror: Unsafe record update\n  ┌─ /src/one/two.gleam:8:12\n  │\n8 │   Wibble(..value, wubble: True)\n  │            ^^^^^ I'm not sure this is always a `Wibble`\n\nThis value cannot be used to build an updated `Wibble` as it could be some\nother variant.\n\nConsider pattern matching on it with a case expression and then\nconstructing a new record with its values.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_wrong_variant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type MyRecord {\\n  A(common: Int, other: String)\\n  B(common: Int, different: Float)\\n}\\n\\npub fn b_to_a(value: MyRecord) {\\n  case value {\\n    A(..) -> value\\n    B(..) as b -> A(..b, other: \\\"Hi\\\")\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type MyRecord {\n  A(common: Int, other: String)\n  B(common: Int, different: Float)\n}\n\npub fn b_to_a(value: MyRecord) {\n  case value {\n    A(..) -> value\n    B(..) as b -> A(..b, other: \"Hi\")\n  }\n}\n\n\n----- ERROR\nerror: Incorrect record update\n   ┌─ /src/one/two.gleam:10:23\n   │\n10 │     B(..) as b -> A(..b, other: \"Hi\")\n   │                       ^ This is a `B`\n\nThis value is a `B` so it cannot be used to build a `A`, even if they share\nsome fields.\n\nNote: If you want to change one variant of a type into another, you should\nspecify all fields explicitly instead of using the record update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__record_update_wrong_variant_imported_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport wibble\\n\\npub fn main(wibble: wibble.Wibble) {\\n  case wibble {\\n    wibble.Wibble(..) as w -> wibble.Wobble(..w, wubble: 10)\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\n\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int)\n  Wobble(wobble: Int, wubble: Int)\n}\n\n-- main.gleam\n\nimport wibble\n\npub fn main(wibble: wibble.Wibble) {\n  case wibble {\n    wibble.Wibble(..) as w -> wibble.Wobble(..w, wubble: 10)\n    _ -> panic\n  }\n}\n\n\n----- ERROR\nerror: Incorrect record update\n  ┌─ /src/one/two.gleam:6:47\n  │\n6 │     wibble.Wibble(..) as w -> wibble.Wobble(..w, wubble: 10)\n  │                                               ^ This is a `Wibble`\n\nThis value is a `Wibble` so it cannot be used to build a `Wobble`, even if\nthey share some fields.\n\nNote: If you want to change one variant of a type into another, you should\nspecify all fields explicitly instead of using the record update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__recursive_var.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let id = fn(x) { x(x) } 1\"\n---\n----- SOURCE CODE\nlet id = fn(x) { x(x) } 1\n\n----- ERROR\nerror: Recursive type\n  ┌─ /src/one/two.gleam:1:20\n  │\n1 │ let id = fn(x) { x(x) } 1\n  │                    ^\n\nI don't know how to work out what type this value has. It seems to be\ndefined in terms of itself.\nHint: Add some type annotations and try again.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__remembering_record_field_when_type_checking_fails.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub type Wibble {\\n  Wibble(x: Int, f: fn(Wobble) -> Int)\\n}\\n\\npub fn wibble() {\\n  Wibble(1, fn(_) { 2 })\\n}\\n\\npub fn wobble(wibble: Wibble) {\\n  wibble.f\\n}\\n\\npub fn woo(wibble: Wibble) {\\n  Wibble(..wibble, x: 1)\\n}\"\n---\n----- SOURCE CODE\npub type Wibble {\n  Wibble(x: Int, f: fn(Wobble) -> Int)\n}\n\npub fn wibble() {\n  Wibble(1, fn(_) { 2 })\n}\n\npub fn wobble(wibble: Wibble) {\n  wibble.f\n}\n\npub fn woo(wibble: Wibble) {\n  Wibble(..wibble, x: 1)\n}\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:2:24\n  │\n2 │   Wibble(x: Int, f: fn(Wobble) -> Int)\n  │                        ^^^^^^ Did you mean `Wibble`?\n\nThe type `Wobble` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import gleam/wibble.{wobble}\\n        import gleam/wibble.{zoo}\\n        pub fn go() { wobble() + zoo() }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\n\n            pub fn wobble() { 1 }\n            pub fn zoo() { 1 }\n            \n\n-- main.gleam\n\n        import gleam/wibble.{wobble}\n        import gleam/wibble.{zoo}\n        pub fn go() { wobble() + zoo() }\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import gleam/wibble.{wobble}\n  │         ---------------------------- First imported here\n3 │         import gleam/wibble.{zoo}\n  │         ^^^^^^^^^^^^^^^^^^^^^^^^^ Reimported here\n\n`wibble` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:34\n  │\n4 │         pub fn go() { wobble() + zoo() }\n  │                                  ^^^\n\nThe name `zoo` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one\\n        import two as one\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one\n        import two as one\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import one\n  │         ---------- First imported here\n3 │         import two as one\n  │         ^^^^^^^^^^^^^^^^^ Reimported here\n\n`one` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one as two\\n        import two\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one as two\n        import two\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import one as two\n  │         ----------------- First imported here\n3 │         import two\n  │         ^^^^^^^^^^ Reimported here\n\n`two` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one as x\\n        import two as x\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one as x\n        import two as x\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import one as x\n  │         --------------- First imported here\n3 │         import two as x\n  │         ^^^^^^^^^^^^^^^ Reimported here\n\n`x` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one.{fn1}\\n        import two.{fn2} as one\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one.{fn1}\n        import two.{fn2} as one\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import one.{fn1}\n  │         ---------------- First imported here\n3 │         import two.{fn2} as one\n  │         ^^^^^^^^^^^^^^^^^^^^^^^ Reimported here\n\n`one` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one.{fn1} as two\\n        import two.{fn2}\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one.{fn1} as two\n        import two.{fn2}\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import one.{fn1} as two\n  │         ----------------------- First imported here\n3 │         import two.{fn2}\n  │         ^^^^^^^^^^^^^^^^ Reimported here\n\n`two` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one.{fn1} as x\\n        import two.{fn2} as x\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one.{fn1} as x\n        import two.{fn2} as x\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:3:9\n  │\n2 │         import one.{fn1} as x\n  │         --------------------- First imported here\n3 │         import two.{fn2} as x\n  │         ^^^^^^^^^^^^^^^^^^^^^ Reimported here\n\n`x` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__same_imports_multiple_times_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n        import one.{\\n          fn1\\n        } as x\\n        import two.{\\n          fn2\\n        } as x\\n        \"\n---\n----- SOURCE CODE\n-- one.gleam\n\n            pub fn fn1() { 1 }\n            \n\n-- two.gleam\n\n            pub fn fn2() { 1 }\n            \n\n-- main.gleam\n\n        import one.{\n          fn1\n        } as x\n        import two.{\n          fn2\n        } as x\n        \n\n----- ERROR\nerror: Duplicate import\n  ┌─ /src/one/two.gleam:5:9\n  │    \n2 │   ╭         import one.{\n3 │   │           fn1\n4 │   │         } as x\n  │   ╰──────────────' First imported here\n5 │ ╭           import two.{\n6 │ │             fn2\n7 │ │           } as x\n  │ ╰────────────────^ Reimported here\n\n`x` has been imported multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__shadowed_fn_argument.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn go(x) {\\n  fn(_y) {\\n    y + x\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  fn(_y) {\n    y + x\n  }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:5\n  │\n3 │   fn(_y) {\n  │      -- This value is discarded\n4 │     y + x\n  │     ^ So this is not in scope\n\nHint: Change `_y` to `y` or reference another variable\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__shadowed_function_argument.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn go(_x) {\\n  x + 1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(_x) {\n  x + 1\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:3:3\n  │\n2 │ pub fn go(_x) {\n  │           -- This value is discarded\n3 │   x + 1\n  │   ^ So this is not in scope\n\nHint: Change `_x` to `x` or reference another variable\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__shadowed_let_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn go() {\\n  let _x = 1\\n  x + 1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let _x = 1\n  x + 1\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n3 │   let _x = 1\n  │       -- This value is discarded\n4 │   x + 1\n  │   ^ So this is not in scope\n\nHint: Change `_x` to `x` or reference another variable\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__shadowed_pattern_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int)\\n}\\n\\npub fn go(x) {\\n  case x {\\n    Wibble(_y) -> y + 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn go(x) {\n  case x {\n    Wibble(_y) -> y + 1\n  }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:8:19\n  │\n8 │     Wibble(_y) -> y + 1\n  │            --     ^ So this is not in scope\n  │            │       \n  │            This value is discarded\n\nHint: Change `_y` to `y` or reference another variable\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__show_only_missing_labels.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn wibble(a a: Int, b b: Float, c c: String) {\\n    todo\\n}\\n\\npub fn wobble() {\\n    wibble(1, 2.0)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(a a: Int, b b: Float, c c: String) {\n    todo\n}\n\npub fn wobble() {\n    wibble(1, 2.0)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:7:5\n  │\n7 │     wibble(1, 2.0)\n  │     ^^^^^^^^^^^^^^ Expected 3 arguments, got 2\n\nThis call accepts these additional labelled arguments:\n\n  - c\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__src_importing_dev_dependency.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport some_module\\n\\npub fn main() {\\n  some_module.main()\\n}\\n\"\n---\n----- SOURCE CODE\n-- some_module.gleam\npub fn main() { Nil }\n\n-- main.gleam\n\nimport some_module\n\npub fn main() {\n  some_module.main()\n}\n\n\n----- ERROR\nerror: App importing dev dependency\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ import some_module\n  │ ^^^^^^^^^^^^^^^^^^\n\nThe application module `themodule` is importing the module `some_module`,\nbut `dev_dependency`, the package it belongs to, is a dev dependency.\n\nDev dependencies are not included in production builds so application\nmodules should not import them. Perhaps change `dev_dependency` to a\nregular dependency.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__subject_int_float_guard_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Float) }\\nfn x() { case X(1, 2.0) { x if x == X(2.0, 1) -> 1 _ -> 2 } }\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Float) }\nfn x() { case X(1, 2.0) { x if x == X(2.0, 1) -> 1 _ -> 2 } }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:39\n  │\n2 │ fn x() { case X(1, 2.0) { x if x == X(2.0, 1) -> 1 _ -> 2 } }\n  │                                       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:44\n  │\n2 │ fn x() { case X(1, 2.0) { x if x == X(2.0, 1) -> 1 _ -> 2 } }\n  │                                            ^\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_unwrapping_a_result_when_types_match.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  let value = Ok(1)\\n  add_1(value)\\n}\\n\\nfn add_1(to x) { x + 1 }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let value = Ok(1)\n  add_1(value)\n}\n\nfn add_1(to x) { x + 1 }\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:9\n  │\n4 │   add_1(value)\n  │         ^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Result(Int, a)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_function_return_value_in_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() -> Result(Int, Bool) {\\n  True\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Result(Int, Bool) {\n  True\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   True\n  │   ^^^^ Did you mean to wrap this in an `Error`?\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Result(Int, Bool)\n\nFound type:\n\n    Bool\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_function_return_value_in_ok.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() -> Result(Int, Bool) {\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Result(Int, Bool) {\n  1\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   1\n  │   ^ Did you mean to wrap this in an `Ok`?\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Result(Int, Bool)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_use_returned_value_in_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() -> Result(Int, Bool) {\\n  use <- want_result\\n  False\\n}\\n\\npub fn want_result(wibble: fn() -> Result(Int, Bool)) {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Result(Int, Bool) {\n  use <- want_result\n  False\n}\n\npub fn want_result(wibble: fn() -> Result(Int, Bool)) {\n  todo\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   False\n  │   ^^^^^ Did you mean to wrap this in an `Error`?\n\nExpected type:\n\n    Result(Int, Bool)\n\nFound type:\n\n    Bool\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_use_returned_value_in_ok.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() -> Result(Int, Bool) {\\n  use <- want_result\\n  1\\n}\\n\\npub fn want_result(wibble: fn() -> Result(Int, Bool)) {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() -> Result(Int, Bool) {\n  use <- want_result\n  1\n}\n\npub fn want_result(wibble: fn() -> Result(Int, Bool)) {\n  todo\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   1\n  │   ^ Did you mean to wrap this in an `Ok`?\n\nExpected type:\n\n    Result(Int, Bool)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_error_if_types_match.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    1 -> Error(1)\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case todo {\n    1 -> Error(1)\n    _ -> 1\n  }\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:5\n  │\n5 │     _ -> 1\n  │     ^^^^^^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Result(a, Int)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_error_if_types_match_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n    wibble(\\\"a\\\")\\n}\\n\\nfn wibble(arg: Result(Int, String)) { todo }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    wibble(\"a\")\n}\n\nfn wibble(arg: Result(Int, String)) { todo }\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:12\n  │\n3 │     wibble(\"a\")\n  │            ^^^ Did you mean to wrap this in an `Error`?\n\nExpected type:\n\n    Result(Int, String)\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_ok_if_types_match.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    1 -> Ok(2)\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case todo {\n    1 -> Ok(2)\n    _ -> 1\n  }\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:5\n  │\n5 │     _ -> 1\n  │     ^^^^^^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Result(Int, a)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_ok_if_types_match_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  wibble(1)\\n}\\n\\nfn wibble(arg: Result(Int, String)) { todo }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  wibble(1)\n}\n\nfn wibble(arg: Result(Int, String)) { todo }\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:10\n  │\n3 │   wibble(1)\n  │          ^ Did you mean to wrap this in an `Ok`?\n\nExpected type:\n\n    Result(Int, String)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_ok_if_types_match_with_block.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    1 -> Ok(2)\\n    _ -> {\\n      todo\\n      1\\n    }\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case todo {\n    1 -> Ok(2)\n    _ -> {\n      todo\n      1\n    }\n  }\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:5\n  │  \n5 │ ╭     _ -> {\n6 │ │       todo\n7 │ │       1\n8 │ │     }\n  │ ╰─────^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Result(Int, a)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_ok_if_types_match_with_multiline_result_in_block.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    1 -> Ok(2)\\n    _ -> {\\n      todo\\n      1\\n      |> add_1\\n    }\\n  }\\n}\\n\\nfn add_1(n: Int) { n + 1 }\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case todo {\n    1 -> Ok(2)\n    _ -> {\n      todo\n      1\n      |> add_1\n    }\n  }\n}\n\nfn add_1(n: Int) { n + 1 }\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:5\n  │  \n5 │ ╭     _ -> {\n6 │ │       todo\n7 │ │       1\n8 │ │       |> add_1\n9 │ │     }\n  │ ╰─────^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Result(Int, a)\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__suggest_wrapping_a_value_into_ok_with_generic_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn first(list: List(a)) -> Result(a, Nil) {\\n  case list {\\n    [] -> Error(Nil)\\n    [first, ..rest] -> first\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn first(list: List(a)) -> Result(a, Nil) {\n  case list {\n    [] -> Error(Nil)\n    [first, ..rest] -> first\n  }\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:5\n  │\n5 │     [first, ..rest] -> first\n  │     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis case clause was found to return a different type than the previous\none, but all case clauses must return the same type.\n\nExpected type:\n\n    Result(a, Nil)\n\nFound type:\n\n    a\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__true_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: let True(x) = 1\n---\n----- SOURCE CODE\nlet True(x) = 1\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let True(x) = 1\n  │     ^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Bool\n\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let True(x) = 1\n  │     ^^^^^^^ Expected no arguments, got 1\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_2_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"#(1, 2) == #(1, 2, 3)\"\n---\n----- SOURCE CODE\n#(1, 2) == #(1, 2, 3)\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:12\n  │\n1 │ #(1, 2) == #(1, 2, 3)\n  │            ^^^^^^^^^^\n\nExpected type:\n\n    #(Int, Int)\n\nFound type:\n\n    #(Int, Int, Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_arity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case #(1, 2) { #(1, _, _, _) -> 1 }\"\n---\n----- SOURCE CODE\ncase #(1, 2) { #(1, _, _, _) -> 1 }\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:1:16\n  │\n1 │ case #(1, 2) { #(1, _, _, _) -> 1 }\n  │                ^^^^^^^^^^^^^ Expected 2 arguments, got 4\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_index_not_a_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: Nil.2\n---\n----- SOURCE CODE\nNil.2\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ Nil.2\n  │ ^^^ This is not a tuple\n\nTo index into this value it needs to be a tuple, however it has this type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_index_not_a_tuple_unbound.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn(a) { a.2 }\"\n---\n----- SOURCE CODE\nfn(a) { a.2 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:9\n  │\n1 │ fn(a) { a.2 }\n  │         ^ What type is this?\n\nTo index into a tuple we need to know its size, but we don't know anything\nabout this type yet. Please add some type annotations so we can continue.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_index_out_of_bounds.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"#(0, 1).2\"\n---\n----- SOURCE CODE\n#(0, 1).2\n\n----- ERROR\nerror: Out of bounds tuple index\n  ┌─ /src/one/two.gleam:1:8\n  │\n1 │ #(0, 1).2\n  │        ^^ This index is too large\n\nThe index being accessed for this tuple is 2, but this tuple has 2 elements\nso the highest valid index is 1.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let #(a, b) = 1\"\n---\n----- SOURCE CODE\nlet #(a, b) = 1\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:5\n  │\n1 │ let #(a, b) = 1\n  │     ^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    #(a, b)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__tuple_int_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"#(1.0, 2, 3) == #(1, 2, 3)\"\n---\n----- SOURCE CODE\n#(1.0, 2, 3) == #(1, 2, 3)\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:17\n  │\n1 │ #(1.0, 2, 3) == #(1, 2, 3)\n  │                 ^^^^^^^^^^\n\nExpected type:\n\n    #(Float, Int, Int)\n\nFound type:\n\n    #(Int, Int, Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_annotations.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn inc(x: a) { x + 1 }\"\n---\n----- SOURCE CODE\nfn inc(x: a) { x + 1 }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:16\n  │\n1 │ fn inc(x: a) { x + 1 }\n  │                ^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    a\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_holes1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type A { A(_) }\"\n---\n----- SOURCE CODE\ntype A { A(_) }\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:1:12\n  │\n1 │ type A { A(_) }\n  │            ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_holes2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\nfn main() -> List(_)\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"a\", \"b\")\nfn main() -> List(_)\n\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:3:19\n  │\n3 │ fn main() -> List(_)\n  │                   ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_holes3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n@external(erlang, \\\"a\\\", \\\"b\\\")\\nfn main(x: List(_)) -> Nil\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"a\", \"b\")\nfn main(x: List(_)) -> Nil\n\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:3:17\n  │\n3 │ fn main(x: List(_)) -> Nil\n  │                 ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_holes4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: type X = List(_)\n---\n----- SOURCE CODE\ntype X = List(_)\n\n----- ERROR\nerror: Unexpected type hole\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ type X = List(_)\n  │               ^ I need to know what this is\n\nWe need to know the exact type here so type holes cannot be used.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_imported_as_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"import gleam/wibble.{Wibble}\"\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub type Wibble {\n               Wobble\n             }\n\n-- main.gleam\nimport gleam/wibble.{Wibble}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ import gleam/wibble.{Wibble}\n  │                      ^^^^^^ Did you mean `type Wibble`?\n\n`Wibble` is only a type, it cannot be imported as a value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_used_as_a_constructor_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() -> Int() {}\"\n---\n----- SOURCE CODE\npub fn main() -> Int() {}\n\n----- ERROR\nerror: Type used as a type constructor\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ pub fn main() -> Int() {}\n  │                     ^^ You can remove this\n\n`Int` is a type with no parameters, but here it's being used as a type\nconstructor.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_used_as_a_constructor_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() {\\n  let a: Int() = todo\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a: Int() = todo\n}\n\n----- ERROR\nerror: Type used as a type constructor\n  ┌─ /src/one/two.gleam:2:13\n  │\n2 │   let a: Int() = todo\n  │             ^^ You can remove this\n\n`Int` is a type with no parameters, but here it's being used as a type\nconstructor.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_used_as_a_constructor_with_more_arguments.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main() {\\n  let a: Int(Int, String) = todo\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a: Int(Int, String) = todo\n}\n\n----- ERROR\nerror: Type used as a type constructor\n  ┌─ /src/one/two.gleam:2:13\n  │\n2 │   let a: Int(Int, String) = todo\n  │             ^^^^^^^^^^^^^ You can remove this\n\n`Int` is a type with no parameters, but here it's being used as a type\nconstructor.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_variables_in_body.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Box(a) {\\n  Box(value: a)\\n}\\npub fn go(box1: Box(a), box2: Box(b)) {\\n  let _: Box(a) = box2\\n  let _: Box(b) = box1\\n  5\\n}\"\n---\n----- SOURCE CODE\n\npub type Box(a) {\n  Box(value: a)\n}\npub fn go(box1: Box(a), box2: Box(b)) {\n  let _: Box(a) = box2\n  let _: Box(b) = box1\n  5\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:6:19\n  │\n6 │   let _: Box(a) = box2\n  │                   ^^^^\n\nExpected type:\n\n    Box(a)\n\nFound type:\n\n    Box(b)\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:19\n  │\n7 │   let _: Box(b) = box1\n  │                   ^^^^\n\nExpected type:\n\n    Box(b)\n\nFound type:\n\n    Box(a)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__type_vars_must_be_declared.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type A(a) { A }\\ntype B = a\"\n---\n----- SOURCE CODE\ntype A(a) { A }\ntype B = a\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:2:10\n  │\n2 │ type B = a\n  │          ^ Did you mean `A`?\n\nThe type `a` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unexpected_arg_with_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n    fn id(x) { x }\\n    fn y() {\\n        let x = 4\\n        id(x:)\\n    }\\n\"\n---\n----- SOURCE CODE\n\n    fn id(x) { x }\n    fn y() {\n        let x = 4\n        id(x:)\n    }\n\n\n----- ERROR\nerror: Unexpected labelled argument\n  ┌─ /src/one/two.gleam:5:12\n  │\n5 │         id(x:)\n  │            ^^\n\nThis argument has been given a label but the function does\nnot expect any. Please remove the label `x`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unexpected_labelled_arg.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn id(x) { x } fn y() { id(x: 4) }\"\n---\n----- SOURCE CODE\nfn id(x) { x } fn y() { id(x: 4) }\n\n----- ERROR\nerror: Unexpected labelled argument\n  ┌─ /src/one/two.gleam:1:28\n  │\n1 │ fn id(x) { x } fn y() { id(x: 4) }\n  │                            ^^^^\n\nThis argument has been given a label but the function does\nnot expect any. Please remove the label `x`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unexpected_labelled_arg_record_constructor.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(Int) } fn y() { X(a: 0) }\"\n---\n----- SOURCE CODE\ntype X { X(Int) } fn y() { X(a: 0) }\n\n----- ERROR\nerror: Unexpected labelled argument\n  ┌─ /src/one/two.gleam:1:30\n  │\n1 │ type X { X(Int) } fn y() { X(a: 0) }\n  │                              ^^^^\n\nThis argument has been given a label but the record constructor does\nnot expect any. Please remove the label `a`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_accessed_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn(a) { a.field }\"\n---\n----- SOURCE CODE\nfn(a) { a.field }\n\n----- ERROR\nerror: Unknown type for record access\n  ┌─ /src/one/two.gleam:1:9\n  │\n1 │ fn(a) { a.field }\n  │         ^ I don't know what type this is\n\nIn order to access a record field we need to know what type it is, but I\ncan't tell the type here. Try adding type annotations to your function and\ntry again.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_constructor_update.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n   Person(name: String, age: Int)\\n}\\npub fn update_person(person: Person) {\\n   NotAPerson(..person)\\n}\"\n---\n----- SOURCE CODE\n\npub type Person {\n   Person(name: String, age: Int)\n}\npub fn update_person(person: Person) {\n   NotAPerson(..person)\n}\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:6:4\n  │\n6 │    NotAPerson(..person)\n  │    ^^^^^^^^^^ Did you mean `Person`?\n\nThe custom type variant constructor `NotAPerson` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_field.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn(a: a) { a.field }\"\n---\n----- SOURCE CODE\nfn(a: a) { a.field }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:1:14\n  │\n1 │ fn(a: a) { a.field }\n  │              ^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    a\n\nIt does not have any fields.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_field_that_appears_in_a_variant_has_note.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(field: Int)\\n  Wobble(not_field: String, field: Int)\\n}\\n\\npub fn main(wibble: Wibble) {\\n  wibble.field\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(field: Int)\n  Wobble(not_field: String, field: Int)\n}\n\npub fn main(wibble: Wibble) {\n  wibble.field\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:8:10\n  │\n8 │   wibble.field\n  │          ^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt does not have fields that are common across all variants.\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_field_that_appears_in_an_imported_variant_has_note.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport some_mod\\npub fn main(wibble: some_mod.Wibble) {\\n  wibble.field\\n}\\n\"\n---\n----- SOURCE CODE\n-- some_mod.gleam\npub type Wibble {\n              Wibble(field: Int)\n              Wobble(not_field: String, field: Int)\n            }\n\n-- main.gleam\n\nimport some_mod\npub fn main(wibble: some_mod.Wibble) {\n  wibble.field\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:4:10\n  │\n4 │   wibble.field\n  │          ^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    some_mod.Wibble\n\nIt does not have fields that are common across all variants.\n\nNote: The field you are trying to access is not defined consistently across\nall variants of this custom type. To fix this, ensure that all variants\ninclude the field with the same name, position, and type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_field_that_does_not_appear_in_variant_has_no_note.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(field: Int)\\n  Wobble(not_field: String, field: Int)\\n}\\n\\npub fn main(wibble: Wibble) {\\n  wibble.wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(field: Int)\n  Wobble(not_field: String, field: Int)\n}\n\npub fn main(wibble: Wibble) {\n  wibble.wibble\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:8:10\n  │\n8 │   wibble.wibble\n  │          ^^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Wibble\n\nIt does not have fields that are common across all variants.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_field_update.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n pub type Person {\\n   Person(name: String)\\n }\\n pub fn update_person(person: Person) {\\n   Person(..person, one: 5)\\n }\"\n---\n----- SOURCE CODE\n\n pub type Person {\n   Person(name: String)\n }\n pub fn update_person(person: Person) {\n   Person(..person, one: 5)\n }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:6:21\n  │\n6 │    Person(..person, one: 5)\n  │                     ^^^^^^ Did you mean `name`?\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_field_update2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n pub type Person {\\n   Person(name: String, age: Int, size: Int)\\n }\\n pub fn update_person(person: Person) {\\n   Person(..person, size: 66, one: 5, age: 3)\\n }\"\n---\n----- SOURCE CODE\n\n pub type Person {\n   Person(name: String, age: Int, size: Int)\n }\n pub fn update_person(person: Person) {\n   Person(..person, size: 66, one: 5, age: 3)\n }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:6:31\n  │\n6 │    Person(..person, size: 66, one: 5, age: 3)\n  │                               ^^^^^^ This field does not exist\n\nThe value being accessed has this type:\n\n    Person\n\nIt has these accessible fields:\n\n    .age\n    .name\n    .size\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_imported_module_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport one/two\\n\\npub fn main(_x: two.Thing) {\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n-- one/two.gleam\n\n\n-- main.gleam\n\nimport one/two\n\npub fn main(_x: two.Thing) {\n  Nil\n}\n\n\n----- ERROR\nerror: Unknown module type\n  ┌─ /src/one/two.gleam:4:17\n  │\n4 │ pub fn main(_x: two.Thing) {\n  │                 ^^^^^^^^^\n\nThe module `one/two` does not have a `Thing` type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_label.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Float) }\\nfn x() {\\n  let x = X(a: 1, c: 2.0)\\n  x\\n}\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Float) }\nfn x() {\n  let x = X(a: 1, c: 2.0)\n  x\n}\n\n----- ERROR\nerror: Unknown label\n  ┌─ /src/one/two.gleam:3:19\n  │\n3 │   let x = X(a: 1, c: 2.0)\n  │                   ^^^^^^ Did you mean `b`?\n\nIt accepts these labels:\n\n    b\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type X { X(a: Int, b: Float) }\\nfn x() {\\n  let c = 2.0\\n  let x = X(a: 1, c:)\\n  x\\n}\"\n---\n----- SOURCE CODE\ntype X { X(a: Int, b: Float) }\nfn x() {\n  let c = 2.0\n  let x = X(a: 1, c:)\n  x\n}\n\n----- ERROR\nerror: Unknown label\n  ┌─ /src/one/two.gleam:4:19\n  │\n4 │   let x = X(a: 1, c:)\n  │                   ^^ Did you mean `b`?\n\nIt accepts these labels:\n\n    b\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: import xpto\n---\n----- SOURCE CODE\nimport xpto\n\n----- ERROR\nerror: Unknown module\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ import xpto\n  │ ^^^^^^^^^^^\n\nNo module has been found with the name `xpto`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_module_suggest_import.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  utils.helpful()\\n}\\n\"\n---\n----- SOURCE CODE\n-- utils.gleam\npub fn helpful() {}\n\n-- main.gleam\n\npub fn main() {\n  utils.helpful()\n}\n\n\n----- ERROR\nerror: Unknown module\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   utils.helpful()\n  │   ^^^^^\n\nNo module has been found with the name `utils`.\nHint: Did you mean to import `utils`?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_module_suggest_typo_for_imported_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nimport wibble\\npub fn main() {\\n  wible.wobble()\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub fn wobble() {}\n\n-- main.gleam\n\nimport wibble\npub fn main() {\n  wible.wobble()\n}\n\n\n----- ERROR\nerror: Unknown module\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   wible.wobble()\n  │   ^^^^^\n\nNo module has been found with the name `wible`.\nHint: Did you mean `wibble`?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_module_suggest_typo_for_unimported_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub fn main() {\\n  woble.wubble()\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble/wobble.gleam\npub fn wubble() {}\n\n-- main.gleam\n\npub fn main() {\n  woble.wubble()\n}\n\n\n----- ERROR\nerror: Unknown module\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   woble.wubble()\n  │   ^^^^^\n\nNo module has been found with the name `woble`.\nHint: Did you mean to import `wibble/wobble` and reference `wobble`?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_record_field.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Box(a) { Box(inner: a) }\\npub fn main(box: Box(Int)) { box.unknown }\\n\"\n---\n----- SOURCE CODE\n\npub type Box(a) { Box(inner: a) }\npub fn main(box: Box(Int)) { box.unknown }\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:3:34\n  │\n3 │ pub fn main(box: Box(Int)) { box.unknown }\n  │                                  ^^^^^^^ Did you mean `inner`?\n\nThe value being accessed has this type:\n\n    Box(Int)\n\nIt has these accessible fields:\n\n    .inner\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_record_field_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Box(a) { Box(inner: a) }\\npub fn main(box: Box(Box(Int))) { box.inner.unknown }\"\n---\n----- SOURCE CODE\n\npub type Box(a) { Box(inner: a) }\npub fn main(box: Box(Box(Int))) { box.inner.unknown }\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:3:45\n  │\n3 │ pub fn main(box: Box(Box(Int))) { box.inner.unknown }\n  │                                             ^^^^^^^ Did you mean `inner`?\n\nThe value being accessed has this type:\n\n    Box(Int)\n\nIt has these accessible fields:\n\n    .inner\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type Thing { Thing(unknown: x) }\"\n---\n----- SOURCE CODE\ntype Thing { Thing(unknown: x) }\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ type Thing { Thing(unknown: x) }\n  │                             ^\n\nThe type `x` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_type_in_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type IntMap = IllMap(Int, Int)\"\n---\n----- SOURCE CODE\ntype IntMap = IllMap(Int, Int)\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ type IntMap = IllMap(Int, Int)\n  │               ^^^^^^^^^^^^^^^^\n\nThe type `IllMap` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_type_in_alias2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"type IntMap = Map(Inf, Int)\"\n---\n----- SOURCE CODE\ntype IntMap = Map(Inf, Int)\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:19\n  │\n1 │ type IntMap = Map(Inf, Int)\n  │                   ^^^ Did you mean `Int`?\n\nThe type `Inf` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_type_var_in_alias2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: type X = List(a)\n---\n----- SOURCE CODE\ntype X = List(a)\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ type X = List(a)\n  │               ^\n\nThe type `a` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: x\n---\n----- SOURCE CODE\nx\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ x\n  │ ^\n\nThe name `x` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_variable_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { x -> 1 1 -> x }\"\n---\n----- SOURCE CODE\ncase 1 { x -> 1 1 -> x }\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ case 1 { x -> 1 1 -> x }\n  │                      ^\n\nThe name `x` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_variable_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let add = fn(x, y) { x + y } 1 |> add(unknown)\"\n---\n----- SOURCE CODE\nlet add = fn(x, y) { x + y } 1 |> add(unknown)\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:39\n  │\n1 │ let add = fn(x, y) { x + y } 1 |> add(unknown)\n  │                                       ^^^^^^^\n\nThe name `unknown` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_variable_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: Int\n---\n----- SOURCE CODE\nInt\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ Int\n  │ ^^^\n\n`Int` is a type, it cannot be used as a value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unknown_variable_update.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Person {\\n  Person(name: String, age: Int)\\n}\\npub fn update_person() {\\n  Person(..person)\\n}\"\n---\n----- SOURCE CODE\n\npub type Person {\n  Person(name: String, age: Int)\n}\npub fn update_person() {\n  Person(..person)\n}\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:6:12\n  │\n6 │   Person(..person)\n  │            ^^^^^^ Did you mean `Person`?\n\nThe name `person` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__unnecessary_spread_operator.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\ntype Triple {\\n  Triple(a: Int, b: Int, c: Int)\\n}\\n\\nfn main() {\\n  let triple = Triple(1,2,3)\\n  let Triple(a, b, c, ..) = triple\\n}\"\n---\n----- SOURCE CODE\n\ntype Triple {\n  Triple(a: Int, b: Int, c: Int)\n}\n\nfn main() {\n  let triple = Triple(1,2,3)\n  let Triple(a, b, c, ..) = triple\n}\n\n----- ERROR\nerror: Unnecessary spread operator\n  ┌─ /src/one/two.gleam:8:23\n  │\n8 │   let Triple(a, b, c, ..) = triple\n  │                       ^^\n\nThis record has 3 fields and you have already assigned variables to all of\nthem.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__update_multi_variant_record.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\npub type Point {\\n  Point2(a: Int, b: Int)\\n  Point3(a: Int, b: Int, c: Int)\\n}\\n\\npub fn main() {\\n  Point3(..Point2(a: 1, b: 2))\\n}\"\n---\n----- SOURCE CODE\n\npub type Point {\n  Point2(a: Int, b: Int)\n  Point3(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  Point3(..Point2(a: 1, b: 2))\n}\n\n----- ERROR\nerror: Incorrect record update\n  ┌─ /src/one/two.gleam:8:12\n  │\n8 │   Point3(..Point2(a: 1, b: 2))\n  │            ^^^^^^^^^^^^^^^^^^ This is a `Point2`\n\nThis value is a `Point2` so it cannot be used to build a `Point3`, even if\nthey share some fields.\n\nNote: If you want to change one variant of a type into another, you should\nspecify all fields explicitly instead of using the record update syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__utf16_codepoint_javascript_target.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nassertion_line: 3282\nexpression: \"\\npub fn main() {\\n  let assert <<a:utf16_codepoint>> = <<10>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<a:utf16_codepoint>> = <<10>>\n}\n\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:3:18\n  │\n3 │   let assert <<a:utf16_codepoint>> = <<10>>\n  │                  ^^^^^^^^^^^^^^^ UTF-codepoint pattern matching is not supported\n\nThe JavaScript target does not support UTF-codepoint pattern matching.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__utf32_codepoint_javascript_target.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nassertion_line: 3293\nexpression: \"\\npub fn main() {\\n  let assert <<a:utf32_codepoint>> = <<10>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<a:utf32_codepoint>> = <<10>>\n}\n\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:3:18\n  │\n3 │   let assert <<a:utf32_codepoint>> = <<10>>\n  │                  ^^^^^^^^^^^^^^^ UTF-codepoint pattern matching is not supported\n\nThe JavaScript target does not support UTF-codepoint pattern matching.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__utf8_codepoint_javascript_target.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nassertion_line: 3271\nexpression: \"\\npub fn main() {\\n  let assert <<a:utf8_codepoint>> = <<10>>\\n}\\n\"\nsnapshot_kind: text\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert <<a:utf8_codepoint>> = <<10>>\n}\n\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:3:18\n  │\n3 │   let assert <<a:utf8_codepoint>> = <<10>>\n  │                  ^^^^^^^^^^^^^^ UTF-codepoint pattern matching is not supported\n\nThe JavaScript target does not support UTF-codepoint pattern matching.\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__value_imported_as_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"import gleam/wibble.{type Wobble}\"\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub type Wibble {\n               Wobble\n             }\n\n-- main.gleam\nimport gleam/wibble.{type Wobble}\n\n----- ERROR\nerror: Unknown module type\n  ┌─ /src/one/two.gleam:1:22\n  │\n1 │ import gleam/wibble.{type Wobble}\n  │                      ^^^^^^^^^^^ Did you mean `Wobble`?\n\n`Wobble` is only a value, it cannot be imported as a type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__wrong_number_of_subjects.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { _, _ -> 1 }\"\n---\n----- SOURCE CODE\ncase 1 { _, _ -> 1 }\n\n----- ERROR\nerror: Incorrect number of patterns\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ case 1 { _, _ -> 1 }\n  │          ^^^^ Expected 1 pattern, got 2\n\nThis case expression has 1 subject, but this pattern matches 2.\nEach clause must have a pattern for every subject value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__wrong_number_of_subjects_alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"case 1 { _, _ | _ | _, _, _ -> 1 }\"\n---\n----- SOURCE CODE\ncase 1 { _, _ | _ | _, _, _ -> 1 }\n\n----- ERROR\nerror: Incorrect number of patterns\n  ┌─ /src/one/two.gleam:1:10\n  │\n1 │ case 1 { _, _ | _ | _, _, _ -> 1 }\n  │          ^^^^ Expected 1 pattern, got 2\n\nThis case expression has 1 subject, but this pattern matches 2.\nEach clause must have a pattern for every subject value.\n\nerror: Incorrect number of patterns\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ case 1 { _, _ | _ | _, _, _ -> 1 }\n  │                     ^^^^^^^ Expected 1 pattern, got 3\n\nThis case expression has 1 subject, but this pattern matches 3.\nEach clause must have a pattern for every subject value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__wrong_type_arg.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\nfn wibble(x: List(Int)) { x }\\nfn main(y: List(something)) {\\n  wibble(y)\\n}\"\n---\n----- SOURCE CODE\n\nfn wibble(x: List(Int)) { x }\nfn main(y: List(something)) {\n  wibble(y)\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:10\n  │\n4 │   wibble(y)\n  │          ^\n\nExpected type:\n\n    List(Int)\n\nFound type:\n\n    List(something)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__wrong_type_ret.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"pub fn main(x: something) -> Int {\\n  let y = x\\n  y\\n}\"\n---\n----- SOURCE CODE\npub fn main(x: something) -> Int {\n  let y = x\n  y\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   y\n  │   ^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Int\n\nFound type:\n\n    something\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__wrong_type_update.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"\\n pub type Person {\\n   Person(name: String, age: Int)\\n }\\n pub type Box(a) {\\n   Box(a)\\n }\\n pub fn update_person(person: Person, box: Box(a)) {\\n   Person(..box)\\n }\"\n---\n----- SOURCE CODE\n\n pub type Person {\n   Person(name: String, age: Int)\n }\n pub type Box(a) {\n   Box(a)\n }\n pub fn update_person(person: Person, box: Box(a)) {\n   Person(..box)\n }\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:9:13\n  │\n9 │    Person(..box)\n  │             ^^^\n\nExpected type:\n\n    Person\n\nFound type:\n\n    Box(a)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__wrong_type_var.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"fn wibble(x: String) { x }\\nfn multi_result(x: some_name) {\\n  wibble(x)\\n}\"\n---\n----- SOURCE CODE\nfn wibble(x: String) { x }\nfn multi_result(x: some_name) {\n  wibble(x)\n}\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:10\n  │\n3 │   wibble(x)\n  │          ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    some_name\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__zero_size_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/errors.rs\nexpression: \"let assert <<1:size(0)>> = <<>>\"\n---\n----- SOURCE CODE\nlet assert <<1:size(0)>> = <<>>\n\n----- ERROR\nerror: Invalid bit array segment\n  ┌─ /src/one/two.gleam:1:16\n  │\n1 │ let assert <<1:size(0)>> = <<>>\n  │                ^^^^^^^ A constant size must be a positive number\n\nSee: https://tour.gleam.run/data-types/bit-arrays/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<>> -> 1\\n    <<1>> -> 1\\n    <<2>> -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<>> -> 1\n    <<1>> -> 1\n    <<2>> -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     <<>> -> 1\n5 │ │     <<1>> -> 1\n6 │ │     <<2>> -> 1\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<>> -> 1\\n    <<1>> -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<>> -> 1\n    <<1>> -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     <<>> -> 1\n5 │ │     <<1>> -> 1\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_bits_catches_everything.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let bit_array = <<>>\\n  case bit_array {\\n    <<_:bits>> -> 1\\n    <<1>> -> 2\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_:bits>> -> 1\n    <<1>> -> 2\n    _ -> 2\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<1>> -> 2\n  │     ^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     _ -> 2\n  │     ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_bytes_needs_catch_all.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let bit_array = <<>>\\n  case bit_array {\\n    <<_:bytes>> -> 1\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_:bytes>> -> 1\n  }\n}\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case bit_array {\n4 │ │     <<_:bytes>> -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_overlapping_patterns_are_redundant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let bit_array = <<>>\\n  case bit_array {\\n    <<1, a:size(16)>> -> a\\n    <<1, b:size(8)-unit(2)>> -> b\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<1, a:size(16)>> -> a\n    <<1, b:size(8)-unit(2)>> -> b\n    _ -> 2\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<1, b:size(8)-unit(2)>> -> b\n  │     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_overlapping_redundant_patterns_with_variable_size.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let bit_array = <<>>\\n  let len = 3\\n  case bit_array {\\n    <<a:size(len), _:size(16)>> -> a\\n    <<_:size(len), b:size(8)-unit(2)>> -> b\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let bit_array = <<>>\n  let len = 3\n  case bit_array {\n    <<a:size(len), _:size(16)>> -> a\n    <<_:size(len), b:size(8)-unit(2)>> -> b\n    _ -> 2\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     <<_:size(len), b:size(8)-unit(2)>> -> b\n  │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bit_array_overlapping_redundant_patterns_with_variable_size_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let bit_array = <<>>\\n  case bit_array {\\n    <<len, _:size(len)-unit(3)>> -> 1\\n    <<len, _:size(len)-unit(2), 1:size(len)>> -> 2\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<len, _:size(len)-unit(3)>> -> 1\n    <<len, _:size(len)-unit(2), 1:size(len)>> -> 2\n    _ -> 2\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<len, _:size(len)-unit(2), 1:size(len)>> -> 2\n  │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bool_false.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    False -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    False -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     False -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    True\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__bool_true.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    True -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    True -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     True -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    False\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_aliased_unqualified_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport wibble.{Wibble, Wobble as Wubble}\\npub fn main(wibble) {\\n    case wibble {\\n        Wibble -> Nil\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport wibble.{Wibble, Wobble as Wubble}\npub fn main(wibble) {\n    case wibble {\n        Wibble -> Nil\n    }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:5\n  │  \n4 │ ╭     case wibble {\n5 │ │         Wibble -> Nil\n6 │ │     }\n  │ ╰─────^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Wubble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_module_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport wibble as wobble\\npub fn main(wibble) {\\n    case wibble {\\n        wobble.Wibble -> Nil\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport wibble as wobble\npub fn main(wibble) {\n    case wibble {\n        wobble.Wibble -> Nil\n    }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:5\n  │  \n4 │ ╭     case wibble {\n5 │ │         wobble.Wibble -> Nil\n6 │ │     }\n  │ ╰─────^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    wobble.Wobble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_module_names.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport wibble\\npub type Things { Thing1 Thing2(Int) }\\npub fn main(wobble_thing) {\\n    case wobble_thing {\\n        #(wibble.Wibble, Thing1) -> Nil\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport wibble\npub type Things { Thing1 Thing2(Int) }\npub fn main(wobble_thing) {\n    case wobble_thing {\n        #(wibble.Wibble, Thing1) -> Nil\n    }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:5\n  │  \n5 │ ╭     case wobble_thing {\n6 │ │         #(wibble.Wibble, Thing1) -> Nil\n7 │ │     }\n  │ ╰─────^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    #(wibble.Wibble, Thing2(_))\n    #(wibble.Wobble, _)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_module_when_aliased_and_shadowed.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport mod.{Wibble as Wobble}\\ntype Wibble { Wobble Wubble }\\npub fn main() {\\n  let wibble = mod.Wibble\\n  case wibble {\\n    mod.Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport mod.{Wibble as Wobble}\ntype Wibble { Wobble Wubble }\npub fn main() {\n  let wibble = mod.Wibble\n  case wibble {\n    mod.Wobble -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:6:3\n  │  \n6 │ ╭   case wibble {\n7 │ │     mod.Wobble -> Nil\n8 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    mod.Wibble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_module_when_shadowed.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport mod.{Wibble}\\ntype Wibble { Wibble Wobble }\\npub fn main() {\\n  let wibble = mod.Wibble\\n  case wibble {\\n    mod.Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport mod.{Wibble}\ntype Wibble { Wibble Wobble }\npub fn main() {\n  let wibble = mod.Wibble\n  case wibble {\n    mod.Wobble -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:6:3\n  │  \n6 │ ╭   case wibble {\n7 │ │     mod.Wobble -> Nil\n8 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    mod.Wibble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_prelude_module_unqualified.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(result: Result(Nil, Nil)) {\\n  case result {\\n    Ok(Nil) -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(result: Result(Nil, Nil)) {\n  case result {\n    Ok(Nil) -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case result {\n4 │ │     Ok(Nil) -> Nil\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_prelude_module_when_shadowed.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport gleam\\ntype MyResult { Ok Error }\\npub fn main(res: Result(Int, Nil)) {\\n  case res {\\n    gleam.Ok(n) -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\nimport gleam\ntype MyResult { Ok Error }\npub fn main(res: Result(Int, Nil)) {\n  case res {\n    gleam.Ok(n) -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:3\n  │  \n5 │ ╭   case res {\n6 │ │     gleam.Ok(n) -> Nil\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    gleam.Error(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_unqualifed_when_aliased.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport mod.{Wibble as Wobble}\\ntype Wibble { Wibble Wubble }\\npub fn main() {\\n  let wibble = mod.Wibble\\n  case wibble {\\n    mod.Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport mod.{Wibble as Wobble}\ntype Wibble { Wibble Wubble }\npub fn main() {\n  let wibble = mod.Wibble\n  case wibble {\n    mod.Wobble -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:6:3\n  │  \n6 │ ╭   case wibble {\n7 │ │     mod.Wobble -> Nil\n8 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Wobble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__case_error_prints_unqualified_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport wibble.{Wibble, Wobble}\\npub fn main(wibble) {\\n    case wibble {\\n        Wibble -> Nil\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble Wobble }\n\n-- main.gleam\n\nimport wibble.{Wibble, Wobble}\npub fn main(wibble) {\n    case wibble {\n        Wibble -> Nil\n    }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:5\n  │  \n4 │ ╭     case wibble {\n5 │ │         Wibble -> Nil\n6 │ │     }\n  │ ╰─────^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Wobble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__compiler_does_not_crash_when_defining_duplicate_alternative_variables.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\ncase todo {\\n  #(a, b) | #(a, a as b) -> todo\\n}\\n\"\n---\n----- SOURCE CODE\n\ncase todo {\n  #(a, b) | #(a, a as b) -> todo\n}\n\n\n----- ERROR\nerror: Duplicate variable in pattern\n  ┌─ /src/one/two.gleam:3:18\n  │\n3 │   #(a, b) | #(a, a as b) -> todo\n  │                  ^ This has already been used\n\nVariables can only be used once per pattern. This variable `a` appears\nmultiple times.\nIf you used the same variable twice deliberately in order to check for\nequality please use a guard clause instead.\ne.g. (x, y) if x == y -> ...\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__compiler_does_not_crash_when_matching_on_utfcodepoint.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport gleam/string\\n\\npub fn main() {\\n  let assert Ok(wibble) = string.utf_codepoint(71)\\n  case wibble {\\n  }\\n}        \"\n---\n----- SOURCE CODE\n-- gleam/string.gleam\n\n@external(erlang, \"gleam_stdlib\", \"identity\")\nfn unsafe_int_to_utf_codepoint(a: Int) -> UtfCodepoint\n\npub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) {\n  case value {\n    i if i > 1_114_111 -> Error(Nil)\n    i if i >= 55_296 && i <= 57_343 -> Error(Nil)\n    i if i < 0 -> Error(Nil)\n    i -> Ok(unsafe_int_to_utf_codepoint(i))\n  }\n}\n            \n\n-- main.gleam\n\nimport gleam/string\n\npub fn main() {\n  let assert Ok(wibble) = string.utf_codepoint(71)\n  case wibble {\n  }\n}        \n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:6:3\n  │  \n6 │ ╭   case wibble {\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__correct_missing_patterns_for_opaque_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nimport mod\\n\\npub fn main(w: mod.Wibble) {\\n  case w {}\\n}\\n\"\n---\n----- SOURCE CODE\n-- mod.gleam\npub opaque type Wibble { Wibble(Int) Wobble(String) }\n\n-- main.gleam\n\nimport mod\n\npub fn main(w: mod.Wibble) {\n  case w {}\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   case w {}\n  │   ^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__correct_missing_patterns_for_opaque_type_in_definition_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub opaque type Wibble { Wibble(Int) Wobble(String) }\\n\\npub fn main(w: Wibble) {\\n  case w {}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub opaque type Wibble { Wibble(Int) Wobble(String) }\n\npub fn main(w: Wibble) {\n  case w {}\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   case w {}\n  │   ^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Wibble(_)\n    Wobble(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__custom_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Type {\\n  One\\n  Two\\n}\\n\\npub fn main(x) {\\n  case x {\\n    One -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Type {\n  One\n  Two\n}\n\npub fn main(x) {\n  case x {\n    One -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n   ┌─ /src/one/two.gleam:8:3\n   │  \n 8 │ ╭   case x {\n 9 │ │     One -> 1\n10 │ │   }\n   │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Two\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__custom_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Type {\\n  One\\n  Two\\n  Three(Type)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    One -> 1\\n    Two -> 2\\n    Three(One) -> 4\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Type {\n  One\n  Two\n  Three(Type)\n}\n\npub fn main(x) {\n  case x {\n    One -> 1\n    Two -> 2\n    Three(One) -> 4\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n   ┌─ /src/one/two.gleam:9:3\n   │  \n 9 │ ╭   case x {\n10 │ │     One -> 1\n11 │ │     Two -> 2\n12 │ │     Three(One) -> 4\n13 │ │   }\n   │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Three(Two)\n    Three(Three(_))\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__discard_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thing {\\n  Thing(a: Bool, b: Bool)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    Thing(a: True, ..) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: True, ..) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:7:3\n  │  \n7 │ ╭   case x {\n8 │ │     Thing(a: True, ..) -> 1\n9 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Thing(a: False, b:)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__discard_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thing {\\n  Thing(a: Bool, b: Bool)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    Thing(a: False, ..) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: False, ..) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:7:3\n  │  \n7 │ ╭   case x {\n8 │ │     Thing(a: False, ..) -> 1\n9 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Thing(a: True, b:)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__discard_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thing {\\n  Thing(a: Bool, b: Bool)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    Thing(a: True, ..) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: True, ..) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:7:3\n  │  \n7 │ ╭   case x {\n8 │ │     Thing(a: True, ..) -> 1\n9 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Thing(a: False, b:)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__discard_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thing {\\n  Thing(a: Bool, b: Bool)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    Thing(a: False, ..) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: False, ..) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:7:3\n  │  \n7 │ ╭   case x {\n8 │ │     Thing(a: False, ..) -> 1\n9 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Thing(a: True, b:)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__discard_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thing {\\n  Thing(a: Bool, b: Bool)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    Thing(False, ..) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(False, ..) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:7:3\n  │  \n7 │ ╭   case x {\n8 │ │     Thing(False, ..) -> 1\n9 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Thing(a: True, b:)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__duplicated_alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  case x {\\n    2 | 2 -> 2\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 1\n  case x {\n    2 | 2 -> 2\n    _ -> panic\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:9\n  │\n5 │     2 | 2 -> 2\n  │         ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__duplicated_pattern_in_alternative.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  case x {\\n    2 -> x\\n    1 | 2 -> x - 4\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 1\n  case x {\n    2 -> x\n    1 | 2 -> x - 4\n    _ -> panic\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:9\n  │\n6 │     1 | 2 -> x - 4\n  │         ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__duplicated_pattern_with_multiple_alternatives.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  case x {\\n    1 -> 1\\n    3 -> 3\\n    5 -> 5\\n    1 | 2 | 3 | 4 | 5 -> x - 1\\n    _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 1\n  case x {\n    1 -> 1\n    3 -> 3\n    5 -> 5\n    1 | 2 | 3 | 4 | 5 -> x - 1\n    _ -> panic\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:8:5\n  │\n8 │     1 | 2 | 3 | 4 | 5 -> x - 1\n  │     ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:8:13\n  │\n8 │     1 | 2 | 3 | 4 | 5 -> x - 1\n  │             ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:8:21\n  │\n8 │     1 | 2 | 3 | 4 | 5 -> x - 1\n  │                     ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_bool.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(b: Bool) {\\n  case b {}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(b: Bool) {\n  case b {}\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   case b {}\n  │   ^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    True\n    False\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_custom_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Wibble { Wibble Wobble Wubble }\\npub fn main(wibble: Wibble) {\\n  case wibble {}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble Wobble Wubble }\npub fn main(wibble: Wibble) {\n  case wibble {}\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   case wibble {}\n  │   ^^^^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Wibble\n    Wobble\n    Wubble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_external.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thingy\\n\\npub fn main(x: Thingy) {\\n  case x {\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thingy\n\npub fn main(x: Thingy) {\n  case x {\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:3\n  │  \n5 │ ╭   case x {\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nlet age = 10.6\\ncase age {}\\n\"\n---\n----- SOURCE CODE\n\nlet age = 10.6\ncase age {}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ case age {}\n  │ ^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_generic.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x: something) {\\n  case x {\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x: something) {\n  case x {\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nlet num = 24\\ncase num {}\\n\"\n---\n----- SOURCE CODE\n\nlet num = 24\ncase num {}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ case num {}\n  │ ^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nlet list = []\\ncase list {}\\n\"\n---\n----- SOURCE CODE\n\nlet list = []\ncase list {}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ case list {}\n  │ ^^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    []\n    [_, ..]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_multi_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(a: Result(a, b), b: Bool) {\\n  case a, b {}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(a: Result(a, b), b: Bool) {\n  case a, b {}\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   case a, b {}\n  │   ^^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(_), _\n    Error(_), _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__empty_case_of_string.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nlet name = \\\"John Doe\\\"\\ncase name {}\\n\"\n---\n----- SOURCE CODE\n\nlet name = \"John Doe\"\ncase name {}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ case name {}\n  │ ^^^^^^^^^^^^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__float_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0.0 -> 1\\n    1.1 -> 1\\n    2.2 -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    1.1 -> 1\n    2.2 -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     0.0 -> 1\n5 │ │     1.1 -> 1\n6 │ │     2.2 -> 1\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__float_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0.0 -> 1\\n    1.1 -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0.0 -> 1\n    1.1 -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     0.0 -> 1\n5 │ │     1.1 -> 1\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__guard.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x, y) {\\n  case x {\\n    _ if y -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x, y) {\n  case x {\n    _ if y -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     _ if y -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__guard_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x, y) {\\n  case x {\\n    True if y -> 1\\n    False -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x, y) {\n  case x {\n    True if y -> 1\n    False -> 2\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     True if y -> 1\n5 │ │     False -> 2\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    True\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__inexhaustive_multi_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nlet a = Ok(1)\\nlet b = True\\ncase a, b {\\n  Error(_), _ -> Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nlet a = Ok(1)\nlet b = True\ncase a, b {\n  Error(_), _ -> Nil\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:1\n  │  \n4 │ ╭ case a, b {\n5 │ │   Error(_), _ -> Nil\n6 │ │ }\n  │ ╰─^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(_), _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__inexhaustive_multi_pattern2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(a: Result(Int, Nil), b: Bool) {\\n  case a, b {\\n    Ok(1), True -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(a: Result(Int, Nil), b: Bool) {\n  case a, b {\n    Ok(1), True -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case a, b {\n4 │ │     Ok(1), True -> Nil\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(_), True\n    Ok(_), False\n    Error(_), _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__inexhaustive_multi_pattern3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nlet a = Ok(1)\\nlet b = True\\ncase a, b {\\n  _, False -> Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nlet a = Ok(1)\nlet b = True\ncase a, b {\n  _, False -> Nil\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:4:1\n  │  \n4 │ ╭ case a, b {\n5 │ │   _, False -> Nil\n6 │ │ }\n  │ ╰─^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _, True\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__inexhaustive_multi_pattern4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(c: Bool) {\\n  let a = 12\\n  let b = 3.14\\n  case a, b, c {\\n    1, 2.0, True -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(c: Bool) {\n  let a = 12\n  let b = 3.14\n  case a, b, c {\n    1, 2.0, True -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:3\n  │  \n5 │ ╭   case a, b, c {\n6 │ │     1, 2.0, True -> Nil\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _, _, True\n    _, _, False\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__inexhaustive_multi_pattern5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(c: Bool) {\\n  let a = 12\\n  let b = 3.14\\n  case a, b, c {\\n    12, _, False -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(c: Bool) {\n  let a = 12\n  let b = 3.14\n  case a, b, c {\n    12, _, False -> Nil\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:5:3\n  │  \n5 │ ╭   case a, b, c {\n6 │ │     12, _, False -> Nil\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _, _, False\n    _, _, True\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__int_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0 -> 1\\n    1 -> 1\\n    2 -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0 -> 1\n    1 -> 1\n    2 -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     0 -> 1\n5 │ │     1 -> 1\n6 │ │     2 -> 1\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__int_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    0 -> 1\\n    1 -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    0 -> 1\n    1 -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     0 -> 1\n5 │ │     1 -> 1\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__label_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Thing {\\n  Thing(a: Bool, b: Bool)\\n}\\n\\npub fn main(x) {\\n  case x {\\n    Thing(a: False, b: True) -> 1\\n    Thing(b: False, a: True) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(a: Bool, b: Bool)\n}\n\npub fn main(x) {\n  case x {\n    Thing(a: False, b: True) -> 1\n    Thing(b: False, a: True) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n   ┌─ /src/one/two.gleam:7:3\n   │  \n 7 │ ╭   case x {\n 8 │ │     Thing(a: False, b: True) -> 1\n 9 │ │     Thing(b: False, a: True) -> 1\n10 │ │   }\n   │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Thing(a: True, b: True)\n    Thing(a: False, b: False)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__let_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  let True = x\\n  0\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let True = x\n  0\n}\n\n\n----- ERROR\nerror: Inexhaustive pattern\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   let True = x\n  │   ^^^^^^^^^^^^\n\nThis assignment uses a pattern that does not match all possible values. If\none of the other values is used then the assignment will crash.\n\nThe missing patterns are:\n\n    False\n\nHint: Use a more general pattern or use `let assert` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_bool_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] -> 1\\n    [True] -> 2\\n    [_, _, ..] -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [] -> 1\n    [True] -> 2\n    [_, _, ..] -> 2\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [] -> 1\n5 │ │     [True] -> 2\n6 │ │     [_, _, ..] -> 2\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    [False]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_bool_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] -> 1\\n    [True] -> 2\\n    [_, False] -> 2\\n    [_, _, _, ..] -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [] -> 1\n    [True] -> 2\n    [_, False] -> 2\n    [_, _, _, ..] -> 2\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [] -> 1\n5 │ │     [True] -> 2\n6 │ │     [_, False] -> 2\n7 │ │     [_, _, _, ..] -> 2\n8 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    [False]\n    [_, True]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_empty.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [] -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [] -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    [_, ..]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_non_empty.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [_, ..] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [_, ..] -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [_, ..] -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    []\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_one.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [_] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [_] -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [_] -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    []\n    [_, _, ..]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_one_two.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [_] -> 1\\n    [_, _] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [_] -> 1\n    [_, _] -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [_] -> 1\n5 │ │     [_, _] -> 1\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    []\n    [_, _, _, ..]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_zero_one_two.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] -> 1\\n    [_] -> 1\\n    [_, _] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [] -> 1\n    [_] -> 1\n    [_, _] -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [] -> 1\n5 │ │     [_] -> 1\n6 │ │     [_, _] -> 1\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    [_, _, _, ..]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__list_zero_two_any.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] -> 1\\n    [_, _] -> 1\\n    [_, _, ..] -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    [] -> 1\n    [_, _] -> 1\n    [_, _, ..] -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     [] -> 1\n5 │ │     [_, _] -> 1\n6 │ │     [_, _, ..] -> 1\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    [_]\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__multiple_unreachable_prefix_patterns.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let string = \\\"\\\"\\n  case string {\\n    \\\"wib\\\" <> rest -> rest\\n    \\\"wibble\\\" <> rest -> rest\\n    \\\"wibblest\\\" <> rest -> rest\\n    _ -> \\\"a\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest -> rest\n    \"wibble\" <> rest -> rest\n    \"wibblest\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     \"wibble\" <> rest -> rest\n  │     ^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     \"wibblest\" <> rest -> rest\n  │     ^^^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__multiple_unreachable_prefix_patterns_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let string = \\\"\\\"\\n  case string {\\n    \\\"wib\\\" <> rest if True -> rest\\n    \\\"wibble\\\" <> rest -> rest\\n    \\\"wibblest\\\" <> rest -> rest\\n    _ -> \\\"a\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest if True -> rest\n    \"wibble\" <> rest -> rest\n    \"wibblest\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     \"wibblest\" <> rest -> rest\n  │     ^^^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__nested_type_parameter_usage.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Returned(a) {\\n  Returned(List(a))\\n}\\n\\nfn wibble(user: Returned(#())) -> Int {\\n  let Returned([#()]) = user\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Returned(a) {\n  Returned(List(a))\n}\n\nfn wibble(user: Returned(#())) -> Int {\n  let Returned([#()]) = user\n  1\n}\n\n\n----- ERROR\nerror: Inexhaustive pattern\n  ┌─ /src/one/two.gleam:7:3\n  │\n7 │   let Returned([#()]) = user\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis assignment uses a pattern that does not match all possible values. If\none of the other values is used then the assignment will crash.\n\nThe missing patterns are:\n\n    Returned([])\n    Returned([#(), _, ..])\n\nHint: Use a more general pattern or use `let assert` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__other_variant_unreachable_when_inferred.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\npub fn main() {\\n  let always_wobble = Wobble\\n  case always_wobble {\\n    Wibble -> panic\\n    Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  let always_wobble = Wobble\n  case always_wobble {\n    Wibble -> panic\n    Wobble -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n   ┌─ /src/warning/wrn.gleam:10:5\n   │\n10 │     Wibble -> panic\n   │     ^^^^^^\n\nThis pattern cannot be reached as it matches on a variant of a type which\nis never present.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__other_variant_unreachable_when_inferred2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n  Wubble\\n}\\n\\npub fn main() {\\n  let always_wobble = Wobble\\n  case always_wobble {\\n    Wibble | Wubble -> panic\\n    Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble\n  Wobble\n  Wubble\n}\n\npub fn main() {\n  let always_wobble = Wobble\n  case always_wobble {\n    Wibble | Wubble -> panic\n    Wobble -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n   ┌─ /src/warning/wrn.gleam:11:5\n   │\n11 │     Wibble | Wubble -> panic\n   │     ^^^^^^\n\nThis pattern cannot be reached as it matches on a variant of a type which\nis never present.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n   ┌─ /src/warning/wrn.gleam:11:14\n   │\n11 │     Wibble | Wubble -> panic\n   │              ^^^^^^\n\nThis pattern cannot be reached as it matches on a variant of a type which\nis never present.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    _ -> 1\\n    _ -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    _ -> 1\n    _ -> 2\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     _ -> 2\n  │     ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    True -> 1\\n    False -> 2\\n    True -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    True -> 1\n    False -> 2\n    True -> 3\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     True -> 3\n  │     ^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\ncase x {\\n59 -> \\\"gleew\\\"\\n14 -> \\\"glabber\\\"\\n1 -> \\\"\\\"\\n_ -> \\\"glooper\\\"\\n2 -> \\\"\\\"\\n3 -> \\\"glen\\\"\\n4 -> \\\"glew\\\"\\n}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\ncase x {\n59 -> \"gleew\"\n14 -> \"glabber\"\n1 -> \"\"\n_ -> \"glooper\"\n2 -> \"\"\n3 -> \"glen\"\n4 -> \"glew\"\n}\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:8:1\n  │\n8 │ 2 -> \"\"\n  │ ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:9:1\n  │\n9 │ 3 -> \"glen\"\n  │ ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n\nwarning: Unreachable pattern\n   ┌─ /src/warning/wrn.gleam:10:1\n   │\n10 │ 4 -> \"glew\"\n   │ ^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\ncase x {\\n\\\"P\\\" -> 4\\n_ -> 3\\n\\\"geeper!\\\" -> 5\\n}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\ncase x {\n\"P\" -> 4\n_ -> 3\n\"geeper!\" -> 5\n}\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:1\n  │\n6 │ \"geeper!\" -> 5\n  │ ^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\ncase x {\\n\\\"P\\\" -> 4\\n\\\"\\\" -> 65\\n\\\"P\\\" -> 19\\n_ -> 3\\n}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\ncase x {\n\"P\" -> 4\n\"\" -> 65\n\"P\" -> 19\n_ -> 3\n}\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:1\n  │\n6 │ \"P\" -> 19\n  │ ^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_float_scientific_notation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    10.0 -> \\\"ten\\\"\\n    1.0e1 -> \\\"also ten\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    10.0 -> \"ten\"\n    1.0e1 -> \"also ten\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1.0e1 -> \"also ten\"\n  │     ^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_float_scientific_notation_and_underscore.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    1.0e2 -> \\\"one hundred\\\"\\n    1_0_0.0 -> \\\"one hundred again\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    1.0e2 -> \"one hundred\"\n    1_0_0.0 -> \"one hundred again\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1_0_0.0 -> \"one hundred again\"\n  │     ^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_float_with_different_formatting.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    1.0 -> \\\"one\\\"\\n    1.00 -> \\\"also one\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    1.0 -> \"one\"\n    1.00 -> \"also one\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1.00 -> \"also one\"\n  │     ^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_float_with_no_trailing_decimal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    1.0 -> \\\"one\\\"\\n    1. -> \\\"another one\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    1.0 -> \"one\"\n    1. -> \"another one\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1. -> \"another one\"\n  │     ^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_float_with_underscore.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    10.0 -> \\\"ten\\\"\\n    1_0.0 -> \\\"also ten\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    10.0 -> \"ten\"\n    1_0.0 -> \"also ten\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1_0.0 -> \"also ten\"\n  │     ^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_int_with_multiple_underscores.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    1_000_000 -> \\\"one million\\\"\\n    1000000 -> \\\"also one million\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    1_000_000 -> \"one million\"\n    1000000 -> \"also one million\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1000000 -> \"also one million\"\n  │     ^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_int_with_underscores.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    10 -> \\\"ten\\\"\\n    1_0 -> \\\"also ten\\\"\\n    _ -> \\\"other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    10 -> \"ten\"\n    1_0 -> \"also ten\"\n    _ -> \"other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     1_0 -> \"also ten\"\n  │     ^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__redundant_missing_patterns.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\nfn wibble(b: Bool, i: Int) {\\n  case b, i {\\n    False, 1 -> todo\\n    True, 2 -> todo\\n  }\\n}\\n\\npub fn main() { wibble(False, 1) }\"\n---\n----- SOURCE CODE\n\nfn wibble(b: Bool, i: Int) {\n  case b, i {\n    False, 1 -> todo\n    True, 2 -> todo\n  }\n}\n\npub fn main() { wibble(False, 1) }\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case b, i {\n4 │ │     False, 1 -> todo\n5 │ │     True, 2 -> todo\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    True, _\n    False, _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__reference_absent_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\ntype Wibble {\\n    One(Int)\\n    Two(Absent)\\n}\\n\\npub fn main(wibble) {\\n    case wibble {\\n        One(x) -> x\\n    }\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n    One(Int)\n    Two(Absent)\n}\n\npub fn main(wibble) {\n    case wibble {\n        One(x) -> x\n    }\n}\n\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:4:9\n  │\n4 │     Two(Absent)\n  │         ^^^^^^\n\nThe type `Absent` is not defined or imported in this module.\n\nerror: Private type used in public interface\n  ┌─ /src/one/two.gleam:7:1\n  │\n7 │ pub fn main(wibble) {\n  │ ^^^^^^^^^^^^^^^^^^^\n\nThe following type is private, but is being used by this public export.\n\n    Wibble\n\nPrivate types can only be used within the module that defines them.\n\nerror: Inexhaustive patterns\n   ┌─ /src/one/two.gleam:8:5\n   │  \n 8 │ ╭     case wibble {\n 9 │ │         One(x) -> x\n10 │ │     }\n   │ ╰─────^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Two(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(False) -> 1\\n    Error(True) -> 2\\n    Error(False) -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(False) -> 1\n    Error(True) -> 2\n    Error(False) -> 3\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(False) -> 1\n5 │ │     Error(True) -> 2\n6 │ │     Error(False) -> 3\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(True)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(True) -> 1\\n    Error(True) -> 2\\n    Error(False) -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Error(True) -> 2\n    Error(False) -> 3\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(True) -> 1\n5 │ │     Error(True) -> 2\n6 │ │     Error(False) -> 3\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(False)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(True) -> 1\\n    Ok(False) -> 2\\n    Error(False) -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 2\n    Error(False) -> 3\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(True) -> 1\n5 │ │     Ok(False) -> 2\n6 │ │     Error(False) -> 3\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(True)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(True) -> 1\\n    Ok(False) -> 2\\n    Error(True) -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 2\n    Error(True) -> 3\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(True) -> 1\n5 │ │     Ok(False) -> 2\n6 │ │     Error(True) -> 3\n7 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(False)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(True) -> 1\\n    Ok(False) -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(True) -> 1\n    Ok(False) -> 2\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(True) -> 1\n5 │ │     Ok(False) -> 2\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Error(True) -> 1\\n    Error(False) -> 2\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Error(True) -> 1\n    Error(False) -> 2\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Error(True) -> 1\n5 │ │     Error(False) -> 2\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Error(True) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Error(True) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Error(True) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(False)\n    Ok(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_bool_8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(False) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(False) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(False) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(True)\n    Error(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Error(_) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Error(_) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Error(_) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_nil_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Error(Nil) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Error(Nil) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Error(Nil) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Ok(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_nil_ok.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(Nil) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(Nil) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(Nil) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__result_ok.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    Ok(_) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    Ok(_) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     Ok(_) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    Error(_)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__same_catch_all_bytes_are_redundant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let bit_array = <<>>\\n  case bit_array {\\n    <<_:bytes>> -> <<>>\\n    <<a:bytes>> -> a\\n    _ -> <<>>\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let bit_array = <<>>\n  case bit_array {\n    <<_:bytes>> -> <<>>\n    <<a:bytes>> -> a\n    _ -> <<>>\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<a:bytes>> -> a\n  │     ^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__string_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    \\\"\\\" -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    \"\" -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     \"\" -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__string_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    \\\"a\\\" -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    \"a\" -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     \"a\" -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__string_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    \\\"a\\\" -> 1\\n    \\\"b\\\" -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    \"a\" -> 1\n    \"b\" -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     \"a\" -> 1\n5 │ │     \"b\" -> 1\n6 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__tuple_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main(x, y) {\\n  case #(x, y) {\\n    #(True, _) -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x, y) {\n  case #(x, y) {\n    #(True, _) -> 1\n  }\n}\n\n\n----- ERROR\nerror: Inexhaustive patterns\n  ┌─ /src/one/two.gleam:3:3\n  │  \n3 │ ╭   case #(x, y) {\n4 │ │     #(True, _) -> 1\n5 │ │   }\n  │ ╰───^\n\nThis case expression does not have a pattern for all possible values. If it\nis run on one of the values without a pattern then it will crash.\n\nThe missing patterns are:\n\n    #(False, _)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__unreachable_alternative_multi_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  let y = 2\\n  case x, y {\\n    1, 2 -> True\\n    3, 4 | 1, 2 -> False\\n    _, _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 1\n  let y = 2\n  case x, y {\n    1, 2 -> True\n    3, 4 | 1, 2 -> False\n    _, _ -> panic\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:7:12\n  │\n7 │     3, 4 | 1, 2 -> False\n  │            ^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__unreachable_multi_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  let y = 2\\n  case x, y {\\n    1, 2 -> True\\n    1, 2 -> False\\n    _, _ -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let x = 1\n  let y = 2\n  case x, y {\n    1, 2 -> True\n    1, 2 -> False\n    _, _ -> panic\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:7:5\n  │\n7 │     1, 2 -> False\n  │     ^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__unreachable_prefix_pattern_after_prefix.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let string = \\\"\\\"\\n  case string {\\n    \\\"wib\\\" <> rest -> rest\\n    \\\"wibble\\\" <> rest -> rest\\n    _ -> \\\"a\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest -> rest\n    \"wibble\" <> rest -> rest\n    _ -> \"a\"\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     \"wibble\" <> rest -> rest\n  │     ^^^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__exhaustiveness__unreachable_string_pattern_after_prefix.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/exhaustiveness.rs\nexpression: \"pub fn main() {\\n  let string = \\\"\\\"\\n  case string {\\n    \\\"wib\\\" <> rest -> rest\\n    \\\"wibble\\\" -> \\\"a\\\"\\n    _ -> \\\"b\\\"\\n  }\\n}\"\n---\n----- SOURCE CODE\npub fn main() {\n  let string = \"\"\n  case string {\n    \"wib\" <> rest -> rest\n    \"wibble\" -> \"a\"\n    _ -> \"b\"\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     \"wibble\" -> \"a\"\n  │     ^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__erlang_only_function_used_by_javascript_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@external(erlang, \\\"one\\\", \\\"two\\\")\\nfn erlang_only() -> Int\\n\\npub fn main() {\\n  erlang_only()\\n}\\n\"\n---\n----- SOURCE CODE\n@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n\npub fn main() {\n  erlang_only()\n}\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   erlang_only()\n  │   ^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the JavaScript target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__erlang_only_function_with_erlang_external.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@external(erlang, \\\"one\\\", \\\"two\\\")\\nfn erlang_only() -> Int\\n\\n@external(erlang, \\\"one\\\", \\\"two\\\")\\npub fn uh_oh() -> Int {\\n  erlang_only()\\n}\\n\"\n---\n----- SOURCE CODE\n@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n\n@external(erlang, \"one\", \"two\")\npub fn uh_oh() -> Int {\n  erlang_only()\n}\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:6:3\n  │\n6 │   erlang_only()\n  │   ^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the JavaScript target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__erlang_targeted_function_cant_contain_javascript_only_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@target(erlang)\\npub fn erlang_only() -> Int {\\n  javascript_only()\\n}\\n\\n@external(javascript, \\\"one\\\", \\\"two\\\")\\nfn javascript_only() -> Int\\n    \"\n---\n----- SOURCE CODE\n@target(erlang)\npub fn erlang_only() -> Int {\n  javascript_only()\n}\n\n@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\n    \n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   javascript_only()\n  │   ^^^^^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__imported_javascript_only_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"import module\\npub fn main() {\\n  module.javascript_only()\\n}\"\n---\n----- SOURCE CODE\n-- module.gleam\n@external(javascript, \"one\", \"two\")\npub fn javascript_only() -> Int\n\n-- main.gleam\nimport module\npub fn main() {\n  module.javascript_only()\n}\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:3:10\n  │\n3 │   module.javascript_only()\n  │          ^^^^^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__javascript_only_constant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"import module\\npub fn main() {\\n  module.javascript_only_constant()\\n}\"\n---\n----- SOURCE CODE\n-- module.gleam\n@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\nconst constant = javascript_only\npub const javascript_only_constant = constant\n\n\n-- main.gleam\nimport module\npub fn main() {\n  module.javascript_only_constant()\n}\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:3:10\n  │\n3 │   module.javascript_only_constant()\n  │          ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__javascript_only_function_used_by_erlang_module.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@external(javascript, \\\"one\\\", \\\"two\\\")\\nfn js_only() -> Int\\n\\npub fn main() {\\n  js_only()\\n}\\n\"\n---\n----- SOURCE CODE\n@external(javascript, \"one\", \"two\")\nfn js_only() -> Int\n\npub fn main() {\n  js_only()\n}\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   js_only()\n  │   ^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__javascript_only_function_with_javascript_external.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@external(javascript, \\\"one\\\", \\\"two\\\")\\nfn javascript_only() -> Int\\n\\n@external(javascript, \\\"one\\\", \\\"two\\\")\\npub fn uh_oh() -> Int {\\n  javascript_only()\\n}\\n\"\n---\n----- SOURCE CODE\n@external(javascript, \"one\", \"two\")\nfn javascript_only() -> Int\n\n@external(javascript, \"one\", \"two\")\npub fn uh_oh() -> Int {\n  javascript_only()\n}\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:6:3\n  │\n6 │   javascript_only()\n  │   ^^^^^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__javascript_targeted_function_cant_contain_erlang_only_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@target(javascript)\\npub fn javascript_only() -> Int {\\n  erlang_only()\\n}\\n\\n@external(erlang, \\\"one\\\", \\\"two\\\")\\nfn erlang_only() -> Int\\n    \"\n---\n----- SOURCE CODE\n@target(javascript)\npub fn javascript_only() -> Int {\n  erlang_only()\n}\n\n@external(erlang, \"one\", \"two\")\nfn erlang_only() -> Int\n    \n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:3:3\n  │\n3 │   erlang_only()\n  │   ^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the JavaScript target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__public_erlang_external.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@external(erlang, \\\"one\\\", \\\"two\\\")\\npub fn main() -> Int\\n\"\n---\n----- SOURCE CODE\n@external(erlang, \"one\", \"two\")\npub fn main() -> Int\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ pub fn main() -> Int\n  │ ^^^^^^^^^^^^^\n\nThe `main` function is public but doesn't have an implementation for the\nJavaScript target. All public functions of a package must be able to\ncompile for a module to be valid.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__public_javascript_external.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"@external(javascript, \\\"one\\\", \\\"two\\\")\\npub fn main() -> Int\\n\"\n---\n----- SOURCE CODE\n@external(javascript, \"one\", \"two\")\npub fn main() -> Int\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ pub fn main() -> Int\n  │ ^^^^^^^^^^^^^\n\nThe `main` function is public but doesn't have an implementation for the\nErlang target. All public functions of a package must be able to compile\nfor a module to be valid.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__externals__unsupported_target_for_unused_import.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/externals.rs\nexpression: \"import mod.{wobble}\"\n---\n----- SOURCE CODE\n-- mod.gleam\n@external(javascript, \"wibble\", \"wobble\") pub fn wobble()\n\n-- main.gleam\nimport mod.{wobble}\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import mod.{wobble}\n  │             ^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__annotation_mismatch_function_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn bad(x: Int) -> Float {\\n  // This does not match the return annotation\\n  1\\n}\\n\\npub fn user() -> Float {\\n  // This checks that the bad function is still usable, the types coming from\\n  // its annotations. This function is valid.\\n  bad(1)\\n}\\n\\n// Another bad function to make sure that analysis has not stopped. This error\\n// should also be emitted.\\npub fn bad_2() {\\n  bad(Nil)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn bad(x: Int) -> Float {\n  // This does not match the return annotation\n  1\n}\n\npub fn user() -> Float {\n  // This checks that the bad function is still usable, the types coming from\n  // its annotations. This function is valid.\n  bad(1)\n}\n\n// Another bad function to make sure that analysis has not stopped. This error\n// should also be emitted.\npub fn bad_2() {\n  bad(Nil)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   1\n  │   ^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:16:7\n   │\n16 │   bad(Nil)\n   │       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__bad_body_function_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn bad(x: Int) -> Float {\\n  // Invalid body.\\n  \\\"\\\" + \\\"\\\"\\n}\\n\\npub fn user() -> Float {\\n  // This checks that the bad function is still usable, the types coming from\\n  // its annotations. This function is valid.\\n  bad(1)\\n}\\n\\n// Another bad function to make sure that analysis has not stopped. This error\\n// should also be emitted.\\npub fn bad_2() {\\n  bad(Nil)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn bad(x: Int) -> Float {\n  // Invalid body.\n  \"\" + \"\"\n}\n\npub fn user() -> Float {\n  // This checks that the bad function is still usable, the types coming from\n  // its annotations. This function is valid.\n  bad(1)\n}\n\n// Another bad function to make sure that analysis has not stopped. This error\n// should also be emitted.\npub fn bad_2() {\n  bad(Nil)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   \"\" + \"\"\n  │   ^^^^^^^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Float\n\nFound type:\n\n    Int\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:6\n  │\n4 │   \"\" + \"\"\n  │      ^ Use <> instead\n\nThe + operator can only be used on Ints.\nTo join two strings together you can use the <> operator.\n\nerror: Type mismatch\n   ┌─ /src/one/two.gleam:16:7\n   │\n16 │   bad(Nil)\n   │       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__case_clause_guard_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    a if a == Wibble -> 0\\n    b if b == Wibble -> 0\\n    _ -> 1\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    a if a == Wibble -> 0\n    b if b == Wibble -> 0\n    _ -> 1\n  }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:5:15\n  │\n5 │     a if a == Wibble -> 0\n  │               ^^^^^^ Did you mean `wibble`?\n\nThe custom type variant constructor `Wibble` is not in scope here.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:6:15\n  │\n6 │     b if b == Wibble -> 0\n  │               ^^^^^^ Did you mean `wibble`?\n\nThe custom type variant constructor `Wibble` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__case_clause_pattern_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    True -> 0\\n    Wibble -> 1\\n    Wibble2 -> 2\\n    _ -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True -> 0\n    Wibble -> 1\n    Wibble2 -> 2\n    _ -> 3\n  }\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:6:5\n  │\n6 │     Wibble -> 1\n  │     ^^^^^^ Did you mean `wibble`?\n\nThe custom type variant constructor `Wibble` is not in scope here.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:7:5\n  │\n7 │     Wibble2 -> 2\n  │     ^^^^^^^ Did you mean `wibble`?\n\nThe custom type variant constructor `Wibble2` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__case_clause_then_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    True -> {\\n      1.0 + 1.0\\n    }\\n    _ -> {\\n      1.0 + 1.0\\n    }\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True -> {\n      1.0 + 1.0\n    }\n    _ -> {\n      1.0 + 1.0\n    }\n  }\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:6:11\n  │\n6 │       1.0 + 1.0\n  │           ^ Use +. instead\n\nThe + operator can only be used on Ints.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:9:11\n  │\n9 │       1.0 + 1.0\n  │           ^ Use +. instead\n\nThe + operator can only be used on Ints.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__function_call_incorrect_arg_types_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\nfn add(x: Int, y: Int) {\\n  x + y\\n}\\n\\npub fn main() {\\n  add(1.0, 1.0)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(x: Int, y: Int) {\n  x + y\n}\n\npub fn main() {\n  add(1.0, 1.0)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:7\n  │\n7 │   add(1.0, 1.0)\n  │       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:12\n  │\n7 │   add(1.0, 1.0)\n  │            ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__function_call_incorrect_arity_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\nfn add(x: Int, y: Int) {\\n  x + y\\n}\\n\\npub fn main() {\\n  add(1.0)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(x: Int, y: Int) {\n  x + y\n}\n\npub fn main() {\n  add(1.0)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:7:3\n  │\n7 │   add(1.0)\n  │   ^^^^^^^^ Expected 2 arguments, got 1\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:7\n  │\n7 │   add(1.0)\n  │       ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__function_call_incorrect_arity_with_label_shorthand_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int) -> Int {\\n  arg1() + arg2\\n}\\n\\npub fn main() {\\n  let wobble = \\\"\\\"\\n  wibble(wobble:)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int) -> Int {\n  arg1() + arg2\n}\n\npub fn main() {\n  let wobble = \"\"\n  wibble(wobble:)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:8:3\n  │\n8 │   wibble(wobble:)\n  │   ^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\nThis call accepts these additional labelled arguments:\n\n  - wibble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__function_call_incorrect_arity_with_label_shorthand_fault_tolerance2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int, wabble arg3: Int) -> Int {\\n  arg1() + arg2 + arg3\\n}\\n\\npub fn main() {\\n  let wobble = \\\"\\\"\\n  wibble(fn() {\\\"\\\"}, wobble:)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int, wabble arg3: Int) -> Int {\n  arg1() + arg2 + arg3\n}\n\npub fn main() {\n  let wobble = \"\"\n  wibble(fn() {\"\"}, wobble:)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:8:3\n  │\n8 │   wibble(fn() {\"\"}, wobble:)\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected 3 arguments, got 2\n\nThis call accepts these additional labelled arguments:\n\n  - wabble\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:8:10\n  │\n8 │   wibble(fn() {\"\"}, wobble:)\n  │          ^^^^^^^^^\n\nExpected type:\n\n    fn() -> Int\n\nFound type:\n\n    fn() -> String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__function_call_incorrect_arity_with_labels_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int) -> Int {\\n  arg1() + arg2\\n}\\n\\npub fn main() {\\n  wibble(wobble: \\\"\\\")\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int) -> Int {\n  arg1() + arg2\n}\n\npub fn main() {\n  wibble(wobble: \"\")\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:7:3\n  │\n7 │   wibble(wobble: \"\")\n  │   ^^^^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\nThis call accepts these additional labelled arguments:\n\n  - wibble\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__function_call_incorrect_arity_with_labels_fault_tolerance2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int, wabble arg3: Int) -> Int {\\n  arg1() + arg2 + arg3\\n}\\n\\npub fn main() {\\n  wibble(fn() {\\\"\\\"}, wobble: \\\"\\\")\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn wibble(wibble arg1: fn() -> Int, wobble arg2: Int, wabble arg3: Int) -> Int {\n  arg1() + arg2 + arg3\n}\n\npub fn main() {\n  wibble(fn() {\"\"}, wobble: \"\")\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:7:3\n  │\n7 │   wibble(fn() {\"\"}, wobble: \"\")\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected 3 arguments, got 2\n\nThis call accepts these additional labelled arguments:\n\n  - wabble\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:7:10\n  │\n7 │   wibble(fn() {\"\"}, wobble: \"\")\n  │          ^^^^^^^^^\n\nExpected type:\n\n    fn() -> Int\n\nFound type:\n\n    fn() -> String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__invalid_javascript_external_do_not_stop_analysis.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\n@external(javascript, \\\"somemodule\\\", \\\"() => 123\\\")\\npub fn one() -> Nil {\\n  Nil\\n}\\n\\npub fn two() -> Nil {\\n  \\\"\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"somemodule\", \"() => 123\")\npub fn one() -> Nil {\n  Nil\n}\n\npub fn two() -> Nil {\n  \"\"\n}\n\n\n----- ERROR\nerror: Invalid JavaScript function\n  ┌─ /src/one/two.gleam:3:1\n  │\n3 │ pub fn one() -> Nil {\n  │ ^^^^^^^^^^^^^^^^^^^\n\nThe function `one` has an external JavaScript implementation but the\nfunction name `() => 123` is not valid.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:8:3\n  │\n8 │   \"\"\n  │   ^^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Nil\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__multiple_bad_statement_assignment_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  let a = 1 + 2.0\\n  let b = 3 + 4.0\\n  let c = a + b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a = 1 + 2.0\n  let b = 3 + 4.0\n  let c = a + b\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:15\n  │\n3 │   let a = 1 + 2.0\n  │               ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:15\n  │\n4 │   let b = 3 + 4.0\n  │               ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__multiple_bad_statement_assignment_with_annotation_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  let a: Int = \\\"not an int\\\"\\n  let b: String = 1\\n  let c = a + 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let a: Int = \"not an int\"\n  let b: String = 1\n  let c = a + 2\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:16\n  │\n3 │   let a: Int = \"not an int\"\n  │                ^^^^^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:19\n  │\n4 │   let b: String = 1\n  │                   ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:11\n  │\n5 │   let c = a + 2\n  │           ^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    String\n\nHint: Strings can be joined using the `<>` operator.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__multiple_bad_statement_assignment_with_annotation_fault_tolerance2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  // Since the value is invalid the type is the annotation\\n  let a: Int = Junk\\n  let b: String = 1\\n  let c = a + 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  // Since the value is invalid the type is the annotation\n  let a: Int = Junk\n  let b: String = 1\n  let c = a + 2\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:16\n  │\n4 │   let a: Int = Junk\n  │                ^^^^\n\nThe custom type variant constructor `Junk` is not in scope here.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:19\n  │\n5 │   let b: String = 1\n  │                   ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__multiple_bad_statement_assignment_with_pattern_fault_tolerance2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  // Since the pattern is invalid no variable is created\\n  let Junk(a) = 7\\n  // Pattern is valid but does not type check\\n  let Ok(b) = 1\\n  let c = a + b\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  // Since the pattern is invalid no variable is created\n  let Junk(a) = 7\n  // Pattern is valid but does not type check\n  let Ok(b) = 1\n  let c = a + b\n}\n\n\n----- ERROR\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   let Junk(a) = 7\n  │       ^^^^^^^\n\nThe custom type variant constructor `Junk` is not in scope here.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:6:7\n  │\n6 │   let Ok(b) = 1\n  │       ^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Result(Int, a)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__multiple_bad_statement_expression_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n  1 + 2.0\\n  3 + 4.0\\n  let c = 1 + 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  1 + 2.0\n  3 + 4.0\n  let c = 1 + 2\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   1 + 2.0\n  │       ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   3 + 4.0\n  │       ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__no_impl_function_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn no_impl() -> Nil\\n\\npub type X = UnknownType\\n\"\n---\n----- SOURCE CODE\n\npub fn no_impl() -> Nil\n\npub type X = UnknownType\n\n\n----- ERROR\nerror: Function without an implementation\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ pub fn no_impl() -> Nil\n  │ ^^^^^^^^^^^^^^^^\n\nWe can't compile this function as it doesn't have an\nimplementation. Add a body or an external implementation\nusing the `@external` attribute.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:4:14\n  │\n4 │ pub type X = UnknownType\n  │              ^^^^^^^^^^^\n\nThe type `UnknownType` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__provide_arg_type_to_fn_arg_infer_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n   fn(x) { x.2 }(z)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n   fn(x) { x.2 }(z)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:12\n  │\n3 │    fn(x) { x.2 }(z)\n  │            ^ What type is this?\n\nTo index into a tuple we need to know its size, but we don't know anything\nabout this type yet. Please add some type annotations so we can continue.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:3:18\n  │\n3 │    fn(x) { x.2 }(z)\n  │                  ^\n\nThe name `z` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__provide_arg_type_to_fn_explicit_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n   let z = #(1,2)\\n   fn(x: #(Int, Int)) { x.2 }(z)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n   let z = #(1,2)\n   fn(x: #(Int, Int)) { x.2 }(z)\n}\n\n\n----- ERROR\nerror: Out of bounds tuple index\n  ┌─ /src/one/two.gleam:4:26\n  │\n4 │    fn(x: #(Int, Int)) { x.2 }(z)\n  │                          ^^ This index is too large\n\nThe index being accessed for this tuple is 2, but this tuple has 2 elements\nso the highest valid index is 1.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__provide_arg_type_to_fn_implicit_error.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n   let z = #(1,2)\\n   fn(x) { x.2 }(z)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n   let z = #(1,2)\n   fn(x) { x.2 }(z)\n}\n\n\n----- ERROR\nerror: Out of bounds tuple index\n  ┌─ /src/one/two.gleam:4:13\n  │\n4 │    fn(x) { x.2 }(z)\n  │             ^^ This index is too large\n\nThe index being accessed for this tuple is 2, but this tuple has 2 elements\nso the highest valid index is 1.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__provide_arg_type_to_fn_not_a_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n   let z = \\\"not a tuple\\\"\\n   fn(x) { x.2 }(z)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n   let z = \"not a tuple\"\n   fn(x) { x.2 }(z)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:12\n  │\n4 │    fn(x) { x.2 }(z)\n  │            ^ This is not a tuple\n\nTo index into this value it needs to be a tuple, however it has this type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__provide_one_arg_type_to_two_args_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n   let a = #(1,2)\\n   fn(x, y) { x.0 + y.1 }(a)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n   let a = #(1,2)\n   fn(x, y) { x.0 + y.1 }(a)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:4:4\n  │\n4 │    fn(x, y) { x.0 + y.1 }(a)\n  │    ^^^^^^^^^^^^^^^^^^^^^^^^^ Expected 2 arguments, got 1\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:15\n  │\n4 │    fn(x, y) { x.0 + y.1 }(a)\n  │               ^ What type is this?\n\nTo index into a tuple we need to know its size, but we don't know anything\nabout this type yet. Please add some type annotations so we can continue.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:21\n  │\n4 │    fn(x, y) { x.0 + y.1 }(a)\n  │                     ^ What type is this?\n\nTo index into a tuple we need to know its size, but we don't know anything\nabout this type yet. Please add some type annotations so we can continue.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__provide_two_args_type_to_fn_wrong_types.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn main() {\\n   let a = 1\\n   let b = \\\"not an int\\\"\\n   fn(x, y) { x + y }(a, b)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n   let a = 1\n   let b = \"not an int\"\n   fn(x, y) { x + y }(a, b)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:19\n  │\n5 │    fn(x, y) { x + y }(a, b)\n  │                   ^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    String\n\nHint: Strings can be joined using the `<>` operator.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__recursive_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\npub fn one(x) {\\n  two([x])\\n}\\n\\npub fn two(x) {\\n  one(x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn one(x) {\n  two([x])\n}\n\npub fn two(x) {\n  one(x)\n}\n\n\n----- ERROR\nerror: Recursive type\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   two([x])\n  │       ^^^\n\nI don't know how to work out what type this value has. It seems to be\ndefined in terms of itself.\nHint: Add some type annotations and try again.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__unlabelled_after_labelled.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"fn main(wibble wibber, wobber) {\\n  Nil\\n}\"\n---\n----- SOURCE CODE\nfn main(wibble wibber, wobber) {\n  Nil\n}\n\n----- ERROR\nerror: Unlabelled argument after labelled argument\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ fn main(wibble wibber, wobber) {\n  │                        ^^^^^^\n\nAll unlabelled arguments must come before any labelled arguments.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__unlabelled_after_labelled_external.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"\\n@external(erlang, \\\"\\\", \\\"\\\")\\nfn main(wibble x: Int, y: Int) -> Int\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"\", \"\")\nfn main(wibble x: Int, y: Int) -> Int\n\n\n----- ERROR\nerror: Unlabelled argument after labelled argument\n  ┌─ /src/one/two.gleam:3:24\n  │\n3 │ fn main(wibble x: Int, y: Int) -> Int\n  │                        ^^^^^^\n\nAll unlabelled arguments must come before any labelled arguments.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__unlabelled_after_labelled_with_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/functions.rs\nexpression: \"fn main(wibble wibber, wobber: Int) {\\n  Nil\\n}\"\n---\n----- SOURCE CODE\nfn main(wibble wibber, wobber: Int) {\n  Nil\n}\n\n----- ERROR\nerror: Unlabelled argument after labelled argument\n  ┌─ /src/one/two.gleam:1:24\n  │\n1 │ fn main(wibble wibber, wobber: Int) {\n  │                        ^^^^^^^^^^^\n\nAll unlabelled arguments must come before any labelled arguments.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__guards__string_variable_access.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/guards.rs\nexpression: \"\\npub fn a(a: String) {\\n  case a {\\n    _ if a.b -> 1\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn a(a: String) {\n  case a {\n    _ if a.b -> 1\n    _ -> 0\n  }\n}\n\n\n----- ERROR\nerror: Unknown record field\n  ┌─ /src/one/two.gleam:4:12\n  │\n4 │     _ if a.b -> 1\n  │            ^ This field does not exist\n\nThe value being accessed has this type:\n\n    String\n\nIt does not have any fields.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__import_errors_do_not_block_analysis.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import unknown_module\\n\\npub fn main() {\\n  1 + Nil\\n}\"\n---\n----- SOURCE CODE\nimport unknown_module\n\npub fn main() {\n  1 + Nil\n}\n\n----- ERROR\nerror: Unknown module\n  ┌─ /src/one/two.gleam:1:1\n  │\n1 │ import unknown_module\n  │ ^^^^^^^^^^^^^^^^^^^^^\n\nNo module has been found with the name `unknown_module`.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   1 + Nil\n  │       ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__import_type_duplicate.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{One, type One}\\n\\npub fn main() -> One {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n-- one.gleam\npub type One = Int\n\n-- main.gleam\nimport one.{One, type One}\n\npub fn main() -> One {\n  todo\n}\n\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{One, type One}\n  │             ^^^ Did you mean `type One`?\n\n`One` is only a type, it cannot be imported as a value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__import_type_duplicate_with_as.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{type One as MyOne, type One as MyOne}\\n\\npub type X = One\\n\"\n---\n----- SOURCE CODE\n-- one.gleam\npub type One = Int\n\n-- main.gleam\nimport one.{type One as MyOne, type One as MyOne}\n\npub type X = One\n\n\n----- ERROR\nerror: Duplicate type definition\n  ┌─ /src/one/two.gleam:1:32\n  │\n1 │ import one.{type One as MyOne, type One as MyOne}\n  │             -----------------  ^^^^^^^^^^^^^^^^^ Redefined here\n  │             │                   \n  │             First defined here\n\nThe type `MyOne` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:3:14\n  │\n3 │ pub type X = One\n  │              ^^^ Did you mean `MyOne`?\n\nThe type `One` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__import_type_duplicate_with_as_multiline.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{\\n          type One as MyOne,\\n          type One as MyOne\\n        }\\n\\npub type X = One\\n\"\n---\n----- SOURCE CODE\n-- one.gleam\npub type One = Int\n\n-- main.gleam\nimport one.{\n          type One as MyOne,\n          type One as MyOne\n        }\n\npub type X = One\n\n\n----- ERROR\nerror: Duplicate type definition\n  ┌─ /src/one/two.gleam:3:11\n  │\n2 │           type One as MyOne,\n  │           ----------------- First defined here\n3 │           type One as MyOne\n  │           ^^^^^^^^^^^^^^^^^ Redefined here\n\nThe type `MyOne` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:6:14\n  │\n6 │ pub type X = One\n  │              ^^^ Did you mean `MyOne`?\n\nThe type `One` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__imported_constructor_instead_of_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import module.{Wibble}\\n\\npub fn main(x: Wibble) {\\n  todo\\n}\"\n---\n----- SOURCE CODE\n-- module.gleam\npub type Wibble { Wibble }\n\n-- main.gleam\nimport module.{Wibble}\n\npub fn main(x: Wibble) {\n  todo\n}\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:3:16\n  │\n3 │ pub fn main(x: Wibble) {\n  │                ^^^^^^\n\nThe type `Wibble` is not defined or imported in this module.\nThere is a value in scope with the name `Wibble`, but no type in scope with\nthat name.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__module_alias_used_as_a_name.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"\\nimport one/two\\n\\npub fn main() {\\n  two\\n}\\n\"\n---\n----- SOURCE CODE\n-- one/two.gleam\n\n\n-- main.gleam\n\nimport one/two\n\npub fn main() {\n  two\n}\n\n\n----- ERROR\nerror: Module `two` used as a value\n  ┌─ /src/one/two.gleam:5:3\n  │\n5 │   two\n  │   ^^^\n\nModules are not values, so you cannot assign them to variables, pass them\nto functions, or anything else that you would do with a value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__unqualified_import_errors_do_not_block_later_unqualified.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import gleam.{Unknown, type Int as Integer}\\n\\npub fn main() -> Integer {\\n  Nil\\n}\"\n---\n----- SOURCE CODE\nimport gleam.{Unknown, type Int as Integer}\n\npub fn main() -> Integer {\n  Nil\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:15\n  │\n1 │ import gleam.{Unknown, type Int as Integer}\n  │               ^^^^^^^\n\nThe module `gleam` does not have a `Unknown` value.\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   Nil\n  │   ^^^\n\nThe type of this returned value doesn't match the return type\nannotation of this function.\n\nExpected type:\n\n    Integer\n\nFound type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__unqualified_using_opaque_constructor.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{Two}\\n\\npub fn main() {\\n  Two\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\npub opaque type Two { Two }\n\n-- main.gleam\nimport one.{Two}\n\npub fn main() {\n  Two\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{Two}\n  │             ^^^ Did you mean `type Two`?\n\n`Two` is only a type, it cannot be imported as a value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   Two\n  │   ^^^\n\nThe custom type variant constructor `Two` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__unqualified_using_private_constructor.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{Two}\\n\\npub fn main() {\\n  Two\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype Two { Two }\n\n-- main.gleam\nimport one.{Two}\n\npub fn main() {\n  Two\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{Two}\n  │             ^^^\n\nThe module `one` does not have a `Two` value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   Two\n  │   ^^^\n\nThe custom type variant constructor `Two` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__unqualified_using_private_constructor_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{Two}\\n\\npub fn main(x) {\\n  let Two = x\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype Two { Two }\n\n-- main.gleam\nimport one.{Two}\n\npub fn main(x) {\n  let Two = x\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{Two}\n  │             ^^^\n\nThe module `one` does not have a `Two` value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   let Two = x\n  │       ^^^\n\nThe custom type variant constructor `Two` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__unqualified_using_private_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{two}\\n\\npub fn main() {\\n  two\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\nfn two() { 2 }\n\n-- main.gleam\nimport one.{two}\n\npub fn main() {\n  two\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{two}\n  │             ^^^\n\nThe module `one` does not have a `two` value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   two\n  │   ^^^\n\nThe name `two` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_opaque_constructor.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main() {\\n  one.Two\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\npub opaque type Two { Two }\n\n-- main.gleam\nimport one\n\npub fn main() {\n  one.Two\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   one.Two\n  │       ^^^\n\none.Two is a type constructor, it cannot be used as a value\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_constructor.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main() {\\n  one.Two\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype Two { Two }\n\n-- main.gleam\nimport one\n\npub fn main() {\n  one.Two\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   one.Two\n  │       ^^^\n\nThe module `one` does not have a `Two` value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_constructor_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main(x) {\\n  let one.Two = x\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype Two { Two }\n\n-- main.gleam\nimport one\n\npub fn main(x) {\n  let one.Two = x\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   let one.Two = x\n  │       ^^^^^^^\n\nThe module `one` does not have a `Two` value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_custom_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main() {\\n  one.X\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype X { Y }\n\n-- main.gleam\nimport one\n\npub fn main() {\n  one.X\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   one.X\n  │       ^\n\nThe module `one` does not have a `X` value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_external_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main() {\\n  one.X\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype X\n\n-- main.gleam\nimport one\n\npub fn main() {\n  one.X\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   one.X\n  │       ^\n\nThe module `one` does not have a `X` value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main() {\\n  one.two\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\nfn two() { 2 }\n\n-- main.gleam\nimport one\n\npub fn main() {\n  one.two\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   one.two\n  │       ^^^\n\nThe module `one` does not have a `two` value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_type_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one\\n\\npub fn main() {\\n  one.X\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype X = Int\n\n-- main.gleam\nimport one\n\npub fn main() {\n  one.X\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:4:7\n  │\n4 │   one.X\n  │       ^\n\nThe module `one` does not have a `X` value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_unqualified_custom_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{X}\\n\\npub fn main() {\\n  X\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype X { Y }\n\n-- main.gleam\nimport one.{X}\n\npub fn main() {\n  X\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{X}\n  │             ^\n\nThe module `one` does not have a `X` value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   X\n  │   ^\n\nThe custom type variant constructor `X` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_unqualified_external_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{X}\\n\\npub fn main() {\\n  X\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype X\n\n-- main.gleam\nimport one.{X}\n\npub fn main() {\n  X\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{X}\n  │             ^\n\nThe module `one` does not have a `X` value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   X\n  │   ^\n\nThe custom type variant constructor `X` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__imports__using_private_unqualified_type_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/imports.rs\nexpression: \"import one.{X}\\n\\npub fn main() {\\n  X\\n}\"\n---\n----- SOURCE CODE\n-- one.gleam\ntype X = Int\n\n-- main.gleam\nimport one.{X}\n\npub fn main() {\n  X\n}\n\n----- ERROR\nerror: Unknown module value\n  ┌─ /src/one/two.gleam:1:13\n  │\n1 │ import one.{X}\n  │             ^\n\nThe module `one` does not have a `X` value.\n\nerror: Unknown variable\n  ┌─ /src/one/two.gleam:4:3\n  │\n4 │   X\n  │   ^\n\nThe custom type variant constructor `X` is not in scope here.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__let_assert__non_string_message.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/let_assert.rs\nexpression: let assert 1 = 2 as 3\n---\n----- SOURCE CODE\nlet assert 1 = 2 as 3\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:1:21\n  │\n1 │ let assert 1 = 2 as 3\n  │                     ^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__pipes__pipe_callback_wrong_arity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/pipes.rs\nexpression: \"\\nfn callback(a: Int) {\\n  fn() -> String {\\n    \\\"Called\\\"\\n  }\\n}\\n\\npub fn main() {\\n  let x = 1 |> callback(2)\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn callback(a: Int) {\n  fn() -> String {\n    \"Called\"\n  }\n}\n\npub fn main() {\n  let x = 1 |> callback(2)\n}\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:9:16\n  │\n9 │   let x = 1 |> callback(2)\n  │                ^^^^^^^^^^^ Expected no arguments, got 1\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__pretty__prelude_type_clash_custom_first.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/pretty.rs\nexpression: \"print(tuple(vec![custom_bool(), bool()]))\"\n---\n#(Bool, gleam.Bool)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__pretty__prelude_type_clash_prelude_first.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/pretty.rs\nexpression: \"print(tuple(vec![bool(), custom_bool()]))\"\n---\n#(Bool, one/two.Bool)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__pretty__repeated_prelude_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/pretty.rs\nexpression: \"print(tuple(vec![int(), int(), int()]))\"\n---\n#(Int, Int, Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__target_implementations__function_with_no_valid_implementations.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/target_implementations.rs\nexpression: \"\\n@external(javascript, \\\"wibble\\\", \\\"wobble\\\")\\nfn javascript_only() -> Int\\n\\n@external(erlang, \\\"wibble\\\", \\\"wobble\\\")\\nfn erlang_only() -> Int\\n\\npub fn main() {\\n    javascript_only()\\n    erlang_only()\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"wibble\", \"wobble\")\nfn javascript_only() -> Int\n\n@external(erlang, \"wibble\", \"wobble\")\nfn erlang_only() -> Int\n\npub fn main() {\n    javascript_only()\n    erlang_only()\n}\n\n\n----- ERROR\nerror: Unsupported target\n  ┌─ /src/one/two.gleam:9:5\n  │\n9 │     javascript_only()\n  │     ^^^^^^^^^^^^^^^\n\nThis value is not available as it is defined using externals, and there is\nno implementation for the Erlang target.\n\nHint: Did you mean to build for a different target?\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__alias_cycle.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype A = B\\ntype B = C\\ntype C = D\\ntype D = E\\ntype E = A\\n\"\n---\n----- SOURCE CODE\n\ntype A = B\ntype B = C\ntype C = D\ntype D = E\ntype E = A\n\n\n----- ERROR\nerror: Type cycle\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ type A = B\n  │ ^^^^^^^^^^\n\nThis type alias is defined in terms of itself.\n\n    ┌─────┐\n    │     E\n    │     ↓\n    │     D\n    │     ↓\n    │     C\n    │     ↓\n    │     B\n    │     ↓\n    │     A\n    └─────┘\nIf we tried to compile this recursive type it would expand\nforever in a loop, and we'd never get the final type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__alias_direct_cycle.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype A = #(A, A)\\n\"\n---\n----- SOURCE CODE\n\ntype A = #(A, A)\n\n\n----- ERROR\nerror: Type cycle\n  ┌─ /src/one/two.gleam:2:1\n  │\n2 │ type A = #(A, A)\n  │ ^^^^^^^^^^^^^^^^\n\nThis type alias is defined in terms of itself.\n\n    ┌─────┐\n    │     A\n    └─────┘\nIf we tried to compile this recursive type it would expand\nforever in a loop, and we'd never get the final type.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__both_errors_are_shown.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype X =\\n  List(Intt)\\n\\nfn example(a: X) {\\n  todo\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype X =\n  List(Intt)\n\nfn example(a: X) {\n  todo\n}\n\n\n----- ERROR\nerror: Unknown type\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │   List(Intt)\n  │        ^^^^ Did you mean `Int`?\n\nThe type `Intt` is not defined or imported in this module.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:5:15\n  │\n5 │ fn example(a: X) {\n  │               ^\n\nThe type `X` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__conflict_with_import.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"import wibble.{type Wobble} type Wobble = Int\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wobble = String\n\n-- main.gleam\nimport wibble.{type Wobble} type Wobble = Int\n\n----- ERROR\nerror: Duplicate type definition\n  ┌─ /src/one/two.gleam:1:29\n  │\n1 │ import wibble.{type Wobble} type Wobble = Int\n  │                -----------  ^^^^^^^^^^^^^^^^^ Redefined here\n  │                │             \n  │                First defined here\n\nThe type `Wobble` has been defined multiple times.\nNames in a Gleam module must be unique so one will need to be renamed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__duplicate_parameter.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype A(a, a) =\\n  List(a)\\n\"\n---\n----- SOURCE CODE\n\ntype A(a, a) =\n  List(a)\n\n\n----- ERROR\nerror: Duplicate type parameter\n  ┌─ /src/one/two.gleam:2:11\n  │\n2 │ type A(a, a) =\n  │           ^\n\nThis definition has multiple type parameters named `a`.\nRename or remove one of them.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__duplicate_variable_error_does_not_stop_analysis.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype Two(a, a) =\\n  #(a, a)\\n\\ntype UnknownType =\\n  Dunno\\n\"\n---\n----- SOURCE CODE\n\ntype Two(a, a) =\n  #(a, a)\n\ntype UnknownType =\n  Dunno\n\n\n----- ERROR\nerror: Duplicate type parameter\n  ┌─ /src/one/two.gleam:2:13\n  │\n2 │ type Two(a, a) =\n  │             ^\n\nThis definition has multiple type parameters named `a`.\nRename or remove one of them.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:6:3\n  │\n6 │   Dunno\n  │   ^^^^^\n\nThe type `Dunno` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__type_alias_error_does_not_stop_analysis.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype UnusedParameter(a) =\\n  Int\\n\\ntype UnknownType =\\n  Dunno\\n\"\n---\n----- SOURCE CODE\n\ntype UnusedParameter(a) =\n  Int\n\ntype UnknownType =\n  Dunno\n\n\n----- ERROR\nerror: Unused type parameter\n  ┌─ /src/one/two.gleam:2:1\n  │  \n2 │ ╭ type UnusedParameter(a) =\n3 │ │   Int\n  │ ╰─────^\n\nThe type variable `a` is unused. It can be safely removed.\n\nerror: Unknown type\n  ┌─ /src/one/two.gleam:6:3\n  │\n6 │   Dunno\n  │   ^^^^^\n\nThe type `Dunno` is not defined or imported in this module.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__type_alias__unused_parameter.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/type_alias.rs\nexpression: \"\\ntype A(a) =\\n  Int\\n\"\n---\n----- SOURCE CODE\n\ntype A(a) =\n  Int\n\n\n----- ERROR\nerror: Unused type parameter\n  ┌─ /src/one/two.gleam:2:1\n  │  \n2 │ ╭ type A(a) =\n3 │ │   Int\n  │ ╰─────^\n\nThe type variable `a` is unused. It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___invalid_call_is_number.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nuse <- 123\\n123\\n\"\n---\n----- SOURCE CODE\n\nuse <- 123\n123\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:2:8\n  │\n2 │ use <- 123\n  │        ^^^\n\nIn a use expression, there should be a function on the right hand side of\n`<-`, but this value has type:\n\n    Int\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___invalid_callback_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { f() + 1 }\\nuse <- x()\\nNil\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { f() + 1 }\nuse <- x()\nNil\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:1\n  │\n4 │ Nil\n  │ ^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Nil\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___invalid_callback_type_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f() }\\nuse <- x()\\nlet n = 1\\nn + 2\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f() }\nuse <- x()\nlet n = 1\nn + 2\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:1\n  │\n5 │ n + 2\n  │ ^^^^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___invalid_callback_type_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f() }\\nlet y = fn(f) { 1 + f() }\\nuse <- x()\\nuse <- y()\\nlet n = 1\\nn + 1\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f() }\nlet y = fn(f) { 1 + f() }\nuse <- x()\nuse <- y()\nlet n = 1\nn + 1\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:1\n  │\n5 │ use <- y()\n  │ ^^^^^^^^^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___invalid_callback_type_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f() }\\nlet y = fn(f) { 1 + f() }\\nlet z = fn(f) { 1.0 +. f() }\\nuse <- x()\\nuse <- y()\\nlet n = 1\\nuse <- z()\\n1.0\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f() }\nlet y = fn(f) { 1 + f() }\nlet z = fn(f) { 1.0 +. f() }\nuse <- x()\nuse <- y()\nlet n = 1\nuse <- z()\n1.0\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:8:1\n  │\n8 │ use <- z()\n  │ ^^^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Float\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:6:1\n  │\n6 │ use <- y()\n  │ ^^^^^^^^^^\n\nExpected type:\n\n    String\n\nFound type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___just_use_in_fn_body.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble()\\n}\\n\\nfn wibble(f) {\\n  f()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use <- wibble()\n}\n\nfn wibble(f) {\n  f()\n}\n\n\n----- WARNING\nwarning: Incomplete use expression\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   use <- wibble()\n  │   ^^^^^^^^^^^^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\nA use expression must always be followed by at least one expression.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___multiple_bad_statement_use_fault_tolerance.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { f() + 1 }\\nuse <- x()\\n\\n1 + 2.0\\n3.0 + 4\\n5\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { f() + 1 }\nuse <- x()\n\n1 + 2.0\n3.0 + 4\n5\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:5:5\n  │\n5 │ 1 + 2.0\n  │     ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n\n\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:6:1\n  │\n6 │ 3.0 + 4\n  │ ^^^\n\nThe + operator expects arguments of this type:\n\n    Int\n\nBut this argument has this type:\n\n    Float\n\nHint: the +. operator can be used with Floats\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___no_callback_body.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  let thingy = fn(f) { f() }\\n  use <- thingy()\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let thingy = fn(f) { f() }\n  use <- thingy()\n}\n\n\n----- WARNING\nwarning: Incomplete use expression\n  ┌─ /src/warning/wrn.gleam:4:3\n  │\n4 │   use <- thingy()\n  │   ^^^^^^^^^^^^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\nA use expression must always be followed by at least one expression.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___typed_pattern_wrong_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\npub fn main() {\\n  use Box(x): Box(Bool), Box(y), Box(z) <- apply(Box(1))\\n  x + y + z\\n}\\n\\ntype Box(a) {\\n  Box(a)\\n}\\n\\nfn apply(arg, fun) {\\n  fun(arg, arg, arg)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  use Box(x): Box(Bool), Box(y), Box(z) <- apply(Box(1))\n  x + y + z\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg, arg, arg)\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:7\n  │\n3 │   use Box(x): Box(Bool), Box(y), Box(z) <- apply(Box(1))\n  │       ^^^^^^^^^^^^^^^^^\n\nExpected type:\n\n    Box(Bool)\n\nFound type:\n\n    Box(Int)\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___use_with_function_that_doesnt_take_callback_as_last_arg_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(a) { a + 1 }\\nuse <- f\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(a) { a + 1 }\nuse <- f\n123\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f\n  │        ^\n\nThe function on the right hand side of `<-` has to take a callback function\nas its last argument. But the last argument of this function has type:\n\n    Int\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___use_with_function_that_doesnt_take_callback_as_last_arg_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn() { 1 }\\nuse <- f\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn() { 1 }\nuse <- f\n123\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f\n  │        ^ Expected no arguments, got 1\n\nThe function on the right of `<-` here takes no arguments, but it has to\ntake at least one argument, a callback function.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___use_with_function_that_doesnt_take_callback_as_last_arg_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(a, b) { a + b }\\nuse <- f(1)\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(a, b) { a + b }\nuse <- f(1)\n123\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f(1)\n  │        ^^^^\n\nThe function on the right hand side of `<-` has to take a callback function\nas its last argument. But the last argument of this function has type:\n\n    Int\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_arity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(callback) { callback(1, 2) }\\nuse <- f\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(callback) { callback(1, 2) }\nuse <- f\n123\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f\n  │ ---    ^\n  │ │       \n  │ Expected 2 arguments, got 0\n\nThis function takes a callback that expects 2 arguments. But none were\nprovided on the left hand side of `<-`.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_arity_less_than_required.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(a, b) { 1 }\\nuse <- f\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(a, b) { 1 }\nuse <- f\n123\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f\n  │        ^ Expected 2 arguments, got 1\n\nThe function on the right of `<-` here takes 2 arguments.\nThe only argument that was supplied is the `use` callback function.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_arity_less_than_required_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(a, b, c) { 1 }\\nuse <- f(1)\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(a, b, c) { 1 }\nuse <- f(1)\n123\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f(1)\n  │        ^^^^ Expected 3 arguments, got 2\n\nThe function on the right of `<-` here takes 3 arguments.\nYou supplied 1 argument and the final one is the `use` callback function.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_arity_more_than_required.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(a, b) { 1 }\\nuse <- f(1, 2)\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(a, b) { 1 }\nuse <- f(1, 2)\n123\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f(1, 2)\n  │        ^^^^^^^ Expected 2 arguments, got 3\n\nThe function on the right of `<-` here takes 2 arguments.\nAll the arguments have already been supplied, so it cannot take the `use`\ncallback function as a final argument.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_arity_more_than_required_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet f = fn(a, b) { 1 }\\nuse <- f(1, 2, 3)\\n123\\n\"\n---\n----- SOURCE CODE\n\nlet f = fn(a, b) { 1 }\nuse <- f(1, 2, 3)\n123\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- f(1, 2, 3)\n  │        ^^^^^^^^^^ Expected 2 arguments, got 4\n\nThe function on the right of `<-` here takes 2 arguments.\nAll the arguments have already been supplied, so it cannot take the `use`\ncallback function as a final argument.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arg.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f(1) }\\nuse n <- x()\\nn <> \\\"Giacomo!\\\"\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse n <- x()\nn <> \"Giacomo!\"\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:4:1\n  │\n4 │ n <> \"Giacomo!\"\n  │ ^\n\nThe <> operator expects arguments of this type:\n\n    String\n\nBut this argument has this type:\n\n    Int\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arg_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\npub type Box {\\n  Box(Int)\\n}\\n\\npub fn main() {\\n  let x = fn(f) { \\\"Hello, \\\" <> f(Box(1)) }\\n  use Box(\\\"hi\\\") <- x()\\n  \\\"Giacomo!\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Box {\n  Box(Int)\n}\n\npub fn main() {\n  let x = fn(f) { \"Hello, \" <> f(Box(1)) }\n  use Box(\"hi\") <- x()\n  \"Giacomo!\"\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:8:11\n  │\n8 │   use Box(\"hi\") <- x()\n  │           ^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arg_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\npub type Box {\\n  Box(Int)\\n}\\n\\npub fn main() {\\n  let x = fn(f) { \\\"Hello, \\\" <> f(1) }\\n  use Box(1) <- x()\\n  \\\"Giacomo!\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Box {\n  Box(Int)\n}\n\npub fn main() {\n  let x = fn(f) { \"Hello, \" <> f(1) }\n  use Box(1) <- x()\n  \"Giacomo!\"\n}\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:8:7\n  │\n8 │   use Box(1) <- x()\n  │       ^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    Box\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arg_with_wrong_annotation.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f(1) }\\nuse n: String <- x()\\nn <> \\\"Giacomo!\\\"\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse n: String <- x()\nn <> \"Giacomo!\"\n\n\n----- ERROR\nerror: Type mismatch\n  ┌─ /src/one/two.gleam:3:5\n  │\n3 │ use n: String <- x()\n  │     ^^^^^^^^^\n\nExpected type:\n\n    Int\n\nFound type:\n\n    String\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f() }\\nuse _ <- x()\\n\\\"Giacomo!\\\"\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f() }\nuse _ <- x()\n\"Giacomo!\"\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:10\n  │\n3 │ use _ <- x()\n  │     -    ^^^\n  │     │     \n  │     Expected no arguments, got 1\n\nThis function takes a callback that expects no arguments. But 1 was\nprovided on the left hand side of `<-`.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arity_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f(1) }\\nuse <- x()\\n\\\"Giacomo!\\\"\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse <- x()\n\"Giacomo!\"\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:8\n  │\n3 │ use <- x()\n  │ ---    ^^^\n  │ │       \n  │ Expected 1 argument, got 0\n\nThis function takes a callback that expects 1 argument. But none were\nprovided on the left hand side of `<-`.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__use___wrong_callback_arity_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/use_.rs\nexpression: \"\\nlet x = fn(f) { \\\"Hello, \\\" <> f(1) }\\nuse _, _ <- x()\\n\\\"Giacomo!\\\"\\n\"\n---\n----- SOURCE CODE\n\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse _, _ <- x()\n\"Giacomo!\"\n\n\n----- ERROR\nerror: Incorrect arity\n  ┌─ /src/one/two.gleam:3:13\n  │\n3 │ use _, _ <- x()\n  │     ----    ^^^\n  │     │        \n  │     Expected 1 argument, got 2\n\nThis function takes a callback that expects 1 argument. But 2 were provided\non the left hand side of `<-`.\n\nSee: https://tour.gleam.run/advanced-features/use/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__aliased_module_used_by_unused_function_is_not_marked_as_unused.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"import wibble as woo\\nfn wobble() {\\n  woo.a\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub const a = 1\n\n-- main.gleam\nimport wibble as woo\nfn wobble() {\n  woo.a\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ fn wobble() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__assert_on_impossible_to_reach_integer_segment.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  let assert <<1, -1, 2, -3>> = x\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  let assert <<1, -1, 2, -3>> = x\n}\n\n----- WARNING\nwarning: Assertion that will always fail\n  ┌─ /src/warning/wrn.gleam:3:14\n  │\n3 │   let assert <<1, -1, 2, -3>> = x\n  │              ^^^^^^^^^^^^^^^^\n  │                   │      │\n  │                   │      A 1 byte unsigned integer will never match this value\n  │                   A 1 byte unsigned integer will never match this value\n\nWe can tell from the code above that the value will never match this\npattern and that this code will always crash.\n\nEither change the pattern or use `panic` to unconditionally fail.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__assert_on_inferred_variant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(w: Int)\\n  Wobble(w: String)\\n}\\n\\npub fn main() {\\n  let assert Wobble(w) = Wibble(10)\\n  w\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble(w: Int)\n  Wobble(w: String)\n}\n\npub fn main() {\n  let assert Wobble(w) = Wibble(10)\n  w\n}\n\n\n----- WARNING\nwarning: Assertion that will always fail\n  ┌─ /src/warning/wrn.gleam:8:14\n  │\n8 │   let assert Wobble(w) = Wibble(10)\n  │              ^^^^^^^^^\n\nWe can tell from the code above that the value will never match this\npattern and that this code will always crash.\n\nEither change the pattern or use `panic` to unconditionally fail.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_negative_truncated_segment.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  // -5 in 2's complement is 1111...111011\\n  // so if we truncate it to its first 3 bits we\\n  // get 011, which is positive 3!\\n  <<-5:size(3)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  // -5 in 2's complement is 1111...111011\n  // so if we truncate it to its first 3 bits we\n  // get 011, which is positive 3!\n  <<-5:size(3)>>\n}\n\n\n----- WARNING\nwarning: Truncated bit array segment\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │   <<-5:size(3)>>\n  │     ^^ You can safely replace this with 3\n\nThis segment is 3 bits long, but -5 doesn't fit in that many bits. It would\nbe truncated by taking its first 3 bits, resulting in the value 3.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_negative_truncated_segment_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<-200:size(8)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<-200:size(8)>>\n}\n\n\n----- WARNING\nwarning: Truncated bit array segment\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<-200:size(8)>>\n  │     ^^^^ You can safely replace this with 56\n\nThis segment is 1 byte long, but -200 doesn't fit in that many bytes. It\nwould be truncated by taking its first byte, resulting in the value 56.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_truncated_segment.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<12:size(1)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<12:size(1)>>\n}\n\n\n----- WARNING\nwarning: Truncated bit array segment\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<12:size(1)>>\n  │     ^^ You can safely replace this with 0\n\nThis segment is 1 bit long, but 12 doesn't fit in that many bits. It would\nbe truncated by taking its first bit, resulting in the value 0.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_truncated_segment_in_bytes.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<258:size(8)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<258:size(8)>>\n}\n\n\n----- WARNING\nwarning: Truncated bit array segment\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<258:size(8)>>\n  │     ^^^ You can safely replace this with 2\n\nThis segment is 1 byte long, but 258 doesn't fit in that many bytes. It\nwould be truncated by taking its first byte, resulting in the value 2.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_truncated_segment_in_bytes_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<65_537:size(2)-unit(8)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<65_537:size(2)-unit(8)>>\n}\n\n\n----- WARNING\nwarning: Truncated bit array segment\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<65_537:size(2)-unit(8)>>\n  │     ^^^^^^ You can safely replace this with 1\n\nThis segment is 2 bytes long, but 65537 doesn't fit in that many bytes. It\nwould be truncated by taking its first 2 bytes, resulting in the value 1.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bool_assert_requires_v1_11.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go(x) {\\n  assert x == 2\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  assert x == 2\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   assert x == 2\n  │   ^^^^^^^^^^^^^ This requires a Gleam version >= 1.11.0\n\nThe bool `assert` statement was introduced in version v1.11.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.11.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bool_literals_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { True == False }\"\n---\n----- SOURCE CODE\npub fn main() { True == False }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { True == False }\n  │                 ^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bool_literals_redundant_comparison_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { True != False }\"\n---\n----- SOURCE CODE\npub fn main() { True != False }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { True != False }\n  │                 ^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__const_record_update_requires_v1_14_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(a: Int, b: Int) }\\nconst base = Wibble(1, 2)\\npub const wobble = Wibble(..base, b: 3)\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(a: Int, b: Int) }\nconst base = Wibble(1, 2)\npub const wobble = Wibble(..base, b: 3)\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:20\n  │\n4 │ pub const wobble = Wibble(..base, b: 3)\n  │                    ^^^^^^^^^^^^^^^^^^^^ This requires a Gleam version >= 1.14.0\n\nThe record update syntax for constants was introduced in version v1.14.0.\nBut the Gleam version range specified in your `gleam.toml` would allow this\ncode to run on an earlier version like v1.0.0, resulting in compilation\nerrors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.14.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__constant_string_concatenation_requires_v1_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub const string = \\\"wibble\\\" <> \\\"wobble\\\"\"\n---\n----- SOURCE CODE\npub const string = \"wibble\" <> \"wobble\"\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:1:20\n  │\n1 │ pub const string = \"wibble\" <> \"wobble\"\n  │                    ^^^^^^^^^^^^^^^^^^^^ This requires a Gleam version >= 1.4.0\n\nConstant strings concatenation was introduced in version v1.4.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.4.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__constructing_anonymous_function_is_pure.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn make_panic(message) {\\n  fn() { panic as message }\\n}\\n\\npub fn main() {\\n  make_panic(\\\"This is a crash\\\")\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn make_panic(message) {\n  fn() { panic as message }\n}\n\npub fn main() {\n  make_panic(\"This is a crash\")\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:7:3\n  │\n7 │   make_panic(\"This is a crash\")\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_constant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@deprecated(\\\"Don't use this!\\\")\\npub const a = Nil\\n\\npub fn b() {\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\n@deprecated(\"Don't use this!\")\npub const a = Nil\n\npub fn b() {\n  a\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:6:3\n  │\n6 │   a\n  │   ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@deprecated(\\\"Don't use this!\\\")\\npub fn a() {\\n  Nil\\n}\\n\\npub fn b() {\\n  a\\n}\\n        \"\n---\n----- SOURCE CODE\n\n@deprecated(\"Don't use this!\")\npub fn a() {\n  Nil\n}\n\npub fn b() {\n  a\n}\n        \n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   a\n  │   ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_imported_call_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module\\n\\npub fn a() {\\n  module.a()\\n}\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n@deprecated(\"Don't use this!\") pub fn a() { Nil }\n\n-- main.gleam\n\nimport module\n\npub fn a() {\n  module.a()\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:5:10\n  │\n5 │   module.a()\n  │          ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_imported_constant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module\\n\\npub fn a() {\\n  module.a\\n}\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n@deprecated(\"Don't use this!\") pub const a = Nil\n\n-- main.gleam\n\nimport module\n\npub fn a() {\n  module.a\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:5:10\n  │\n5 │   module.a\n  │          ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_imported_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module\\n\\npub fn a() {\\n  module.a\\n}\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n@deprecated(\"Don't use this!\") pub fn a() { Nil }\n\n-- main.gleam\n\nimport module\n\npub fn a() {\n  module.a\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:5:10\n  │\n5 │   module.a\n  │          ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_imported_unqualified_constant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module.{a}\\n\\npub fn b() {\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n@deprecated(\"Don't use this!\") pub const a = Nil\n\n-- main.gleam\n\nimport module.{a}\n\npub fn b() {\n  a\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   a\n  │   ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_imported_unqualified_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module.{a}\\n\\npub fn b() {\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n@deprecated(\"Don't use this!\") pub fn a() { Nil }\n\n-- main.gleam\n\nimport module.{a}\n\npub fn b() {\n  a\n}\n\n\n----- WARNING\nwarning: Deprecated value used\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   a\n  │   ^ This value has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_list_append_syntax.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n      let letters = [\\\"b\\\", \\\"c\\\"]\\n      [\\\"a\\\"..letters]\\n    }\\n        \"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n      let letters = [\"b\", \"c\"]\n      [\"a\"..letters]\n    }\n        \n\n----- WARNING\nwarning: Deprecated prepend syntax\n  ┌─ test/path:4:11\n  │\n4 │       [\"a\"..letters]\n  │           ^^ This spread should be preceded by a comma\n\nThis syntax for prepending to a list is deprecated.\nWhen prepending an item to a list it should be preceded by a comma, like\nthis: `[item, ..list]`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_list_pattern_syntax.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n      let letters = [\\\"b\\\", \\\"c\\\"]\\n      case letters {\\n        [\\\"a\\\"..rest] -> rest\\n        _ -> []\\n      }\\n    }\\n        \"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n      let letters = [\"b\", \"c\"]\n      case letters {\n        [\"a\"..rest] -> rest\n        _ -> []\n      }\n    }\n        \n\n----- WARNING\nwarning: Deprecated list pattern matching syntax\n  ┌─ test/path:5:13\n  │\n5 │         [\"a\"..rest] -> rest\n  │             ^^ This spread should be preceded by a comma\n\nThis syntax for pattern matching on a list is deprecated.\nWhen matching on the rest of a list it should always be preceded by a\ncomma, like this: `[item, ..list]`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_list_pattern_syntax_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n      let letters = [\\\"b\\\", \\\"c\\\"]\\n      case letters {\\n        [] -> []\\n        [..] -> []\\n      }\\n    }\\n        \"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n      let letters = [\"b\", \"c\"]\n      case letters {\n        [] -> []\n        [..] -> []\n      }\n    }\n        \n\n----- WARNING\nwarning: Deprecated list pattern matching syntax\n  ┌─ test/path:6:9\n  │\n6 │         [..] -> []\n  │         ^^^^ This can be replaced with `_`\n\nThis syntax for pattern matching on lists is deprecated.\nTo match on all possible lists, use the `_` catch-all pattern instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_record_pattern_syntax.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(one: Int, two: Int)\\n}\\n\\npub fn main() {\\n  let wibble = Wibble(one: 1, two: 2)\\n  case wibble {\\n    Wibble(one: one ..) -> one\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one: one ..) -> one\n  }\n}\n\n\n----- WARNING\nwarning: Deprecated record pattern matching syntax\n  ┌─ test/path:9:21\n  │\n9 │     Wibble(one: one ..) -> one\n  │                     ^^ This should be preceded by a comma\n\nThis syntax for pattern matching on a record is deprecated.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_record_pattern_syntax_with_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(one: Int, two: Int)\\n}\\n\\npub fn main() {\\n  let wibble = Wibble(one: 1, two: 2)\\n  case wibble {\\n    Wibble(one: ..) -> one\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one: ..) -> one\n  }\n}\n\n\n----- WARNING\nwarning: Deprecated record pattern matching syntax\n  ┌─ test/path:9:17\n  │\n9 │     Wibble(one: ..) -> one\n  │                 ^^ This should be preceded by a comma\n\nThis syntax for pattern matching on a record is deprecated.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_record_pattern_syntax_with_no_labels.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(one: Int, two: Int)\\n}\\n\\npub fn main() {\\n  let wibble = Wibble(one: 1, two: 2)\\n  case wibble {\\n    Wibble(one ..) -> one\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one ..) -> one\n  }\n}\n\n\n----- WARNING\nwarning: Deprecated record pattern matching syntax\n  ┌─ test/path:9:16\n  │\n9 │     Wibble(one ..) -> one\n  │                ^^ This should be preceded by a comma\n\nThis syntax for pattern matching on a record is deprecated.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_erlang.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@target(erl)\\npub fn wibble() { panic }\\n\"\n---\n----- SOURCE CODE\n\n@target(erl)\npub fn wibble() { panic }\n\n\n----- WARNING\nwarning: Deprecated target shorthand syntax\n  ┌─ test/path:2:9\n  │\n2 │ @target(erl)\n  │         ^^^ This should be replaced with `erlang`\n\nThis shorthand target name is deprecated. Use the full name: `erlang`\ninstead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_javascript.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@target(js)\\npub fn wibble() { panic }\\n\"\n---\n----- SOURCE CODE\n\n@target(js)\npub fn wibble() { panic }\n\n\n----- WARNING\nwarning: Deprecated target shorthand syntax\n  ┌─ test/path:2:9\n  │\n2 │ @target(js)\n  │         ^^ This should be replaced with `javascript`\n\nThis shorthand target name is deprecated. Use the full name: `javascript`\ninstead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_type_used_as_arg.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@deprecated(\\\"Don't use this!\\\")\\npub type Cat {\\n    Cat(name: String)\\n}\\n\\npub fn cat_name(cat: Cat) {\\n  cat.name\\n}\\n        \"\n---\n----- SOURCE CODE\n\n@deprecated(\"Don't use this!\")\npub type Cat {\n    Cat(name: String)\n}\n\npub fn cat_name(cat: Cat) {\n  cat.name\n}\n        \n\n----- WARNING\nwarning: Deprecated type used\n  ┌─ /src/warning/wrn.gleam:7:22\n  │\n7 │ pub fn cat_name(cat: Cat) {\n  │                      ^^^ This type has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_type_used_as_case_clause.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@deprecated(\\\"The type Animal has been deprecated.\\\")\\npub type Animal {\\n    Cat\\n    Dog\\n}\\n\\npub fn sound(animal) -> String {\\n  case animal {\\n    Dog -> \\\"Woof\\\"\\n    Cat -> \\\"Meow\\\"\\n  }\\n}\\n\\npub fn main(){\\n    let cat = Cat\\n    sound(cat)\\n}\\n        \"\n---\n----- SOURCE CODE\n\n@deprecated(\"The type Animal has been deprecated.\")\npub type Animal {\n    Cat\n    Dog\n}\n\npub fn sound(animal) -> String {\n  case animal {\n    Dog -> \"Woof\"\n    Cat -> \"Meow\"\n  }\n}\n\npub fn main(){\n    let cat = Cat\n    sound(cat)\n}\n        \n\n----- WARNING\nwarning: Deprecated value used\n   ┌─ /src/warning/wrn.gleam:10:5\n   │\n10 │     Dog -> \"Woof\"\n   │     ^^^ This value has been deprecated\n\nIt was deprecated with this message: The type Animal has been deprecated.\n\nwarning: Deprecated value used\n   ┌─ /src/warning/wrn.gleam:11:5\n   │\n11 │     Cat -> \"Meow\"\n   │     ^^^ This value has been deprecated\n\nIt was deprecated with this message: The type Animal has been deprecated.\n\nwarning: Deprecated value used\n   ┌─ /src/warning/wrn.gleam:16:15\n   │\n16 │     let cat = Cat\n   │               ^^^ This value has been deprecated\n\nIt was deprecated with this message: The type Animal has been deprecated.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_type_used_in_alias.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@deprecated(\\\"Don't use this!\\\")\\npub type Cat {\\n    Cat(name: String)\\n}\\n\\npub type Dog = Cat\\n        \"\n---\n----- SOURCE CODE\n\n@deprecated(\"Don't use this!\")\npub type Cat {\n    Cat(name: String)\n}\n\npub type Dog = Cat\n        \n\n----- WARNING\nwarning: Deprecated type used\n  ┌─ /src/warning/wrn.gleam:7:16\n  │\n7 │ pub type Dog = Cat\n  │                ^^^ This type has been deprecated\n\nIt was deprecated with this message: Don't use this!\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__detached_doc_comment.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n/// This comment is detached\\n//\\n\\n/// This is actual documentation\\npub const pi = 3.14\\n\"\n---\n----- SOURCE CODE\n\n/// This comment is detached\n//\n\n/// This is actual documentation\npub const pi = 3.14\n\n\n----- WARNING\nwarning: Detached doc comment\n  ┌─ test/path:2:4\n  │\n2 │ /// This comment is detached\n  │    ^^^^^^^^^^^^^^^^^^^^^^^^^ This is not attached to a definition\n\nThis doc comment is followed by a regular comment so it is not attached to\nany definition.\nHint: Move the comment above the doc comment\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__different_records_0_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Either {\\n  Left\\n  Right\\n}\\n\\npub fn main() -> Bool {\\n  Left == Right\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Either {\n  Left\n  Right\n}\n\npub fn main() -> Bool {\n  Left == Right\n}\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   Left == Right\n  │   ^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__different_records_1_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Either {\\n  Left(Int)\\n  Right\\n}\\n\\npub fn main() -> Bool {\\n  Left(1) == Right\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Either {\n  Left(Int)\n  Right\n}\n\npub fn main() -> Bool {\n  Left(1) == Right\n}\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   Left(1) == Right\n  │   ^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__different_records_2_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Either {\\n  Left(Int)\\n  Right(Int)\\n}\\n\\npub fn main() -> Bool {\\n  Left(1) == Right(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Either {\n  Left(Int)\n  Right(Int)\n}\n\npub fn main() -> Bool {\n  Left(1) == Right(1)\n}\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   Left(1) == Right(1)\n  │   ^^^^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__different_records_3_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Either {\\n  Left\\n  Right(Int)\\n}\\n\\npub fn main() -> Bool {\\n  Left == Right(1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Either {\n  Left\n  Right(Int)\n}\n\npub fn main() -> Bool {\n  Left == Right(1)\n}\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   Left == Right(1)\n  │   ^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__doesnt_warn_twice_for_unreachable_code_if_has_already_warned_in_a_block_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_) { 1 }\\n        pub fn main() {\\n            panic\\n            let _ = \\\"unreachable\\\" // warning here\\n            panic\\n            \\\"no warning here!\\\"\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            panic\n            let _ = \"unreachable\" // warning here\n            panic\n            \"no warning here!\"\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:5:21\n  │\n5 │             let _ = \"unreachable\" // warning here\n  │                     ^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__doesnt_warn_twice_for_unreachable_code_if_has_already_warned_in_a_block_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main() {\\n            let _ = {\\n              panic\\n              1 // warning here\\n            }\\n            \\\"no warning here!\\\"\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main() {\n            let _ = {\n              panic\n              1 // warning here\n            }\n            \"no warning here!\"\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:5:15\n  │\n5 │               1 // warning here\n  │               ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__double_unary_bool_literal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { let _ = !!True }\"\n---\n----- SOURCE CODE\npub fn main() { let _ = !!True }\n\n----- WARNING\nwarning: Unnecessary double negation (!!) on bool\n  ┌─ /src/warning/wrn.gleam:1:25\n  │\n1 │ pub fn main() { let _ = !!True }\n  │                         ^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__double_unary_bool_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main() {\\n            let x = True\\n            let _ = !!x\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main() {\n            let x = True\n            let _ = !!x\n        }\n        \n\n----- WARNING\nwarning: Unnecessary double negation (!!) on bool\n  ┌─ /src/warning/wrn.gleam:4:21\n  │\n4 │             let _ = !!x\n  │                     ^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__double_unary_integer_literal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { let _ = --7 }\"\n---\n----- SOURCE CODE\npub fn main() { let _ = --7 }\n\n----- WARNING\nwarning: Unnecessary double negation (--) on integer\n  ┌─ /src/warning/wrn.gleam:1:25\n  │\n1 │ pub fn main() { let _ = --7 }\n  │                         ^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__double_unary_integer_variable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main() {\\n            let x = 7\\n            let _ = --x\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main() {\n            let x = 7\n            let _ = --x\n        }\n        \n\n----- WARNING\nwarning: Unnecessary double negation (--) on integer\n  ┌─ /src/warning/wrn.gleam:4:21\n  │\n4 │             let _ = --x\n  │                     ^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__echo_followed_by_panic.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  echo panic\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  echo panic\n}\n\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   echo panic\n  │   ^^^^^^^^^^\n\nThis `echo` won't print anything because the expression it should be\nprinting always panics.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__echo_followed_by_panicking_expression.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(a) {\\n  echo case a {\\n    1 -> panic\\n    _ -> [1, panic]\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(a) {\n  echo case a {\n    1 -> panic\n    _ -> [1, panic]\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:3:3\n  │  \n3 │ ╭   echo case a {\n4 │ │     1 -> panic\n5 │ │     _ -> [1, panic]\n6 │ │   }\n  │ ╰───^\n\nThis `echo` won't print anything because the expression it should be\nprinting always panics.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__empty_func_warning_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { wibble() }\\npub fn wibble() { }\\n\"\n---\n----- SOURCE CODE\npub fn main() { wibble() }\npub fn wibble() { }\n\n\n----- WARNING\nwarning: Unimplemented function\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ pub fn wibble() { }\n  │ ^^^^^^^^^^^^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__empty_guard_clause.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n    let wibble = 10\\n    case wibble {\\n        10 if -> True\\n        _ -> False\\n    }\\n\\n}\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let wibble = 10\n    case wibble {\n        10 if -> True\n        _ -> False\n    }\n\n}\n\n----- WARNING\nwarning: Deprecated empty guard syntax\n  ┌─ test/path:5:12\n  │\n5 │         10 if -> True\n  │            ^^ This can be removed.\n\nThis syntax for an empty guard is deprecated. To have a clause without a\nguard, remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__even_number_of_multiple_bool_negations_raise_a_single_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { let _ = !!!!True }\"\n---\n----- SOURCE CODE\npub fn main() { let _ = !!!!True }\n\n----- WARNING\nwarning: Unnecessary double negation (!!) on bool\n  ┌─ /src/warning/wrn.gleam:1:25\n  │\n1 │ pub fn main() { let _ = !!!!True }\n  │                         ^^^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__even_number_of_multiple_integer_negations_raise_a_single_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { let _ = ----7 }\"\n---\n----- SOURCE CODE\npub fn main() { let _ = ----7 }\n\n----- WARNING\nwarning: Unnecessary double negation (--) on integer\n  ┌─ /src/warning/wrn.gleam:1:25\n  │\n1 │ pub fn main() { let _ = ----7 }\n  │                         ^^^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__expression_in_expression_segment_size_requires_v1_12_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<1:size(3 * 8)>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<1:size(3 * 8)>>\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:12\n  │\n3 │   <<1:size(3 * 8)>>\n  │            ^^^^^ This requires a Gleam version >= 1.12.0\n\nExpressions in segment sizes were introduced in version v1.12.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.12.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__expression_in_pattern_segment_size_requires_v1_12_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<_:size(3*8)>> -> 1\\n    _ -> 2\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<_:size(3*8)>> -> 1\n    _ -> 2\n  }\n}\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:14\n  │\n4 │     <<_:size(3*8)>> -> 1\n  │              ^^^ This requires a Gleam version >= 1.12.0\n\nExpressions in segment sizes were introduced in version v1.12.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.12.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__external_annotation_on_custom_type_requires_v1_14.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@external(erlang, \\\"wibble\\\", \\\"wobble\\\")\\npub type Wobble\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"wibble\", \"wobble\")\npub type Wobble\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:1\n  │\n3 │ pub type Wobble\n  │ ^^^^^^^^^^^^^^^ This requires a Gleam version >= 1.14.0\n\nThe `@external` annotation on custom types was introduced in version\nv1.14.0. But the Gleam version range specified in your `gleam.toml` would\nallow this code to run on an earlier version like v1.0.0, resulting in\ncompilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.14.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_divide_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n  _ if 1.0 /. 1.0 == 0.0 -> Nil\\n  _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n  _ if 1.0 /. 1.0 == 0.0 -> Nil\n  _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   _ if 1.0 /. 1.0 == 0.0 -> Nil\n  │        ^^^^^^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 == 1.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 == 1.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 == 1.0 }\n  │                 ^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 == 2.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 == 2.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 == 2.0 }\n  │                 ^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 != 1.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 != 1.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 != 1.0 }\n  │                 ^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 != 2.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 != 2.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 != 2.0 }\n  │                 ^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 >. 2.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 >. 2.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 >. 2.0 }\n  │                 ^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 <=. 2.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 <=. 2.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 <=. 2.0 }\n  │                 ^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 <. 2.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 <. 2.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 <. 2.0 }\n  │                 ^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 >=. 2.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 >=. 2.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 >=. 2.0 }\n  │                 ^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_different_repr.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1_0.0 == 10.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 1_0.0 == 10.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1_0.0 == 10.0 }\n  │                 ^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_different_repr_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 10.0 == 1.0e1 }\"\n---\n----- SOURCE CODE\npub fn main() { 10.0 == 1.0e1 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 10.0 == 1.0e1 }\n  │                 ^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_infinity.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0e500 == 1.0e600 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0e500 == 1.0e600 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0e500 == 1.0e600 }\n  │                 ^^^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_omitted_zero.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 10. == 10.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 10. == 10.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 10. == 10.0 }\n  │                 ^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_precision_loss.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0e-500 == 1.0e-600 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0e-500 == 1.0e-600 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0e-500 == 1.0e-600 }\n  │                 ^^^^^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_literals_redundant_comparison_signed_zero.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 0.0 == -0.0 }\"\n---\n----- SOURCE CODE\npub fn main() { 0.0 == -0.0 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 0.0 == -0.0 }\n  │                 ^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_minus_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n    _ if 1.0 -. 1.0 == 0.0 -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n    _ if 1.0 -. 1.0 == 0.0 -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:10\n  │\n4 │     _ if 1.0 -. 1.0 == 0.0 -> Nil\n  │          ^^^^^^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_multiplication_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n  _ if 1.0 *. 1.0 == 0.0 -> Nil\\n  _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n  _ if 1.0 *. 1.0 == 0.0 -> Nil\n  _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   _ if 1.0 *. 1.0 == 0.0 -> Nil\n  │        ^^^^^^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__float_plus_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n    _ if 1.0 +. 1.0 == 2.0 -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n    _ if 1.0 +. 1.0 == 2.0 -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:10\n  │\n4 │     _ if 1.0 +. 1.0 == 2.0 -> Nil\n  │          ^^^^^^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__function_is_impure_if_uses_todo.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn add(a: Int, b: Int) -> Int {\\n  case a + b {\\n    0 -> todo as \\\"Handle zero\\\"\\n    x -> x\\n  }\\n}\\n\\npub fn main() {\\n  add(1, 2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(a: Int, b: Int) -> Int {\n  case a + b {\n    0 -> todo as \"Handle zero\"\n    x -> x\n  }\n}\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:4:10\n  │\n4 │     0 -> todo as \"Handle zero\"\n  │          ^^^^^^^^^^^^^^^^^^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n\nHint: I think its type is `Int`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__function_is_pure_on_erlang_if_external_on_js.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@external(javascript, \\\"./maths.mjs\\\", \\\"add\\\")\\nfn add(a: Int, b: Int) -> Int { a + b }\\n\\npub fn main() {\\n  add(1, 2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"./maths.mjs\", \"add\")\nfn add(a: Int, b: Int) -> Int { a + b }\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:6:3\n  │\n6 │   add(1, 2)\n  │   ^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__function_is_pure_on_js_if_external_on_erlang.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@external(erlang, \\\"maths\\\", \\\"add\\\")\\nfn add(a: Int, b: Int) -> Int { a + b }\\n\\npub fn main() {\\n  add(1, 2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\n@external(erlang, \"maths\", \"add\")\nfn add(a: Int, b: Int) -> Int { a + b }\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:6:3\n  │\n6 │   add(1, 2)\n  │   ^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__import_module_twice.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"import gleam/wibble as a\\nimport gleam/wibble as b\\n\\npub fn main() {\\n  a.wobble() + b.wobble()\\n}\\n\"\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub fn wobble() { 1 }\n\n-- main.gleam\nimport gleam/wibble as a\nimport gleam/wibble as b\n\npub fn main() {\n  a.wobble() + b.wobble()\n}\n\n\n----- WARNING\nwarning: Duplicate import\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n1 │ import gleam/wibble as a\n  │ ------------------------ First imported here\n2 │ import gleam/wibble as b\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^ Reimported here\n\nThe gleam/wibble module has been imported twice.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__importing_non_direct_dep_package.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport some_module\\npub const x = some_module.x\\n        \"\n---\n----- SOURCE CODE\n-- some_module.gleam\npub const x = 1\n\n-- main.gleam\n\nimport some_module\npub const x = some_module.x\n        \n\n----- WARNING\nwarning: Transitive dependency imported\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import some_module\n  │ ^^^^^^^^^^^^^^^^^^\n\nThe module `some_module` is being imported, but `non-dependency-package`,\nthe package it belongs to, is not a direct dependency of your package.\nIn a future version of Gleam this may become a compile error.\n\nRun this command to add it to your dependencies:\n\n    gleam add non-dependency-package\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__impossible_to_reach_integer_segment.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<9:size(2)>> -> True\\n    _ -> False\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<9:size(2)>> -> True\n    _ -> False\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     <<9:size(2)>> -> True\n  │     ^^^^^^^^^^^^^\n  │       │\n  │       A 2 bits unsigned integer will never match this value\n\nThis pattern cannot be reached as it contains segments that will never\nmatch.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__impossible_to_reach_integer_segment_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<-9:unsigned>> -> True\\n    _ -> False\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<-9:unsigned>> -> True\n    _ -> False\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     <<-9:unsigned>> -> True\n  │     ^^^^^^^^^^^^^^^\n  │       │\n  │       A 1 byte unsigned integer will never match this value\n\nThis pattern cannot be reached as it contains segments that will never\nmatch.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__impossible_to_reach_integer_segment_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<312>> -> True\\n    _ -> False\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<312>> -> True\n    _ -> False\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     <<312>> -> True\n  │     ^^^^^^^\n  │       │\n  │       A 1 byte unsigned integer will never match this value\n\nThis pattern cannot be reached as it contains segments that will never\nmatch.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__impossible_to_reach_integer_segment_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<-1>> -> True\\n    _ -> False\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<-1>> -> True\n    _ -> False\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     <<-1>> -> True\n  │     ^^^^^^\n  │       │\n  │       A 1 byte unsigned integer will never match this value\n\nThis pattern cannot be reached as it contains segments that will never\nmatch.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__incomplete_code_block_raises_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n    {}\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    {}\n}\n\n\n----- WARNING\nwarning: Incomplete block\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │     {}\n  │     ^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\nA block must always contain at least one expression.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_divide_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n  _ if 1 / 1 == 0 -> Nil\\n  _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n  _ if 1 / 1 == 0 -> Nil\n  _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   _ if 1 / 1 == 0 -> Nil\n  │        ^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 == 1 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 == 1 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 == 1 }\n  │                 ^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 == 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 == 2 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 == 2 }\n  │                 ^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 != 1 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 != 1 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 != 1 }\n  │                 ^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 != 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 != 2 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 != 2 }\n  │                 ^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 > 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 > 2 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 > 2 }\n  │                 ^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 <= 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 <= 2 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 <= 2 }\n  │                 ^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 < 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 < 2 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 < 2 }\n  │                 ^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_literals_redundant_comparison_8.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 >= 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 >= 2 }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 >= 2 }\n  │                 ^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_minus_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n    _ if 1 - 1 == 0 -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n    _ if 1 - 1 == 0 -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:10\n  │\n4 │     _ if 1 - 1 == 0 -> Nil\n  │          ^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_multiplication_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n  _ if 1 * 1 == 0 -> Nil\\n  _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n  _ if 1 * 1 == 0 -> Nil\n  _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   _ if 1 * 1 == 0 -> Nil\n  │        ^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_plus_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n    _ if 1 + 1 == 2 -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n    _ if 1 + 1 == 2 -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:10\n  │\n4 │     _ if 1 + 1 == 2 -> Nil\n  │          ^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__int_remainder_in_guards_requires_v1_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  case Nil {\\n  _ if 1 % 1 == 0 -> Nil\\n  _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  case Nil {\n  _ if 1 % 1 == 0 -> Nil\n  _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   _ if 1 % 1 == 0 -> Nil\n  │        ^^^^^ This requires a Gleam version >= 1.3.0\n\nArithmetic operations in guards were introduced in version v1.3.0. But the\nGleam version range specified in your `gleam.toml` would allow this code to\nrun on an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.3.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__internal_annotation_on_constant_requires_v1_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@internal\\npub const wibble = 1\\n\"\n---\n----- SOURCE CODE\n\n@internal\npub const wibble = 1\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ This requires a Gleam version >= 1.1.0\n\nThe `@internal` annotation was introduced in version v1.1.0. But the Gleam\nversion range specified in your `gleam.toml` would allow this code to run\non an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.1.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__internal_annotation_on_function_requires_v1_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@internal\\npub fn wibble() { Nil }\\n\"\n---\n----- SOURCE CODE\n\n@internal\npub fn wibble() { Nil }\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ This requires a Gleam version >= 1.1.0\n\nThe `@internal` annotation was introduced in version v1.1.0. But the Gleam\nversion range specified in your `gleam.toml` would allow this code to run\non an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.1.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__internal_annotation_on_type_requires_v1_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@internal\\npub type Wibble\\n\"\n---\n----- SOURCE CODE\n\n@internal\npub type Wibble\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ @internal\n  │ ^^^^^^^^^ This requires a Gleam version >= 1.1.0\n\nThe `@internal` annotation was introduced in version v1.1.0. But the Gleam\nversion range specified in your `gleam.toml` would allow this code to run\non an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.1.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_external_module_with_at_requires_v1_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n@external(javascript, \\\"module@module\\\", \\\"func\\\")\\npub fn main() { Nil }\\n\"\n---\n----- SOURCE CODE\n\n@external(javascript, \"module@module\", \"func\")\npub fn main() { Nil }\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ @external(javascript, \"module@module\", \"func\")\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This requires a Gleam version >= 1.2.0\n\nThe ability to have `@` in a Javascript module's name was introduced in\nversion v1.2.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.0.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.2.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_binary.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  [\\n    0b11111111111111111111111111111111111111111111111111110,\\n    0b11111111111111111111111111111111111111111111111111111,\\n    0b100000000000000000000000000000000000000000000000000000,\\n  ]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  [\n    0b11111111111111111111111111111111111111111111111111110,\n    0b11111111111111111111111111111111111111111111111111111,\n    0b100000000000000000000000000000000000000000000000000000,\n  ]\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     0b100000000000000000000000000000000000000000000000000000,\n  │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_decimal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  [\\n    9_007_199_254_740_990,\\n    9_007_199_254_740_991,\\n    9_007_199_254_740_992,\\n    -9_007_199_254_740_990,\\n    -9_007_199_254_740_991,\\n    -9_007_199_254_740_992,\\n  ]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  [\n    9_007_199_254_740_990,\n    9_007_199_254_740_991,\n    9_007_199_254_740_992,\n    -9_007_199_254_740_990,\n    -9_007_199_254_740_991,\n    -9_007_199_254_740_992,\n  ]\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     9_007_199_254_740_992,\n  │     ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:9:5\n  │\n9 │     -9_007_199_254_740_992,\n  │     ^^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_hex.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  [\\n    0x1FFFFFFFFFFFFE,\\n    0x1FFFFFFFFFFFFF,\\n    0x20000000000000,\\n  ]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  [\n    0x1FFFFFFFFFFFFE,\n    0x1FFFFFFFFFFFFF,\n    0x20000000000000,\n  ]\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     0x20000000000000,\n  │     ^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: pub const i = 9_007_199_254_740_992\n---\n----- SOURCE CODE\npub const i = 9_007_199_254_740_992\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:1:15\n  │\n1 │ pub const i = 9_007_199_254_740_992\n  │               ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_const_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub const i = #(9_007_199_254_740_992)\"\n---\n----- SOURCE CODE\npub const i = #(9_007_199_254_740_992)\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub const i = #(9_007_199_254_740_992)\n  │                 ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  let assert <<9_007_199_254_740_992:64>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let assert <<9_007_199_254_740_992:64>> = <<>>\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:3:16\n  │\n3 │   let assert <<9_007_199_254_740_992:64>> = <<>>\n  │                ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  #(9_007_199_254_740_992)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  #(9_007_199_254_740_992)\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   #(9_007_199_254_740_992)\n  │     ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_octal.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  [\\n    0o377777777777777776,\\n    0o377777777777777777,\\n    0o400000000000000000,\\n  ]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  [\n    0o377777777777777776,\n    0o377777777777777777,\n    0o400000000000000000,\n  ]\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     0o400000000000000000,\n  │     ^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_in_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  <<9_007_199_254_740_992:64>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  <<9_007_199_254_740_992:64>>\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<9_007_199_254_740_992:64>>\n  │     ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_in_const_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub const i = <<9_007_199_254_740_992:64>>\\n\"\n---\n----- SOURCE CODE\n\npub const i = <<9_007_199_254_740_992:64>>\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:2:17\n  │\n2 │ pub const i = <<9_007_199_254_740_992:64>>\n  │                 ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_size_in_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  [\\n    <<0:9_007_199_254_740_992>>,\\n    <<0:size(9_007_199_254_740_992)>>,\\n  ]\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  [\n    <<0:9_007_199_254_740_992>>,\n    <<0:size(9_007_199_254_740_992)>>,\n  ]\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:4:9\n  │\n4 │     <<0:9_007_199_254_740_992>>,\n  │         ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:5:14\n  │\n5 │     <<0:size(9_007_199_254_740_992)>>,\n  │              ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_size_in_const_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub const ints = [\\n  <<0:9_007_199_254_740_992>>,\\n  <<0:size(9_007_199_254_740_992)>>,\\n]\\n\"\n---\n----- SOURCE CODE\n\npub const ints = [\n  <<0:9_007_199_254_740_992>>,\n  <<0:size(9_007_199_254_740_992)>>,\n]\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:3:7\n  │\n3 │   <<0:9_007_199_254_740_992>>,\n  │       ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:4:12\n  │\n4 │   <<0:size(9_007_199_254_740_992)>>,\n  │            ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_size_in_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go() {\\n  let assert <<0:9_007_199_254_740_992>> = <<>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go() {\n  let assert <<0:9_007_199_254_740_992>> = <<>>\n}\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:3:18\n  │\n3 │   let assert <<0:9_007_199_254_740_992>> = <<>>\n  │                  ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_with_external_function_call.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  helper() + 9_007_199_254_740_992\\n}\\n\\n@external(javascript, \\\"a\\\", \\\"b\\\")\\nfn helper() -> Int\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  helper() + 9_007_199_254_740_992\n}\n\n@external(javascript, \"a\", \"b\")\nfn helper() -> Int\n\n\n----- WARNING\nwarning: Int is outside JavaScript's safe integer range\n  ┌─ /src/warning/wrn.gleam:3:14\n  │\n3 │   helper() + 9_007_199_254_740_992\n  │              ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript\n\nThis integer value is too large to be represented accurately by\nJavaScript's number type. To avoid this warning integer values must be in\nthe range -(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER\nproperties for more information.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__label_shorthand_in_call_requires_v1_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(wibble: Int) }\\n\\npub fn main() {\\n  let wibble = 1\\n  Wibble(wibble:)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(wibble: Int) }\n\npub fn main() {\n  let wibble = 1\n  Wibble(wibble:)\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:6:10\n  │\n6 │   Wibble(wibble:)\n  │          ^^^^^^^ This requires a Gleam version >= 1.4.0\n\nThe label shorthand syntax was introduced in version v1.4.0. But the Gleam\nversion range specified in your `gleam.toml` would allow this code to run\non an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.4.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__label_shorthand_in_constand_requires_v1_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(wibble: Int) }\\n\\npub const wibble = 1\\npub const wobble = Wibble(wibble:)\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(wibble: Int) }\n\npub const wibble = 1\npub const wobble = Wibble(wibble:)\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:5:27\n  │\n5 │ pub const wobble = Wibble(wibble:)\n  │                           ^^^^^^^ This requires a Gleam version >= 1.4.0\n\nThe label shorthand syntax was introduced in version v1.4.0. But the Gleam\nversion range specified in your `gleam.toml` would allow this code to run\non an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.4.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__label_shorthand_in_pattern_requires_v1_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(wibble: Int) }\\n\\npub fn main(wibble) {\\n  case wibble {\\n    Wibble(wibble:) -> wibble\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(wibble: Int) }\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(wibble:) -> wibble\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:6:12\n  │\n6 │     Wibble(wibble:) -> wibble\n  │            ^^^^^^^ This requires a Gleam version >= 1.4.0\n\nThe label shorthand syntax was introduced in version v1.4.0. But the Gleam\nversion range specified in your `gleam.toml` would allow this code to run\non an earlier version like v1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.4.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__let_assert_with_message_requires_v1_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let assert Ok(10) = Ok(20) as \\\"This will crash...\\\"\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert Ok(10) = Ok(20) as \"This will crash...\"\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:33\n  │\n3 │   let assert Ok(10) = Ok(20) as \"This will crash...\"\n  │                                 ^^^^^^^^^^^^^^^^^^^^ This requires a Gleam version >= 1.7.0\n\nSpecifying a custom panic message when using let assert was introduced in\nversion v1.7.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.0.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.7.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__list_literals_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main(a, b) { [1] == [a, b(1)] }\"\n---\n----- SOURCE CODE\npub fn main(a, b) { [1] == [a, b(1)] }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:21\n  │\n1 │ pub fn main(a, b) { [1] == [a, b(1)] }\n  │                     ^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__list_literals_redundant_comparison_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main(a, b) { [1] != [a, b(1)] }\"\n---\n----- SOURCE CODE\npub fn main(a, b) { [1] != [a, b(1)] }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:21\n  │\n1 │ pub fn main(a, b) { [1] != [a, b(1)] }\n  │                     ^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__list_literals_redundant_comparison_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { [1] != [1] }\"\n---\n----- SOURCE CODE\npub fn main() { [1] != [1] }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { [1] != [1] }\n  │                 ^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__list_literals_redundant_comparison_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main(a) { [1, ..[1, a]] == [1, ..[1, a]] }\"\n---\n----- SOURCE CODE\npub fn main(a) { [1, ..[1, a]] == [1, ..[1, a]] }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:18\n  │\n1 │ pub fn main(a) { [1, ..[1, a]] == [1, ..[1, a]] }\n  │                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__list_literals_redundant_comparison_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main(a) { [1, ..a] == [1, ..a] }\"\n---\n----- SOURCE CODE\npub fn main(a) { [1, ..a] == [1, ..a] }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:18\n  │\n1 │ pub fn main(a) { [1, ..a] == [1, ..a] }\n  │                  ^^^^^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__list_literals_redundant_comparison_7.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main(a) { [a(1), 2] == [a(1), 3] }\"\n---\n----- SOURCE CODE\npub fn main(a) { [a(1), 2] == [a(1), 3] }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:18\n  │\n1 │ pub fn main(a) { [a(1), 2] == [a(1), 3] }\n  │                  ^^^^^^^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__missing_float_option_in_bit_array_constant_segment_requires_v1_10.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: pub const bits = <<1.2>>\n---\n----- SOURCE CODE\npub const bits = <<1.2>>\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:1:20\n  │\n1 │ pub const bits = <<1.2>>\n  │                    ^^^ This requires a Gleam version >= 1.10.0\n\nThe ability to omit the `float` annotation for float segments was\nintroduced in version v1.10.0. But the Gleam version range specified in\nyour `gleam.toml` would allow this code to run on an earlier version like\nv1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.10.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__missing_float_option_in_bit_array_pattern_segment_requires_v1_10.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(a) {\\n  case a {\\n    <<1.2>> -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(a) {\n  case a {\n    <<1.2>> -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:7\n  │\n4 │     <<1.2>> -> Nil\n  │       ^^^ This requires a Gleam version >= 1.10.0\n\nThe ability to omit the `float` annotation for float segments was\nintroduced in version v1.10.0. But the Gleam version range specified in\nyour `gleam.toml` would allow this code to run on an earlier version like\nv1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.10.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__missing_float_option_in_bit_array_segment_requires_v1_10.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<1.2>>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<1.2>>\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<1.2>>\n  │     ^^^ This requires a Gleam version >= 1.10.0\n\nThe ability to omit the `float` annotation for float segments was\nintroduced in version v1.10.0. But the Gleam version range specified in\nyour `gleam.toml` would allow this code to run on an earlier version like\nv1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.10.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__missing_utf_8_option_in_bit_array_constant_segment_requires_v1_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub const bits = <<\\\"hello\\\">>\"\n---\n----- SOURCE CODE\npub const bits = <<\"hello\">>\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:1:20\n  │\n1 │ pub const bits = <<\"hello\">>\n  │                    ^^^^^^^ This requires a Gleam version >= 1.5.0\n\nThe ability to omit the `utf8` annotation for string segments was\nintroduced in version v1.5.0. But the Gleam version range specified in your\n`gleam.toml` would allow this code to run on an earlier version like\nv1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.5.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__missing_utf_8_option_in_bit_array_pattern_segment_requires_v1_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(a) {\\n  case a {\\n    <<\\\"hello\\\">> -> Nil\\n    _ -> Nil\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(a) {\n  case a {\n    <<\"hello\">> -> Nil\n    _ -> Nil\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:7\n  │\n4 │     <<\"hello\">> -> Nil\n  │       ^^^^^^^ This requires a Gleam version >= 1.5.0\n\nThe ability to omit the `utf8` annotation for string segments was\nintroduced in version v1.5.0. But the Gleam version range specified in your\n`gleam.toml` would allow this code to run on an earlier version like\nv1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.5.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__missing_utf_8_option_in_bit_array_segment_requires_v1_5.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  <<\\\"hello\\\">>\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  <<\"hello\">>\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │   <<\"hello\">>\n  │     ^^^^^^^ This requires a Gleam version >= 1.5.0\n\nThe ability to omit the `utf8` annotation for string segments was\nintroduced in version v1.5.0. But the Gleam version range specified in your\n`gleam.toml` would allow this code to run on an earlier version like\nv1.0.0, resulting in compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.5.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__module_used_by_unused_function_is_not_marked_as_unused.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"import wibble\\nfn wobble() {\\n  wibble.a\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub const a = 1\n\n-- main.gleam\nimport wibble\nfn wobble() {\n  wibble.a\n}\n\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ fn wobble() {\n  │ ^^^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__multiple_impossible_to_reach_integer_segments.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    <<1, -1, 2, -3>> -> True\\n    _ -> False\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    <<1, -1, 2, -3>> -> True\n    _ -> False\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     <<1, -1, 2, -3>> -> True\n  │     ^^^^^^^^^^^^^^^^\n  │          │      │\n  │          │      A 1 byte unsigned integer will never match this value\n  │          A 1 byte unsigned integer will never match this value\n\nThis pattern cannot be reached as it contains segments that will never\nmatch.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__nested_tuple_access_requires_v1_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let tuple = #(1, #(1, 1))\\n  tuple.1.0\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let tuple = #(1, #(1, 1))\n  tuple.1.0\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:4:3\n  │\n4 │   tuple.1.0\n  │   ^^^^^^^^^ This requires a Gleam version >= 1.1.0\n\nThe ability to access nested tuple fields was introduced in version v1.1.0.\nBut the Gleam version range specified in your `gleam.toml` would allow this\ncode to run on an earlier version like v1.0.0, resulting in compilation\nerrors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.1.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__odd_number_of_multiple_bool_negations_raise_a_single_warning_that_highlights_the_unnecessary_ones.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { let _ = !!!!!False }\"\n---\n----- SOURCE CODE\npub fn main() { let _ = !!!!!False }\n\n----- WARNING\nwarning: Unnecessary double negation (!!) on bool\n  ┌─ /src/warning/wrn.gleam:1:25\n  │\n1 │ pub fn main() { let _ = !!!!!False }\n  │                         ^^^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__odd_number_of_multiple_integer_negations_raise_a_single_warning_that_highlights_the_unnecessary_ones.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { let _ = -----7 }\"\n---\n----- SOURCE CODE\npub fn main() { let _ = -----7 }\n\n----- WARNING\nwarning: Unnecessary double negation (--) on integer\n  ┌─ /src/warning/wrn.gleam:1:25\n  │\n1 │ pub fn main() { let _ = -----7 }\n  │                         ^^^^ You can safely remove this.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__opaque_external_type_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: pub opaque type External\n---\n----- SOURCE CODE\npub opaque type External\n\n----- WARNING\nwarning: Opaque external type\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ pub opaque type External\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis type has no constructors so making it opaque is redundant.\nHint: Remove the `opaque` qualifier from the type definition.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__panic_used_as_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          panic()\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          panic()\n        }\n\n----- WARNING\nwarning: Panic used as a function\n  ┌─ /src/warning/wrn.gleam:2:11\n  │\n2 │           panic()\n  │           ^^^^^^^\n\n`panic` is not a function, you can just write `panic` instead of `panic()`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__panic_used_as_function_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          panic(1)\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          panic(1)\n        }\n\n----- WARNING\nwarning: Panic used as a function\n  ┌─ /src/warning/wrn.gleam:2:17\n  │\n2 │           panic(1)\n  │                 ^\n\n`panic` is not a function and will crash before it can do anything with\nthis argument.\n\nHint: if you want to display an error message you should write\n`panic as \"my error message\"`\nSee: https://tour.gleam.run/advanced-features/panic/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__panic_used_as_function_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          panic(1, Nil)\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          panic(1, Nil)\n        }\n\n----- WARNING\nwarning: Panic used as a function\n  ┌─ /src/warning/wrn.gleam:2:17\n  │\n2 │           panic(1, Nil)\n  │                 ^^^^^^\n\n`panic` is not a function and will crash before it can do anything with\nthese arguments.\n\nHint: if you want to display an error message you should write\n`panic as \"my error message\"`\nSee: https://tour.gleam.run/advanced-features/panic/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__panic_used_as_function_inside_pipeline.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_) { 1 }\\n        pub fn main() {\\n            1 |> panic |> wibble\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            1 |> panic |> wibble\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:27\n  │\n4 │             1 |> panic |> wibble\n  │                           ^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_64_float_float_is_unreachable.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    <<_:64-float>> -> \\\"Float\\\"\\n    <<_:64-float>> -> \\\"unreachable\\\"\\n    _ -> \\\"Other\\\"\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-float>> -> \"unreachable\"\n    _ -> \"Other\"\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<_:64-float>> -> \"unreachable\"\n  │     ^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_empty_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        case <<>> {\\n            _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        case <<>> {\n            _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:2:14\n  │\n2 │         case <<>> {\n  │              ^^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_empty_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        case [] {\\n            _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        case [] {\n            _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:2:14\n  │\n2 │         case [] {\n  │              ^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_empty_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        case #() {\\n            _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        case #() {\n            _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:2:14\n  │\n2 │         case #() {\n  │              ^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble }\\npub fn main() {\\n  case 1.0 {\\n    _ -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble }\npub fn main() {\n  case 1.0 {\n    _ -> Nil\n  }\n}\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   case 1.0 {\n  │        ^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble }\\npub fn main() {\\n  case 1 {\\n    _ -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble }\npub fn main() {\n  case 1 {\n    _ -> Nil\n  }\n}\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   case 1 {\n  │        ^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        case [1, 2] {\\n            _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        case [1, 2] {\n            _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Redundant list\n  ┌─ /src/warning/wrn.gleam:2:14\n  │\n2 │         case [1, 2] {\n  │              ^^^^^^ You can remove this list wrapper\n\nInstead of building a list and matching on it, you can match on its\ncontents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {\n      _, _ -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_list_with_tail.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        case [1, 2, ..[]] {\\n            _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        case [1, 2, ..[]] {\n            _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Redundant list\n  ┌─ /src/warning/wrn.gleam:2:14\n  │\n2 │         case [1, 2, ..[]] {\n  │              ^^^^^^^^^^^^ You can remove this list wrapper\n\nInstead of building a list and matching on it, you can match on its\ncontents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {\n      _, _ -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_record.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(Int) }\\npub fn main() {\\n  let n = 1\\n  case Wibble(n) {\\n    _ -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(Int) }\npub fn main() {\n  let n = 1\n  case Wibble(n) {\n    _ -> Nil\n  }\n}\n\n----- WARNING\nwarning: Redundant record\n  ┌─ /src/warning/wrn.gleam:5:8\n  │\n5 │   case Wibble(n) {\n  │        ^^^^^^^^^ You can remove this record wrapper\n\nInstead of building a record and matching on it, you can match on its\ncontents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {\n      _, _ -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_record_with_no_args.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble }\\npub fn main() {\\n  case Wibble {\\n    _ -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble }\npub fn main() {\n  case Wibble {\n    _ -> Nil\n  }\n}\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   case Wibble {\n  │        ^^^^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_string.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble }\\npub fn main() {\\n  case \\\"hello\\\" {\\n    _ -> Nil\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble }\npub fn main() {\n  case \"hello\" {\n    _ -> Nil\n  }\n}\n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:4:8\n  │\n4 │   case \"hello\" {\n  │        ^^^^^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_literal_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        case #(1, 2) {\\n            _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        case #(1, 2) {\n            _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Redundant tuple\n  ┌─ /src/warning/wrn.gleam:2:14\n  │\n2 │         case #(1, 2) {\n  │              ^^^^^^^ You can remove this tuple wrapper\n\nInstead of building a tuple and matching on it, you can match on its\ncontents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {\n      _, _ -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pattern_matching_on_multiple_literal_tuples.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        let wibble = 1\\n        case #(1, 2), #(wibble, wibble) {\\n            _, _ -> Nil\\n        }\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        let wibble = 1\n        case #(1, 2), #(wibble, wibble) {\n            _, _ -> Nil\n        }\n      }\n\n----- WARNING\nwarning: Redundant tuple\n  ┌─ /src/warning/wrn.gleam:3:14\n  │\n3 │         case #(1, 2), #(wibble, wibble) {\n  │              ^^^^^^^ You can remove this tuple wrapper\n\nInstead of building a tuple and matching on it, you can match on its\ncontents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {\n      _, _ -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\n\nwarning: Redundant tuple\n  ┌─ /src/warning/wrn.gleam:3:23\n  │\n3 │         case #(1, 2), #(wibble, wibble) {\n  │                       ^^^^^^^^^^^^^^^^^ You can remove this tuple wrapper\n\nInstead of building a tuple and matching on it, you can match on its\ncontents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {\n      _, _ -> todo\n    }\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_0_eq_list_length.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = 0 == list.length(a_list)\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 == list.length(a_list)\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = 0 == list.length(a_list)\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list == []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_0_lt_list_length.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = 0 < list.length(a_list)\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 < list.length(a_list)\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = 0 < list.length(a_list)\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list != []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_0_not_eq_list_length.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = 0 != list.length(a_list)\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 != list.length(a_list)\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = 0 != list.length(a_list)\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list != []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_eq_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) == 0\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) == 0\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) == 0\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list == []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_eq_negative_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) == -0\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) == -0\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) == -0\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list == []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_gt_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) > 0\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) > 0\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) > 0\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list != []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_gt_negative_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) > 0\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) > 0\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) > 0\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list != []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_lt_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) < 1\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) < 1\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) < 1\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list == []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_lt_eq_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) <= 0\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) <= 0\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) <= 0\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list == []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_list_length_not_eq_0.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = list.length(a_list) != 0\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) != 0\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = list.length(a_list) != 0\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list != []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_negative_0_eq_list_length.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = -0 == list.length(a_list)\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = -0 == list.length(a_list)\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = -0 == list.length(a_list)\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list == []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__prefer_list_is_empty_over_negative_0_lt_list_length.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        import gleam/list\\n\\n        pub fn main() {\\n            let a_list = []\\n            let _ = 0 < list.length(a_list)\\n        }\\n        \"\n---\n----- SOURCE CODE\n-- gleam/list.gleam\npub fn length(_list: List(a)) -> Int { 0 }\n\n-- main.gleam\n\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 < list.length(a_list)\n        }\n        \n\n----- WARNING\nwarning: Inefficient use of `list.length`\n  ┌─ /src/warning/wrn.gleam:6:21\n  │\n6 │             let _ = 0 < list.length(a_list)\n  │                     ^^^^^^^^^^^^^^^^^^^^^^^\n\nThe `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\nHint: You can use `the_list != []` instead.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pure_pipeline_raises_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn add(a, b) { a + b }\\n\\npub fn main() {\\n  1 |> add(2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(a, b) { a + b }\n\npub fn main() {\n  1 |> add(2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   1 |> add(2)\n  │   ^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pure_pipeline_with_many_steps_raises_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn add(a, b) { a + b }\\n\\npub fn main() {\\n  1 |> add(2) |> add(3) |> add(4)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(a, b) { a + b }\n\npub fn main() {\n  1 |> add(2) |> add(3) |> add(4)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   1 |> add(2) |> add(3) |> add(4)\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__pure_standard_library_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport gleam/dict\\n\\npub fn main() {\\n  dict.insert(dict.new(), 1, 2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n-- gleam/dict.gleam\n\npub type Dict(key, value)\n\n@external(erlang, \"map\", \"new\")\npub fn new() -> Dict(a, b)\n\n@external(erlang, \"map\", \"insert\")\npub fn insert(dict: Dict(key, value), key: key, value: value) -> Dict(key, value)\n\n\n-- main.gleam\n\nimport gleam/dict\n\npub fn main() {\n  dict.insert(dict.new(), 1, 2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   dict.insert(dict.new(), 1, 2)\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__reachable_pattern_after_unreachable_equal_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn wibble(bits) {\\n  case bits {\\n    <<97:3>> -> 1\\n    <<\\\"a\\\">> -> 2\\n    _ -> 3\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn wibble(bits) {\n  case bits {\n    <<97:3>> -> 1\n    <<\"a\">> -> 2\n    _ -> 3\n  }\n}\n\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     <<97:3>> -> 1\n  │     ^^^^^^^^\n  │       │\n  │       A 3 bits unsigned integer will never match this value\n\nThis pattern cannot be reached as it contains segments that will never\nmatch.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_access_variant_inference_requires_v1_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n  Wobble(a: Int, c: Int)\\n}\\n\\npub fn main(wibble) {\\n  case wibble {\\n    Wibble(..) -> wibble.b\\n    Wobble(..) -> wibble.c\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(..) -> wibble.b\n    Wobble(..) -> wibble.c\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:9:26\n  │\n9 │     Wibble(..) -> wibble.b\n  │                          ^ This requires a Gleam version >= 1.6.0\n\nField access on custom types when the variant is known was introduced in\nversion v1.6.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.0.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.6.0\"\n\nwarning: Incompatible gleam version range\n   ┌─ /src/warning/wrn.gleam:10:26\n   │\n10 │     Wobble(..) -> wibble.c\n   │                          ^ This requires a Gleam version >= 1.6.0\n\nField access on custom types when the variant is known was introduced in\nversion v1.6.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.0.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.6.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_select_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(field: Int)\\n}\\n\\npub fn main(wibble: Wibble) { wibble.field == wibble.field }\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(field: Int)\n}\n\npub fn main(wibble: Wibble) { wibble.field == wibble.field }\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:6:31\n  │\n6 │ pub fn main(wibble: Wibble) { wibble.field == wibble.field }\n  │                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_select_redundant_comparison_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(field: Int)\\n}\\n\\npub fn main(wibble: Wibble) { wibble.field != wibble.field }\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(field: Int)\n}\n\npub fn main(wibble: Wibble) { wibble.field != wibble.field }\n\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:6:31\n  │\n6 │ pub fn main(wibble: Wibble) { wibble.field != wibble.field }\n  │                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_update_variant_inference_requires_v1_6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Int)\\n  Wobble(a: Int, c: Int)\\n}\\n\\npub fn main(wibble) {\\n  case wibble {\\n    Wibble(..) -> Wibble(..wibble, b: 10)\\n    Wobble(..) -> panic\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(..) -> Wibble(..wibble, b: 10)\n    Wobble(..) -> panic\n  }\n}\n\n\n----- WARNING\nwarning: Incompatible gleam version range\n  ┌─ /src/warning/wrn.gleam:9:28\n  │\n9 │     Wibble(..) -> Wibble(..wibble, b: 10)\n  │                            ^^^^^^ This requires a Gleam version >= 1.6.0\n\nRecord updates for custom types when the variant is known was introduced in\nversion v1.6.0. But the Gleam version range specified in your `gleam.toml`\nwould allow this code to run on an earlier version like v1.0.0, resulting\nin compilation errors!\nHint: Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \">= 1.6.0\"\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_update_warnings_test2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub type Person {\\n            Person(name: String, age: Int)\\n        }\\n        pub fn update_person() {\\n            let past = Person(\\\"Quinn\\\", 27)\\n            let present = Person(..past)\\n            present\\n        }\"\n---\n----- SOURCE CODE\n\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person() {\n            let past = Person(\"Quinn\", 27)\n            let present = Person(..past)\n            present\n        }\n\n----- WARNING\nwarning: Fieldless record update\n  ┌─ /src/warning/wrn.gleam:7:27\n  │\n7 │             let present = Person(..past)\n  │                           ^^^^^^^^^^^^^^ This record update doesn't change any fields\n\nHint: Add some fields to change or replace it with the record itself.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_update_warnings_test3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub type Person {\\n            Person(name: String, age: Int)\\n        }\\n        pub fn update_person() {\\n            let past = Person(\\\"Quinn\\\", 27)\\n            let present = Person(..past, name: \\\"Quinn\\\", age: 28)\\n            present\\n        }\"\n---\n----- SOURCE CODE\n\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person() {\n            let past = Person(\"Quinn\", 27)\n            let present = Person(..past, name: \"Quinn\", age: 28)\n            present\n        }\n\n----- WARNING\nwarning: Redundant record update\n  ┌─ /src/warning/wrn.gleam:7:27\n  │\n7 │             let present = Person(..past, name: \"Quinn\", age: 28)\n  │                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This record update specifies all fields\n\nHint: It is better style to use the record creation syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__record_update_with_wrong_types_but_all_fields_produces_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn main() {\\n  let original = Wibble(a: 1, b: True)\\n  Wibble(..original, a: True, b: 1)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn main() {\n  let original = Wibble(a: 1, b: True)\n  Wibble(..original, a: True, b: 1)\n}\n\n\n----- WARNING\nwarning: Redundant record update\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   Wibble(..original, a: True, b: 1)\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This record update specifies all fields\n\nHint: It is better style to use the record creation syntax.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__redundant_function_capture_in_pipe_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n  pub fn wibble(_, _) { 1 }\\n\\n  pub fn main() {\\n    1 |> wibble(_, 2) |> wibble(2)\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn wibble(_, _) { 1 }\n\n  pub fn main() {\n    1 |> wibble(_, 2) |> wibble(2)\n  }\n\n\n----- WARNING\nwarning: Redundant function capture\n  ┌─ /src/warning/wrn.gleam:5:17\n  │\n5 │     1 |> wibble(_, 2) |> wibble(2)\n  │                 ^ You can safely remove this\n\nThis function capture is redundant since the value is already piped as the\nfirst argument of this call.\n\nSee: https://tour.gleam.run/functions/pipelines/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__redundant_function_capture_in_pipe_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n  pub fn wobble(_) { 1 }\\n\\n  pub fn main() {\\n    1 |> wobble(_) |> wobble\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn wobble(_) { 1 }\n\n  pub fn main() {\n    1 |> wobble(_) |> wobble\n  }\n\n\n----- WARNING\nwarning: Redundant function capture\n  ┌─ /src/warning/wrn.gleam:5:17\n  │\n5 │     1 |> wobble(_) |> wobble\n  │                 ^ You can safely remove this\n\nThis function capture is redundant since the value is already piped as the\nfirst argument of this call.\n\nSee: https://tour.gleam.run/functions/pipelines/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__redundant_function_capture_in_pipe_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n  pub fn wobble(_) { 1 }\\n\\n  pub fn main() {\\n    1 |> wobble |> wobble(_)\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn wobble(_) { 1 }\n\n  pub fn main() {\n    1 |> wobble |> wobble(_)\n  }\n\n\n----- WARNING\nwarning: Redundant function capture\n  ┌─ /src/warning/wrn.gleam:5:27\n  │\n5 │     1 |> wobble |> wobble(_)\n  │                           ^ You can safely remove this\n\nThis function capture is redundant since the value is already piped as the\nfirst argument of this call.\n\nSee: https://tour.gleam.run/functions/pipelines/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__redundant_function_capture_in_pipe_4.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n  pub fn wibble(_, _) { 1 }\\n\\n  pub fn main() {\\n    1 |> wibble(2) |> wibble(_, 2)\\n  }\\n\"\n---\n----- SOURCE CODE\n\n  pub fn wibble(_, _) { 1 }\n\n  pub fn main() {\n    1 |> wibble(2) |> wibble(_, 2)\n  }\n\n\n----- WARNING\nwarning: Redundant function capture\n  ┌─ /src/warning/wrn.gleam:5:30\n  │\n5 │     1 |> wibble(2) |> wibble(_, 2)\n  │                              ^ You can safely remove this\n\nThis function capture is redundant since the value is already piped as the\nfirst argument of this call.\n\nSee: https://tour.gleam.run/functions/pipelines/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__redundant_let_assert.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let assert wibble = [1, 2, 3]\\n  wibble\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert wibble = [1, 2, 3]\n  wibble\n}\n\n\n----- WARNING\nwarning: Redundant assertion\n  ┌─ /src/warning/wrn.gleam:3:7\n  │\n3 │   let assert wibble = [1, 2, 3]\n  │       ^^^^^^ You can remove this\n\nThis assertion is redundant since the pattern covers all possibilities.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__redundant_let_assert_on_custom_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble {\\n    Wibble(Int, Bool)\\n}\\n\\npub fn main() {\\n  let assert Wibble(_, bool) = Wibble(1, True)\\n  bool\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble {\n    Wibble(Int, Bool)\n}\n\npub fn main() {\n  let assert Wibble(_, bool) = Wibble(1, True)\n  bool\n}\n\n\n----- WARNING\nwarning: Redundant assertion\n  ┌─ /src/warning/wrn.gleam:7:7\n  │\n7 │   let assert Wibble(_, bool) = Wibble(1, True)\n  │       ^^^^^^ You can remove this\n\nThis assertion is redundant since the pattern covers all possibilities.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__result_discard_warning_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn wibble() { Ok(5) }\\npub fn main() {\\n  wibble()\\n  5\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble() { Ok(5) }\npub fn main() {\n  wibble()\n  5\n}\n\n----- WARNING\nwarning: Unused result value\n  ┌─ /src/warning/wrn.gleam:4:3\n  │\n4 │   wibble()\n  │   ^^^^^^^^ The Result value created here is unused\n\nHint: If you are sure you don't need it you can assign it to `_`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__result_in_case_discarded.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    _ -> Error(Nil)\\n  }\\n  Nil\\n}\"\n---\n----- SOURCE CODE\n\npub fn main(x) {\n  case x {\n    _ -> Error(Nil)\n  }\n  Nil\n}\n\n----- WARNING\nwarning: Unused result value\n  ┌─ /src/warning/wrn.gleam:3:3\n  │  \n3 │ ╭   case x {\n4 │ │     _ -> Error(Nil)\n5 │ │   }\n  │ ╰───^ The Result value created here is unused\n\nHint: If you are sure you don't need it you can assign it to `_`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__shadow_imported_constant.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module.{value}\\n\\npub const value = 1\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n\npub const value = 1\n\n\n-- main.gleam\n\nimport module.{value}\n\npub const value = 1\n\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import module.{value}\n  │ ^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n\nwarning: Shadowed Import\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ pub const value = 1\n  │ ^^^^^^^^^^^^^^^ `value` is defined here\n\nDefinition of value shadows an imported value.\nThe imported value could not be used in this module anyway.\nHint: Either rename the definition or remove the import.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__shadow_imported_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport module.{wibble}\\n\\npub fn wibble() { Nil }\\n\"\n---\n----- SOURCE CODE\n-- module.gleam\n\npub fn wibble() { Nil }\n\n\n-- main.gleam\n\nimport module.{wibble}\n\npub fn wibble() { Nil }\n\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ import module.{wibble}\n  │ ^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n\nwarning: Shadowed Import\n  ┌─ /src/warning/wrn.gleam:4:1\n  │\n4 │ pub fn wibble() { Nil }\n  │ ^^^^^^^^^^^^^^^ `wibble` is defined here\n\nDefinition of wibble shadows an imported value.\nThe imported value could not be used in this module anyway.\nHint: Either rename the definition or remove the import.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__string_literals_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { \\\"wibble\\\" == \\\"wobble\\\" }\"\n---\n----- SOURCE CODE\npub fn main() { \"wibble\" == \"wobble\" }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { \"wibble\" == \"wobble\" }\n  │                 ^^^^^^^^^^^^^^^^^^^^ This is always `False`\n\nThis comparison is redundant since it always fails.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__string_literals_redundant_comparison_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { \\\"wibble\\\" != \\\"wobble\\\" }\"\n---\n----- SOURCE CODE\npub fn main() { \"wibble\" != \"wobble\" }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { \"wibble\" != \"wobble\" }\n  │                 ^^^^^^^^^^^^^^^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__todo_used_as_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          todo()\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          todo()\n        }\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:2:11\n  │\n2 │           todo()\n  │           ^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n\nHint: I think its type is `fn() -> a`.\n\n\nwarning: Todo used as a function\n  ┌─ /src/warning/wrn.gleam:2:11\n  │\n2 │           todo()\n  │           ^^^^^^\n\n`todo` is not a function, you can just write `todo` instead of `todo()`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__todo_used_as_function_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          todo(1)\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          todo(1)\n        }\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:2:11\n  │\n2 │           todo(1)\n  │           ^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n\nHint: I think its type is `fn(Int) -> a`.\n\n\nwarning: Todo used as a function\n  ┌─ /src/warning/wrn.gleam:2:16\n  │\n2 │           todo(1)\n  │                ^\n\n`todo` is not a function and will crash before it can do anything with this\nargument.\n\nHint: if you want to display an error message you should write\n`todo as \"my error message\"`\nSee: https://tour.gleam.run/advanced-features/todo/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__todo_used_as_function_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          todo(1, Nil)\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          todo(1, Nil)\n        }\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:2:11\n  │\n2 │           todo(1, Nil)\n  │           ^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n\nHint: I think its type is `fn(Int, Nil) -> a`.\n\n\nwarning: Todo used as a function\n  ┌─ /src/warning/wrn.gleam:2:16\n  │\n2 │           todo(1, Nil)\n  │                ^^^^^^\n\n`todo` is not a function and will crash before it can do anything with\nthese arguments.\n\nHint: if you want to display an error message you should write\n`todo as \"my error message\"`\nSee: https://tour.gleam.run/advanced-features/todo/\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__todo_warning_correct_location.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n        todo\\n      }\"\n---\n----- SOURCE CODE\npub fn main() {\n        todo\n      }\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:2:9\n  │\n2 │         todo\n  │         ^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__todo_warning_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 == todo }\"\n---\n----- SOURCE CODE\npub fn main() { 1 == todo }\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:1:22\n  │\n1 │ pub fn main() { 1 == todo }\n  │                      ^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n\nHint: I think its type is `Int`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__todo_with_known_type.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() -> String {\\n  todo\\n}\"\n---\n----- SOURCE CODE\npub fn main() -> String {\n  todo\n}\n\n----- WARNING\nwarning: Todo found\n  ┌─ /src/warning/wrn.gleam:2:3\n  │\n2 │   todo\n  │   ^^^^ This code is incomplete\n\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\n\nHint: I think its type is `String`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_code_after_case_subject_panics_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main(a, b) {\\n            case a, panic, b {\\n                _, _, _ -> \\\"no warning here!\\\"\\n            }\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main(a, b) {\n            case a, panic, b {\n                _, _, _ -> \"no warning here!\"\n            }\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:3:28\n  │\n3 │             case a, panic, b {\n  │                            ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_code_after_case_subject_panics_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main(a, b) {\\n            case a, b, panic {\\n                _, _, _ -> \\\"no warning here!\\\"\\n            }\\n            \\\"warning here!\\\"\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main(a, b) {\n            case a, b, panic {\n                _, _, _ -> \"no warning here!\"\n            }\n            \"warning here!\"\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:6:13\n  │\n6 │             \"warning here!\"\n  │             ^^^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_code_analysis_treats_anonymous_functions_independently_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main() {\\n            let _ = fn() {\\n              panic\\n              \\\"warning here!\\\"\\n            }\\n            panic\\n            \\\"warning here!\\\"\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main() {\n            let _ = fn() {\n              panic\n              \"warning here!\"\n            }\n            panic\n            \"warning here!\"\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:5:15\n  │\n5 │               \"warning here!\"\n  │               ^^^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:8:13\n  │\n8 │             \"warning here!\"\n  │             ^^^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_code_analysis_treats_anonymous_functions_independently_3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn main() {\\n            panic\\n            let _ = \\\"warning here!\\\"\\n            let _ = fn() {\\n              panic\\n              \\\"warning here!\\\"\\n            }\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn main() {\n            panic\n            let _ = \"warning here!\"\n            let _ = fn() {\n              panic\n              \"warning here!\"\n            }\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:21\n  │\n4 │             let _ = \"warning here!\"\n  │                     ^^^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:7:15\n  │\n7 │               \"warning here!\"\n  │               ^^^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_code_for_panic_as_first_pipeline_item.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_) { 1 }\\n        pub fn main() {\\n            panic |> wibble\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            panic |> wibble\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:22\n  │\n4 │             panic |> wibble\n  │                      ^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_function_argument_if_panic_is_argument.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_, _) { 1 }\\n        pub fn main() {\\n          wibble(panic, 1)\\n        }\"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_, _) { 1 }\n        pub fn main() {\n          wibble(panic, 1)\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:25\n  │\n4 │           wibble(panic, 1)\n  │                         ^\n\nThis argument is unreachable because the previous one always panics. Your\ncode will crash before reaching this point.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_function_call_if_panic_is_last_argument_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_, _) { 1 }\\n        pub fn main() {\\n          wibble(1, panic)\\n          1\\n        }\"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_, _) { 1 }\n        pub fn main() {\n          wibble(1, panic)\n          1\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:11\n  │\n4 │           wibble(1, panic)\n  │           ^^^^^^\n\nThis function call is unreachable because its last argument always panics.\nYour code will crash before reaching this point.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_function_call_if_panic_is_last_argument_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_, _) { 1 }\\n        pub fn main() {\\n          wibble(1, panic)\\n        }\"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_, _) { 1 }\n        pub fn main() {\n          wibble(1, panic)\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:11\n  │\n4 │           wibble(1, panic)\n  │           ^^^^^^\n\nThis function call is unreachable because its last argument always panics.\nYour code will crash before reaching this point.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_int_pattern_with_prefix_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn wibble(bits) {\\n  case bits {\\n    <<0b1:1, _:1>> -> 1\\n    <<0b11:2>> -> 2\\n    _ -> 3\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble(bits) {\n  case bits {\n    <<0b1:1, _:1>> -> 1\n    <<0b11:2>> -> 2\n    _ -> 3\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<0b11:2>> -> 2\n  │     ^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_int_pattern_with_string_of_same_value.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn wibble(bits) {\\n  case bits {\\n    <<\\\"a\\\">> -> 1\\n    <<97>> -> 2\\n    _ -> 3\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble(bits) {\n  case bits {\n    <<\"a\">> -> 1\n    <<97>> -> 2\n    _ -> 3\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:5:5\n  │\n5 │     <<97>> -> 2\n  │     ^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_string_pattern_with_different_encodings.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn wibble(bits) {\\n  case bits {\\n    <<\\\"\\\\u{0000}a\\\\u{0000}b\\\":utf8>> -> 1\\n    // This is the same as the one above, it shouldn't be reachable\\n    <<\\\"ab\\\":utf16>> -> 2\\n    _ -> 3\\n  }\\n}\"\n---\n----- SOURCE CODE\n\npub fn wibble(bits) {\n  case bits {\n    <<\"\\u{0000}a\\u{0000}b\":utf8>> -> 1\n    // This is the same as the one above, it shouldn't be reachable\n    <<\"ab\":utf16>> -> 2\n    _ -> 3\n  }\n}\n\n----- WARNING\nwarning: Unreachable pattern\n  ┌─ /src/warning/wrn.gleam:6:5\n  │\n6 │     <<\"ab\":utf16>> -> 2\n  │     ^^^^^^^^^^^^^^\n\nThis pattern cannot be reached as a previous pattern matches the same\nvalues.\n\nHint: It can be safely removed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_use_after_panic.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_) { 1 }\\n        pub fn main() {\\n            panic\\n            use <- wibble\\n            1\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            panic\n            use <- wibble\n            1\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:5:20\n  │\n5 │             use <- wibble\n  │                    ^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          panic\\n          1\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          panic\n          1\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:3:11\n  │\n3 │           1\n  │           ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          let _ = panic\\n          1\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          let _ = panic\n          1\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:3:11\n  │\n3 │           1\n  │           ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_doesnt_escape_out_of_a_block_if_panic_is_not_last.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          let n = {\\n            panic\\n            1\\n          }\\n          n\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          let n = {\n            panic\n            1\n          }\n          n\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:4:13\n  │\n4 │             1\n  │             ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_for_panic_as_last_item_of_pipe_on_next_expression.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n        pub fn wibble(_) { 1 }\\n        pub fn main() {\\n            1 |> wibble |> panic\\n            \\\"unreachable\\\"\\n        }\\n        \"\n---\n----- SOURCE CODE\n\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            1 |> wibble |> panic\n            \"unreachable\"\n        }\n        \n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:5:13\n  │\n5 │             \"unreachable\"\n  │             ^^^^^^^^^^^^^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_if_all_branches_panic.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          let n = 1\\n          case n {\\n            0 -> panic\\n            _ -> panic\\n          }\\n          1\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          let n = 1\n          case n {\n            0 -> panic\n            _ -> panic\n          }\n          1\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:7:11\n  │\n7 │           1\n  │           ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_if_all_branches_panic_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          let n = 1\\n          case n {\\n            0 -> {\\n              panic\\n              2\\n            }\\n            _ -> panic\\n          }\\n          1\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          let n = 1\n          case n {\n            0 -> {\n              panic\n              2\n            }\n            _ -> panic\n          }\n          1\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:6:15\n  │\n6 │               2\n  │               ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unreachable_warning_on_following_expression_if_panic_is_last_in_a_block.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n          let _ = {\\n            panic\\n          }\\n          1\\n        }\"\n---\n----- SOURCE CODE\npub fn main() {\n          let _ = {\n            panic\n          }\n          1\n        }\n\n----- WARNING\nwarning: Unreachable code\n  ┌─ /src/warning/wrn.gleam:5:11\n  │\n5 │           1\n  │           ^\n\nThis code is unreachable because it comes after a `panic`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_alias_for_duplicate_module_no_warning_for_alias_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n            import a/wibble\\n            import b/wibble as wobble\\n            pub const one = wibble.one\\n        \"\n---\n----- SOURCE CODE\n-- a/wibble.gleam\npub const one = 1\n\n-- b/wibble.gleam\npub const two = 2\n\n-- main.gleam\n\n            import a/wibble\n            import b/wibble as wobble\n            pub const one = wibble.one\n        \n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:3:13\n  │\n3 │             import b/wibble as wobble\n  │             ^^^^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_alias_warning_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n            import gleam/wibble.{one} as wobble\\n            pub const one = one\\n        \"\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub const one = 1\n\n-- main.gleam\n\n            import gleam/wibble.{one} as wobble\n            pub const one = one\n        \n\n----- WARNING\nwarning: Unused imported module alias\n  ┌─ /src/warning/wrn.gleam:2:39\n  │\n2 │             import gleam/wibble.{one} as wobble\n  │                                       ^^^^^^^^^ This alias is never used\n\nHint: You can safely remove it.\n\n    import gleam/wibble as _\n\n\nwarning: Shadowed Import\n  ┌─ /src/warning/wrn.gleam:3:13\n  │\n3 │             pub const one = one\n  │             ^^^^^^^^^^^^^ `one` is defined here\n\nDefinition of one shadows an imported value.\nThe imported value could not be used in this module anyway.\nHint: Either rename the definition or remove the import.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_binary_operation_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let string = \\\"a\\\" <> \\\"b\\\" \\\"c\\\" <> \\\"d\\\"\\n  string\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let string = \"a\" <> \"b\" \"c\" <> \"d\"\n  string\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:27\n  │\n3 │   let string = \"a\" <> \"b\" \"c\" <> \"d\"\n  │                           ^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_bit_array.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n        <<3>>\\n\\t\\t\\t\\t2\\n    }\"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        <<3>>\n\t\t\t\t2\n    }\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:3:9\n  │\n3 │         <<3>>\n  │         ^^^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_block_wrapping_pure_expression.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  { 1 }\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  { 1 }\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   { 1 }\n  │   ^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_block_wrapping_pure_expressions.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  {\\n    True\\n    1\\n  }\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  {\n    True\n    1\n  }\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:3\n  │  \n3 │ ╭   {\n4 │ │     True\n5 │ │     1\n6 │ │   }\n  │ ╰───^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     True\n  │     ^^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_bool_negation_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  !True\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  !True\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   !True\n  │   ^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_case_expression.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n    let a = 1\\n    case a {\\n        1 -> a\\n        _ -> 12\\n    }\\n    Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    let a = 1\n    case a {\n        1 -> a\n        _ -> 12\n    }\n    Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:4:5\n  │  \n4 │ ╭     case a {\n5 │ │         1 -> a\n6 │ │         _ -> 12\n7 │ │     }\n  │ ╰─────^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_destructure.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn a(b) { case b { #(c, _) -> 5 } }\"\n---\n----- SOURCE CODE\npub fn a(b) { case b { #(c, _) -> 5 } }\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:1:26\n  │\n1 │ pub fn a(b) { case b { #(c, _) -> 5 } }\n  │                          ^ This variable is never used\n\nHint: You can ignore it with an underscore: `_c`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_discard_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() {\\n  let a = 10\\n  let _ = case a {\\n    _ as b -> b\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\npub fn main() {\n  let a = 10\n  let _ = case a {\n    _ as b -> b\n  }\n}\n\n\n----- WARNING\nwarning: Unused discard pattern\n  ┌─ /src/warning/wrn.gleam:4:5\n  │\n4 │     _ as b -> b\n  │     ^^^^^^\n\n`_ as b` can be written more concisely as `b`\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_float.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1.0 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1.0 2 }\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1.0 2 }\n  │                 ^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_fn_function_call.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n    fn(a) { a + 1 }(1)\\n    Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    fn(a) { a + 1 }(1)\n    Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:5\n  │\n3 │     fn(a) { a + 1 }(1)\n  │     ^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_function_literal_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  fn(n) { n + 1 }\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  fn(n) { n + 1 }\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   fn(n) { n + 1 }\n  │   ^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_imported_module_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: import gleam/wibble\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub fn wobble() { 1 }\n\n-- main.gleam\nimport gleam/wibble\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ import gleam/wibble\n  │ ^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_imported_module_with_alias_and_unqualified_name_no_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"import gleam/one.{two} as three\\npub fn wibble() { two() }\"\n---\n----- SOURCE CODE\n-- gleam/one.gleam\npub fn two() { 1 }\n\n-- main.gleam\nimport gleam/one.{two} as three\npub fn wibble() { two() }\n\n----- WARNING\nwarning: Unused imported module alias\n  ┌─ /src/warning/wrn.gleam:1:24\n  │\n1 │ import gleam/one.{two} as three\n  │                        ^^^^^^^^ This alias is never used\n\nHint: You can safely remove it.\n\n    import gleam/one as _\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_imported_module_with_alias_and_unqualified_name_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"import gleam/one.{two} as three\"\n---\n----- SOURCE CODE\n-- gleam/one.gleam\npub fn two() { 1 }\n\n-- main.gleam\nimport gleam/one.{two} as three\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ import gleam/one.{two} as three\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_imported_module_with_alias_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: import gleam/wibble as wobble\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub fn wobble() { 1 }\n\n-- main.gleam\nimport gleam/wibble as wobble\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ import gleam/wibble as wobble\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_int.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main() { 1 2 }\"\n---\n----- SOURCE CODE\npub fn main() { 1 2 }\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:1:17\n  │\n1 │ pub fn main() { 1 2 }\n  │                 ^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_int_negation_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  -1\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  -1\n  1\n}\n\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   -1\n  │   ^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_label_shorthand_pattern_arg.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(arg1: Int, arg2: Bool ) }\\n\\npub fn main() {\\n  let Wibble(arg1:, arg2:) = Wibble(1, True)\\n  arg1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(arg1: Int, arg2: Bool ) }\n\npub fn main() {\n  let Wibble(arg1:, arg2:) = Wibble(1, True)\n  arg1\n}\n\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:5:21\n  │\n5 │   let Wibble(arg1:, arg2:) = Wibble(1, True)\n  │                     ^^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `arg2: _`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_label_shorthand_pattern_arg_shadowing.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble { Wibble(arg1: Int, arg2: Bool ) }\\n\\npub fn main() {\\n  let Wibble(arg1:, arg2:) = Wibble(1, True)\\n  let arg1 = False\\n  arg1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble { Wibble(arg1: Int, arg2: Bool ) }\n\npub fn main() {\n  let Wibble(arg1:, arg2:) = Wibble(1, True)\n  let arg1 = False\n  arg1\n}\n\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:5:14\n  │\n5 │   let Wibble(arg1:, arg2:) = Wibble(1, True)\n  │              ^^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `arg1: _`.\n\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:5:21\n  │\n5 │   let Wibble(arg1:, arg2:) = Wibble(1, True)\n  │                     ^^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `arg2: _`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_list.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n        [1, 2, 3]\\n\\t\\t\\t\\t2\\n    }\"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        [1, 2, 3]\n\t\t\t\t2\n    }\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:3:9\n  │\n3 │         [1, 2, 3]\n  │         ^^^^^^^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_module_select_const.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.a\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub const a = 1\n\n-- main.gleam\n\nimport wibble\n\npub fn main() {\n  wibble.a\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   wibble.a\n  │   ^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_module_select_constructor.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.Wibble\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble(Int) }\n\n-- main.gleam\n\nimport wibble\n\npub fn main() {\n  wibble.Wibble\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   wibble.Wibble\n  │   ^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_module_select_constructor_call.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.Wibble(1)\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble(Int) }\n\n-- main.gleam\n\nimport wibble\n\npub fn main() {\n  wibble.Wibble(1)\n  1\n}\n\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   wibble.Wibble(1)\n  │   ^^^^^^^^^^^^^^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_module_select_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.println\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub fn println(a) { Nil }\n\n-- main.gleam\n\nimport wibble\n\npub fn main() {\n  wibble.println\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   wibble.println\n  │   ^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_module_wuth_alias_warning_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: import gleam/wibble as wobble\n---\n----- SOURCE CODE\n-- gleam/wibble.gleam\npub const one = 1\n\n-- main.gleam\nimport gleam/wibble as wobble\n\n----- WARNING\nwarning: Unused imported module\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ import gleam/wibble as wobble\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_pipeline_ending_with_pure_fn.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n    1\\n    |> fn(n) { n + 1 }\\n\\n    Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    1\n    |> fn(n) { n + 1 }\n\n    Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:5\n  │  \n3 │ ╭     1\n4 │ │     |> fn(n) { n + 1 }\n  │ ╰──────────────────────^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_pipeline_ending_with_variant_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Wibble(a) { Wibble(a) }\\npub fn wibble(a) { a }\\n\\npub fn main() {\\n  1 |> wibble |> Wibble\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Wibble(a) { Wibble(a) }\npub fn wibble(a) { a }\n\npub fn main() {\n  1 |> wibble |> Wibble\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:6:3\n  │\n6 │   1 |> wibble |> Wibble\n  │   ^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_pipeline_ending_with_variant_raises_a_warning_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nimport wibble\\n\\npub fn wobble(a) { a }\\n\\npub fn main() {\\n  1 |> wobble |> wibble.Wibble\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n-- wibble.gleam\npub type Wibble { Wibble(Int) }\n\n-- main.gleam\n\nimport wibble\n\npub fn wobble(a) { a }\n\npub fn main() {\n  1 |> wobble |> wibble.Wibble\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:7:3\n  │\n7 │   1 |> wobble |> wibble.Wibble\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_private_const_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: const a = 1\n---\n----- SOURCE CODE\nconst a = 1\n\n----- WARNING\nwarning: Unused private constant\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ const a = 1\n  │ ^^^^^^^ This private constant is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_private_fn_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"fn a() { 1 }\"\n---\n----- SOURCE CODE\nfn a() { 1 }\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ fn a() { 1 }\n  │ ^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_private_type_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: type X\n---\n----- SOURCE CODE\ntype X\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ type X\n  │ ^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_private_type_warnings_test3.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: type X = Int\n---\n----- SOURCE CODE\ntype X = Int\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ type X = Int\n  │ ^^^^^^^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_private_type_warnings_test6.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"type X { X }\"\n---\n----- SOURCE CODE\ntype X { X }\n\n----- WARNING\nwarning: Unused private type\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ type X { X }\n  │ ^^^^^^ This private type is never used\n\nHint: You can safely remove it.\n\nwarning: Unused private constructor\n  ┌─ /src/warning/wrn.gleam:1:10\n  │\n1 │ type X { X }\n  │          ^ This private constructor is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_pure_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn add(a, b) { a + b }\\n\\npub fn main() {\\n  add(1, 2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn add(a, b) { a + b }\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:5:3\n  │\n5 │   add(1, 2)\n  │   ^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_pure_function_that_calls_other_pure_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn sub(a, b) { add(a, -b) }\\n\\nfn add(a, b) { a + b }\\n\\npub fn main() {\\n  sub(1, 2)\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\nfn sub(a, b) { add(a, -b) }\n\nfn add(a, b) { a + b }\n\npub fn main() {\n  sub(1, 2)\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:7:3\n  │\n7 │   sub(1, 2)\n  │   ^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_record_access_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Thing {\\n  Thing(value: Int)\\n}\\n\\npub fn main() {\\n  let thing = Thing(1)\\n  thing.value\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(value: Int)\n}\n\npub fn main() {\n  let thing = Thing(1)\n  thing.value\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   thing.value\n  │   ^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_record_constructor_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Thing {\\n  Thing(value: Int)\\n}\\n\\npub fn main() {\\n  Thing(1)\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(value: Int)\n}\n\npub fn main() {\n  Thing(1)\n  1\n}\n\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:7:3\n  │\n7 │   Thing(1)\n  │   ^^^^^^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_record_update_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub type Thing {\\n  Thing(value: Int, other: Int)\\n}\\n\\npub fn main() {\\n  let thing = Thing(1, 2)\\n  Thing(..thing, value: 1)\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub type Thing {\n  Thing(value: Int, other: Int)\n}\n\npub fn main() {\n  let thing = Thing(1, 2)\n  Thing(..thing, value: 1)\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:8:3\n  │\n8 │   Thing(..thing, value: 1)\n  │   ^^^^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_recursive_function_argument.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x: Int) {\\n  main(x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x: Int) {\n  main(x)\n}\n\n\n----- WARNING\nwarning: Unused function argument\n  ┌─ /src/warning/wrn.gleam:2:13\n  │\n2 │ pub fn main(x: Int) {\n  │             ^ This argument is never used\n\nThis argument is passed to the function when recursing, but it's never used\nfor anything.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_recursive_function_argument_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x, times) {\\n  case times {\\n    0 -> main(x, 0)\\n    _ -> main(x, times - 1)\\n  }\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x, times) {\n  case times {\n    0 -> main(x, 0)\n    _ -> main(x, times - 1)\n  }\n}\n\n\n----- WARNING\nwarning: Unused function argument\n  ┌─ /src/warning/wrn.gleam:2:13\n  │\n2 │ pub fn main(x, times) {\n  │             ^ This argument is never used\n\nThis argument is passed to the function when recursing, but it's never used\nfor anything.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_recursive_function_inside_anonymous_function.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x: Int) {\\n  let _useless = fn(_) { main(x) }\\n  Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x: Int) {\n  let _useless = fn(_) { main(x) }\n  Nil\n}\n\n\n----- WARNING\nwarning: Unused function argument\n  ┌─ /src/warning/wrn.gleam:2:13\n  │\n2 │ pub fn main(x: Int) {\n  │             ^ This argument is never used\n\nThis argument is passed to the function when recursing, but it's never used\nfor anything.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_recursive_function_with_shadowing.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main(x: Int) {\\n  let _useless = fn(x) { main(x) }\\n  main(x)\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main(x: Int) {\n  let _useless = fn(x) { main(x) }\n  main(x)\n}\n\n\n----- WARNING\nwarning: Unused function argument\n  ┌─ /src/warning/wrn.gleam:2:13\n  │\n2 │ pub fn main(x: Int) {\n  │             ^ This argument is never used\n\nThis argument is passed to the function when recursing, but it's never used\nfor anything.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_string.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n        \\\"1\\\"\\n                2\\n    }\"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        \"1\"\n                2\n    }\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:3:9\n  │\n3 │         \"1\"\n  │         ^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_tuple.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n        #(1.0, \\\"Hello world\\\")\\n\\t\\t\\t\\t2\\n    }\"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        #(1.0, \"Hello world\")\n\t\t\t\t2\n    }\n\n----- WARNING\nwarning: Unused literal\n  ┌─ /src/warning/wrn.gleam:3:9\n  │\n3 │         #(1.0, \"Hello world\")\n  │         ^^^^^^^^^^^^^^^^^^^^^ This value is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_tuple_index_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  #(1, 2).0\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  #(1, 2).0\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:3\n  │\n3 │   #(1, 2).0\n  │   ^^^^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_assignment_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Int)\\n}\\n\\npub fn main() {\\n  let Wibble(a:, ..) as w = Wibble(1, 2)\\n  a\\n}\\n\"\n---\n----- SOURCE CODE\n\ntype Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let Wibble(a:, ..) as w = Wibble(1, 2)\n  a\n}\n\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:7:25\n  │\n7 │   let Wibble(a:, ..) as w = Wibble(1, 2)\n  │                         ^ This variable is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_raises_a_warning.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let number = 1\\n  number\\n  1\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let number = 1\n  number\n  1\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:4:3\n  │\n4 │   number\n  │   ^^^^^^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_shadowing_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn a() { let b = 1 let b = 2 b }\"\n---\n----- SOURCE CODE\npub fn a() { let b = 1 let b = 2 b }\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:1:18\n  │\n1 │ pub fn a() { let b = 1 let b = 2 b }\n  │                  ^ This variable is never used\n\nHint: You can ignore it with an underscore: `_b`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_string_prefix_pattern.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let assert \\\"hello\\\" as hello <> rest = \\\"hello, world\\\"\\n  rest\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert \"hello\" as hello <> rest = \"hello, world\"\n  rest\n}\n\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:3:25\n  │\n3 │   let assert \"hello\" as hello <> rest = \"hello, world\"\n  │                         ^^^^^ This variable is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_string_prefix_pattern2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n  let assert \\\"hello\\\" as hello <> rest = \\\"hello, world\\\"\\n  hello\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n  let assert \"hello\" as hello <> rest = \"hello, world\"\n  hello\n}\n\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:3:34\n  │\n3 │   let assert \"hello\" as hello <> rest = \"hello, world\"\n  │                                  ^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `_rest`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_warnings_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn a(b) { 1 }\"\n---\n----- SOURCE CODE\npub fn a(b) { 1 }\n\n----- WARNING\nwarning: Unused function argument\n  ┌─ /src/warning/wrn.gleam:1:10\n  │\n1 │ pub fn a(b) { 1 }\n  │          ^ This argument is never used\n\nHint: You can ignore it with an underscore: `_b`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__unused_variable_warnings_test2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn a() { let b = 1 5 }\"\n---\n----- SOURCE CODE\npub fn a() { let b = 1 5 }\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:1:18\n  │\n1 │ pub fn a() { let b = 1 5 }\n  │                  ^ This variable is never used\n\nHint: You can ignore it with an underscore: `_b`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__use_with_pure_fn_expression_is_marked_as_unused.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn main() {\\n    {\\n        use _ <- fn(a) { a }\\n        1\\n    }\\n\\n    Nil\\n}\\n\"\n---\n----- SOURCE CODE\n\npub fn main() {\n    {\n        use _ <- fn(a) { a }\n        1\n    }\n\n    Nil\n}\n\n\n----- WARNING\nwarning: Unused value\n  ┌─ /src/warning/wrn.gleam:3:5\n  │  \n3 │ ╭     {\n4 │ │         use _ <- fn(a) { a }\n5 │ │         1\n6 │ │     }\n  │ ╰─────^ This value is never used\n\nThis expression computes a value without any side effects, but then the\nvalue isn't used at all. You might want to assign it to a variable, or\ndelete the expression entirely if it's not needed.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__variables_redundant_comparison.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"pub fn main(a) { a == a }\"\n---\n----- SOURCE CODE\npub fn main(a) { a == a }\n\n----- WARNING\nwarning: Redundant comparison\n  ┌─ /src/warning/wrn.gleam:1:18\n  │\n1 │ pub fn main(a) { a == a }\n  │                  ^^^^^^ This is always `True`\n\nThis comparison is redundant since it always succeeds.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__warning_many_at_same_time.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\nfn main() { let five = 5 }\"\n---\n----- SOURCE CODE\n\nfn main() { let five = 5 }\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:2:1\n  │\n2 │ fn main() { let five = 5 }\n  │ ^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:2:17\n  │\n2 │ fn main() { let five = 5 }\n  │                 ^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `_five`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__warning_private_function_never_used.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"fn main() { 5 }\"\n---\n----- SOURCE CODE\nfn main() { 5 }\n\n----- WARNING\nwarning: Unused private function\n  ┌─ /src/warning/wrn.gleam:1:1\n  │\n1 │ fn main() { 5 }\n  │ ^^^^^^^^^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__warning_variable_never_used_test.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\npub fn wibble() { Ok(5) }\\npub fn main() { let five = wibble() }\"\n---\n----- SOURCE CODE\n\npub fn wibble() { Ok(5) }\npub fn main() { let five = wibble() }\n\n----- WARNING\nwarning: Unused variable\n  ┌─ /src/warning/wrn.gleam:3:21\n  │\n3 │ pub fn main() { let five = wibble() }\n  │                     ^^^^ This variable is never used\n\nHint: You can ignore it with an underscore: `_five`.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__warnings_for_matches_on_literal_values_that_are_not_like_an_if_1.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n        case True {\\n          _ -> 1\\n        }\\n    }\\n        \"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        case True {\n          _ -> 1\n        }\n    }\n        \n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:3:14\n  │\n3 │         case True {\n  │              ^^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__warnings_for_matches_on_literal_values_that_are_not_like_an_if_2.snap",
    "content": "---\nsource: compiler-core/src/type_/tests/warnings.rs\nexpression: \"\\n    pub fn main() {\\n        case True {\\n          True -> 1\\n        }\\n    }\\n        \"\n---\n----- SOURCE CODE\n\n    pub fn main() {\n        case True {\n          True -> 1\n        }\n    }\n        \n\n----- WARNING\nwarning: Match on a literal value\n  ┌─ /src/warning/wrn.gleam:3:14\n  │\n3 │         case True {\n  │              ^^^^ There's no need to pattern match on this value\n\nMatching on a literal value is redundant since you can already tell which\nbranch is going to match with this value.\n"
  },
  {
    "path": "compiler-core/src/type_/tests/target_implementations.rs",
    "content": "use ecow::EcoString;\nuse itertools::Itertools;\n\nuse crate::{\n    analyse::TargetSupport, assert_module_error, build::Target, type_::expression::Implementations,\n};\n\nuse super::compile_module_with_opts;\n\nmacro_rules! assert_targets {\n    ($src:expr, $implementations:expr $(,)?) => {\n        let result = $crate::type_::tests::target_implementations::implementations($src);\n        let expected = $implementations\n            .iter()\n            .map(|(name, expected_impl)| ((*name).into(), *expected_impl))\n            .collect_vec();\n        assert_eq!(expected, result);\n    };\n}\n\npub fn implementations(src: &str) -> Vec<(EcoString, Implementations)> {\n    compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::Erlang,\n        TargetSupport::NotEnforced,\n        None,\n    )\n    .expect(\"compile src\")\n    .type_info\n    .values\n    .into_iter()\n    .map(|(name, value)| (name, value.variant.implementations()))\n    .sorted()\n    .collect_vec()\n}\n\n#[test]\npub fn pure_gleam_function() {\n    assert_targets!(\n        r#\"\npub fn pure_gleam_1() { 1 + 1 }\npub fn pure_gleam_2() { pure_gleam_1() * 2 }\n\"#,\n        [\n            (\n                \"pure_gleam_1\",\n                Implementations {\n                    gleam: true,\n                    uses_erlang_externals: false,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"pure_gleam_2\",\n                Implementations {\n                    gleam: true,\n                    uses_erlang_externals: false,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            )\n        ],\n    );\n}\n\n#[test]\npub fn erlang_only_function() {\n    assert_targets!(\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\npub fn erlang_only_1() -> Int\n\npub fn erlang_only_2() { erlang_only_1() * 2 }\n\"#,\n        [\n            (\n                \"erlang_only_1\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: false,\n                }\n            ),\n            (\n                \"erlang_only_2\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: false,\n                }\n            )\n        ],\n    );\n}\n\n#[test]\npub fn externals_only_function() {\n    assert_targets!(\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\n@external(javascript, \"wibble\", \"wobble\")\npub fn all_externals_1() -> Int\n\npub fn all_externals_2() { all_externals_1() * 2 }\n\"#,\n        [\n            (\n                \"all_externals_1\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"all_externals_2\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            )\n        ],\n    );\n}\n\n#[test]\npub fn externals_with_pure_gleam_body() {\n    assert_targets!(\n        r#\"\n@external(javascript, \"wibble\", \"wobble\")\npub fn javascript_external_and_pure_body() -> Int { 1 + 1 }\n\n@external(erlang, \"wibble\", \"wobble\")\npub fn erlang_external_and_pure_body() -> Int { 1 + 1 }\n\npub fn pure_gleam() {\n  javascript_external_and_pure_body() + erlang_external_and_pure_body()\n}\n\"#,\n        [\n            (\n                \"erlang_external_and_pure_body\",\n                Implementations {\n                    gleam: true,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"javascript_external_and_pure_body\",\n                Implementations {\n                    gleam: true,\n                    uses_erlang_externals: false,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"pure_gleam\",\n                Implementations {\n                    gleam: true,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            )\n        ],\n    );\n}\n\n#[test]\npub fn erlang_external_with_javascript_body() {\n    assert_targets!(\n        r#\"\n@external(javascript, \"wibble\", \"wobble\")\nfn javascript_only() -> Int\n\n@external(erlang, \"wibble\", \"wobble\")\npub fn erlang_external_and_javascript_body() -> Int { javascript_only() }\n\npub fn all_externals() -> Int { erlang_external_and_javascript_body() }\n\"#,\n        [\n            (\n                \"all_externals\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"erlang_external_and_javascript_body\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"javascript_only\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: false,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: false,\n                    can_run_on_javascript: true,\n                }\n            )\n        ],\n    );\n}\n\n#[test]\npub fn javascript_external_with_erlang_body() {\n    assert_targets!(\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\npub fn erlang_only() -> Int\n\n@external(javascript, \"wibble\", \"wobble\")\npub fn javascript_external_and_erlang_body() -> Int { erlang_only() }\n\npub fn all_externals() -> Int { javascript_external_and_erlang_body() }\n\"#,\n        [\n            (\n                \"all_externals\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            ),\n            (\n                \"erlang_only\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: false,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: false,\n                }\n            ),\n            (\n                \"javascript_external_and_erlang_body\",\n                Implementations {\n                    gleam: false,\n                    uses_erlang_externals: true,\n                    uses_javascript_externals: true,\n                    can_run_on_erlang: true,\n                    can_run_on_javascript: true,\n                }\n            )\n        ],\n    );\n}\n\n#[test]\npub fn function_with_no_valid_implementations() {\n    assert_module_error!(\n        r#\"\n@external(javascript, \"wibble\", \"wobble\")\nfn javascript_only() -> Int\n\n@external(erlang, \"wibble\", \"wobble\")\nfn erlang_only() -> Int\n\npub fn main() {\n    javascript_only()\n    erlang_only()\n}\n\"#\n    );\n}\n\n#[test]\npub fn invalid_both_and_one_called_from_erlang() {\n    let src = r#\"\n@external(erlang, \"wibble\", \"wobble\")\n@external(javascript, \"wibble\", \"wobble\")\nfn both_external() -> Int\n\n@external(javascript, \"wibble\", \"wobble\")\nfn javascript_only() -> Int\n\npub fn no_valid_erlang_impl() {\n  both_external()\n  javascript_only()\n}\n\"#;\n    let out = compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::Erlang,\n        TargetSupport::Enforced,\n        None,\n    );\n    assert!(out.into_result().is_err());\n}\n\n#[test]\npub fn invalid_both_and_one_called_from_javascript() {\n    let src = r#\"\n@external(erlang, \"wibble\", \"wobble\")\n@external(javascript, \"wibble\", \"wobble\")\nfn both_external() -> Int\n\n@external(erlang, \"wibble\", \"wobble\")\nfn erlang_only() -> Int\n\npub fn no_valid_javascript_impl() {\n  both_external()\n  erlang_only()\n}\n\"#;\n    let out = compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::JavaScript,\n        TargetSupport::Enforced,\n        None,\n    );\n    assert!(out.into_result().is_err());\n}\n\n#[test]\npub fn invalid_both_and_one_called_from_erlang_flipped() {\n    let src = r#\"\n@external(erlang, \"wibble\", \"wobble\")\n@external(javascript, \"wibble\", \"wobble\")\nfn both_external() -> Int\n\n@external(javascript, \"wibble\", \"wobble\")\nfn javascript_only() -> Int\n\npub fn no_valid_erlang_impl() {\n  javascript_only()\n  both_external()\n}\n\"#;\n    let out = compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::Erlang,\n        TargetSupport::Enforced,\n        None,\n    );\n    assert!(out.into_result().is_err());\n}\n\n#[test]\npub fn invalid_both_and_one_called_from_javascript_flipped() {\n    let src = r#\"\n@external(erlang, \"wibble\", \"wobble\")\n@external(javascript, \"wibble\", \"wobble\")\nfn both_external() -> Int\n\n@external(erlang, \"wibble\", \"wobble\")\nfn erlang_only() -> Int\n\npub fn no_valid_javascript_impl() {\n  erlang_only()\n  both_external()\n}\n\"#;\n    let out = compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::JavaScript,\n        TargetSupport::Enforced,\n        None,\n    );\n    assert!(out.into_result().is_err());\n}\n\n#[test]\npub fn invalid_erlang_with_external() {\n    let src = r#\"\n@external(javascript, \"wibble\", \"wobble\")\nfn javascript_only() -> Int\n\n@external(javascript, \"one\", \"two\")\npub fn no_valid_erlang_impl() {\n  javascript_only()\n}\n\"#;\n    let out = compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::Erlang,\n        TargetSupport::Enforced,\n        None,\n    );\n    assert!(out.into_result().is_err());\n}\n\n#[test]\npub fn invalid_javascript_with_external() {\n    let src = r#\"\n@external(erlang, \"wibble\", \"wobble\")\nfn erlang_only() -> Int\n\n@external(erlang, \"one\", \"two\")\npub fn no_valid_javascript_impl() {\n  erlang_only()\n}\n\"#;\n    let out = compile_module_with_opts(\n        \"test_module\",\n        src,\n        None,\n        vec![],\n        Target::JavaScript,\n        TargetSupport::Enforced,\n        None,\n    );\n    assert!(out.into_result().is_err());\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/type_alias.rs",
    "content": "use crate::{assert_module_error, assert_module_infer};\n\n#[test]\nfn alias_dep() {\n    assert_module_infer!(\n        r#\"\ntype E = #(F, C)\ntype F = fn(CustomA) -> CustomB(B)\ntype A = Int\ntype B = C\ntype C = CustomA\ntype D = CustomB(C)\n\ntype CustomA {\n  CustomA()\n}\ntype CustomB(a) {\n  CustomB(a)\n}\n\"#,\n        vec![],\n    )\n}\n\n#[test]\nfn custom_type_dep() {\n    assert_module_infer!(\n        r#\"\ntype A {\n    A(Blah)\n}\n\ntype Blah {\n    B(Int)\n}\n\"#,\n        vec![],\n    )\n}\n\n#[test]\nfn alias_cycle() {\n    assert_module_error!(\n        r#\"\ntype A = B\ntype B = C\ntype C = D\ntype D = E\ntype E = A\n\"#\n    );\n}\n\n#[test]\nfn alias_direct_cycle() {\n    assert_module_error!(\n        r#\"\ntype A = #(A, A)\n\"#\n    );\n}\n\n#[test]\nfn alias_different_module() {\n    assert_module_infer!(\n        (\"other\", \"pub type Blah = Bool\"),\n        r#\"\n            import other\n\n            type Blah = #(other.Blah, other.Blah)\n        \"#,\n        vec![],\n    );\n}\n\n#[test]\nfn duplicate_parameter() {\n    assert_module_error!(\n        r#\"\ntype A(a, a) =\n  List(a)\n\"#\n    );\n}\n\n#[test]\nfn unused_parameter() {\n    assert_module_error!(\n        r#\"\ntype A(a) =\n  Int\n\"#\n    );\n}\n\n#[test]\nfn type_alias_error_does_not_stop_analysis() {\n    // Both these aliases have errors! We do not stop on the first one.\n    assert_module_error!(\n        r#\"\ntype UnusedParameter(a) =\n  Int\n\ntype UnknownType =\n  Dunno\n\"#\n    );\n}\n\n#[test]\nfn duplicate_variable_error_does_not_stop_analysis() {\n    // Both these aliases have errors! We do not stop on the first one.\n    assert_module_error!(\n        r#\"\ntype Two(a, a) =\n  #(a, a)\n\ntype UnknownType =\n  Dunno\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3191\n#[test]\nfn both_errors_are_shown() {\n    // The alias has an error, and it causes the function to have an error as it\n    // refers to the type that does not exist.\n    assert_module_error!(\n        r#\"\ntype X =\n  List(Intt)\n\nfn example(a: X) {\n  todo\n}\n\"#\n    );\n}\n\n#[test]\nfn conflict_with_import() {\n    // We cannot declare a type with the same name as an imported type\n    assert_module_error!(\n        (\"wibble\", \"pub type Wobble = String\"),\n        \"import wibble.{type Wobble} type Wobble = Int\",\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/use_.rs",
    "content": "use crate::{assert_error, assert_infer, assert_module_error, assert_module_infer, assert_warning};\n\n#[test]\nfn arity_1() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use <- pair()\n  123\n}\n\nfn pair(f) {\n  let x = f()\n  #(x, x)\n}\n\"#,\n        vec![(\"main\", \"fn() -> #(Int, Int)\")],\n    )\n}\n\n#[test]\nfn arity_2() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use <- pair(1.0)\n  123\n}\n\nfn pair(x, f) {\n  let y = f()\n  #(x, y)\n}\n\"#,\n        vec![(\"main\", \"fn() -> #(Float, Int)\")],\n    )\n}\n\n#[test]\nfn arity_3() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use <- trip(1.0, \"\")\n  123\n}\n\nfn trip(x, y, f) {\n  let z = f()\n  #(x, y, z)\n}\n\"#,\n        vec![(\"main\", \"fn() -> #(Float, String, Int)\")],\n    )\n}\n\n#[test]\nfn call_is_variable() {\n    assert_infer!(\n        r#\"\nlet call = fn(f) { f() }\nuse <- call\n123\n\"#,\n        \"Int\"\n    );\n}\n\n#[test]\nfn call_is_literal() {\n    assert_infer!(\n        r#\"\nuse <- fn(f) { f() }\n123.0\n\"#,\n        \"Float\"\n    );\n}\n\n#[test]\nfn call_is_capture() {\n    assert_infer!(\n        r#\"\nlet f = fn(a, b) { a() + b }\nuse <- f(_, 123)\n123\n\"#,\n        \"Int\"\n    );\n}\n\n#[test]\nfn invalid_call_is_number() {\n    assert_error!(\n        r#\"\nuse <- 123\n123\n\"#\n    );\n}\n\n#[test]\nfn wrong_arity() {\n    assert_error!(\n        r#\"\nlet f = fn(callback) { callback(1, 2) }\nuse <- f\n123\n\"#\n    );\n}\n\n#[test]\nfn use_with_function_that_doesnt_take_callback_as_last_arg_1() {\n    assert_error!(\n        r#\"\nlet f = fn(a) { a + 1 }\nuse <- f\n123\n\"#\n    );\n}\n\n#[test]\nfn use_with_function_that_doesnt_take_callback_as_last_arg_2() {\n    assert_error!(\n        r#\"\nlet f = fn() { 1 }\nuse <- f\n123\n\"#\n    );\n}\n\n#[test]\nfn use_with_function_that_doesnt_take_callback_as_last_arg_3() {\n    assert_error!(\n        r#\"\nlet f = fn(a, b) { a + b }\nuse <- f(1)\n123\n\"#\n    );\n}\n\n#[test]\nfn wrong_arity_less_than_required() {\n    assert_error!(\n        r#\"\nlet f = fn(a, b) { 1 }\nuse <- f\n123\n\"#\n    );\n}\n\n#[test]\nfn wrong_arity_less_than_required_2() {\n    assert_error!(\n        r#\"\nlet f = fn(a, b, c) { 1 }\nuse <- f(1)\n123\n\"#\n    );\n}\n\n#[test]\nfn wrong_arity_more_than_required() {\n    assert_error!(\n        r#\"\nlet f = fn(a, b) { 1 }\nuse <- f(1, 2)\n123\n\"#\n    );\n}\n\n#[test]\nfn wrong_arity_more_than_required_2() {\n    assert_error!(\n        r#\"\nlet f = fn(a, b) { 1 }\nuse <- f(1, 2, 3)\n123\n\"#\n    );\n}\n\n#[test]\nfn no_callback_body() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  let thingy = fn(f) { f() }\n  use <- thingy()\n}\n\"#\n    );\n}\n\n#[test]\nfn invalid_callback_type() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { f() + 1 }\nuse <- x()\nNil\n\"#\n    );\n}\n\n#[test]\nfn invalid_callback_type_2() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f() }\nuse <- x()\nlet n = 1\nn + 2\n\"#\n    );\n}\n\n#[test]\nfn invalid_callback_type_3() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f() }\nlet y = fn(f) { 1 + f() }\nuse <- x()\nuse <- y()\nlet n = 1\nn + 1\n\"#\n    );\n}\n\n#[test]\nfn invalid_callback_type_4() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f() }\nlet y = fn(f) { 1 + f() }\nlet z = fn(f) { 1.0 +. f() }\nuse <- x()\nuse <- y()\nlet n = 1\nuse <- z()\n1.0\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arity() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f() }\nuse _ <- x()\n\"Giacomo!\"\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arity_2() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse <- x()\n\"Giacomo!\"\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arity_3() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse _, _ <- x()\n\"Giacomo!\"\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arg() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse n <- x()\nn <> \"Giacomo!\"\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arg_with_wrong_annotation() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { \"Hello, \" <> f(1) }\nuse n: String <- x()\nn <> \"Giacomo!\"\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arg_2() {\n    assert_module_error!(\n        r#\"\npub type Box {\n  Box(Int)\n}\n\npub fn main() {\n  let x = fn(f) { \"Hello, \" <> f(Box(1)) }\n  use Box(\"hi\") <- x()\n  \"Giacomo!\"\n}\n\"#\n    );\n}\n\n#[test]\nfn wrong_callback_arg_3() {\n    assert_module_error!(\n        r#\"\npub type Box {\n  Box(Int)\n}\n\npub fn main() {\n  let x = fn(f) { \"Hello, \" <> f(1) }\n  use Box(1) <- x()\n  \"Giacomo!\"\n}\n\"#\n    );\n}\n\n#[test]\nfn discard() {\n    assert_infer!(\n        r#\"\nlet x = fn(f) { f(123) }\nuse _ <- x()\nNil\n\"#,\n        \"Nil\",\n    );\n}\n\n#[test]\nfn discard_named() {\n    assert_infer!(\n        r#\"\nlet x = fn(f) { f(123) }\nuse _wibble <- x()\nNil\n\"#,\n        \"Nil\",\n    );\n}\n\n#[test]\nfn just_use_in_fn_body() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  use <- wibble()\n}\n\nfn wibble(f) {\n  f()\n}\n\"#\n    );\n}\n\n#[test]\nfn labels() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use x <- apply(arg: 1)\n  x\n}\n\nfn apply(fun fun, arg arg) {\n  fun(arg)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn patterns() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use Box(x) <- apply(Box(1))\n  x\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn multiple_patterns() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use Box(x), Box(y), Box(z) <- apply(Box(1))\n  x + y + z\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg, arg, arg)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn typed_pattern() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  use Box(x): Box(Int), Box(y), Box(z) <- apply(Box(1))\n  x + y + z\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg, arg, arg)\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn typed_pattern_wrong_type() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  use Box(x): Box(Bool), Box(y), Box(z) <- apply(Box(1))\n  x + y + z\n}\n\ntype Box(a) {\n  Box(a)\n}\n\nfn apply(arg, fun) {\n  fun(arg, arg, arg)\n}\n\"#\n    );\n}\n\n#[test]\nfn multiple_bad_statement_use_fault_tolerance() {\n    assert_error!(\n        r#\"\nlet x = fn(f) { f() + 1 }\nuse <- x()\n\n1 + 2.0\n3.0 + 4\n5\n\"#\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/version_inference.rs",
    "content": "use hexpm::version::Version;\n\nuse super::compile_module;\n\nfn infer_version(module: &str) -> Version {\n    compile_module(\"test_module\", module, None, vec![])\n        .expect(\"module to compile\")\n        .type_info\n        .minimum_required_version\n}\n\n#[test]\nfn internal_annotation_on_constant_requires_v1_1() {\n    let version = infer_version(\n        \"\n@internal\npub const wibble = 1\n\",\n    );\n    assert_eq!(version, Version::new(1, 1, 0));\n}\n\n#[test]\nfn internal_annotation_on_type_requires_v1_1() {\n    let version = infer_version(\n        \"\n@internal\npub type Wibble\n\",\n    );\n    assert_eq!(version, Version::new(1, 1, 0));\n}\n\n#[test]\nfn internal_annotation_on_function_requires_v1_1() {\n    let version = infer_version(\n        \"\n@internal\npub fn wibble() {}\n\",\n    );\n    assert_eq!(version, Version::new(1, 1, 0));\n}\n\n#[test]\nfn nested_tuple_access_requires_v1_1() {\n    let version = infer_version(\n        \"\npub fn main() {\n  let tuple = #(1, #(1, 1))\n  tuple.1.0\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 1, 0));\n}\n\n#[test]\nfn javascript_external_module_with_at_requires_v1_2() {\n    let version = infer_version(\n        \"\n@external(javascript, \\\"module@module\\\", \\\"func\\\")\npub fn main() {}\n\",\n    );\n    assert_eq!(version, Version::new(1, 2, 0));\n}\n\n#[test]\nfn int_plus_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1 + 1 == 2 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn float_plus_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1.0 +. 1.0 == 2.0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn int_minus_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1 - 1 == 0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn float_minus_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1.0 -. 1.0 == 0.0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn int_multiplication_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1 * 1 == 0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn float_multiplication_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1.0 *. 1.0 == 0.0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn int_divide_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1 / 1 == 0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn float_divide_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1.0 /. 1.0 == 0.0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn int_remainder_in_guards_requires_v1_3() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    _ if 1 % 1 == 0 -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 3, 0));\n}\n\n#[test]\nfn label_shorthand_in_constand_requires_v1_4() {\n    let version = infer_version(\n        \"\npub type Wibble { Wibble(wibble: Int) }\n\npub const wibble = 1\npub const wobble = Wibble(wibble:)\n\",\n    );\n    assert_eq!(version, Version::new(1, 4, 0));\n}\n\n#[test]\nfn label_shorthand_in_call_requires_v1_4() {\n    let version = infer_version(\n        \"\npub type Wibble { Wibble(wibble: Int) }\n\npub fn main() {\n  let wibble = 1\n  Wibble(wibble:)\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 4, 0));\n}\n\n#[test]\nfn label_shorthand_in_pattern_requires_v1_4() {\n    let version = infer_version(\n        \"\npub type Wibble { Wibble(wibble: Int) }\n\npub fn main() {\n  case Wibble(1) {\n    Wibble(wibble:) -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 4, 0));\n}\n\n#[test]\nfn label_shorthand_in_record_update_requires_v1_4() {\n    let version = infer_version(\n        \"\npub type Vec2 { Vec2(x: Int, y: Int) }\n\npub fn main() {\n  let x = 1\n  Vec2(..Vec2(0, 0), x:)\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 4, 0));\n}\n\n#[test]\nfn constant_string_concatenation_requires_v1_4() {\n    let version = infer_version(\"pub const string = \\\"wibble\\\" <> \\\"wobble\\\"\");\n    assert_eq!(version, Version::new(1, 4, 0));\n}\n\n#[test]\nfn missing_utf_8_option_in_bit_array_segment_requires_v1_5() {\n    let version = infer_version(\n        \"\npub fn main() {\n  <<\\\"hello\\\", \\\" world!\\\">>\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 5, 0));\n}\n\n#[test]\nfn missing_utf_8_option_in_bit_array_constant_segment_requires_v1_5() {\n    let version = infer_version(\"const bits = <<\\\"hello\\\", \\\" world!\\\">>\");\n    assert_eq!(version, Version::new(1, 5, 0));\n}\n\n#[test]\nfn missing_utf_8_option_in_bit_array_pattern_segment_requires_v1_5() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    <<\\\"hello\\\", \\\" world!\\\">> -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 5, 0));\n}\n\n#[test]\nfn missing_float_option_in_bit_array_segment_requires_v1_10() {\n    let version = infer_version(\n        \"\npub fn main() {\n  <<1.2>>\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 10, 0));\n}\n\n#[test]\nfn missing_float_option_in_bit_array_constant_segment_requires_v1_10() {\n    let version = infer_version(\"const bits = <<1.2>>\");\n    assert_eq!(version, Version::new(1, 10, 0));\n}\n\n#[test]\nfn missing_float_option_in_bit_array_pattern_segment_requires_v1_10() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    <<1.11>> -> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 10, 0));\n}\n\n#[test]\nfn const_record_update_requires_v1_14() {\n    let version = infer_version(\n        \"\npub type Wibble { Wibble(a: Int, b: Int) }\nconst base = Wibble(1, 2)\nconst wobble = Wibble(..base, a: 3)\n\",\n    );\n    assert_eq!(version, Version::new(1, 14, 0));\n}\n\n#[test]\nfn inference_picks_the_bigger_of_two_versions() {\n    let version = infer_version(\n        \"\npub fn main() {\n  case todo {\n    <<\\\"hello\\\", \\\" world!\\\">> -> todo\n    _ if 1 + 1 == 2-> todo\n    _ -> todo\n  }\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 5, 0));\n}\n\n#[test]\nfn inference_picks_the_bigger_of_two_versions_2() {\n    let version = infer_version(\n        \"\n@external(javascript, \\\"module@module\\\", \\\"func\\\")\npub fn main() {\n  let tuple = #(1, #(1, 1))\n  tuple.1.0\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 2, 0));\n}\n\n#[test]\nfn bool_assert_requires_v1_11() {\n    let version = infer_version(\n        \"\npub fn main() {\n  assert 1 != 2\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 11, 0));\n}\n\n#[test]\nfn expression_in_expression_segment_size_requires_v1_12() {\n    let version = infer_version(\n        \"\npub fn main() {\n  <<1:size(3 * 8)>>\n}\n\",\n    );\n    assert_eq!(version, Version::new(1, 12, 0));\n}\n\n#[test]\nfn expression_in_pattern_segment_size_requires_v1_12() {\n    let version = infer_version(\n        \"\npub fn main(x) {\n  case x {\n    <<_:size(3*8)>> -> 1\n    _ -> 2\n  }\n}\",\n    );\n    assert_eq!(version, Version::new(1, 12, 0));\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests/warnings.rs",
    "content": "use super::*;\nuse crate::{\n    assert_js_no_warnings, assert_js_warning, assert_no_warnings, assert_warning,\n    assert_warnings_with_gleam_version,\n};\n\n#[test]\nfn unknown_label() {\n    // https://github.com/gleam-lang/gleam/issues/1098\n    // calling function with unused labelled argument should not emit warnings\n    assert_no_warnings!(\n        r#\"fn greet(name name: String, title _title: String) { name }\n           pub fn main() { greet(name: \"Sam\", title: \"Mr\") }\"#,\n    );\n}\n\n#[test]\nfn todo_warning_test() {\n    assert_warning!(\"pub fn main() { 1 == todo }\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/1669\n#[test]\nfn todo_warning_correct_location() {\n    assert_warning!(\n        \"pub fn main() {\n        todo\n      }\"\n    );\n}\n\n#[test]\nfn todo_with_known_type() {\n    assert_warning!(\n        \"pub fn main() -> String {\n  todo\n}\"\n    );\n}\n\n#[test]\nfn empty_func_warning_test() {\n    assert_warning!(\n        \"pub fn main() { wibble() }\npub fn wibble() { }\n\"\n    );\n}\n\n#[test]\nfn warning_variable_never_used_test() {\n    assert_warning!(\n        \"\npub fn wibble() { Ok(5) }\npub fn main() { let five = wibble() }\"\n    );\n}\n\n#[test]\nfn warning_private_function_never_used() {\n    assert_warning!(\"fn main() { 5 }\");\n}\n\n#[test]\nfn warning_many_at_same_time() {\n    assert_warning!(\n        \"\nfn main() { let five = 5 }\"\n    );\n}\n\n#[test]\nfn result_discard_warning_test() {\n    // Implicitly discarded Results emit warnings\n    assert_warning!(\n        \"\npub fn wibble() { Ok(5) }\npub fn main() {\n  wibble()\n  5\n}\"\n    );\n}\n\n#[test]\nfn result_discard_warning_test2() {\n    // Explicitly discarded Results do not emit warnings\n    assert_no_warnings!(\n        \"\npub fn wibble() { Ok(5) }\npub fn main() { let _ = wibble() 5 }\",\n    );\n}\n\n#[test]\nfn unused_int() {\n    assert_warning!(\"pub fn main() { 1 2 }\");\n}\n\n#[test]\nfn unused_float() {\n    assert_warning!(\"pub fn main() { 1.0 2 }\");\n}\n\n#[test]\nfn unused_string() {\n    assert_warning!(\n        \"\n    pub fn main() {\n        \\\"1\\\"\n                2\n    }\"\n    );\n}\n\n#[test]\nfn unused_bit_array() {\n    assert_warning!(\n        \"\n    pub fn main() {\n        <<3>>\n\t\t\t\t2\n    }\"\n    );\n}\n\n#[test]\nfn unused_tuple() {\n    assert_warning!(\n        \"\n    pub fn main() {\n        #(1.0, \\\"Hello world\\\")\n\t\t\t\t2\n    }\"\n    );\n}\n\n#[test]\nfn unused_list() {\n    assert_warning!(\n        \"\n    pub fn main() {\n        [1, 2, 3]\n\t\t\t\t2\n    }\"\n    );\n}\n\n#[test]\nfn record_update_warnings_test() {\n    // Some fields are given in a record update do not emit warnings\n    assert_no_warnings!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person() {\n            let past = Person(\\\"Quinn\\\", 27)\n            let present = Person(..past, name: \\\"Santi\\\")\n            present\n        }\",\n    );\n}\n\n#[test]\nfn record_update_warnings_test2() {\n    // No fields are given in a record update emit warnings\n    assert_warning!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person() {\n            let past = Person(\\\"Quinn\\\", 27)\n            let present = Person(..past)\n            present\n        }\"\n    );\n}\n\n#[test]\nfn record_update_warnings_test3() {\n    // All fields given in a record update emits warnings\n    assert_warning!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person() {\n            let past = Person(\\\"Quinn\\\", 27)\n            let present = Person(..past, name: \\\"Quinn\\\", age: 28)\n            present\n        }\"\n    );\n}\n\n#[test]\nfn unused_private_type_warnings_test() {\n    // External type\n    assert_warning!(\"type X\");\n}\n\n#[test]\nfn unused_private_type_warnings_test2() {\n    assert_no_warnings!(\"pub type Y\");\n}\n\n#[test]\nfn unused_private_type_warnings_test3() {\n    // Type alias\n    assert_warning!(\"type X = Int\");\n}\n\n#[test]\nfn unused_private_type_warnings_test4() {\n    assert_no_warnings!(\"pub type Y = Int\");\n}\n\n#[test]\nfn unused_private_type_warnings_test5() {\n    assert_no_warnings!(\"type Y = Int pub fn run(x: Y) { x }\");\n}\n\n#[test]\nfn unused_private_type_warnings_test6() {\n    // Custom type\n    assert_warning!(\"type X { X }\");\n}\n\n#[test]\nfn unused_private_type_warnings_test7() {\n    assert_no_warnings!(\"pub type X { X }\");\n}\n\n#[test]\nfn unused_private_type_warnings_test8() {\n    assert_no_warnings!(\n        \"\ntype X { X }\n\npub fn a() {\n  let b = X\n  case b {\n    X -> 1\n  }\n}\"\n    );\n}\n\n#[test]\nfn unused_private_fn_warnings_test() {\n    assert_warning!(\"fn a() { 1 }\");\n}\n\n#[test]\nfn used_private_fn_warnings_test() {\n    assert_no_warnings!(\"pub fn a() { 1 }\");\n}\n\n#[test]\nfn used_private_fn_warnings_test2() {\n    assert_no_warnings!(\"fn a() { 1 } pub fn b() { a }\");\n}\n\n#[test]\nfn unused_private_const_warnings_test() {\n    assert_warning!(\"const a = 1\");\n}\n\n#[test]\nfn used_private_const_warnings_test() {\n    assert_no_warnings!(\"pub const a = 1\");\n}\n\n#[test]\nfn used_private_const_warnings_test2() {\n    assert_no_warnings!(\"const a = 1 pub fn b() { a }\");\n}\n\n#[test]\nfn unused_variable_warnings_test() {\n    // function argument\n    assert_warning!(\"pub fn a(b) { 1 }\");\n}\n\n#[test]\nfn used_variable_warnings_test() {\n    assert_no_warnings!(\"pub fn a(b) { b }\");\n}\n\n#[test]\nfn unused_variable_warnings_test2() {\n    // Simple let\n    assert_warning!(\"pub fn a() { let b = 1 5 }\");\n}\n\n#[test]\nfn used_variable_warnings_test2() {\n    assert_no_warnings!(\"pub fn a() { let b = 1 b }\");\n}\n\n#[test]\nfn unused_variable_shadowing_test() {\n    assert_warning!(\"pub fn a() { let b = 1 let b = 2 b }\");\n}\n\n#[test]\nfn used_variable_shadowing_test() {\n    assert_no_warnings!(\"pub fn a() { let b = 1 let b = b + 1 b }\");\n}\n\n#[test]\nfn unused_destructure() {\n    // Destructure\n    assert_warning!(\"pub fn a(b) { case b { #(c, _) -> 5 } }\");\n}\n\n#[test]\nfn used_destructure() {\n    assert_no_warnings!(\"pub fn a(b) { case b { #(c, _) -> c } }\");\n}\n\n#[test]\nfn unused_imported_module_warnings_test() {\n    assert_warning!(\n        (\"gleam/wibble\", \"pub fn wobble() { 1 }\"),\n        \"import gleam/wibble\"\n    );\n}\n\n#[test]\nfn unused_imported_module_with_alias_warnings_test() {\n    assert_warning!(\n        (\"gleam/wibble\", \"pub fn wobble() { 1 }\"),\n        \"import gleam/wibble as wobble\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2326\n#[test]\nfn unused_imported_module_with_alias_and_unqualified_name_warnings_test() {\n    assert_warning!(\n        (\"thepackage\", \"gleam/one\", \"pub fn two() { 1 }\"),\n        \"import gleam/one.{two} as three\"\n    );\n}\n\n#[test]\nfn unused_imported_module_with_alias_and_unqualified_name_no_warnings_test() {\n    assert_warning!(\n        (\"package\", \"gleam/one\", \"pub fn two() { 1 }\"),\n        \"import gleam/one.{two} as three\\npub fn wibble() { two() }\"\n    );\n}\n\n#[test]\nfn unused_imported_module_no_warning_on_used_function_test() {\n    assert_no_warnings!(\n        (\"thepackage\", \"gleam/wibble\", \"pub fn wobble() { 1 }\"),\n        \"import gleam/wibble pub fn wibble() { wibble.wobble() }\",\n    );\n}\n\n#[test]\nfn unused_imported_module_no_warning_on_used_type_test() {\n    assert_no_warnings!(\n        (\"thepackage\", \"gleam/wibble\", \"pub type Wibble = Int\"),\n        \"import gleam/wibble pub fn wibble(a: wibble.Wibble) { a }\",\n    );\n}\n\n#[test]\nfn unused_imported_module_no_warning_on_used_unqualified_function_test() {\n    assert_no_warnings!(\n        (\"thepackage\", \"gleam/wibble\", \"pub fn wobble() { 1 }\"),\n        \"import gleam/wibble.{wobble} pub fn wibble() { wobble() }\",\n    );\n}\n\n#[test]\nfn unused_imported_module_no_warning_on_used_unqualified_type_test() {\n    assert_no_warnings!(\n        (\"thepackage\", \"gleam/wibble\", \"pub type Wibble = Int\"),\n        \"import gleam/wibble.{type Wibble} pub fn wibble(a: Wibble) { a }\",\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3313\n#[test]\nfn imported_module_with_alias_no_warning_when_only_used_in_case_test() {\n    assert_no_warnings!(\n        (\n            \"thepackage\",\n            \"gleam/wibble\",\n            \"pub type Wibble { Wibble(Int) }\"\n        ),\n        \"import gleam/wibble as f\\npub fn wibble(a) { case a { f.Wibble(int) -> { int } }  }\",\n    );\n}\n\n#[test]\nfn module_access_registers_import_usage() {\n    assert_no_warnings!(\n        (\"thepackage\", \"gleam/bibble\", \"pub const bobble = 1\"),\n        \"import gleam/bibble pub fn main() { bibble.bobble }\",\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/978\n#[test]\nfn bit_pattern_var_use() {\n    assert_no_warnings!(\n        \"\npub fn main(x) {\n  let assert <<name_size:8, name:bytes-size(name_size)>> = x\n  name\n}\",\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/989\n#[test]\nfn alternative_case_clause_pattern_variable_usage() {\n    assert_no_warnings!(\n        \"\npub fn main(s) {\n  case s {\n    [a] | [a, _] -> a\n    _ -> 0\n  }\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1742\n#[test]\nfn imported_function_referenced_in_constant() {\n    assert_no_warnings!(\n        (\"thepackage\", \"one\", \"pub fn two() { 2 }\"),\n        \"\nimport one\n\npub const make_two = one.two\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1742\n#[test]\nfn imported_constructor_referenced_in_constant() {\n    assert_no_warnings!(\n        (\"thepackage\", \"one\", \"pub type Two { Two(Int) }\"),\n        \"\nimport one\n\npub const make_two = one.Two\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2050\n#[test]\nfn double_unary_integer_literal() {\n    assert_warning!(\"pub fn main() { let _ = --7 }\");\n}\n\n#[test]\nfn even_number_of_multiple_integer_negations_raise_a_single_warning() {\n    assert_warning!(\"pub fn main() { let _ = ----7 }\");\n}\n\n#[test]\nfn odd_number_of_multiple_integer_negations_raise_a_single_warning_that_highlights_the_unnecessary_ones()\n {\n    assert_warning!(\"pub fn main() { let _ = -----7 }\");\n}\n\n#[test]\nfn even_number_of_multiple_bool_negations_raise_a_single_warning() {\n    assert_warning!(\"pub fn main() { let _ = !!!!True }\");\n}\n\n#[test]\nfn odd_number_of_multiple_bool_negations_raise_a_single_warning_that_highlights_the_unnecessary_ones()\n {\n    assert_warning!(\"pub fn main() { let _ = !!!!!False }\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/2050\n#[test]\nfn double_unary_integer_variable() {\n    assert_warning!(\n        r#\"\n        pub fn main() {\n            let x = 7\n            let _ = --x\n        }\n        \"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2050\n#[test]\nfn double_unary_bool_literal() {\n    assert_warning!(\"pub fn main() { let _ = !!True }\");\n}\n\n// https://github.com/gleam-lang/gleam/issues/2050\n#[test]\nfn double_unary_bool_variable() {\n    assert_warning!(\n        r#\"\n        pub fn main() {\n            let x = True\n            let _ = !!x\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_list_length_eq_0() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) == 0\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_list_length_eq_negative_0() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) == -0\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_0_eq_list_length() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 == list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_negative_0_eq_list_length() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = -0 == list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_list_length_not_eq_0() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) != 0\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_0_not_eq_list_length() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 != list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_list_length_lt_eq_0() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) <= 0\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn prefer_list_is_empty_over_list_length_lt_1() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) < 1\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/4861\n#[test]\nfn prefer_list_is_empty_over_list_length_gt_negative_0() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) > 0\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/4861\n#[test]\nfn prefer_list_is_empty_over_negative_0_lt_list_length() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 < list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/4861\n#[test]\nfn prefer_list_is_empty_over_list_length_gt_0() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) > 0\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/4861\n#[test]\nfn prefer_list_is_empty_over_0_lt_list_length() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 0 < list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn allow_list_length_eq_1() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) == 1\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn allow_1_eq_list_length() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 1 == list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn allow_list_length_eq_3() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) == 3\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn allow_1_lt_list_length() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = 1 < list.length(a_list)\n        }\n        \"#\n    );\n}\n\n/// https://github.com/gleam-lang/gleam/issues/2067\n#[test]\nfn allow_list_length_gt_1() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/list\",\n            \"pub fn length(_list: List(a)) -> Int { 0 }\"\n        ),\n        r#\"\n        import gleam/list\n\n        pub fn main() {\n            let a_list = []\n            let _ = list.length(a_list) > 1\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unused_external_function_arguments() {\n    // https://github.com/gleam-lang/gleam/issues/2259\n    assert_no_warnings!(\n        r#\"\n@external(erlang, \"go\", \"go\")\npub fn go(a: item_a) -> Nil\n\"#,\n    );\n}\n\n#[test]\nfn importing_non_direct_dep_package() {\n    // Warn if an imported module is from a package that is not a direct dependency\n    assert_warning!(\n        // Magic string package name that the test setup will detect to not\n        // register this package as a dep.\n        (\"non-dependency-package\", \"some_module\", \"pub const x = 1\"),\n        r#\"\nimport some_module\npub const x = some_module.x\n        \"#\n    );\n}\n\n#[test]\nfn deprecated_constant() {\n    assert_warning!(\n        r#\"\n@deprecated(\"Don't use this!\")\npub const a = Nil\n\npub fn b() {\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_imported_constant() {\n    assert_warning!(\n        (\n            \"package\",\n            \"module\",\n            r#\"@deprecated(\"Don't use this!\") pub const a = Nil\"#\n        ),\n        r#\"\nimport module\n\npub fn a() {\n  module.a\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_imported_unqualified_constant() {\n    assert_warning!(\n        (\n            \"package\",\n            \"module\",\n            r#\"@deprecated(\"Don't use this!\") pub const a = Nil\"#\n        ),\n        r#\"\nimport module.{a}\n\npub fn b() {\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_function() {\n    assert_warning!(\n        r#\"\n@deprecated(\"Don't use this!\")\npub fn a() {\n  Nil\n}\n\npub fn b() {\n  a\n}\n        \"#\n    );\n}\n\n#[test]\nfn deprecated_imported_function() {\n    assert_warning!(\n        (\n            \"package\",\n            \"module\",\n            r#\"@deprecated(\"Don't use this!\") pub fn a() { Nil }\"#\n        ),\n        r#\"\nimport module\n\npub fn a() {\n  module.a\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_imported_call_function() {\n    assert_warning!(\n        (\n            \"package\",\n            \"module\",\n            r#\"@deprecated(\"Don't use this!\") pub fn a() { Nil }\"#\n        ),\n        r#\"\nimport module\n\npub fn a() {\n  module.a()\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_imported_unqualified_function() {\n    assert_warning!(\n        (\n            \"package\",\n            \"module\",\n            r#\"@deprecated(\"Don't use this!\") pub fn a() { Nil }\"#\n        ),\n        r#\"\nimport module.{a}\n\npub fn b() {\n  a\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_type_used_in_alias() {\n    assert_warning!(\n        r#\"\n@deprecated(\"Don't use this!\")\npub type Cat {\n    Cat(name: String)\n}\n\npub type Dog = Cat\n        \"#\n    );\n}\n\n#[test]\nfn deprecated_type_used_as_arg() {\n    assert_warning!(\n        r#\"\n@deprecated(\"Don't use this!\")\npub type Cat {\n    Cat(name: String)\n}\n\npub fn cat_name(cat: Cat) {\n  cat.name\n}\n        \"#\n    );\n}\n\n#[test]\nfn deprecated_type_used_as_case_clause() {\n    assert_warning!(\n        r#\"\n@deprecated(\"The type Animal has been deprecated.\")\npub type Animal {\n    Cat\n    Dog\n}\n\npub fn sound(animal) -> String {\n  case animal {\n    Dog -> \"Woof\"\n    Cat -> \"Meow\"\n  }\n}\n\npub fn main(){\n    let cat = Cat\n    sound(cat)\n}\n        \"#\n    );\n}\n\n#[test]\nfn const_bytes_option() {\n    assert_no_warnings!(\"pub const x = <<<<>>:bits>>\");\n}\n\n#[test]\nfn unused_module_wuth_alias_warning_test() {\n    assert_warning!(\n        (\"gleam/wibble\", \"pub const one = 1\"),\n        \"import gleam/wibble as wobble\"\n    );\n}\n\n#[test]\nfn unused_alias_warning_test() {\n    assert_warning!(\n        (\"gleam/wibble\", \"pub const one = 1\"),\n        r#\"\n            import gleam/wibble.{one} as wobble\n            pub const one = one\n        \"#,\n    );\n}\n\n#[test]\nfn used_type_with_import_alias_no_warning_test() {\n    assert_no_warnings!(\n        (\"gleam\", \"gleam/wibble\", \"pub const one = 1\"),\n        \"import gleam/wibble as _wobble\"\n    );\n}\n\n#[test]\nfn discarded_module_no_warnings_test() {\n    assert_no_warnings!(\n        (\"gleam\", \"wibble\", \"pub const one = 1\"),\n        \"import wibble as _wobble\"\n    );\n}\n\n#[test]\nfn unused_alias_for_duplicate_module_no_warning_for_alias_test() {\n    assert_warning!(\n        (\"a/wibble\", \"pub const one = 1\"),\n        (\"b/wibble\", \"pub const two = 2\"),\n        r#\"\n            import a/wibble\n            import b/wibble as wobble\n            pub const one = wibble.one\n        \"#,\n    );\n}\n\n#[test]\nfn result_in_case_discarded() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  case x {\n    _ -> Error(Nil)\n  }\n  Nil\n}\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_tuple() {\n    assert_warning!(\n        \"pub fn main() {\n        case #(1, 2) {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_multiple_literal_tuples() {\n    assert_warning!(\n        \"pub fn main() {\n        let wibble = 1\n        case #(1, 2), #(wibble, wibble) {\n            _, _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_tuples_doesnt_raise_a_warning() {\n    assert_no_warnings!(\n        \"pub fn main() {\n        let wibble = #(1, 2)\n        // This doesn't raise a warning since `wibble` is not a literal tuple.\n        case wibble {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_empty_tuple() {\n    assert_warning!(\n        \"pub fn main() {\n        case #() {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_list() {\n    assert_warning!(\n        \"pub fn main() {\n        case [1, 2] {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_list_with_tail() {\n    assert_warning!(\n        \"pub fn main() {\n        case [1, 2, ..[]] {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_empty_list() {\n    assert_warning!(\n        \"pub fn main() {\n        case [] {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_empty_bit_array() {\n    assert_warning!(\n        \"pub fn main() {\n        case <<>> {\n            _ -> Nil\n        }\n      }\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_record() {\n    assert_warning!(\n        \"\npub type Wibble { Wibble(Int) }\npub fn main() {\n  let n = 1\n  case Wibble(n) {\n    _ -> Nil\n  }\n}\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_record_with_no_args() {\n    assert_warning!(\n        \"\npub type Wibble { Wibble }\npub fn main() {\n  case Wibble {\n    _ -> Nil\n  }\n}\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_int() {\n    assert_warning!(\n        \"\npub type Wibble { Wibble }\npub fn main() {\n  case 1 {\n    _ -> Nil\n  }\n}\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_float() {\n    assert_warning!(\n        \"\npub type Wibble { Wibble }\npub fn main() {\n  case 1.0 {\n    _ -> Nil\n  }\n}\"\n    );\n}\n\n#[test]\nfn pattern_matching_on_literal_string() {\n    assert_warning!(\n        \"\npub type Wibble { Wibble }\npub fn main() {\n  case \\\"hello\\\" {\n    _ -> Nil\n  }\n}\"\n    );\n}\n\n#[test]\nfn opaque_external_type_raises_a_warning() {\n    assert_warning!(\"pub opaque type External\");\n}\n\n#[test]\nfn unused_binary_operation_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  let string = \"a\" <> \"b\" \"c\" <> \"d\"\n  string\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_record_access_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub type Thing {\n  Thing(value: Int)\n}\n\npub fn main() {\n  let thing = Thing(1)\n  thing.value\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_record_constructor_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub type Thing {\n  Thing(value: Int)\n}\n\npub fn main() {\n  Thing(1)\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_record_update_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub type Thing {\n  Thing(value: Int, other: Int)\n}\n\npub fn main() {\n  let thing = Thing(1, 2)\n  Thing(..thing, value: 1)\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_variable_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  let number = 1\n  number\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_function_literal_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  fn(n) { n + 1 }\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_tuple_index_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  #(1, 2).0\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_bool_negation_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  !True\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_int_negation_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  -1\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_pipeline_ending_with_variant_raises_a_warning() {\n    assert_warning!(\n        r#\"\npub type Wibble(a) { Wibble(a) }\npub fn wibble(a) { a }\n\npub fn main() {\n  1 |> wibble |> Wibble\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_pipeline_ending_with_variant_raises_a_warning_2() {\n    assert_warning!(\n        (\"wibble\", \"pub type Wibble { Wibble(Int) }\"),\n        r#\"\nimport wibble\n\npub fn wobble(a) { a }\n\npub fn main() {\n  1 |> wobble |> wibble.Wibble\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_pipeline_not_ending_with_variant_raises_no_warnings() {\n    assert_no_warnings!(\n        r#\"\npub type Wibble(a) { Wibble(a) }\npub fn wibble(a) { echo a }\n\npub fn main() {\n  1 |> wibble |> wibble\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_module_select_constructor() {\n    assert_warning!(\n        (\"wibble\", \"pub type Wibble { Wibble(Int) }\"),\n        r#\"\nimport wibble\n\npub fn main() {\n  wibble.Wibble\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_module_select_constructor_call() {\n    assert_warning!(\n        (\"wibble\", \"pub type Wibble { Wibble(Int) }\"),\n        r#\"\nimport wibble\n\npub fn main() {\n  wibble.Wibble(1)\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_module_select_function() {\n    assert_warning!(\n        (\"wibble\", \"pub fn println(a) { Nil }\"),\n        r#\"\nimport wibble\n\npub fn main() {\n  wibble.println\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_module_select_const() {\n    assert_warning!(\n        (\"wibble\", \"pub const a = 1\"),\n        r#\"\nimport wibble\n\npub fn main() {\n  wibble.a\n  1\n}\n\"#\n    );\n}\n\n#[test]\nfn module_used_by_unused_function_is_not_marked_as_unused() {\n    assert_warning!(\n        (\"wibble\", \"pub const a = 1\"),\n        \"import wibble\nfn wobble() {\n  wibble.a\n}\n\"\n    );\n}\n\n#[test]\nfn aliased_module_used_by_unused_function_is_not_marked_as_unused() {\n    assert_warning!(\n        (\"wibble\", \"pub const a = 1\"),\n        \"import wibble as woo\nfn wobble() {\n  woo.a\n}\n\"\n    );\n}\n\n#[test]\nfn calling_function_from_other_module_is_not_marked_unused() {\n    assert_no_warnings!(\n        (\"wibble\", \"wibble\", \"pub fn println(a) { panic }\"),\n        r#\"\nimport wibble\n\npub fn main() {\n  wibble.println(\"hello!\")\n  1\n}\n\"#\n    );\n}\n\n/*\n\nTODO: These tests are commented out until we figure out a better way to deal\n      with reexports of internal types and reintroduce the warning.\n      As things stand it would break both Lustre and Mist.\n      You can see the thread starting around here for more context:\n      https://discord.com/channels/768594524158427167/768594524158427170/1227250677734969386\n\n#[test]\nfn internal_type_in_public_function_return() {\n    assert_warning!(\n        \"\n@internal\npub type Wibble {\n  Wibble\n}\n\npub fn wibble() -> Wibble { Wibble }\n\"\n    );\n}\n\n#[test]\nfn type_from_internal_module_in_public_function_return() {\n    assert_warning!(\n        (\"thepackage/internal\", \"pub type Wibble { Wibble }\"),\n        \"\nimport thepackage/internal.{type Wibble, Wibble}\n\npub fn wibble() -> Wibble {\n  Wibble\n}\"\n    );\n}\n\n#[test]\nfn internal_type_in_public_function_argument() {\n    assert_warning!(\n        \"\n@internal\npub type Wibble {\n  Wibble\n}\n\npub fn wibble(_wibble: Wibble) -> Int { 1 }\n\"\n    );\n}\n\n#[test]\nfn type_from_internal_module_in_public_function_argument() {\n    assert_warning!(\n        (\"thepackage/internal\", \"pub type Wibble { Wibble }\"),\n        \"\nimport thepackage/internal.{type Wibble}\n\npub fn wibble(_wibble: Wibble) -> Int {\n  1\n}\n\"\n    );\n}\n\n#[test]\nfn internal_type_in_public_constructor() {\n    assert_warning!(\n        \"\n@internal\npub type Wibble {\n  Wibble\n}\n\npub type Wobble {\n    Wobble(Wibble)\n}\n\"\n    );\n}\n\n#[test]\nfn type_from_internal_module_in_public_constructor() {\n    assert_warning!(\n        (\"thepackage/internal\", \"pub type Wibble { Wibble }\"),\n        \"\nimport thepackage/internal.{type Wibble}\n\npub type Wobble {\n  Wobble(Wibble)\n}\"\n    );\n}\n\n#[test]\nfn type_from_internal_module_dependency_in_public_constructor() {\n    assert_warning!(\n        (\"dep\", \"dep/internal\", \"pub type Wibble { Wibble }\"),\n        \"\nimport dep/internal.{type Wibble}\n\npub type Wobble {\n  Wobble(Wibble)\n}\"\n    );\n}\n\n*/\n\n#[test]\nfn redundant_let_assert() {\n    assert_warning!(\n        \"\npub fn main() {\n  let assert wibble = [1, 2, 3]\n  wibble\n}\n\"\n    );\n}\n\n#[test]\nfn redundant_let_assert_on_custom_type() {\n    assert_warning!(\n        \"\npub type Wibble {\n    Wibble(Int, Bool)\n}\n\npub fn main() {\n  let assert Wibble(_, bool) = Wibble(1, True)\n  bool\n}\n\"\n    );\n}\n\n#[test]\nfn panic_used_as_function() {\n    assert_warning!(\n        \"pub fn main() {\n          panic()\n        }\"\n    );\n}\n\n#[test]\nfn panic_used_as_function_2() {\n    assert_warning!(\n        \"pub fn main() {\n          panic(1)\n        }\"\n    );\n}\n\n#[test]\nfn panic_used_as_function_3() {\n    assert_warning!(\n        \"pub fn main() {\n          panic(1, Nil)\n        }\"\n    );\n}\n\n#[test]\nfn todo_used_as_function() {\n    assert_warning!(\n        \"pub fn main() {\n          todo()\n        }\"\n    );\n}\n\n#[test]\nfn todo_used_as_function_2() {\n    assert_warning!(\n        \"pub fn main() {\n          todo(1)\n        }\"\n    );\n}\n\n#[test]\nfn todo_used_as_function_3() {\n    assert_warning!(\n        \"pub fn main() {\n          todo(1, Nil)\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_warning_1() {\n    assert_warning!(\n        \"pub fn main() {\n          panic\n          1\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_warning_2() {\n    assert_warning!(\n        \"pub fn main() {\n          let _ = panic\n          1\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_warning_if_all_branches_panic() {\n    assert_warning!(\n        \"pub fn main() {\n          let n = 1\n          case n {\n            0 -> panic\n            _ -> panic\n          }\n          1\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_warning_if_all_branches_panic_2() {\n    assert_warning!(\n        \"pub fn main() {\n          let n = 1\n          case n {\n            0 -> {\n              panic\n              2\n            }\n            _ -> panic\n          }\n          1\n        }\"\n    );\n}\n\n#[test]\nfn no_unreachable_warning_if_at_least_a_branch_is_reachable() {\n    assert_no_warnings!(\n        \"pub fn main() {\n          let n = 1\n          case n {\n            0 -> panic\n            _ -> 1\n          }\n          1\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_warning_doesnt_escape_out_of_a_block_if_panic_is_not_last() {\n    assert_warning!(\n        \"pub fn main() {\n          let n = {\n            panic\n            1\n          }\n          n\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_warning_on_following_expression_if_panic_is_last_in_a_block() {\n    assert_warning!(\n        \"pub fn main() {\n          let _ = {\n            panic\n          }\n          1\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_function_argument_if_panic_is_argument() {\n    assert_warning!(\n        \"\n        pub fn wibble(_, _) { 1 }\n        pub fn main() {\n          wibble(panic, 1)\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_function_call_if_panic_is_last_argument_1() {\n    assert_warning!(\n        \"\n        pub fn wibble(_, _) { 1 }\n        pub fn main() {\n          wibble(1, panic)\n          1\n        }\"\n    );\n}\n\n#[test]\nfn unreachable_function_call_if_panic_is_last_argument_2() {\n    assert_warning!(\n        \"\n        pub fn wibble(_, _) { 1 }\n        pub fn main() {\n          wibble(1, panic)\n        }\"\n    );\n}\n\n#[test]\nfn no_unreachable_warning_if_panic_comes_last_in_function_body() {\n    assert_no_warnings!(\n        \"\n        pub fn wibble() { panic }\n        pub fn main() { panic }\"\n    );\n}\n\n#[test]\nfn unreachable_code_for_panic_as_first_pipeline_item() {\n    assert_warning!(\n        \"\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            panic |> wibble\n        }\n        \"\n    );\n}\n\n#[test]\nfn panic_used_as_function_inside_pipeline() {\n    assert_warning!(\n        \"\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            1 |> panic |> wibble\n        }\n        \"\n    );\n}\n\n#[test]\nfn unreachable_warning_for_panic_as_last_item_of_pipe_on_next_expression() {\n    assert_warning!(\n        r#\"\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            1 |> wibble |> panic\n            \"unreachable\"\n        }\n        \"#\n    );\n}\n\n#[test]\nfn doesnt_warn_twice_for_unreachable_code_if_has_already_warned_in_a_block_1() {\n    assert_warning!(\n        r#\"\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            panic\n            let _ = \"unreachable\" // warning here\n            panic\n            \"no warning here!\"\n        }\n        \"#\n    );\n}\n\n#[test]\nfn doesnt_warn_twice_for_unreachable_code_if_has_already_warned_in_a_block_2() {\n    assert_warning!(\n        r#\"\n        pub fn main() {\n            let _ = {\n              panic\n              1 // warning here\n            }\n            \"no warning here!\"\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unreachable_use_after_panic() {\n    assert_warning!(\n        r#\"\n        pub fn wibble(_) { 1 }\n        pub fn main() {\n            panic\n            use <- wibble\n            1\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unreachable_code_after_case_subject_panics_1() {\n    assert_warning!(\n        r#\"\n        pub fn main(a, b) {\n            case a, panic, b {\n                _, _, _ -> \"no warning here!\"\n            }\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unreachable_code_after_case_subject_panics_2() {\n    assert_warning!(\n        r#\"\n        pub fn main(a, b) {\n            case a, b, panic {\n                _, _, _ -> \"no warning here!\"\n            }\n            \"warning here!\"\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unreachable_code_analysis_treats_anonymous_functions_independently_1() {\n    assert_no_warnings!(\n        r#\"\n        pub fn main() {\n            let _ = fn() {\n              panic\n            }\n            \"no warning here!\"\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unreachable_code_analysis_treats_anonymous_functions_independently_2() {\n    assert_warning!(\n        r#\"\n        pub fn main() {\n            let _ = fn() {\n              panic\n              \"warning here!\"\n            }\n            panic\n            \"warning here!\"\n        }\n        \"#\n    );\n}\n\n#[test]\nfn unreachable_code_analysis_treats_anonymous_functions_independently_3() {\n    assert_warning!(\n        r#\"\n        pub fn main() {\n            panic\n            let _ = \"warning here!\"\n            let _ = fn() {\n              panic\n              \"warning here!\"\n            }\n        }\n        \"#\n    );\n}\n\n#[test]\nfn no_warnings_for_matches_used_like_ifs() {\n    assert_no_warnings!(\n        r#\"\n    pub fn main() {\n        case True {\n          _ if True -> 1\n          _ -> 2\n        }\n    }\n        \"#\n    );\n}\n\n#[test]\nfn no_warnings_for_matches_used_like_ifs_2() {\n    assert_no_warnings!(\n        r#\"\n    pub fn main() {\n        case 1 {\n          _ if True -> 1\n          _ -> 2\n        }\n    }\n        \"#\n    );\n}\n\n#[test]\nfn warnings_for_matches_on_literal_values_that_are_not_like_an_if_1() {\n    assert_warning!(\n        r#\"\n    pub fn main() {\n        case True {\n          _ -> 1\n        }\n    }\n        \"#\n    );\n}\n\n#[test]\nfn warnings_for_matches_on_literal_values_that_are_not_like_an_if_2() {\n    assert_warning!(\n        r#\"\n    pub fn main() {\n        case True {\n          True -> 1\n        }\n    }\n        \"#\n    );\n}\n\n#[test]\nfn redundant_function_capture_in_pipe_1() {\n    assert_warning!(\n        \"\n  pub fn wibble(_, _) { 1 }\n\n  pub fn main() {\n    1 |> wibble(_, 2) |> wibble(2)\n  }\n\"\n    );\n}\n\n#[test]\nfn redundant_function_capture_in_pipe_2() {\n    assert_warning!(\n        \"\n  pub fn wobble(_) { 1 }\n\n  pub fn main() {\n    1 |> wobble(_) |> wobble\n  }\n\"\n    );\n}\n\n#[test]\nfn redundant_function_capture_in_pipe_3() {\n    assert_warning!(\n        \"\n  pub fn wobble(_) { 1 }\n\n  pub fn main() {\n    1 |> wobble |> wobble(_)\n  }\n\"\n    );\n}\n\n#[test]\nfn redundant_function_capture_in_pipe_4() {\n    assert_warning!(\n        \"\n  pub fn wibble(_, _) { 1 }\n\n  pub fn main() {\n    1 |> wibble(2) |> wibble(_, 2)\n  }\n\"\n    );\n}\n\n#[test]\nfn redundant_function_capture_in_pipe_5() {\n    assert_no_warnings!(\n        \"\n  pub fn wibble(_, _) { 1 }\n\n  pub fn main() {\n    1 |> wibble(2, _)\n  }\n\"\n    );\n}\n\n#[test]\nfn deprecated_list_append_syntax() {\n    assert_warning!(\n        r#\"\n    pub fn main() {\n      let letters = [\"b\", \"c\"]\n      [\"a\"..letters]\n    }\n        \"#\n    );\n}\n\n#[test]\nfn deprecated_list_pattern_syntax() {\n    assert_warning!(\n        r#\"\n    pub fn main() {\n      let letters = [\"b\", \"c\"]\n      case letters {\n        [\"a\"..rest] -> rest\n        _ -> []\n      }\n    }\n        \"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3383\n#[test]\nfn deprecated_list_pattern_syntax_1() {\n    assert_warning!(\n        r#\"\n    pub fn main() {\n      let letters = [\"b\", \"c\"]\n      case letters {\n        [] -> []\n        [..] -> []\n      }\n    }\n        \"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3473\n#[test]\nfn deprecated_record_pattern_syntax() {\n    assert_warning!(\n        r#\"\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one: one ..) -> one\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_record_pattern_syntax_with_no_labels() {\n    assert_warning!(\n        r#\"\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one ..) -> one\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_record_pattern_syntax_with_label_shorthand() {\n    assert_warning!(\n        r#\"\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one: ..) -> one\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_record_pattern_syntax_has_no_warning_if_everything_is_discarded() {\n    assert_no_warnings!(\n        r#\"\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(..) -> 1\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_record_pattern_syntax_has_no_warning_if_there_is_a_comma_before_spread() {\n    assert_no_warnings!(\n        r#\"\npub type Wibble {\n  Wibble(one: Int, two: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(one: 1, two: 2)\n  case wibble {\n    Wibble(one: one, ..) -> one\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_label_shorthand_pattern_arg() {\n    assert_warning!(\n        r#\"\npub type Wibble { Wibble(arg1: Int, arg2: Bool ) }\n\npub fn main() {\n  let Wibble(arg1:, arg2:) = Wibble(1, True)\n  arg1\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_label_shorthand_pattern_arg_shadowing() {\n    assert_warning!(\n        r#\"\npub type Wibble { Wibble(arg1: Int, arg2: Bool ) }\n\npub fn main() {\n  let Wibble(arg1:, arg2:) = Wibble(1, True)\n  let arg1 = False\n  arg1\n}\n\"#\n    );\n}\n\n#[test]\nfn internal_annotation_on_constant_requires_v1_1() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\n@internal\npub const wibble = 1\n\",\n    );\n}\n\n#[test]\nfn internal_annotation_on_type_requires_v1_1() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\n@internal\npub type Wibble\n\",\n    );\n}\n\n#[test]\nfn internal_annotation_on_function_requires_v1_1() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\n@internal\npub fn wibble() { Nil }\n\",\n    );\n}\n\n#[test]\nfn nested_tuple_access_requires_v1_1() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  let tuple = #(1, #(1, 1))\n  tuple.1.0\n}\n\",\n    );\n}\n\n#[test]\nfn javascript_external_module_with_at_requires_v1_2() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\n@external(javascript, \\\"module@module\\\", \\\"func\\\")\npub fn main() { Nil }\n\",\n    );\n}\n\n#[test]\nfn int_plus_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n    _ if 1 + 1 == 2 -> Nil\n    _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn float_plus_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n    _ if 1.0 +. 1.0 == 2.0 -> Nil\n    _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn int_minus_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n    _ if 1 - 1 == 0 -> Nil\n    _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn float_minus_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n    _ if 1.0 -. 1.0 == 0.0 -> Nil\n    _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn int_multiplication_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n  _ if 1 * 1 == 0 -> Nil\n  _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn float_multiplication_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n  _ if 1.0 *. 1.0 == 0.0 -> Nil\n  _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn int_divide_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n  _ if 1 / 1 == 0 -> Nil\n  _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn float_divide_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n  _ if 1.0 /. 1.0 == 0.0 -> Nil\n  _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn int_remainder_in_guards_requires_v1_3() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  case Nil {\n  _ if 1 % 1 == 0 -> Nil\n  _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn label_shorthand_in_constand_requires_v1_4() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub type Wibble { Wibble(wibble: Int) }\n\npub const wibble = 1\npub const wobble = Wibble(wibble:)\n\",\n    );\n}\n\n#[test]\nfn label_shorthand_in_call_requires_v1_4() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub type Wibble { Wibble(wibble: Int) }\n\npub fn main() {\n  let wibble = 1\n  Wibble(wibble:)\n}\n\",\n    );\n}\n\n#[test]\nfn label_shorthand_in_pattern_requires_v1_4() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub type Wibble { Wibble(wibble: Int) }\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(wibble:) -> wibble\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn constant_string_concatenation_requires_v1_4() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"pub const string = \\\"wibble\\\" <> \\\"wobble\\\"\"\n    );\n}\n\n#[test]\nfn missing_utf_8_option_in_bit_array_segment_requires_v1_5() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  <<\\\"hello\\\">>\n}\n\",\n    );\n}\n\n#[test]\nfn missing_utf_8_option_in_bit_array_constant_segment_requires_v1_5() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"pub const bits = <<\\\"hello\\\">>\"\n    );\n}\n\n#[test]\nfn missing_utf_8_option_in_bit_array_pattern_segment_requires_v1_5() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main(a) {\n  case a {\n    <<\\\"hello\\\">> -> Nil\n    _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn missing_float_option_in_bit_array_segment_requires_v1_10() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  <<1.2>>\n}\n\",\n    );\n}\n\n#[test]\nfn missing_float_option_in_bit_array_constant_segment_requires_v1_10() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"pub const bits = <<1.2>>\"\n    );\n}\n\n#[test]\nfn missing_float_option_in_bit_array_pattern_segment_requires_v1_10() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main(a) {\n  case a {\n    <<1.2>> -> Nil\n    _ -> Nil\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn record_update_variant_inference_requires_v1_6() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(..) -> Wibble(..wibble, b: 10)\n    Wobble(..) -> panic\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn record_access_variant_inference_requires_v1_6() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(..) -> wibble.b\n    Wobble(..) -> wibble.c\n  }\n}\n\",\n    );\n}\n\n#[test]\nfn let_assert_with_message_requires_v1_7() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        r#\"\npub fn main() {\n  let assert Ok(10) = Ok(20) as \"This will crash...\"\n}\n\"#,\n    );\n}\n\n#[test]\nfn bool_assert_requires_v1_11() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn go(x) {\n  assert x == 2\n}\n\",\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_decimal() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  [\n    9_007_199_254_740_990,\n    9_007_199_254_740_991,\n    9_007_199_254_740_992,\n    -9_007_199_254_740_990,\n    -9_007_199_254_740_991,\n    -9_007_199_254_740_992,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_binary() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  [\n    0b11111111111111111111111111111111111111111111111111110,\n    0b11111111111111111111111111111111111111111111111111111,\n    0b100000000000000000000000000000000000000000000000000000,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_octal() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  [\n    0o377777777777777776,\n    0o377777777777777777,\n    0o400000000000000000,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_hex() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  [\n    0x1FFFFFFFFFFFFE,\n    0x1FFFFFFFFFFFFF,\n    0x20000000000000,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_in_tuple() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  #(9_007_199_254_740_992)\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_segment_in_bit_array() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  <<9_007_199_254_740_992:64>>\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_segment_size_in_bit_array() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  [\n    <<0:9_007_199_254_740_992>>,\n    <<0:size(9_007_199_254_740_992)>>,\n  ]\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_in_const() {\n    assert_js_warning!(r#\"pub const i = 9_007_199_254_740_992\"#);\n}\n\n#[test]\nfn javascript_unsafe_int_in_const_tuple() {\n    assert_js_warning!(r#\"pub const i = #(9_007_199_254_740_992)\"#);\n}\n\n#[test]\nfn javascript_unsafe_int_segment_in_const_bit_array() {\n    assert_js_warning!(\n        r#\"\npub const i = <<9_007_199_254_740_992:64>>\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_segment_size_in_const_bit_array() {\n    assert_js_warning!(\n        r#\"\npub const ints = [\n  <<0:9_007_199_254_740_992>>,\n  <<0:size(9_007_199_254_740_992)>>,\n]\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_in_pattern() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  let assert <<9_007_199_254_740_992:64>> = <<>>\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_segment_size_in_pattern() {\n    assert_js_warning!(\n        r#\"\npub fn go() {\n  let assert <<0:9_007_199_254_740_992>> = <<>>\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_with_external_implementation() {\n    assert_js_no_warnings!(\n        r#\"\n@external(javascript, \"./test.mjs\", \"go\")\npub fn go() -> Int {\n  9_007_199_254_740_992\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_segment_in_pattern_with_external_implementation() {\n    assert_js_no_warnings!(\n        r#\"\n@external(javascript, \"./test.mjs\", \"go\")\npub fn go(b: BitArray) -> BitArray {\n  let assert <<0xFFF0000000000000:64>> = b\n}\n\"#\n    );\n}\n\n#[test]\nfn javascript_unsafe_int_with_external_function_call() {\n    assert_js_warning!(\n        r#\"\npub fn main() {\n  helper() + 9_007_199_254_740_992\n}\n\n@external(javascript, \"a\", \"b\")\nfn helper() -> Int\n\"#\n    );\n}\n\n#[test]\nfn incomplete_code_block_raises_warning() {\n    assert_warning!(\n        r#\"\npub fn main() {\n    {}\n}\n\"#\n    );\n}\n\n#[test]\nfn deprecated_target_shorthand_erlang() {\n    assert_warning!(\n        \"\n@target(erl)\npub fn wibble() { panic }\n\"\n    );\n}\n\n#[test]\nfn deprecated_target_shorthand_javascript() {\n    assert_warning!(\n        \"\n@target(js)\npub fn wibble() { panic }\n\"\n    );\n}\n\n#[test]\nfn unused_block_wrapping_pure_expressions() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  {\n    True\n    1\n  }\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_block_wrapping_pure_expression() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  { 1 }\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_block_wrapping_impure_expressions_is_not_reported_as_pure() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n  {\n    wibble()\n    1\n  }\n  Nil\n}\n\nfn wibble() { panic }\n\"#\n    );\n}\n\n#[test]\nfn unused_case_expression() {\n    assert_warning!(\n        r#\"\npub fn main() {\n    let a = 1\n    case a {\n        1 -> a\n        _ -> 12\n    }\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn impure_case_expression_is_not_marked_as_unused() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n    let a = 1\n    case a {\n        1 -> wibble()\n        _ -> 12\n    }\n    Nil\n}\n\nfn wibble() { panic }\n\"#\n    );\n}\n\n#[test]\nfn impure_case_expression_is_not_marked_as_unused_2() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n    let a = 1\n    case wibble() {\n        1 -> a\n        _ -> 12\n    }\n    Nil\n}\n\nfn wibble() { panic }\n\"#\n    );\n}\n\n#[test]\nfn unused_fn_function_call() {\n    assert_warning!(\n        r#\"\npub fn main() {\n    fn(a) { a + 1 }(1)\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn impure_fn_function_call_not_mark_as_unused() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n    fn(_) { panic }(1)\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_pipeline_ending_with_pure_fn() {\n    assert_warning!(\n        r#\"\npub fn main() {\n    1\n    |> fn(n) { n + 1 }\n\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_pipeline_ending_with_impure_fn() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n    1\n    |> fn(_) { panic }\n\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pipeline_with_regular_function_call_is_never_marked_unused() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n    1 |> wibble\n\n    Nil\n}\n\nfn wibble(n) { echo n }\n\"#\n    );\n}\n\n#[test]\nfn use_with_pure_fn_expression_is_marked_as_unused() {\n    assert_warning!(\n        r#\"\npub fn main() {\n    {\n        use _ <- fn(a) { a }\n        1\n    }\n\n    Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn use_statement_calling_regular_function_is_never_marked_unused() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n    {\n        use _ <- each([1, 2, 3])\n        1\n    }\n\n    Nil\n}\n\nfn each(list, _fun) { echo list }\n\"#\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3425\nfn unused_variable_assignment_pattern() {\n    assert_warning!(\n        \"\ntype Wibble {\n  Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n  let Wibble(a:, ..) as w = Wibble(1, 2)\n  a\n}\n\"\n    );\n}\n\n#[test]\nfn unused_variable_string_prefix_pattern() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  let assert \"hello\" as hello <> rest = \"hello, world\"\n  rest\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_variable_string_prefix_pattern2() {\n    assert_warning!(\n        r#\"\npub fn main() {\n  let assert \"hello\" as hello <> rest = \"hello, world\"\n  hello\n}\n\"#\n    );\n}\n\n#[test]\nfn echo_followed_by_panic() {\n    assert_warning!(\n        \"\npub fn main() {\n  echo panic\n}\n\"\n    );\n}\n\n#[test]\nfn echo_followed_by_panicking_expression() {\n    assert_warning!(\n        \"\npub fn main(a) {\n  echo case a {\n    1 -> panic\n    _ -> [1, panic]\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn assert_on_inferred_variant() {\n    assert_warning!(\n        \"\ntype Wibble {\n  Wibble(w: Int)\n  Wobble(w: String)\n}\n\npub fn main() {\n  let assert Wobble(w) = Wibble(10)\n  w\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_truncated_segment() {\n    assert_warning!(\n        \"\npub fn main() {\n  <<12:size(1)>>\n}\n\"\n    );\n}\n\n#[test]\nfn unused_pure_function() {\n    assert_warning!(\n        \"\nfn add(a, b) { a + b }\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_truncated_segment_in_bytes() {\n    assert_warning!(\n        \"\npub fn main() {\n  <<258:size(8)>>\n}\n\"\n    );\n}\n#[test]\n\nfn unused_pure_function_that_calls_other_pure_function() {\n    assert_warning!(\n        \"\nfn sub(a, b) { add(a, -b) }\n\nfn add(a, b) { a + b }\n\npub fn main() {\n  sub(1, 2)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_truncated_segment_in_bytes_2() {\n    assert_warning!(\n        \"\npub fn main() {\n  <<65_537:size(2)-unit(8)>>\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_truncated_segment_in_range() {\n    assert_no_warnings!(\n        \"\npub fn main() {\n  <<255>>\n}\n\"\n    );\n}\n\n#[test]\nfn function_is_impure_if_external() {\n    assert_no_warnings!(\n        r#\"\n@external(erlang, \"maths\", \"add\")\nfn add(a: Int, b: Int) -> Int\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_truncated_segment_in_range_2() {\n    assert_no_warnings!(\n        \"\npub fn main() {\n  <<0>>\n}\n\"\n    );\n}\n\n#[test]\nfn function_is_impure_if_uses_echo() {\n    assert_no_warnings!(\n        r#\"\nfn add(a: Int, b: Int) -> Int {\n  echo a + b\n}\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn bit_array_negative_truncated_segment() {\n    assert_warning!(\n        \"\npub fn main() {\n  // -5 in 2's complement is 1111...111011\n  // so if we truncate it to its first 3 bits we\n  // get 011, which is positive 3!\n  <<-5:size(3)>>\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_negative_truncated_segment_2() {\n    assert_warning!(\n        \"\npub fn main() {\n  <<-200:size(8)>>\n}\n\"\n    );\n}\n\n#[test]\nfn bit_array_negative_truncated_segment_in_range() {\n    assert_no_warnings!(\n        \"\npub fn main() {\n  <<-128>>\n}\n\"\n    );\n}\n\n#[test]\nfn function_is_impure_if_uses_panic() {\n    assert_no_warnings!(\n        r#\"\nfn add(a: Int, b: Int) -> Int {\n  case a + b {\n    0 -> panic as \"Cannot add to zero\"\n    x -> x\n  }\n}\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn function_is_impure_if_uses_todo() {\n    // We have to use `assert_warning` here instead of `assert_no_warnings`, because\n    // `todo` will always emit a warning. However, that should be the only warning;\n    // there should not be an unused function warning.\n    assert_warning!(\n        r#\"\nfn add(a: Int, b: Int) -> Int {\n  case a + b {\n    0 -> todo as \"Handle zero\"\n    x -> x\n  }\n}\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn function_is_impure_if_uses_let_assert() {\n    assert_no_warnings!(\n        r#\"\nfn assert_ok(x: Result(a, b)) -> a {\n  let assert Ok(x) = x\n  x\n}\n\npub fn main() {\n  assert_ok(Ok(10))\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn function_is_impure_if_uses_assert() {\n    assert_no_warnings!(\n        r#\"\nfn assert_equal(a, b) {\n  assert a == b\n}\n\npub fn main() {\n  assert_equal(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn function_is_impure_if_call_impure_function() {\n    assert_no_warnings!(\n        r#\"\n@external(erlang, \"erlang\", \"something\")\nfn impure() -> Nil\n\nfn add(a: Int, b: Int) -> Int {\n  impure()\n  a + b\n}\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pure_pipeline_raises_warning() {\n    assert_warning!(\n        \"\nfn add(a, b) { a + b }\n\npub fn main() {\n  1 |> add(2)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn pure_pipeline_with_many_steps_raises_warning() {\n    assert_warning!(\n        \"\nfn add(a, b) { a + b }\n\npub fn main() {\n  1 |> add(2) |> add(3) |> add(4)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn pipeline_with_echo_is_impure() {\n    assert_no_warnings!(\n        \"\nfn add(a, b) { a + b }\n\npub fn main() {\n  1 |> add(2) |> echo |> add(3)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn pipeline_with_impure_function_raises_no_warnings() {\n    assert_no_warnings!(\n        \"\nfn add(a, b) { echo a + b }\n\npub fn main() {\n  1 |> add(2)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn function_is_pure_on_js_if_external_on_erlang() {\n    assert_js_warning!(\n        r#\"\n@external(erlang, \"maths\", \"add\")\nfn add(a: Int, b: Int) -> Int { a + b }\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn function_is_pure_on_erlang_if_external_on_js() {\n    assert_warning!(\n        r#\"\n@external(javascript, \"./maths.mjs\", \"add\")\nfn add(a: Int, b: Int) -> Int { a + b }\n\npub fn main() {\n  add(1, 2)\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn pure_standard_library_function() {\n    assert_warning!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/dict\",\n            r#\"\npub type Dict(key, value)\n\n@external(erlang, \"map\", \"new\")\npub fn new() -> Dict(a, b)\n\n@external(erlang, \"map\", \"insert\")\npub fn insert(dict: Dict(key, value), key: key, value: value) -> Dict(key, value)\n\"#\n        ),\n        \"\nimport gleam/dict\n\npub fn main() {\n  dict.insert(dict.new(), 1, 2)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn impure_standard_library_function() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/io\",\n            r#\"\n@external(erlang, \"io\", \"print\")\npub fn println(message: String) -> Nil\n\"#\n        ),\n        r#\"\nimport gleam/io\n\npub fn main() {\n  io.println(\"Hello, world!\")\n  Nil\n}\n\"#\n    );\n}\n\n#[test]\nfn trusted_pure_standard_library_function_that_panics_is_impure() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/int\",\n            r#\"\npub fn add(_a, _b) {\n  panic\n}\n\"#\n        ),\n        \"\nimport gleam/int\npub fn main() {\n  int.add(1, 2)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn higher_order_function_is_not_marked_as_pure() {\n    assert_no_warnings!(\n        (\n            \"gleam/list\",\n            r#\"\npub fn each(list, f) {\n  case list {\n    [] -> Nil\n    [first, ..rest] -> {\n      f(first)\n      each(rest, f)\n    }\n  }\n}\n\"#\n        ),\n        \"\nimport gleam/list\npub fn main() {\n  list.each([1, 2, 3, 4], fn(x) { echo x })\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn stdlib_list_each_is_not_marked_as_pure() {\n    assert_no_warnings!(\n        (\n            \"gleam\",\n            \"gleam/list\",\n            r#\"\npub fn each(list, f) {\n  case list {\n    [] -> Nil\n    [first, ..rest] -> {\n      f(first)\n      each(rest, f)\n    }\n  }\n}\n\"#\n        ),\n        \"\nimport gleam/list\npub fn main() {\n  list.each([1, 2, 3, 4], fn(x) { echo x })\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn dict_each_function_is_not_marked_as_pure() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/dict\",\n            r#\"\npub type Dict(key, value)\n\n@external(erlang, \"maps\", \"new\")\n@external(javascript, \"../dict.mjs\", \"make\")\npub fn new() -> Dict(k, v)\n\npub fn each(dict: Dict(k, v), fun: fn(k, v) -> a) -> Nil {\n  fold(dict, Nil, fn(nil, k, v) {\n    fun(k, v)\n    nil\n  })\n}\n\n@external(javascript, \"../dict.mjs\", \"fold\")\npub fn fold(\n  over dict: Dict(k, v),\n  from initial: acc,\n  with fun: fn(acc, k, v) -> acc,\n) -> acc {\n  let fun = fn(key, value, acc) { fun(acc, key, value) }\n  do_fold(fun, initial, dict)\n}\n\n@external(erlang, \"maps\", \"fold\")\nfn do_fold(fun: fn(k, v, acc) -> acc, initial: acc, dict: Dict(k, v)) -> acc\n\"#\n        ),\n        \"\nimport gleam/dict\npub fn main() {\n  dict.each(dict.new(), fn(_, _) { echo 1 })\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn dict_fold_function_is_not_marked_as_pure() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/dict\",\n            r#\"\npub type Dict(key, value)\n\n@external(erlang, \"maps\", \"new\")\n@external(javascript, \"../dict.mjs\", \"make\")\npub fn new() -> Dict(k, v)\n\n@external(javascript, \"../dict.mjs\", \"fold\")\npub fn fold(\n  over dict: Dict(k, v),\n  from initial: acc,\n  with fun: fn(acc, k, v) -> acc,\n) -> acc {\n  let fun = fn(key, value, acc) { fun(acc, key, value) }\n  do_fold(fun, initial, dict)\n}\n\n@external(erlang, \"maps\", \"fold\")\nfn do_fold(fun: fn(k, v, acc) -> acc, initial: acc, dict: Dict(k, v)) -> acc\n\"#\n        ),\n        \"\nimport gleam/dict\npub fn main() {\n  dict.fold(dict.new(), Nil, fn(_, _, _) { Nil })\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn calling_local_variable_not_marked_as_pure() {\n    assert_no_warnings!(\n        \"\npub fn main() {\n  let side_effects = fn() { panic }\n\n  side_effects()\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn constructing_anonymous_function_is_pure() {\n    assert_warning!(\n        r#\"\nfn make_panic(message) {\n  fn() { panic as message }\n}\n\npub fn main() {\n  make_panic(\"This is a crash\")\n  Nil\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4504\n#[test]\nfn impure_stdlib_test_function() {\n    assert_no_warnings!(\n        (\n            \"gleam_stdlib\",\n            \"gleam/should\",\n            r#\"\n@external(erlang, \"gleam_test_ffi\", \"should_equal\")\npub fn equal(a: t, b: t) -> Nil\n\"#\n        ),\n        \"\nimport gleam/should\n\npub fn main() {\n  1 |> should.equal(1)\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4505\n#[test]\nfn impure_function_using_a_pipe() {\n    assert_no_warnings!(\n        \"\nfn impure(_x) {\n  panic\n}\n\nfn also_impure(x) {\n  x |> impure\n}\n\npub fn main() {\n  also_impure(10)\n  Nil\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4505\n#[test]\nfn impure_function_using_a_pipe_with_a_call() {\n    assert_no_warnings!(\n        \"\nfn impure(_x, _y) {\n  panic\n}\n\nfn also_impure(x) {\n  x |> impure(1)\n}\n\npub fn main() {\n  also_impure(10)\n  Nil\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4505\n#[test]\nfn impure_function_using_a_pipe_into_anonymous_function() {\n    assert_no_warnings!(\n        \"\n\nfn impure(x) {\n  x |> fn(_x) { panic }\n}\n\npub fn main() {\n  impure(10)\n  Nil\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4505\n#[test]\nfn impure_function_using_a_pipe_into_echo() {\n    assert_no_warnings!(\n        \"\n\nfn impure(x) {\n  x |> echo\n}\n\npub fn main() {\n  impure(10)\n  Nil\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4505\n#[test]\nfn impure_function_using_a_pipe_into_result_of_call() {\n    assert_no_warnings!(\n        \"\nfn make_panic() {\n  fn(_x) { panic }\n}\n\nfn impure(x) {\n  x |> make_panic()\n}\n\npub fn main() {\n  impure(10)\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn no_assert_warning_for_bit_array_with_variable() {\n    assert_no_warnings!(\n        r#\"\n@external(erlang, \"gleam@function\", \"identity\")\nfn codepoint(value: Int) -> UtfCodepoint\n\npub fn main() {\n  let codepoint = codepoint(32)\n  assert <<codepoint:utf8_codepoint>> == <<\" \">>\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4637\n#[test]\nfn pattern_matching_on_32_float_plus_infinity_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7f800000:32>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn no_assert_warning_for_tuple_with_variable() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n  let x = 3\n  assert #(1, 2, x) == #(1, 2, 3)\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_plus_infinity_still_reachable_2() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7f80:16, 0x0000:16>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn no_assert_warning_for_list_with_variable() {\n    assert_no_warnings!(\n        r#\"\npub fn main() {\n  let x = 3\n  assert [1, 2, x] == [1, 2, 3]\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_minus_infinity_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0xff800000:32>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn no_assert_warning_for_constructor_with_variable() {\n    assert_no_warnings!(\n        r#\"\ntype Box(t) {\n  Box(t)\n}\n\npub fn main() {\n  let x = 42\n  assert Box(x) == Box(42)\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_minus_infinity_still_reachable_2() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0xff80:16, 0x0000:16>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_nan_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7fc00000:32>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_32_float_nan_still_reachable_2() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:32-float>> -> \"Float\"\n    <<0x7fc0:16, 0x0000:16>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_plus_infinity_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff0000000000000:64>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_plus_infinity_still_reachable_2() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff00000:32, 0x00000000:32>> -> \"+Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_minus_infinity_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0xfff0000000000000:64>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_minus_infinity_still_reachable_2() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0xfff00000:32, 0x00000000:32>> -> \"-Infinity\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_nan_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff8000000000000:64>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_nan_still_reachable_2() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<0x7ff80000:32, 0x00000000:32>> -> \"NaN\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_int_is_still_reachable() {\n    assert_no_warnings!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-int>> -> \"Int\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn pattern_matching_on_64_float_float_is_unreachable() {\n    assert_warning!(\n        r#\"\npub fn go(x) {\n  case x {\n    <<_:64-float>> -> \"Float\"\n    <<_:64-float>> -> \"unreachable\"\n    _ -> \"Other\"\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn import_module_twice() {\n    assert_warning!(\n        (\"gleam/wibble\", \"pub fn wobble() { 1 }\"),\n        \"import gleam/wibble as a\nimport gleam/wibble as b\n\npub fn main() {\n  a.wobble() + b.wobble()\n}\n\"\n    );\n}\n//https://github.com/gleam-lang/gleam/issues/4666\n#[test]\nfn shadow_imported_function() {\n    assert_warning!(\n        (\n            \"thepackage\",\n            \"module\",\n            r#\"\npub fn wibble() { Nil }\n\"#\n        ),\n        r#\"\nimport module.{wibble}\n\npub fn wibble() { Nil }\n\"#\n    );\n}\n//https://github.com/gleam-lang/gleam/issues/4666\n#[test]\nfn shadow_imported_constant() {\n    assert_warning!(\n        (\n            \"thepackage\",\n            \"module\",\n            r#\"\npub const value = 1\n\"#\n        ),\n        r#\"\nimport module.{value}\n\npub const value = 1\n\"#\n    );\n}\n\n#[test]\nfn int_literals_redundant_comparison() {\n    assert_warning!(\"pub fn main() { 1 == 1 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_2() {\n    assert_warning!(\"pub fn main() { 1 == 2 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_3() {\n    assert_warning!(\"pub fn main() { 1 != 1 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_4() {\n    assert_warning!(\"pub fn main() { 1 != 2 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_5() {\n    assert_warning!(\"pub fn main() { 1 > 2 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_6() {\n    assert_warning!(\"pub fn main() { 1 <= 2 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_7() {\n    assert_warning!(\"pub fn main() { 1 < 2 }\");\n}\n\n#[test]\nfn int_literals_redundant_comparison_8() {\n    assert_warning!(\"pub fn main() { 1 >= 2 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison() {\n    assert_warning!(\"pub fn main() { 1.0 == 1.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_2() {\n    assert_warning!(\"pub fn main() { 1.0 == 2.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_3() {\n    assert_warning!(\"pub fn main() { 1.0 != 1.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_4() {\n    assert_warning!(\"pub fn main() { 1.0 != 2.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_5() {\n    assert_warning!(\"pub fn main() { 1.0 >. 2.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_6() {\n    assert_warning!(\"pub fn main() { 1.0 <=. 2.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_7() {\n    assert_warning!(\"pub fn main() { 1.0 <. 2.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_8() {\n    assert_warning!(\"pub fn main() { 1.0 >=. 2.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_different_repr() {\n    assert_warning!(\"pub fn main() { 1_0.0 == 10.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_different_repr_2() {\n    assert_warning!(\"pub fn main() { 10.0 == 1.0e1 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_precision_loss() {\n    assert_warning!(\"pub fn main() { 1.0e-500 == 1.0e-600 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_infinity() {\n    assert_warning!(\"pub fn main() { 1.0e500 == 1.0e600 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_signed_zero() {\n    assert_warning!(\"pub fn main() { 0.0 == -0.0 }\");\n}\n\n#[test]\nfn float_literals_redundant_comparison_omitted_zero() {\n    assert_warning!(\"pub fn main() { 10. == 10.0 }\");\n}\n\n#[test]\nfn bool_literals_redundant_comparison() {\n    assert_warning!(\"pub fn main() { True == False }\");\n}\n\n#[test]\nfn bool_literals_redundant_comparison_1() {\n    assert_warning!(\"pub fn main() { True != False }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison() {\n    assert_warning!(\"pub fn main(a, b) { [1] == [a, b(1)] }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison_2() {\n    assert_warning!(\"pub fn main(a, b) { [1] != [a, b(1)] }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison_3() {\n    assert_warning!(\"pub fn main() { [1] != [1] }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison_4() {\n    assert_warning!(\"pub fn main(a) { [1, ..[1, a]] == [1, ..[1, a]] }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison_5() {\n    assert_warning!(\"pub fn main(a) { [1, ..a] == [1, ..a] }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison_6() {\n    assert_no_warnings!(\"pub fn main(a) { [a(1)] == [a(1)] }\");\n}\n\n#[test]\nfn list_literals_redundant_comparison_7() {\n    assert_warning!(\"pub fn main(a) { [a(1), 2] == [a(1), 3] }\");\n}\n\n#[test]\nfn string_literals_redundant_comparison() {\n    assert_warning!(\"pub fn main() { \\\"wibble\\\" == \\\"wobble\\\" }\");\n}\n\n#[test]\nfn string_literals_redundant_comparison_1() {\n    assert_warning!(\"pub fn main() { \\\"wibble\\\" != \\\"wobble\\\" }\");\n}\n\n#[test]\nfn variables_redundant_comparison() {\n    assert_warning!(\"pub fn main(a) { a == a }\");\n}\n\n#[test]\nfn variables_not_redundant_comparison() {\n    assert_no_warnings!(\"pub fn main(a, b) { a != b }\");\n}\n\n#[test]\nfn constructor_functions_not_redundant_comparison() {\n    assert_no_warnings!(\n        \"\ntype Comparison {\n  Wobble(String)\n}\n\npub fn main() {\n  Wobble == Wobble\n}\n\"\n    );\n}\n\n#[test]\nfn record_select_redundant_comparison() {\n    assert_warning!(\n        \"\npub type Wibble {\n  Wibble(field: Int)\n}\n\npub fn main(wibble: Wibble) { wibble.field == wibble.field }\n\"\n    );\n}\n\n#[test]\nfn record_select_redundant_comparison_1() {\n    assert_warning!(\n        \"\npub type Wibble {\n  Wibble(field: Int)\n}\n\npub fn main(wibble: Wibble) { wibble.field != wibble.field }\n\"\n    );\n}\n\n#[test]\nfn record_select_not_redundant_comparison() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble(field: Int)\n}\n\npub fn main(wibble: Wibble, wobble: Wibble) { wibble.field == wobble.field }\n\"\n    );\n}\n\n#[test]\nfn record_select_not_redundant_comparison_2() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble(field: Int)\n}\n\nfn new() -> Wibble { Wibble(1) }\n\npub fn main() {\n  new().field == new().field\n  // ^^ functions might have side effects so we can't\n  //    tell if this is redundant or not!\n}\n\"\n    );\n}\n\n#[test]\nfn different_records_0_redundant_comparison() {\n    assert_warning!(\n        \"\npub type Either {\n  Left\n  Right\n}\n\npub fn main() -> Bool {\n  Left == Right\n}\n\"\n    );\n}\n\n#[test]\nfn different_records_1_redundant_comparison() {\n    assert_warning!(\n        \"\npub type Either {\n  Left(Int)\n  Right\n}\n\npub fn main() -> Bool {\n  Left(1) == Right\n}\n\"\n    );\n}\n\n#[test]\nfn different_records_2_redundant_comparison() {\n    assert_warning!(\n        \"\npub type Either {\n  Left(Int)\n  Right(Int)\n}\n\npub fn main() -> Bool {\n  Left(1) == Right(1)\n}\n\"\n    );\n}\n\n#[test]\nfn different_records_3_redundant_comparison() {\n    assert_warning!(\n        \"\npub type Either {\n  Left\n  Right(Int)\n}\n\npub fn main() -> Bool {\n  Left == Right(1)\n}\n\"\n    );\n}\n\n#[test]\nfn unused_discard_pattern() {\n    assert_warning!(\n        \"pub fn main() {\n  let a = 10\n  let _ = case a {\n    _ as b -> b\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn discarded_argument_suggestion_is_not_given_for_different_functions() {\n    assert_no_warnings!(\n        \"\npub fn main(_x) { 1 }\npub fn wibble() { x }\n\"\n    );\n}\n\n#[test]\nfn empty_guard_clause() {\n    assert_warning!(\n        \"\npub fn main() {\n    let wibble = 10\n    case wibble {\n        10 if -> True\n        _ -> False\n    }\n\n}\"\n    );\n}\n\n#[test]\nfn impossible_to_reach_integer_segment() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  case x {\n    <<9:size(2)>> -> True\n    _ -> False\n  }\n}\"\n    );\n}\n\n#[test]\nfn impossible_to_reach_integer_segment_2() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  case x {\n    <<-9:unsigned>> -> True\n    _ -> False\n  }\n}\"\n    );\n}\n\n#[test]\nfn impossible_to_reach_integer_segment_3() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  case x {\n    <<312>> -> True\n    _ -> False\n  }\n}\"\n    );\n}\n\n#[test]\nfn impossible_to_reach_integer_segment_4() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  case x {\n    <<-1>> -> True\n    _ -> False\n  }\n}\"\n    );\n}\n\n#[test]\nfn multiple_impossible_to_reach_integer_segments() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  case x {\n    <<1, -1, 2, -3>> -> True\n    _ -> False\n  }\n}\"\n    );\n}\n\n#[test]\nfn assert_on_impossible_to_reach_integer_segment() {\n    assert_warning!(\n        \"\npub fn main(x) {\n  let assert <<1, -1, 2, -3>> = x\n}\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4958\n#[test]\nfn unreachable_string_pattern_with_different_encodings() {\n    assert_warning!(\n        r#\"\npub fn wibble(bits) {\n  case bits {\n    <<\"\\u{0000}a\\u{0000}b\":utf8>> -> 1\n    // This is the same as the one above, it shouldn't be reachable\n    <<\"ab\":utf16>> -> 2\n    _ -> 3\n  }\n}\"#\n    );\n}\n\n#[test]\nfn unreachable_int_pattern_with_string_of_same_value() {\n    assert_warning!(\n        r#\"\npub fn wibble(bits) {\n  case bits {\n    <<\"a\">> -> 1\n    <<97>> -> 2\n    _ -> 3\n  }\n}\"#\n    );\n}\n\n#[test]\nfn unreachable_int_pattern_with_prefix_int() {\n    assert_warning!(\n        r#\"\npub fn wibble(bits) {\n  case bits {\n    <<0b1:1, _:1>> -> 1\n    <<0b11:2>> -> 2\n    _ -> 3\n  }\n}\"#\n    );\n}\n\n#[test]\nfn reachable_pattern_after_unreachable_equal_pattern() {\n    assert_warning!(\n        r#\"\npub fn wibble(bits) {\n  case bits {\n    <<97:3>> -> 1\n    <<\"a\">> -> 2\n    _ -> 3\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn unused_recursive_function_argument() {\n    assert_warning!(\n        \"\npub fn main(x: Int) {\n  main(x)\n}\n\"\n    );\n}\n\n#[test]\nfn unused_recursive_function_argument_2() {\n    assert_warning!(\n        \"\npub fn main(x, times) {\n  case times {\n    0 -> main(x, 0)\n    _ -> main(x, times - 1)\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unused_recursive_function_with_shadowing() {\n    assert_warning!(\n        \"\npub fn main(x: Int) {\n  let _useless = fn(x) { main(x) }\n  main(x)\n}\n\"\n    );\n}\n\n#[test]\nfn unused_recursive_function_inside_anonymous_function() {\n    assert_warning!(\n        \"\npub fn main(x: Int) {\n  let _useless = fn(_) { main(x) }\n  Nil\n}\n\"\n    );\n}\n\n#[test]\nfn unused_recursive_function_with_variable_shadowing() {\n    assert_no_warnings!(\n        \"\npub fn main(x: Int) {\n  let x = x * 2\n  main(x)\n}\n\"\n    );\n}\n\n#[test]\nfn unused_recursive_function_passing_argument_in_a_different_position_counts_as_using_it() {\n    assert_no_warnings!(\n        \"\npub fn main(x: Int, y) {\n  case y {\n    0 -> main(1, x)\n    _ -> main(0, 0)\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn unused_recursive_function_with_shadowed_function() {\n    assert_no_warnings!(\n        \"\npub fn main(x: Int) {\n  let main = fn(x) { x }\n  main(x)\n}\n\"\n    );\n}\n\n#[test]\nfn external_annotation_on_custom_type_requires_v1_14() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        r#\"\n@external(erlang, \"wibble\", \"wobble\")\npub type Wobble\n\"#,\n    );\n}\n\n#[test]\nfn detached_doc_comment() {\n    assert_warning!(\n        \"\n/// This comment is detached\n//\n\n/// This is actual documentation\npub const pi = 3.14\n\"\n    );\n}\n\n#[test]\nfn const_record_update_requires_v1_14_warning() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub type Wibble { Wibble(a: Int, b: Int) }\nconst base = Wibble(1, 2)\npub const wobble = Wibble(..base, b: 3)\n\",\n    );\n}\n\n#[test]\nfn expression_in_expression_segment_size_requires_v1_12_warning() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main() {\n  <<1:size(3 * 8)>>\n}\n\",\n    );\n}\n\n#[test]\nfn expression_in_pattern_segment_size_requires_v1_12_warning() {\n    assert_warnings_with_gleam_version!(\n        Range::higher_than(Version::new(1, 0, 0)),\n        \"\npub fn main(x) {\n  case x {\n    <<_:size(3*8)>> -> 1\n    _ -> 2\n  }\n}\",\n    );\n}\n\n#[test]\nfn record_update_with_all_wrong_fields_produces_no_warnings_1() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn main() {\n  let original = Wibble(a: 1, b: True)\n  Wibble(..original, c: 2)\n}\n\",\n    );\n}\n\n#[test]\nfn record_update_with_all_wrong_fields_produces_no_warnings_2() {\n    assert_no_warnings!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn main() {\n  let original = Wibble(a: 1, b: True)\n  Wibble(..original, a: True)\n}\n\",\n    );\n}\n\n#[test]\nfn record_update_with_wrong_types_but_all_fields_produces_warning() {\n    assert_warning!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn main() {\n  let original = Wibble(a: 1, b: True)\n  Wibble(..original, a: True, b: 1)\n}\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_/tests.rs",
    "content": "use super::*;\nuse crate::{\n    analyse::TargetSupport,\n    ast::{TypedModule, TypedStatement, UntypedExpr, UntypedModule},\n    build::{Origin, Outcome, Target},\n    config::{GleamVersion, PackageConfig},\n    error::Error,\n    type_::{build_prelude, expression::FunctionDefinition, pretty::Printer},\n    uid::UniqueIdGenerator,\n    warning::{TypeWarningEmitter, VectorWarningEmitterIO, WarningEmitter, WarningEmitterIO},\n};\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse pubgrub::Range;\nuse std::rc::Rc;\nuse vec1::Vec1;\n\nuse camino::Utf8PathBuf;\n\nmod accessors;\nmod assert;\nmod assignments;\nmod conditional_compilation;\nmod custom_types;\nmod dead_code_detection;\nmod echo;\nmod errors;\nmod exhaustiveness;\nmod externals;\nmod functions;\nmod guards;\nmod imports;\nmod let_assert;\nmod pipes;\nmod pretty;\nmod target_implementations;\nmod type_alias;\nmod use_;\nmod version_inference;\nmod warnings;\n\n#[macro_export]\nmacro_rules! assert_infer {\n    ($src:expr, $type_:expr $(,)?) => {\n        let t = $crate::type_::tests::infer($src);\n        assert_eq!(($src, t), ($src, $type_.to_string()),);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_module_infer {\n    ($(($name:expr, $module_src:literal)),+, $src:literal, $module:expr $(,)?) => {\n        let constructors =\n            $crate::type_::tests::infer_module($src, vec![$((\"thepackage\", $name, $module_src)),*]);\n        let expected = $crate::type_::tests::stringify_tuple_strs($module);\n\n        assert_eq!(($src, constructors), ($src, expected));\n    };\n\n    ($src:expr, $module:expr $(,)?) => {{\n        let constructors = $crate::type_::tests::infer_module($src, vec![]);\n        let expected = $crate::type_::tests::stringify_tuple_strs($module);\n        assert_eq!(($src, constructors), ($src, expected));\n    }};\n}\n\n#[macro_export]\nmacro_rules! assert_js_module_infer {\n    ($src:expr, $module:expr $(,)?) => {{\n        let constructors = $crate::type_::tests::infer_module_with_target(\n            \"test_module\",\n            $src,\n            vec![],\n            $crate::build::Target::JavaScript,\n        );\n        let expected = $crate::type_::tests::stringify_tuple_strs($module);\n        assert_eq!(($src, constructors), ($src, expected));\n    }};\n}\n\n#[macro_export]\nmacro_rules! assert_module_error {\n    ($src:expr) => {\n        let error = $crate::type_::tests::module_error($src, vec![]);\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\", $src, error);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n\n    ($(($name:expr, $module_src:literal)),+, $src:literal $(,)?) => {\n        let error = $crate::type_::tests::module_error(\n            $src,\n            vec![\n                $((\"thepackage\", $name, $module_src)),*\n            ],\n        );\n\n        let mut output = String::from(\"----- SOURCE CODE\\n\");\n        for (name, src) in [$(($name, $module_src)),*] {\n            output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n        }\n        output.push_str(&format!(\"-- main.gleam\\n{}\\n\\n----- ERROR\\n{error}\", $src));\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n\n    ($(($package:literal, $name:expr, $module_src:literal)),+, $src:literal $(,)?) => {\n        let error = $crate::type_::tests::module_error(\n            $src,\n            vec![\n                $(($package, $name, $module_src)),*\n            ],\n        );\n\n        let mut output = String::from(\"----- SOURCE CODE\\n\");\n        for (name, src) in [$(($name, $module_src)),*] {\n            output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n        }\n        output.push_str(&format!(\"-- main.gleam\\n{}\\n\\n----- ERROR\\n{error}\", $src));\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_internal_module_error {\n    ($src:expr) => {\n        let error = $crate::type_::tests::internal_module_error($src, vec![]);\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\", $src, error);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_js_module_error {\n    ($src:expr) => {\n        let error = $crate::type_::tests::module_error_with_target(\n            $src,\n            vec![],\n            $crate::build::Target::JavaScript,\n        );\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\", $src, error);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_module_syntax_error {\n    ($src:expr) => {\n        let error = $crate::type_::tests::syntax_error($src);\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\", $src, error);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_error {\n    ($src:expr, $error:expr $(,)?) => {\n        let result = $crate::type_::tests::compile_statement_sequence($src)\n            .expect_err(\"should infer an error\");\n        assert_eq!(($src, sort_options($error)), ($src, sort_options(result)),);\n    };\n\n    ($src:expr) => {\n        let (error, names) = $crate::type_::tests::compile_statement_sequence($src)\n            .expect_err(\"should infer an error\");\n        let error = $crate::error::Error::Type {\n            names: Box::new(names),\n            src: $src.into(),\n            path: camino::Utf8PathBuf::from(\"/src/one/two.gleam\"),\n            errors: error,\n        };\n        let error_string = error.pretty_string();\n        let output = format!(\n            \"----- SOURCE CODE\\n{}\\n\\n----- ERROR\\n{}\",\n            $src, error_string\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\nfn get_warnings(\n    src: &str,\n    deps: Vec<DependencyModule<'_>>,\n    target: Target,\n    gleam_version: Option<Range<Version>>,\n) -> Vec<crate::warning::Warning> {\n    let warnings = VectorWarningEmitterIO::default();\n    _ = compile_module_with_opts(\n        \"test_module\",\n        src,\n        Some(Rc::new(warnings.clone())),\n        deps,\n        target,\n        TargetSupport::NotEnforced,\n        gleam_version,\n    );\n    warnings.take().into_iter().collect_vec()\n}\n\npub(crate) fn get_printed_warnings(\n    src: &str,\n    deps: Vec<DependencyModule<'_>>,\n    target: Target,\n    gleam_version: Option<Range<Version>>,\n) -> String {\n    print_warnings(get_warnings(src, deps, target, gleam_version))\n}\n\nfn print_warnings(warnings: Vec<crate::warning::Warning>) -> String {\n    let mut nocolor = termcolor::Buffer::no_color();\n    for warning in warnings {\n        warning.pretty(&mut nocolor);\n    }\n    String::from_utf8(nocolor.into_inner()).expect(\"Error printing produced invalid utf8\")\n}\n\n#[macro_export]\nmacro_rules! assert_warning {\n    ($src:expr) => {\n        let warning = $crate::type_::tests::get_printed_warnings($src, vec![], crate::build::Target::Erlang, None);\n        assert!(!warning.is_empty());\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- WARNING\\n{}\", $src, warning);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n\n    ($(($name:expr, $module_src:literal)),+, $src:literal $(,)?) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![\n                $((\"thepackage\", $name, $module_src)),*\n            ],\n            crate::build::Target::Erlang,\n            None\n        );\n        assert!(!warning.is_empty());\n\n        let mut output = String::from(\"----- SOURCE CODE\\n\");\n        for (name, src) in [$(($name, $module_src)),*] {\n            output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n        }\n        output.push_str(&format!(\"-- main.gleam\\n{}\\n\\n----- WARNING\\n{warning}\", $src));\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n\n    ($(($package:expr, $name:expr, $module_src:literal)),+, $src:expr) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![$(($package, $name, $module_src)),*],\n            crate::build::Target::Erlang,\n            None\n        );\n        assert!(!warning.is_empty());\n\n        let mut output = String::from(\"----- SOURCE CODE\\n\");\n        for (name, src) in [$(($name, $module_src)),*] {\n            output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n        }\n        output.push_str(&format!(\"-- main.gleam\\n{}\\n\\n----- WARNING\\n{warning}\", $src));\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_js_warning {\n    ($src:expr) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![],\n            crate::build::Target::JavaScript,\n            None,\n        );\n        assert!(!warning.is_empty());\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- WARNING\\n{}\", $src, warning);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_js_no_warnings {\n    ($src:expr) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![],\n            crate::build::Target::JavaScript,\n            None,\n        );\n        assert!(warning.is_empty());\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_warnings_with_gleam_version {\n    ($gleam_version:expr, $src:expr$(,)?) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![],\n            crate::build::Target::Erlang,\n            Some($gleam_version),\n        );\n        assert!(!warning.is_empty());\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- WARNING\\n{}\", $src, warning);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_js_warnings_with_gleam_version {\n    ($gleam_version:expr, $src:expr$(,)?) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![],\n            crate::build::Target::JavaScript,\n            Some($gleam_version),\n        );\n        assert!(!warning.is_empty());\n        let output = format!(\"----- SOURCE CODE\\n{}\\n\\n----- WARNING\\n{}\", $src, warning);\n        insta::assert_snapshot!(insta::internals::AutoName, output, $src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_js_no_warnings_with_gleam_version {\n    ($gleam_version:expr, $src:expr$(,)?) => {\n        let warning = $crate::type_::tests::get_printed_warnings(\n            $src,\n            vec![],\n            crate::build::Target::JavaScript,\n            Some($gleam_version),\n        );\n        assert!(warning.is_empty());\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_no_warnings {\n    ($src:expr $(,)?) => {\n        let warnings = $crate::type_::tests::get_warnings($src, vec![], crate::build::Target::Erlang, None);\n        assert_eq!(warnings, vec![]);\n    };\n    ($(($name:expr, $module_src:literal)),+, $src:expr $(,)?) => {\n        let warnings = $crate::type_::tests::get_warnings(\n            $src,\n            vec![$((\"thepackage\", $name, $module_src)),*],\n            crate::build::Target::Erlang,\n            None,\n        );\n        assert_eq!(warnings, vec![]);\n    };\n    ($(($package:expr, $name:expr, $module_src:literal)),+, $src:expr $(,)?) => {\n        let warnings = $crate::type_::tests::get_warnings(\n            $src,\n            vec![$(($package, $name, $module_src)),*],\n            crate::build::Target::Erlang,\n            None,\n        );\n        assert_eq!(warnings, vec![]);\n    };\n}\n\nfn compile_statement_sequence(\n    src: &str,\n) -> Result<Vec1<TypedStatement>, (Vec1<crate::type_::Error>, Names)> {\n    let ast = crate::parse::parse_statement_sequence(src).expect(\"syntax error\");\n    let mut modules = im::HashMap::new();\n    let ids = UniqueIdGenerator::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids));\n    let mut problems = Problems::new();\n    let dev_dependencies = HashSet::new();\n    let mut environment = EnvironmentArguments {\n        ids,\n        current_package: \"thepackage\".into(),\n        gleam_version: None,\n        current_module: \"themodule\".into(),\n        target: Target::Erlang,\n        importable_modules: &modules,\n        target_support: TargetSupport::Enforced,\n        current_origin: Origin::Src,\n        dev_dependencies: &dev_dependencies,\n    }\n    .build();\n    let res = ExprTyper::new(\n        &mut environment,\n        FunctionDefinition {\n            has_body: true,\n            has_erlang_external: false,\n            has_javascript_external: false,\n        },\n        &mut problems,\n    )\n    .infer_statements(ast);\n    match Vec1::try_from_vec(problems.take_errors()) {\n        Err(_) => Ok(res),\n        Ok(errors) => Err((errors, environment.names)),\n    }\n}\n\nfn infer(src: &str) -> String {\n    let mut printer = Printer::new();\n    let result = compile_statement_sequence(src).expect(\"should successfully infer\");\n    printer.pretty_print(result.last().type_().as_ref(), 0)\n}\n\npub fn stringify_tuple_strs(module: Vec<(&str, &str)>) -> Vec<(EcoString, String)> {\n    module\n        .into_iter()\n        .map(|(k, v)| (k.into(), v.into()))\n        .collect()\n}\n\n/// A module loaded as a dependency in the tests.\n///\n/// In order the tuple elements indicate:\n/// 1. The package name.\n/// 2. The module name.\n/// 3. The module source.\ntype DependencyModule<'a> = (&'a str, &'a str, &'a str);\n\npub fn infer_module(src: &str, dep: Vec<DependencyModule<'_>>) -> Vec<(EcoString, String)> {\n    infer_module_with_target(\"test_module\", src, dep, Target::Erlang)\n}\n\npub fn infer_module_with_target(\n    module_name: &str,\n    src: &str,\n    dep: Vec<DependencyModule<'_>>,\n    target: Target,\n) -> Vec<(EcoString, String)> {\n    let ast = compile_module_with_opts(\n        module_name,\n        src,\n        None,\n        dep,\n        target,\n        TargetSupport::NotEnforced,\n        None,\n    )\n    .expect(\"should successfully infer\");\n    ast.type_info\n        .values\n        .iter()\n        .filter(|(_, v)| v.publicity.is_importable())\n        .map(|(k, v)| {\n            let mut printer = Printer::new();\n            (k.clone(), printer.pretty_print(&v.type_, 0))\n        })\n        .sorted()\n        .collect()\n}\n\npub fn compile_module(\n    module_name: &str,\n    src: &str,\n    warnings: Option<Rc<dyn WarningEmitterIO>>,\n    dep: Vec<DependencyModule<'_>>,\n) -> Outcome<TypedModule, Vec1<super::Error>> {\n    compile_module_with_opts(\n        module_name,\n        src,\n        warnings,\n        dep,\n        Target::Erlang,\n        TargetSupport::NotEnforced,\n        None,\n    )\n}\n\npub fn compile_module_with_opts(\n    module_name: &str,\n    src: &str,\n    warnings: Option<Rc<dyn WarningEmitterIO>>,\n    dep: Vec<DependencyModule<'_>>,\n    target: Target,\n    target_support: TargetSupport,\n    gleam_version: Option<Range<Version>>,\n) -> Outcome<TypedModule, Vec1<super::Error>> {\n    let ids = UniqueIdGenerator::new();\n    let mut modules = im::HashMap::new();\n\n    let emitter =\n        WarningEmitter::new(warnings.unwrap_or_else(|| Rc::new(VectorWarningEmitterIO::default())));\n\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids));\n    let mut direct_dependencies = HashMap::from_iter(vec![]);\n\n    for (package, name, module_src) in dep {\n        let parsed =\n            crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), module_src, &emitter)\n                .expect(\"syntax error\");\n        let mut ast = parsed.module;\n        ast.name = name.into();\n        let line_numbers = LineNumbers::new(module_src);\n        let mut config = PackageConfig::default();\n        config.name = package.into();\n        let module = crate::analyse::ModuleAnalyzerConstructor::<()> {\n            target,\n            ids: &ids,\n            origin: Origin::Src,\n            importable_modules: &modules,\n            warnings: &TypeWarningEmitter::null(),\n            direct_dependencies: &HashMap::new(),\n            dev_dependencies: &HashSet::new(),\n            target_support,\n            package_config: &config,\n        }\n        .infer_module(ast, line_numbers, \"\".into())\n        .expect(\"should successfully infer\");\n        let _ = modules.insert(name.into(), module.type_info);\n\n        if package != \"non-dependency-package\" {\n            let _ = direct_dependencies.insert(package.into(), ());\n        }\n    }\n\n    let parsed = crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &emitter)\n        .expect(\"syntax error\");\n    let mut ast = parsed.module;\n    ast.name = module_name.into();\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n    config.gleam_version = gleam_version.map(GleamVersion::from_pubgrub);\n\n    let warnings = TypeWarningEmitter::new(\"/src/warning/wrn.gleam\".into(), src.into(), emitter);\n    crate::analyse::ModuleAnalyzerConstructor::<()> {\n        target,\n        ids: &ids,\n        origin: Origin::Src,\n        importable_modules: &modules,\n        warnings: &warnings,\n        direct_dependencies: &direct_dependencies,\n        dev_dependencies: &HashSet::from_iter([\"dev_dependency\".into()]),\n        target_support: TargetSupport::Enforced,\n        package_config: &config,\n    }\n    .infer_module(ast, LineNumbers::new(src), \"\".into())\n}\n\npub fn module_error(src: &str, deps: Vec<DependencyModule<'_>>) -> String {\n    module_error_with_target(src, deps, Target::Erlang)\n}\n\npub fn module_error_with_target(\n    src: &str,\n    deps: Vec<DependencyModule<'_>>,\n    target: Target,\n) -> String {\n    let outcome = compile_module_with_opts(\n        \"themodule\",\n        src,\n        None,\n        deps,\n        target,\n        TargetSupport::NotEnforced,\n        None,\n    );\n\n    let (error, names) = match outcome {\n        Outcome::Ok(_) => panic!(\"should infer an error\"),\n        Outcome::PartialFailure(ast, errors) => (errors.into(), ast.names),\n        Outcome::TotalFailure(errors) => (errors.into(), Default::default()),\n    };\n\n    let error = Error::Type {\n        names: Box::new(names),\n        src: src.into(),\n        path: Utf8PathBuf::from(\"/src/one/two.gleam\"),\n        errors: Vec1::try_from_vec(error).expect(\"should have at least one error\"),\n    };\n    error.pretty_string()\n}\n\npub fn internal_module_error(src: &str, deps: Vec<DependencyModule<'_>>) -> String {\n    internal_module_error_with_target(src, deps, Target::Erlang)\n}\n\npub fn internal_module_error_with_target(\n    src: &str,\n    deps: Vec<DependencyModule<'_>>,\n    target: Target,\n) -> String {\n    let outcome = compile_module_with_opts(\n        \"thepackage/internal/themodule\",\n        src,\n        None,\n        deps,\n        target,\n        TargetSupport::NotEnforced,\n        None,\n    );\n\n    let (error, names) = match outcome {\n        Outcome::Ok(_) => panic!(\"should infer an error\"),\n        Outcome::PartialFailure(ast, errors) => (errors.into(), ast.names),\n        Outcome::TotalFailure(errors) => (errors.into(), Default::default()),\n    };\n\n    let error = Error::Type {\n        names: Box::new(names),\n        src: src.into(),\n        path: Utf8PathBuf::from(\"/src/one/two.gleam\"),\n        errors: Vec1::try_from_vec(error).expect(\"should have at least one error\"),\n    };\n    error.pretty_string()\n}\n\npub fn syntax_error(src: &str) -> String {\n    let error =\n        crate::parse::parse_module(Utf8PathBuf::from(\"test/path\"), src, &WarningEmitter::null())\n            .expect_err(\"should trigger an error when parsing\");\n    let error = Error::Parse {\n        src: src.into(),\n        path: Utf8PathBuf::from(\"/src/one/two.gleam\"),\n        error: Box::new(error),\n    };\n    error.pretty_string()\n}\n\n#[test]\nfn field_map_reorder_test() {\n    let int = |value: &str| UntypedExpr::Int {\n        value: value.into(),\n        int_value: crate::parse::parse_int_value(value).unwrap(),\n        location: SrcSpan { start: 0, end: 0 },\n    };\n\n    struct Case {\n        arity: u32,\n        fields: HashMap<EcoString, u32>,\n        arguments: Vec<CallArg<UntypedExpr>>,\n        expected_result: Result<(), crate::type_::Error>,\n        expected_arguments: Vec<CallArg<UntypedExpr>>,\n    }\n\n    impl Case {\n        fn test(self) {\n            let mut arguments = self.arguments;\n            let fm = FieldMap {\n                arity: self.arity,\n                fields: self.fields,\n            };\n            let location = SrcSpan { start: 0, end: 0 };\n            assert_eq!(\n                self.expected_result,\n                fm.reorder(&mut arguments, location, IncorrectArityContext::Function)\n            );\n            assert_eq!(self.expected_arguments, arguments);\n        }\n    }\n\n    Case {\n        arity: 0,\n        fields: HashMap::new(),\n        arguments: vec![],\n        expected_result: Ok(()),\n        expected_arguments: vec![],\n    }\n    .test();\n\n    Case {\n        arity: 3,\n        fields: HashMap::new(),\n        arguments: vec![\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"1\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"2\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"3\"),\n            },\n        ],\n        expected_result: Ok(()),\n        expected_arguments: vec![\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"1\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"2\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"3\"),\n            },\n        ],\n    }\n    .test();\n\n    Case {\n        arity: 3,\n        fields: [(\"last\".into(), 2)].into(),\n        arguments: vec![\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"1\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"2\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: Some(\"last\".into()),\n                value: int(\"3\"),\n            },\n        ],\n        expected_result: Ok(()),\n        expected_arguments: vec![\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"1\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: None,\n                value: int(\"2\"),\n            },\n            CallArg {\n                implicit: None,\n                location: Default::default(),\n                label: Some(\"last\".into()),\n                value: int(\"3\"),\n            },\n        ],\n    }\n    .test();\n}\n\n#[test]\nfn infer_module_type_retention_test() {\n    let module: UntypedModule = crate::ast::Module {\n        documentation: vec![],\n        name: \"ok\".into(),\n        definitions: vec![],\n        type_info: (),\n        names: Default::default(),\n        unused_definition_positions: Default::default(),\n    };\n    let direct_dependencies = HashMap::from_iter(vec![]);\n    let ids = UniqueIdGenerator::new();\n    let mut modules = im::HashMap::new();\n    // DUPE: preludeinsertion\n    // TODO: Currently we do this here and also in the tests. It would be better\n    // to have one place where we create all this required state for use in each\n    // place.\n    let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids));\n    let mut config = PackageConfig::default();\n    config.name = \"thepackage\".into();\n\n    let module = crate::analyse::ModuleAnalyzerConstructor::<()> {\n        target: Target::Erlang,\n        ids: &ids,\n        origin: Origin::Src,\n        importable_modules: &modules,\n        warnings: &TypeWarningEmitter::null(),\n        direct_dependencies: &direct_dependencies,\n        dev_dependencies: &HashSet::new(),\n        target_support: TargetSupport::Enforced,\n        package_config: &config,\n    }\n    .infer_module(module, LineNumbers::new(\"\"), \"\".into())\n    .expect(\"Should infer OK\");\n\n    assert_eq!(\n        module.type_info,\n        ModuleInterface {\n            warnings: vec![],\n            origin: Origin::Src,\n            package: \"thepackage\".into(),\n            name: \"ok\".into(),\n            is_internal: false,\n            types: HashMap::new(),\n            types_value_constructors: HashMap::from([\n                (\n                    \"Bool\".into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![],\n                        variants: vec![\n                            TypeValueConstructor {\n                                name: \"True\".into(),\n                                parameters: vec![],\n                                documentation: None,\n                            },\n                            TypeValueConstructor {\n                                name: \"False\".into(),\n                                parameters: vec![],\n                                documentation: None,\n                            }\n                        ],\n                        opaque: Opaque::NotOpaque,\n                    }\n                ),\n                (\n                    \"UtfCodepoint\".into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![],\n                        variants: vec![],\n                        opaque: Opaque::NotOpaque,\n                    }\n                ),\n                (\n                    \"Result\".into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![1, 2],\n                        variants: vec![\n                            TypeValueConstructor {\n                                name: \"Ok\".into(),\n                                parameters: vec![TypeValueConstructorField {\n                                    type_: generic_var(1),\n                                    label: None,\n                                    documentation: None,\n                                }],\n                                documentation: None,\n                            },\n                            TypeValueConstructor {\n                                name: \"Error\".into(),\n                                parameters: vec![TypeValueConstructorField {\n                                    type_: generic_var(2),\n                                    label: None,\n                                    documentation: None,\n                                }],\n                                documentation: None,\n                            }\n                        ],\n                        opaque: Opaque::NotOpaque,\n                    }\n                ),\n                (\n                    \"Nil\".into(),\n                    TypeVariantConstructors {\n                        type_parameters_ids: vec![],\n                        variants: vec![TypeValueConstructor {\n                            name: \"Nil\".into(),\n                            parameters: vec![],\n                            documentation: None,\n                        }],\n                        opaque: Opaque::NotOpaque,\n                    }\n                )\n            ]),\n            values: HashMap::new(),\n            accessors: HashMap::new(),\n            line_numbers: LineNumbers::new(\"\"),\n            src_path: \"\".into(),\n            minimum_required_version: Version::new(0, 1, 0),\n            type_aliases: HashMap::new(),\n            documentation: Vec::new(),\n            contains_echo: false,\n            references: References::default(),\n            inline_functions: HashMap::new(),\n        }\n    );\n}\n\n#[test]\nfn simple_exprs() {\n    assert_infer!(\"True\", \"Bool\");\n    assert_infer!(\"False\", \"Bool\");\n    assert_infer!(\"1\", \"Int\");\n    assert_infer!(\"-2\", \"Int\");\n    assert_infer!(\"1.0\", \"Float\");\n    assert_infer!(\"-8.0\", \"Float\");\n    assert_infer!(\"\\\"ok\\\"\", \"String\");\n    assert_infer!(\"\\\"ok\\\"\", \"String\");\n    assert_infer!(\"[]\", \"List(a)\");\n    assert_infer!(\"4 % 1\", \"Int\");\n    assert_infer!(\"4 > 1\", \"Bool\");\n    assert_infer!(\"4 >= 1\", \"Bool\");\n    assert_infer!(\"4 <= 1\", \"Bool\");\n    assert_infer!(\"4 < 1\", \"Bool\");\n\n    // Numbers with _'s\n    assert_infer!(\"1000_000\", \"Int\");\n    assert_infer!(\"1_000\", \"Int\");\n    assert_infer!(\"1_000.\", \"Float\");\n    assert_infer!(\"10_000.001\", \"Float\");\n    assert_infer!(\"100_000.\", \"Float\");\n\n    // Nil\n    assert_infer!(\"Nil\", \"Nil\");\n\n    // todo\n    assert_infer!(\"todo\", \"a\");\n    assert_infer!(\"1 == todo\", \"Bool\");\n    assert_infer!(\"todo != 1\", \"Bool\");\n    assert_infer!(\"todo + 1\", \"Int\");\n    assert_infer!(\"todo(\\\"test\\\") + 1\", \"Int\");\n\n    // hex, octal, and binary literals\n    assert_infer!(\"0xF\", \"Int\");\n    assert_infer!(\"0o11\", \"Int\");\n    assert_infer!(\"0b1010\", \"Int\");\n\n    // scientific notation\n    assert_infer!(\"6.02e23\", \"Float\");\n    assert_infer!(\"6.02e-23\", \"Float\");\n}\n\n#[test]\nfn assert() {\n    assert_infer!(\"let assert [] = [] 1\", \"Int\");\n    assert_infer!(\"let assert [a] = [1] a\", \"Int\");\n    assert_infer!(\"let assert [a, 2] = [1] a\", \"Int\");\n    assert_infer!(\"let assert [a, .._] = [1] a\", \"Int\");\n    assert_infer!(\"let assert [a, .._,] = [1] a\", \"Int\");\n    assert_infer!(\"fn(x) { let assert [a] = x a }\", \"fn(List(a)) -> a\");\n    assert_infer!(\"fn(x) { let assert [a] = x a + 1 }\", \"fn(List(Int)) -> Int\");\n    assert_infer!(\"let assert _x = 1 2.0\", \"Float\");\n    assert_infer!(\"let assert _ = 1 2.0\", \"Float\");\n    assert_infer!(\"let assert #(tag, x) = #(1.0, 1) x\", \"Int\");\n    assert_infer!(\"fn(x) { let assert #(a, b) = x a }\", \"fn(#(a, b)) -> a\");\n    assert_infer!(\"let assert 5: Int = 5 5\", \"Int\");\n}\n\n#[test]\nfn lists() {\n    assert_infer!(\"[]\", \"List(a)\");\n    assert_infer!(\"[1]\", \"List(Int)\");\n    assert_infer!(\"[1, 2, 3]\", \"List(Int)\");\n    assert_infer!(\"[[]]\", \"List(List(a))\");\n    assert_infer!(\"[[1.0, 2.0]]\", \"List(List(Float))\");\n    assert_infer!(\"[fn(x) { x }]\", \"List(fn(a) -> a)\");\n    assert_infer!(\"[fn(x) { x + 1 }]\", \"List(fn(Int) -> Int)\");\n    assert_infer!(\"[fn(x) { x }, fn(x) { x + 1 }]\", \"List(fn(Int) -> Int)\");\n    assert_infer!(\"[fn(x) { x + 1 }, fn(x) { x }]\", \"List(fn(Int) -> Int)\");\n    assert_infer!(\"[[], []]\", \"List(List(a))\");\n    assert_infer!(\"[[], [1]]\", \"List(List(Int))\");\n\n    assert_infer!(\"[1, ..[2, ..[]]]\", \"List(Int)\");\n    assert_infer!(\"[fn(x) { x }, ..[]]\", \"List(fn(a) -> a)\");\n    assert_infer!(\"let x = [1, ..[]] [2, ..x]\", \"List(Int)\");\n}\n\n#[test]\nfn trailing_comma_lists() {\n    assert_infer!(\"[1, ..[2, ..[],]]\", \"List(Int)\");\n    assert_infer!(\"[fn(x) { x },..[]]\", \"List(fn(a) -> a)\");\n\n    assert_infer!(\"let f = fn(x) { x } [f, f]\", \"List(fn(a) -> a)\");\n    assert_infer!(\"[#([], [])]\", \"List(#(List(a), List(b)))\");\n}\n\n#[test]\nfn tuples() {\n    assert_infer!(\"#(1)\", \"#(Int)\");\n    assert_infer!(\"#(1, 2.0)\", \"#(Int, Float)\");\n    assert_infer!(\"#(1, 2.0, 3)\", \"#(Int, Float, Int)\");\n    assert_infer!(\"#(1, 2.0, #(1, 1))\", \"#(Int, Float, #(Int, Int))\",);\n}\n\n#[test]\nfn expr_fn() {\n    assert_infer!(\"fn(x) { x }\", \"fn(a) -> a\");\n    assert_infer!(\"fn(x) { x }\", \"fn(a) -> a\");\n    assert_infer!(\"fn(x, y) { x }\", \"fn(a, b) -> a\");\n    assert_infer!(\"fn(x, y) { [] }\", \"fn(a, b) -> List(c)\");\n    assert_infer!(\"let x = 1.0 1\", \"Int\");\n    assert_infer!(\"let id = fn(x) { x } id(1)\", \"Int\");\n    assert_infer!(\"let x = fn() { 1.0 } x()\", \"Float\");\n    assert_infer!(\"fn(x) { x }(1)\", \"Int\");\n    assert_infer!(\"fn() { 1 }\", \"fn() -> Int\");\n    assert_infer!(\"fn() { 1.1 }\", \"fn() -> Float\");\n    assert_infer!(\"fn(x) { 1.1 }\", \"fn(a) -> Float\");\n    assert_infer!(\"fn(x) { x }\", \"fn(a) -> a\");\n    assert_infer!(\"let x = fn(x) { 1.1 } x\", \"fn(a) -> Float\");\n    assert_infer!(\"fn(x, y, z) { 1 }\", \"fn(a, b, c) -> Int\");\n    assert_infer!(\"fn(x) { let y = x y }\", \"fn(a) -> a\");\n    assert_infer!(\"let id = fn(x) { x } id(1)\", \"Int\");\n    assert_infer!(\n        \"let constant = fn(x) { fn(y) { x } } let one = constant(1) one(2.0)\",\n        \"Int\",\n    );\n\n    assert_infer!(\"fn(f) { f(1) }\", \"fn(fn(Int) -> a) -> a\");\n    assert_infer!(\"fn(f, x) { f(x) }\", \"fn(fn(a) -> b, a) -> b\");\n    assert_infer!(\"fn(f) { fn(x) { f(x) } }\", \"fn(fn(a) -> b) -> fn(a) -> b\");\n    assert_infer!(\n        \"fn(f) { fn(x) { fn(y) { f(x, y) } } }\",\n        \"fn(fn(a, b) -> c) -> fn(a) -> fn(b) -> c\",\n    );\n    assert_infer!(\n        \"fn(f) { fn(x, y) { f(x)(y) } }\",\n        \"fn(fn(a) -> fn(b) -> c) -> fn(a, b) -> c\",\n    );\n    assert_infer!(\n        \"fn(f) { fn(x) { let ff = f ff(x) } }\",\n        \"fn(fn(a) -> b) -> fn(a) -> b\",\n    );\n    assert_infer!(\n        \"fn(f) { fn(x, y) { let ff = f(x) ff(y) } }\",\n        \"fn(fn(a) -> fn(b) -> c) -> fn(a, b) -> c\",\n    );\n    assert_infer!(\"fn(x) { fn(y) { x } }\", \"fn(a) -> fn(b) -> a\");\n    assert_infer!(\"fn(f) { f() }\", \"fn(fn() -> a) -> a\");\n    assert_infer!(\"fn(f, x) { f(f(x)) }\", \"fn(fn(a) -> a, a) -> a\");\n    assert_infer!(\n        \"let id = fn(a) { a } fn(x) { x(id) }\",\n        \"fn(fn(fn(a) -> a) -> b) -> b\",\n    );\n\n    assert_infer!(\"let add = fn(x, y) { x + y } add(_, 2)\", \"fn(Int) -> Int\");\n    assert_infer!(\"fn(x) { #(1, x) }\", \"fn(a) -> #(Int, a)\");\n    assert_infer!(\"fn(x, y) { #(x, y) }\", \"fn(a, b) -> #(a, b)\");\n    assert_infer!(\"fn(x) { #(x, x) }\", \"fn(a) -> #(a, a)\");\n    assert_infer!(\"fn(x) -> Int { x }\", \"fn(Int) -> Int\");\n    assert_infer!(\"fn(x) -> a { x }\", \"fn(a) -> a\");\n    assert_infer!(\"fn() -> Int { 2 }\", \"fn() -> Int\");\n}\n\n#[test]\nfn case() {\n    assert_infer!(\"case 1 { a -> 1 }\", \"Int\");\n    assert_infer!(\"case 1 { a -> 1.0 b -> 2.0 c -> 3.0 }\", \"Float\");\n    assert_infer!(\"case 1 { a -> a }\", \"Int\");\n    assert_infer!(\"case 1 { 1 -> 10 2 -> 20 x -> x * 10 }\", \"Int\");\n    assert_infer!(\"case 2.0 { 2.0 -> 1 x -> 0 }\", \"Int\");\n    assert_infer!(r#\"case \"ok\" { \"ko\" -> 1 x -> 0 }\"#, \"Int\");\n}\n\n#[test]\nfn multiple_subject_case() {\n    assert_infer!(\"case 1, 2.0 { a, b -> a }\", \"Int\");\n    assert_infer!(\"case 1, 2.0 { a, b -> b }\", \"Float\");\n    assert_infer!(\"case 1, 2.0, 3 { a, b, c -> a + c }\", \"Int\");\n}\n\n#[test]\nfn tuple_index() {\n    assert_infer!(\"#(1, 2.0).0\", \"Int\");\n    assert_infer!(\"#(1, 2.0).1\", \"Float\");\n}\n\n#[test]\nfn pipe() {\n    assert_infer!(\"1 |> fn(x) { x }\", \"Int\");\n    assert_infer!(\"1.0 |> fn(x) { x }\", \"Float\");\n    assert_infer!(\"let id = fn(x) { x } 1 |> id\", \"Int\");\n    assert_infer!(\"let id = fn(x) { x } 1.0 |> id\", \"Float\");\n    assert_infer!(\"let add = fn(x, y) { x + y } 1 |> add(_, 2)\", \"Int\");\n    assert_infer!(\"let add = fn(x, y) { x + y } 1 |> add(2, _)\", \"Int\");\n    assert_infer!(\"let add = fn(x, y) { x + y } 1 |> add(2)\", \"Int\");\n    assert_infer!(\"let id = fn(x) { x } 1 |> id()\", \"Int\");\n    assert_infer!(\"let add = fn(x) { fn(y) { y + x } } 1 |> add(1)\", \"Int\");\n    assert_infer!(\n        \"let add = fn(x, _, _) { fn(y) { y + x } } 1 |> add(1, 2, 3)\",\n        \"Int\"\n    );\n}\n\n#[test]\nfn bit_array() {\n    assert_infer!(\"let assert <<x>> = <<1>> x\", \"Int\");\n}\n\n#[test]\nfn bit_array2() {\n    assert_infer!(\"let assert <<x>> = <<1>> x\", \"Int\");\n}\n\n#[test]\nfn bit_array3() {\n    assert_infer!(\"let assert <<x:float>> = <<1>> x\", \"Float\");\n}\n\n#[test]\nfn bit_array4() {\n    assert_infer!(\"let assert <<x:bytes>> = <<1>> x\", \"BitArray\");\n}\n\n#[test]\nfn bit_array5() {\n    assert_infer!(\"let assert <<x:bytes>> = <<1>> x\", \"BitArray\");\n}\n\n#[test]\nfn bit_array6() {\n    assert_infer!(\"let assert <<x:bits>> = <<1>> x\", \"BitArray\");\n}\n\n#[test]\nfn bit_array7() {\n    assert_infer!(\"let assert <<x:bits>> = <<1>> x\", \"BitArray\");\n}\n\n#[test]\nfn bit_array8() {\n    assert_infer!(\n        \"let assert <<x:utf8_codepoint>> = <<128013:32>> x\",\n        \"UtfCodepoint\"\n    );\n}\n\n#[test]\nfn bit_array9() {\n    assert_infer!(\n        \"let assert <<x:utf16_codepoint>> = <<128013:32>> x\",\n        \"UtfCodepoint\"\n    );\n}\n\n#[test]\nfn bit_array10() {\n    assert_infer!(\n        \"let assert <<x:utf32_codepoint>> = <<128013:32>> x\",\n        \"UtfCodepoint\"\n    );\n}\n\n#[test]\nfn bit_array11() {\n    assert_infer!(\n        \"let a = <<1>> let assert <<x:bits>> = <<1, a:2-bits>> x\",\n        \"BitArray\"\n    );\n}\n\n#[test]\nfn bit_array12() {\n    assert_infer!(\"let x = <<<<1>>:bits, <<2>>:bits>> x\", \"BitArray\");\n}\n\n#[test]\nfn infer_module_test() {\n    assert_module_infer!(\n        \"pub fn repeat(i, x) {\n           case i {\n             0 -> []\n             i -> [x .. repeat(i - 1, x)]\n           }\n         }\",\n        vec![(\"repeat\", \"fn(Int, a) -> List(a)\")],\n    );\n}\n\n#[test]\nfn infer_module_test1() {\n    assert_module_infer!(\n        \"pub fn length(list) {\n           case list {\n           [] -> 0\n           [x .. xs] -> length(xs) + 1\n           }\n        }\",\n        vec![(\"length\", \"fn(List(a)) -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test2() {\n    assert_module_infer!(\n        \"fn private() { 1 }\n         pub fn public() { 1 }\",\n        vec![(\"public\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test3() {\n    assert_module_infer!(\n        \"pub type Is { Yes No }\n         pub fn yes() { Yes }\n         pub fn no() { No }\",\n        vec![\n            (\"No\", \"Is\"),\n            (\"Yes\", \"Is\"),\n            (\"no\", \"fn() -> Is\"),\n            (\"yes\", \"fn() -> Is\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_module_test4() {\n    assert_module_infer!(\n        \"pub type Num { I(Int) }\n         pub fn one() { I(1) }\",\n        vec![(\"I\", \"fn(Int) -> Num\"), (\"one\", \"fn() -> Num\")],\n    );\n}\n\n#[test]\nfn infer_module_test5() {\n    assert_module_infer!(\n        \"pub type Box(a) { Box(a) }\n        pub fn int() { Box(1) }\n        pub fn float() { Box(1.0) }\",\n        vec![\n            (\"Box\", \"fn(a) -> Box(a)\"),\n            (\"float\", \"fn() -> Box(Float)\"),\n            (\"int\", \"fn() -> Box(Int)\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_module_test6() {\n    assert_module_infer!(\n        \"pub type Singleton { Singleton }\n        pub fn go(x) { let Singleton = x 1 }\",\n        vec![(\"Singleton\", \"Singleton\"), (\"go\", \"fn(Singleton) -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test7() {\n    assert_module_infer!(\n        \"pub type Box(a) { Box(a) }\n        pub fn unbox(x) { let Box(a) = x a }\",\n        vec![(\"Box\", \"fn(a) -> Box(a)\"), (\"unbox\", \"fn(Box(a)) -> a\")],\n    );\n}\n\n#[test]\nfn infer_module_test8() {\n    assert_module_infer!(\n        \"pub type I { I(Int) }\n        pub fn open(x) { case x { I(i) -> i  } }\",\n        vec![(\"I\", \"fn(Int) -> I\"), (\"open\", \"fn(I) -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test9() {\n    assert_module_infer!(\n        \"pub fn status() { 1 } pub fn list_of(x) { [x] }\",\n        vec![(\"list_of\", \"fn(a) -> List(a)\"), (\"status\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test10() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(x: String) -> String\n\",\n        vec![(\"go\", \"fn(String) -> String\")],\n    );\n}\n\n#[test]\nfn infer_module_test11() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(x: Int) -> Float\n\",\n        vec![(\"go\", \"fn(Int) -> Float\")],\n    );\n}\n\n#[test]\nfn infer_module_test12() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(x: Int) -> Int\n\",\n        vec![(\"go\", \"fn(Int) -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test13() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn ok() -> fn(Int) -> Int\n\",\n        vec![(\"ok\", \"fn() -> fn(Int) -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test14() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(x: Int) -> b\n\",\n        vec![(\"go\", \"fn(Int) -> a\")],\n    );\n}\n\n#[test]\nfn infer_module_test15() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(x: Bool) -> b\n\",\n        vec![(\"go\", \"fn(Bool) -> a\")],\n    );\n}\n\n#[test]\nfn infer_module_test16() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(x: List(a)) -> a\n\",\n        vec![(\"go\", \"fn(List(a)) -> a\")],\n    );\n}\n\n#[test]\nfn infer_module_test17() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\nfn go(x: Int) -> b\n        pub fn x() { go(1) }\",\n        vec![(\"x\", \"fn() -> a\")],\n    );\n}\n\n#[test]\nfn infer_module_test18() {\n    assert_module_infer!(\n        \"@external(erlang, \\\"\\\", \\\"\\\")\n        fn id(a: a) -> a\n        pub fn i(x) { id(x) }\n        pub fn a() { id(1) }\n        pub fn b() { id(1.0) }\",\n        vec![\n            (\"a\", \"fn() -> Int\"),\n            (\"b\", \"fn() -> Float\"),\n            (\"i\", \"fn(a) -> a\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_module_test19() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn len(a: List(a)) -> Int\n\",\n        vec![(\"len\", \"fn(List(a)) -> Int\")],\n    );\n}\n\n#[test]\nfn infer_module_test20() {\n    assert_module_infer!(\n        \"pub type Connection\\n\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn is_open(x: Connection) -> Bool\n\",\n        vec![(\"is_open\", \"fn(Connection) -> Bool\")],\n    );\n}\n\n#[test]\nfn infer_module_test21() {\n    assert_module_infer!(\n        \"pub type Pair(a, b)\\n\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn pair(x: a) -> Pair(a, a)\n\",\n        vec![(\"pair\", \"fn(a) -> Pair(a, a)\")],\n    );\n}\n\n#[test]\nfn infer_module_test22() {\n    assert_module_infer!(\n        \"pub fn one() { 1 }\n         pub fn zero() { one() - 1 }\n         pub fn two() { one() + zero() }\",\n        vec![\n            (\"one\", \"fn() -> Int\"),\n            (\"two\", \"fn() -> Int\"),\n            (\"zero\", \"fn() -> Int\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_module_test23() {\n    assert_module_infer!(\n        \"pub fn one() { 1 }\n         pub fn zero() { one() - 1 }\n         pub fn two() { one() + zero() }\",\n        vec![\n            (\"one\", \"fn() -> Int\"),\n            (\"two\", \"fn() -> Int\"),\n            (\"zero\", \"fn() -> Int\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_module_test24() {\n    // Structs\n    assert_module_infer!(\n        \"pub type Box { Box(boxed: Int) }\",\n        vec![(\"Box\", \"fn(Int) -> Box\")]\n    );\n}\n\n#[test]\nfn infer_module_test25() {\n    assert_module_infer!(\n        \"pub type Tup(a, b) { Tup(first: a, second: b) }\",\n        vec![(\"Tup\", \"fn(a, b) -> Tup(a, b)\")]\n    );\n}\n\n#[test]\nfn infer_module_test26() {\n    assert_module_infer!(\n        \"pub type Tup(a, b, c) { Tup(first: a, second: b, third: c) }\n         pub fn third(t) { let Tup(_ , _, third: a) = t a }\",\n        vec![\n            (\"Tup\", \"fn(a, b, c) -> Tup(a, b, c)\"),\n            (\"third\", \"fn(Tup(a, b, c)) -> c\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_label_shorthand_pattern() {\n    assert_module_infer!(\n        \"pub type Tup(a, b, c) { Tup(first: a, second: b, third: c) }\n         pub fn third(t) { let Tup(_, _, third:) = t third }\",\n        vec![\n            (\"Tup\", \"fn(a, b, c) -> Tup(a, b, c)\"),\n            (\"third\", \"fn(Tup(a, b, c)) -> c\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_module_test27() {\n    // Anon structs\n    assert_module_infer!(\n        \"pub fn ok(x) { #(1, x) }\",\n        vec![(\"ok\", \"fn(a) -> #(Int, a)\")],\n    );\n}\n\n#[test]\nfn infer_module_test28() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn ok(a: Int) -> #(Int, Int)\n\",\n        vec![(\"ok\", \"fn(Int) -> #(Int, Int)\")],\n    );\n}\n\n#[test]\nfn infer_module_test29() {\n    assert_module_infer!(\n        \"\n@external(erlang, \\\"\\\", \\\"\\\")\npub fn go(a: #(a, c)) -> c\n\",\n        vec![(\"go\", \"fn(#(a, b)) -> b\")],\n    );\n}\n\n#[test]\nfn infer_module_test30() {\n    assert_module_infer!(\n        \"pub fn always(ignore _a, return b) { b }\",\n        vec![(\"always\", \"fn(a, b) -> b\")],\n    );\n}\n\n#[test]\nfn infer_module_test31() {\n    // Using types before they are defined\n\n    assert_module_infer!(\n        \"pub type I { I(Num) } pub type Num { Num }\",\n        vec![(\"I\", \"fn(Num) -> I\"), (\"Num\", \"Num\")]\n    );\n}\n\n#[test]\nfn infer_module_test32() {\n    assert_module_infer!(\n        \"pub type I { I(Num) } pub type Num\",\n        vec![(\"I\", \"fn(Num) -> I\")]\n    );\n}\n\n#[test]\nfn type_alias() {\n    assert_module_infer!(\n        \"type Html = String\n         pub fn go() { 1 }\",\n        vec![(\"go\", \"fn() -> Int\")],\n    );\n    assert_module_infer!(\n        \"type IntString = Result(Int, String)\n         pub fn ok_one() -> IntString { Ok(1) }\",\n        vec![(\"ok_one\", \"fn() -> Result(Int, String)\")]\n    );\n}\n\n#[test]\nfn build_in_type_alias_shadow() {\n    // We can create an alias with the same name as a built in type\n    assert_module_infer!(\n        \"type Int = Float\n         pub fn ok_one() -> Int { 1.0 }\",\n        vec![(\"ok_one\", \"fn() -> Float\")]\n    );\n}\n\n#[test]\nfn accessor() {\n    // We can access fields on custom types with only one variant\n    assert_module_infer!(\n        \"\npub type Person { Person(name: String, age: Int) }\npub fn get_age(person: Person) { person.age }\npub fn get_name(person: Person) { person.name }\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"get_age\", \"fn(Person) -> Int\"),\n            (\"get_name\", \"fn(Person) -> String\"),\n        ]\n    );\n\n    // We can access fields on custom types with only one variant\n    assert_module_infer!(\n        \"\npub type One { One(name: String) }\npub type Two { Two(one: One) }\npub fn get(x: Two) { x.one.name }\",\n        vec![\n            (\"One\", \"fn(String) -> One\"),\n            (\"Two\", \"fn(One) -> Two\"),\n            (\"get\", \"fn(Two) -> String\"),\n        ]\n    );\n}\n\n#[test]\nfn generic_accessor() {\n    // Field access correctly handles type parameters\n    assert_module_infer!(\n        \"\npub type Box(a) { Box(inner: a) }\npub fn get_box(x: Box(Box(a))) { x.inner }\npub fn get_generic(x: Box(a)) { x.inner }\npub fn get_get_box(x: Box(Box(a))) { x.inner.inner }\npub fn get_int(x: Box(Int)) { x.inner }\npub fn get_string(x: Box(String)) { x.inner }\n\",\n        vec![\n            (\"Box\", \"fn(a) -> Box(a)\"),\n            (\"get_box\", \"fn(Box(Box(a))) -> Box(a)\"),\n            (\"get_generic\", \"fn(Box(a)) -> a\"),\n            (\"get_get_box\", \"fn(Box(Box(a))) -> a\"),\n            (\"get_int\", \"fn(Box(Int)) -> Int\"),\n            (\"get_string\", \"fn(Box(String)) -> String\"),\n        ]\n    );\n}\n\n#[test]\nfn generic_accessor_later_defined() {\n    // Field access works before type is defined\n    assert_module_infer!(\n        \"\npub fn name(cat: Cat) {\n  cat.name\n}\n\npub opaque type Cat {\n  Cat(name: String)\n}\",\n        vec![(\"name\", \"fn(Cat) -> String\"),]\n    );\n}\n\n#[test]\nfn custom_type_annotation() {\n    // We can annotate let with custom types\n    assert_module_infer!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n\n        pub fn create_person(name: String) {\n            let x: Person = Person(name: name, age: 1)\n            x\n        }\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"create_person\", \"fn(String) -> Person\"),\n        ]\n    );\n\n    assert_module_infer!(\n        \"\n        pub type Box(inner) {\n            Box(inner)\n        }\n\n        pub fn create_int_box(value: Int) {\n            let x: Box(Int) = Box(value)\n            x\n        }\n\n        pub fn create_float_box(value: Float) {\n            let x: Box(Float) = Box(value)\n            x\n        }\",\n        vec![\n            (\"Box\", \"fn(a) -> Box(a)\"),\n            (\"create_float_box\", \"fn(Float) -> Box(Float)\"),\n            (\"create_int_box\", \"fn(Int) -> Box(Int)\"),\n        ]\n    );\n}\n\n#[test]\nfn opaque_accessors() {\n    // Opaque type constructors are available in the module where they are defined\n    // but are not exported\n    assert_module_infer!(\n        \"\npub opaque type One { One(name: String) }\npub fn get(x: One) { x.name }\",\n        vec![(\"get\", \"fn(One) -> String\"),]\n    );\n}\n\n#[test]\nfn fn_annotation_reused() {\n    // Type variables are shared between function annotations and function\n    // annotations within their body\n    assert_module_infer!(\n        \"\n        pub type Box(a) {\n            Box(value: a)\n        }\n        pub fn go(box1: Box(a)) {\n            fn(box2: Box(a)) { box1.value == box2.value }\n        }\",\n        vec![\n            (\"Box\", \"fn(a) -> Box(a)\"),\n            (\"go\", \"fn(Box(a)) -> fn(Box(a)) -> Bool\")\n        ]\n    );\n\n    // Type variables are shared between function annotations and let\n    // annotations within their body\n    assert_module_infer!(\n        \"\n        pub type Box(a) {\n            Box(value: a)\n        }\n        pub fn go(box1: Box(a)) {\n            let x: Box(a) = box1\n            fn(box2: Box(a)) { x.value == box2.value }\n        }\",\n        vec![\n            (\"Box\", \"fn(a) -> Box(a)\"),\n            (\"go\", \"fn(Box(a)) -> fn(Box(a)) -> Bool\")\n        ]\n    );\n}\n\n#[test]\nfn accessor_multiple_variants() {\n    // We can access fields on custom types with multiple variants\n    assert_module_infer!(\n        \"\npub type Person {\n    Teacher(name: String, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\",\n        vec![\n            (\"Student\", \"fn(String, Int) -> Person\"),\n            (\"Teacher\", \"fn(String, String) -> Person\"),\n            (\"get_name\", \"fn(Person) -> String\"),\n        ]\n    );\n}\n\n#[test]\nfn record_accessor_multiple_variants_parameterised_types() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_module_infer!(\n        \"\npub type Person {\n    Teacher(name: String, age: List(Int), title: String)\n    Student(name: String, age: List(Int))\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\",\n        vec![\n            (\"Student\", \"fn(String, List(Int)) -> Person\"),\n            (\"Teacher\", \"fn(String, List(Int), String) -> Person\"),\n            (\"get_age\", \"fn(Person) -> List(Int)\"),\n            (\"get_name\", \"fn(Person) -> String\"),\n        ]\n    );\n}\n\n#[test]\nfn accessor_multiple_variants_positions_other_than_first() {\n    // We can access fields on custom types with multiple variants\n    // In positions other than the 1st field\n    assert_module_infer!(\n        \"\npub type Person {\n    Teacher(name: String, age: Int, title: String)\n    Student(name: String, age: Int)\n}\npub fn get_name(person: Person) { person.name }\npub fn get_age(person: Person) { person.age }\",\n        vec![\n            (\"Student\", \"fn(String, Int) -> Person\"),\n            (\"Teacher\", \"fn(String, Int, String) -> Person\"),\n            (\"get_age\", \"fn(Person) -> Int\"),\n            (\"get_name\", \"fn(Person) -> String\"),\n        ]\n    );\n}\n\n#[test]\nfn box_record() {\n    assert_module_infer!(\n        \"\npub type Box {\n  Box(a: Nil, b: Int, c: Int, d: Int)\n}\n\npub fn main() {\n  Box(b: 1, c: 1, d: 1, a: Nil)\n}\",\n        vec![\n            (\"Box\", \"fn(Nil, Int, Int, Int) -> Box\"),\n            (\"main\", \"fn() -> Box\"),\n        ],\n    );\n}\n\n#[test]\nfn record_update_no_fields() {\n    // No arguments given to a record update\n    assert_module_infer!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn identity(person: Person) {\n            Person(..person)\n        }\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"identity\", \"fn(Person) -> Person\")\n        ]\n    );\n}\n\n#[test]\nfn record_update() {\n    // Some arguments given to a record update\n    assert_module_infer!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_name(person: Person, name: String) {\n            Person(..person, name: name)\n        }\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"update_name\", \"fn(Person, String) -> Person\")\n        ]\n    );\n}\n\n#[test]\nfn record_update_all_fields() {\n    // All arguments given in order to a record update\n    assert_module_infer!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person(person: Person, name: String, age: Int) {\n            Person(..person, name: name, age: age, )\n        }\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"update_person\", \"fn(Person, String, Int) -> Person\")\n        ]\n    );\n}\n\n#[test]\nfn record_update_out_of_order() {\n    // All arguments given out of order to a record update\n    assert_module_infer!(\n        \"\n        pub type Person {\n            Person(name: String, age: Int)\n        }\n        pub fn update_person(person: Person, name: String, age: Int) {\n            Person(..person, age: age, name: name)\n        }\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"update_person\", \"fn(Person, String, Int) -> Person\")\n        ]\n    );\n}\n\n#[test]\nfn record_update_generic() {\n    // A record update with polymorphic types\n    assert_module_infer!(\n        \"\n        pub type Box(a, b) {\n            Box(left: a, right: b)\n        }\n\n        pub fn combine_boxes(a: Box(Int, Bool), b: Box(Bool, Int)) {\n            Box(..a, left: a.left + b.right, right: b.left)\n        }\",\n        vec![\n            (\"Box\", \"fn(a, b) -> Box(a, b)\"),\n            (\n                \"combine_boxes\",\n                \"fn(Box(Int, Bool), Box(Bool, Int)) -> Box(Int, Bool)\"\n            )\n        ]\n    );\n}\n\n#[test]\nfn record_update_generic_unannotated() {\n    // A record update with unannotated polymorphic types\n    assert_module_infer!(\n        \"\n        pub type Box(a, b) {\n            Box(left: a, right: b)\n        }\n\n        pub fn combine_boxes(a: Box(t1, t2), b: Box(t2, t1)) {\n            Box(..a, left: b.right, right: b.left)\n        }\",\n        vec![\n            (\"Box\", \"fn(a, b) -> Box(a, b)\"),\n            (\"combine_boxes\", \"fn(Box(a, b), Box(b, a)) -> Box(a, b)\")\n        ]\n    );\n}\n\n#[test]\nfn record_update_variant_inference() {\n    assert_module_infer!(\n        \"\npub type Shape {\n  Circle(cx: Int, cy: Int, radius: Int)\n  Square(x: Int, y: Int, width: Int, height: Int)\n}\n\npub fn grow(shape) {\n  case shape {\n    Circle(radius:, ..) as circle -> Circle(..circle, radius: radius + 1)\n    Square(width:, height:, ..) as square -> Square(..square, width: width + 1, height: height + 1)\n  }\n}\n\",\n        vec![\n            (\"Circle\", \"fn(Int, Int, Int) -> Shape\"),\n            (\"Square\", \"fn(Int, Int, Int, Int) -> Shape\"),\n            (\"grow\", \"fn(Shape) -> Shape\")\n        ]\n    );\n}\n\n#[test]\nfn record_access_variant_inference() {\n    assert_module_infer!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn get(wibble) {\n  case wibble {\n    Wibble(..) as w -> w.b\n    Wobble(..) as w -> w.c\n  }\n}\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Int) -> Wibble\"),\n            (\"Wobble\", \"fn(Int, Int) -> Wibble\"),\n            (\"get\", \"fn(Wibble) -> Int\")\n        ]\n    );\n}\n\n#[test]\nfn local_variable_variant_inference() {\n    assert_module_infer!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn main() {\n  let always_wibble = Wibble(1, 2)\n  always_wibble.b\n}\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Int) -> Wibble\"),\n            (\"Wobble\", \"fn(Int, Int) -> Wibble\"),\n            (\"main\", \"fn() -> Int\")\n        ]\n    );\n}\n\n#[test]\nfn record_update_variant_inference_for_original_variable() {\n    assert_module_infer!(\n        r#\"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn update(wibble: Wibble) -> Wibble {\n  case wibble {\n    Wibble(..) -> Wibble(..wibble, a: 1)\n    Wobble(..) -> Wobble(..wibble, c: \"hello\")\n  }\n}\n\"#,\n        vec![\n            (\"Wibble\", \"fn(Int, Int) -> Wibble\"),\n            (\"Wobble\", \"fn(Int, String) -> Wibble\"),\n            (\"update\", \"fn(Wibble) -> Wibble\")\n        ]\n    );\n}\n\n#[test]\nfn record_access_variant_inference_for_original_variable() {\n    assert_module_infer!(\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\npub fn get(wibble) {\n  case wibble {\n    Wibble(..) -> wibble.b\n    Wobble(..) -> wibble.c\n  }\n}\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Int) -> Wibble\"),\n            (\"Wobble\", \"fn(Int, Int) -> Wibble\"),\n            (\"get\", \"fn(Wibble) -> Int\")\n        ]\n    );\n}\n\n#[test]\nfn variant_inference_for_imported_type() {\n    assert_module_infer!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\"\n        ),\n        \"\nimport wibble.{Wibble, Wobble}\n\npub fn main(wibble) {\n  case wibble {\n    Wibble(..) -> Wibble(a: 1, b: wibble.b + 1)\n    Wobble(..) -> Wobble(..wibble, c: wibble.c - 4)\n  }\n}\n\",\n        vec![(\"main\", \"fn(Wibble) -> Wibble\")]\n    );\n}\n\n#[test]\nfn local_variable_variant_inference_for_imported_type() {\n    assert_module_infer!(\n        (\n            \"wibble\",\n            \"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: Int)\n}\n\"\n        ),\n        \"\nimport wibble.{Wibble}\n\npub fn main() {\n  let wibble = Wibble(4, 9)\n  Wibble(..wibble, b: wibble.b)\n}\n\",\n        vec![(\"main\", \"fn() -> Wibble\")]\n    );\n}\n\n#[test]\nfn record_update_variant_inference_fails_for_several_possible_variants() {\n    assert_module_error!(\n        \"\npub type Vector {\n  Vector2(x: Float, y: Float)\n  Vector3(x: Float, y: Float, z: Float)\n}\n\npub fn increase_y(vector, by increase) {\n  case vector {\n    Vector2(y:, ..) as vector | Vector3(y:, ..) as vector ->\n      Vector2(..vector, y: y +. increase)\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn record_update_variant_inference_fails_for_several_possible_variants_on_subject_variable() {\n    assert_module_error!(\n        r#\"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn update(wibble: Wibble) -> Wibble {\n  case wibble {\n    Wibble(..) | Wobble(..) -> Wibble(..wibble, a: 1)\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn type_unification_does_not_cause_false_positives_for_variant_matching() {\n    assert_module_error!(\n        r#\"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn wibbler() { todo }\n\npub fn main() {\n  let c = wibbler()\n\n  case todo {\n    Wibble(..) -> Wibble(..c, b: 1)\n    _ -> todo\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn type_unification_does_not_allow_different_variants_to_be_treated_as_safe() {\n    assert_module_error!(\n        r#\"\npub type Wibble {\n  Wibble(a: Int, b: Int)\n  Wobble(a: Int, c: String)\n}\n\npub fn main() {\n  let a = case todo {\n    Wibble(..) as b -> Wibble(..b, b: 1)\n    Wobble(..) as b -> Wobble(..b, c: \"a\")\n  }\n\n  a.b\n}\n\"#\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1358\n#[test]\nfn type_unification_does_not_allow_lowercase_bools_in_match_clause() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  case 42 > 42 {\n    true -> 1\n    false -> 2\n  }\n}\n\"#\n    );\n}\n\n#[test]\nfn record_update_variant_inference_in_alternate_pattern_with_all_same_variants() {\n    assert_module_infer!(\n        r#\"\npub type Vector {\n  Vector2(x: Float, y: Float)\n  Vector3(x: Float, y: Float, z: Float)\n}\n\npub fn increase_y(vector, by increase) {\n  case vector {\n    Vector2(y:, ..) as vector -> Vector2(..vector, y: y +. increase)\n    Vector3(y:, z: 12.3, ..) as vector | Vector3(y:, z: 15.0, ..) as vector ->\n      Vector3(..vector, y: y +. increase, z: 0.0)\n    _ -> panic as \"Could not increase Y\"\n  }\n}\n\"#,\n        vec![\n            (\"Vector2\", \"fn(Float, Float) -> Vector\"),\n            (\"Vector3\", \"fn(Float, Float, Float) -> Vector\"),\n            (\"increase_y\", \"fn(Vector, Float) -> Vector\")\n        ]\n    );\n}\n\n#[test]\nfn variant_inference_does_not_escape_clause_scope() {\n    assert_module_error!(\n        \"\npub type Thingy {\n  A(a: Int)\n  B(x: Int, b: Int)\n}\n\npub fn fun(x) {\n  case x {\n    A(..) -> x.a\n    B(..) -> x.b\n  }\n  x.b\n}\n\"\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3797\nfn type_unification_removes_inferred_variant_in_tuples() {\n    assert_module_error!(\n        r#\"\npub type Either(a, b) {\n  Left(value: a)\n  Right(value: b)\n}\n\nfn a_or_b(_first: value, second: value) -> value {\n  second\n}\n\npub fn main() {\n  let #(right) = a_or_b(#(Left(5)), #(Right(\"hello\")))\n  Left(..right, value: 10)\n}\n\"#\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3797\nfn type_unification_removes_inferred_variant_in_functions() {\n    assert_module_error!(\n        r#\"\npub type Either(a, b) {\n  Left(value: a)\n  Right(value: b)\n}\n\nfn a_or_b(_first: value, second: value) -> value {\n  second\n}\n\npub fn main() {\n  let func = a_or_b(fn() { Left(1) }, fn() { Right(\"hello\") })\n  Left(..func(), value: 10)\n}\n\"#\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3797\nfn type_unification_removes_inferred_variant_in_nested_type() {\n    assert_module_error!(\n        r#\"\npub type Box(a) {\n  Box(inner: a)\n}\n\npub type Either(a, b) {\n  Left(value: a)\n  Right(value: b)\n}\n\nfn a_or_b(_first: value, second: value) -> value {\n  second\n}\n\npub fn main() {\n  let Box(inner) = a_or_b(Box(Left(1)), Box(Right(\"hello\")))\n  Left(..inner, value: 10)\n}\n\"#\n    );\n}\n\n#[test]\nfn module_constants() {\n    assert_module_infer!(\n        \"\n    pub const test_int1 = 123\n    pub const test_int2: Int = 321\n    pub const test_int3 = 0xE\n    pub const test_int4 = 0o10\n    pub const test_int5 = 0o10011\n    pub const test_float: Float = 4.2\n    pub const test_string = \\\"hey!\\\"\n    pub const test_list = [1,2,3]\n    pub const test_tuple = #(\\\"yes!\\\", 42)\n    pub const test_var1 = test_int1\n    pub const test_var2: Int = test_int1\",\n        vec![\n            (\"test_float\", \"Float\"),\n            (\"test_int1\", \"Int\"),\n            (\"test_int2\", \"Int\"),\n            (\"test_int3\", \"Int\"),\n            (\"test_int4\", \"Int\"),\n            (\"test_int5\", \"Int\"),\n            (\"test_list\", \"List(Int)\"),\n            (\"test_string\", \"String\"),\n            (\"test_tuple\", \"#(String, Int)\"),\n            (\"test_var1\", \"Int\"),\n            (\"test_var2\", \"Int\")\n        ],\n    );\n}\n\n#[test]\nfn custom_type_module_constants() {\n    assert_module_infer!(\n        \"pub type Test { A }\n        pub const some_test = A\",\n        vec![(\"A\", \"Test\"), (\"some_test\", \"Test\")],\n    );\n}\n\n#[test]\nfn const_record_update() {\n    assert_module_infer!(\n        \"pub type Person { Person(name: String, age: Int) }\n\n        pub const alice = Person(\\\"Alice\\\", 30)\n        pub const bob = Person(..alice, name: \\\"Bob\\\")\",\n        vec![\n            (\"Person\", \"fn(String, Int) -> Person\"),\n            (\"alice\", \"Person\"),\n            (\"bob\", \"Person\")\n        ],\n    );\n}\n\n#[test]\nfn const_record_update_all_fields() {\n    assert_warning!(\n        \"pub type Person { Person(name: String, age: Int, city: String) }\n\n        pub const base = Person(\\\"Alice\\\", 30, \\\"London\\\")\n        pub const updated = Person(..base, name: \\\"Bob\\\", age: 25, city: \\\"Paris\\\")\"\n    );\n}\n\n#[test]\nfn const_record_update_chain() {\n    assert_module_infer!(\n        \"pub type Person { Person(name: String, age: Int, city: String) }\n\n        pub const alice = Person(\\\"Alice\\\", 30, \\\"London\\\")\n        pub const bob = Person(..alice, name: \\\"Bob\\\")\n        pub const charlie = Person(..bob, age: 25)\",\n        vec![\n            (\"Person\", \"fn(String, Int, String) -> Person\"),\n            (\"alice\", \"Person\"),\n            (\"bob\", \"Person\"),\n            (\"charlie\", \"Person\")\n        ],\n    );\n}\n\n#[test]\nfn const_record_update_with_labeled_args() {\n    assert_module_infer!(\n        \"pub type Person { Person(name: String, age: Int, city: String) }\n        pub const alice = Person(name: \\\"Alice\\\", age: 30, city: \\\"London\\\")\n        pub const bob = Person(..alice, name: \\\"Bob\\\")\",\n        vec![\n            (\"Person\", \"fn(String, Int, String) -> Person\"),\n            (\"alice\", \"Person\"),\n            (\"bob\", \"Person\")\n        ],\n    );\n}\n\n#[test]\nfn const_record_update_type_mismatch_error() {\n    assert_module_error!(\n        \"pub type Person { Person(name: String, age: Int) }\n        pub type Animal { Animal(species: String) }\n\n        pub const alice = Person(\\\"Alice\\\", 30)\n        pub const dog = Animal(..alice)\"\n    );\n}\n\n#[test]\nfn const_record_update_variant_mismatch_error() {\n    assert_module_error!(\n        \"pub type Subject {\n            Person(name: String, age: Int)\n            Animal(species: String)\n        }\n\n        pub const alice = Person(\\\"Alice\\\", 30)\n        pub const dog = Animal(..alice)\"\n    );\n}\n\n#[test]\nfn const_record_update_field_type_mismatch_error() {\n    assert_module_error!(\n        \"pub type Person { Person(name: String, age: Int) }\n\n        pub const alice = Person(\\\"Alice\\\", 30)\n        pub const bob = Person(..alice, age: \\\"not a number\\\")\"\n    );\n}\n\n#[test]\nfn const_record_update_nonexistent_field() {\n    assert_module_error!(\n        \"pub type Person { Person(name: String, age: Int) }\n\n        pub const alice = Person(\\\"Alice\\\", 30)\n        pub const bob = Person(..alice, nonexistent: \\\"value\\\")\"\n    );\n}\n\n#[test]\nfn const_record_update_non_record() {\n    assert_module_error!(\n        \"pub type Person { Person(name: String, age: Int) }\n\n        pub const number = 42\n        pub const bob = Person(..number, name: \\\"Bob\\\")\"\n    );\n}\n\n#[test]\nfn const_record_update_fieldless_warning() {\n    assert_warning!(\n        \"pub type Animal { Animal(species: String) }\n\n        pub const alice = Animal(\\\"Cat\\\")\n        pub const dog = Animal(..alice)\"\n    );\n}\n\n#[test]\nfn const_record_update_multi_variant() {\n    assert_module_infer!(\n        \"pub type Pet {\n          Dog(name: String, age: Int)\n          Cat(name: String, breed: String)\n        }\n\n        pub const my_dog = Dog(\\\"Rex\\\", 5)\n        pub const another_dog = Dog(..my_dog, name: \\\"Max\\\")\",\n        vec![\n            (\"Cat\", \"fn(String, String) -> Pet\"),\n            (\"Dog\", \"fn(String, Int) -> Pet\"),\n            (\"another_dog\", \"Pet\"),\n            (\"my_dog\", \"Pet\"),\n        ]\n    );\n}\n\n#[test]\nfn const_record_update_variant_without_args() {\n    assert_module_error!(\n        \"pub type Status { Active Inactive }\n        pub const status1 = Active\n        pub const status2 = Active(..status1)\"\n    );\n}\n\n#[test]\nfn const_record_update_unlabelled_fields() {\n    assert_module_error!(\n        \"pub type Point { Point(Int, Int) }\n\n        pub const origin = Point(0, 0)\n        pub const point = Point(..origin)\"\n    );\n}\n\n#[test]\nfn const_record_update_generic_respecialization() {\n    assert_module_infer!(\n        \"pub type Box(a) {\n            Box(name: String, value: a)\n        }\n\n        pub const base = Box(\\\"score\\\", 50)\n        pub const updated = Box(..base, value: \\\"Hello\\\")\",\n        vec![\n            (\"Box\", \"fn(String, a) -> Box(a)\"),\n            (\"base\", \"Box(Int)\"),\n            (\"updated\", \"Box(String)\")\n        ],\n    );\n}\n\n#[test]\nfn generic_unlabelled_field_in_updated_const_record_wrong_type() {\n    assert_module_error!(\n        \"pub type Wibble(a) {\n            Wibble(a, b: Int, c: a)\n        }\n\n        const w = Wibble(1, 2, 3)\n        const w2 = Wibble(..w, c: False)\"\n    );\n}\n\n#[test]\nfn module_constant_functions() {\n    assert_module_infer!(\n        \"pub fn int_identity(i: Int) -> Int { i }\n        pub const int_identity_alias1 = int_identity\n        pub const int_identity_alias2 = int_identity_alias1\n        pub const int_identity_alias3: fn(Int) -> Int = int_identity_alias2\",\n        vec![\n            (\"int_identity\", \"fn(Int) -> Int\"),\n            (\"int_identity_alias1\", \"fn(Int) -> Int\"),\n            (\"int_identity_alias2\", \"fn(Int) -> Int\"),\n            (\"int_identity_alias3\", \"fn(Int) -> Int\"),\n        ]\n    );\n}\n\n#[test]\nfn functions_used_before_definition() {\n    assert_module_infer!(\n        \"pub fn a() { b() }\n         pub fn b() { 1 }\",\n        vec![(\"a\", \"fn() -> Int\"), (\"b\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn functions_used_before_definition1() {\n    assert_module_infer!(\n        \"pub fn a() { b() + c() }\n         fn b() { 1 }\n         fn c() { 1 }\",\n        vec![(\"a\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn functions_used_before_definition2() {\n    assert_module_infer!(\n        \"fn b() { 1 }\n         pub fn a() { b() + c() }\n         fn c() { 1 }\",\n        vec![(\"a\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn functions_used_before_definition3() {\n    assert_module_infer!(\n        \"pub fn a() { Thing }\n         pub type Thing { Thing }\",\n        vec![(\"Thing\", \"Thing\"), (\"a\", \"fn() -> Thing\"),],\n    );\n}\n\n#[test]\nfn types_used_before_definition() {\n    assert_module_infer!(\n        \"pub type Y { Y(X) }\n         pub type X\",\n        vec![(\"Y\", \"fn(X) -> Y\")],\n    );\n}\n\n#[test]\nfn types_used_before_definition1() {\n    assert_module_infer!(\n        \"pub type Y { Y(x: X) }\n         pub type X\",\n        vec![(\"Y\", \"fn(X) -> Y\")],\n    );\n}\n\n#[test]\nfn consts_used_before_definition() {\n    assert_module_infer!(\n        \"pub fn a() { b }\n        const b = 1\",\n        vec![(\"a\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn mutual_recursion() {\n    assert_module_infer!(\n        \"pub fn a() { b() }\n         fn b() { a() }\",\n        vec![(\"a\", \"fn() -> a\")],\n    );\n\n    assert_module_infer!(\n        \"pub fn a() { b() }\n         fn b() { a() + 1 }\",\n        vec![(\"a\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn type_annotations() {\n    assert_module_infer!(\n        \"pub type Box(x) { Box(label: String, contents: x) }\n         pub fn id(x: Box(y)) { x }\",\n        vec![\n            (\"Box\", \"fn(String, a) -> Box(a)\"),\n            (\"id\", \"fn(Box(a)) -> Box(a)\"),\n        ],\n    );\n\n    assert_module_infer!(\"pub fn go(x: Int) { x }\", vec![(\"go\", \"fn(Int) -> Int\")],);\n    assert_module_infer!(\"pub fn go(x: b) -> b { x }\", vec![(\"go\", \"fn(a) -> a\")],);\n    assert_module_infer!(\"pub fn go(x) -> b { x }\", vec![(\"go\", \"fn(a) -> a\")],);\n    assert_module_infer!(\"pub fn go(x: b) { x }\", vec![(\"go\", \"fn(a) -> a\")],);\n    assert_module_infer!(\n        \"pub fn go(x: List(b)) -> List(b) { x }\",\n        vec![(\"go\", \"fn(List(a)) -> List(a)\")],\n    );\n    assert_module_infer!(\n        \"pub fn go(x: List(b)) { x }\",\n        vec![(\"go\", \"fn(List(a)) -> List(a)\")],\n    );\n    assert_module_infer!(\n        \"pub fn go(x: List(String)) { x }\",\n        vec![(\"go\", \"fn(List(String)) -> List(String)\")],\n    );\n    assert_module_infer!(\"pub fn go(x: b, y: c) { x }\", vec![(\"go\", \"fn(a, b) -> a\")],);\n    assert_module_infer!(\"pub fn go(x) -> Int { x }\", vec![(\"go\", \"fn(Int) -> Int\")],);\n\n    assert_module_infer!(\n        \"pub fn id(x: x) { x }\n         pub fn float() { id(1.0) }\n         pub fn int() { id(1) }\",\n        vec![\n            (\"float\", \"fn() -> Float\"),\n            (\"id\", \"fn(a) -> a\"),\n            (\"int\", \"fn() -> Int\"),\n        ],\n    );\n}\n\n#[test]\nfn early_function_generalisation() {\n    assert_module_infer!(\n        \"pub fn id(x) { x }\n         pub fn int() { id(1) }\",\n        vec![(\"id\", \"fn(a) -> a\"), (\"int\", \"fn() -> Int\")],\n    );\n}\n\n#[test]\nfn early_function_generalisation2() {\n    assert_module_infer!(\n        \"pub fn id(x) { x }\n         pub fn int() { id(1) }\n         pub fn float() { id(1.0) }\n         \",\n        vec![\n            (\"float\", \"fn() -> Float\"),\n            (\"id\", \"fn(a) -> a\"),\n            (\"int\", \"fn() -> Int\"),\n        ],\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/970\n#[test]\nfn bit_array_pattern_unification() {\n    assert_module_infer!(\n        \"pub fn m(x) { case x { <<>> -> Nil _ -> Nil} }\",\n        vec![(\"m\", \"fn(BitArray) -> Nil\")],\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/970\n#[test]\nfn bit_array_pattern_unification2() {\n    assert_module_infer!(\n        \"pub fn m(x) { case x { <<>> -> Nil _ -> Nil} }\",\n        vec![(\"m\", \"fn(BitArray) -> Nil\")],\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/983\n#[test]\nfn qualified_prelude() {\n    assert_module_infer!(\n        \"import gleam\npub fn a() {\n  gleam.Ok(1)\n}\",\n        vec![(\"a\", \"fn() -> Result(Int, a)\")],\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1029\n#[test]\nfn empty_list_const() {\n    assert_module_infer!(\n        \"pub const empty = []\npub fn a() {\n    empty\n}\",\n        vec![(\"a\", \"fn() -> List(a)\"), (\"empty\", \"List(a)\")],\n    );\n}\n\n#[test]\nfn let_as_expression() {\n    assert_infer!(\"let x = 1\", \"Int\");\n}\n\n#[test]\nfn let_as_expression1() {\n    assert_infer!(\"let x = { let x = 1 }\", \"Int\");\n}\n\n#[test]\nfn let_as_expression2() {\n    assert_infer!(\"let x = { let x = 1. }\", \"Float\");\n}\n\n#[test]\nfn string_concat_ok() {\n    assert_infer!(r#\" \"1\" <> \"2\" \"#, \"String\");\n}\n\n#[test]\nfn string_concat_ko_1() {\n    assert_error!(r#\" \"1\" <> 2 \"#);\n}\n\n#[test]\nfn string_concat_ko_2() {\n    assert_error!(r#\" 1 <> \"2\" \"#);\n}\n\n// https://github.com/gleam-lang/gleam/issues/1087\n#[test]\nfn generic_inner_access() {\n    assert_module_infer!(\n        \"pub type B(b) { B(value: b) }\npub fn b_get_first(b: B(#(a))) {\n  b.value.0\n}\",\n        vec![(\"B\", \"fn(a) -> B(a)\"), (\"b_get_first\", \"fn(B(#(a))) -> a\")],\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1093\n#[test]\nfn fn_contextual_info() {\n    assert_module_infer!(\n        \"\ntype Box {\n  Box(inner: Int)\n}\n\nfn call(argument: t, function: fn(t) -> tt) -> tt {\n  function(argument)\n}\n\npub fn main() {\n  call(Box(1), fn(box) { box.inner })\n}\n\",\n        vec![(\"main\", \"fn() -> Int\")],\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/1519\n#[test]\nfn permit_holes_in_fn_args_and_returns() {\n    assert_module_infer!(\n        \"pub fn run(args: List(_)) -> List(_) {\n  todo\n}\",\n        vec![(\"run\", \"fn(List(a)) -> List(b)\")],\n    );\n}\n\n// Rattard's parser issue\n#[test]\nfn block_maths() {\n    assert_module_infer!(\n        \"pub fn do(max, min) {\n  { max -. min } /. { max +. min }\n}\",\n        vec![(\"do\", \"fn(Float, Float) -> Float\")],\n    );\n}\n\n#[test]\nfn infer_label_shorthand_in_call_arg() {\n    assert_module_infer!(\n        \"\n    pub fn main() {\n        let arg1 = 1\n        let arg2 = 1.0\n        let arg3 = False\n        wibble(arg2:, arg3:, arg1:)\n    }\n\n    pub fn wibble(arg1 arg1: Int, arg2 arg2: Float, arg3 arg3: Bool) { Nil }\n        \",\n        vec![\n            (\"main\", \"fn() -> Nil\"),\n            (\"wibble\", \"fn(Int, Float, Bool) -> Nil\")\n        ],\n    );\n}\n\n#[test]\nfn infer_label_shorthand_in_constructor_arg() {\n    assert_module_infer!(\n        \"\n    pub type Wibble { Wibble(arg1: Int, arg2: Bool, arg3: Float) }\n    pub fn main() {\n        let arg1 = 1\n        let arg2 = True\n        let arg3 = 1.0\n        Wibble(arg2:, arg3:, arg1:)\n    }\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Bool, Float) -> Wibble\"),\n            (\"main\", \"fn() -> Wibble\"),\n        ],\n    );\n}\n\n#[test]\nfn infer_label_shorthand_in_constant_constructor_arg() {\n    assert_module_infer!(\n        \"\n    pub type Wibble { Wibble(arg1: Int, arg2: Bool, arg3: Float) }\n    pub const arg1 = 1\n    pub const arg2 = True\n    pub const arg3 = 1.0\n\n    pub const wibble = Wibble(arg2:, arg3:, arg1:)\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Bool, Float) -> Wibble\"),\n            (\"arg1\", \"Int\"),\n            (\"arg2\", \"Bool\"),\n            (\"arg3\", \"Float\"),\n            (\"wibble\", \"Wibble\")\n        ],\n    );\n}\n\n#[test]\nfn infer_label_shorthand_in_pattern_arg() {\n    assert_module_infer!(\n        \"\n    pub type Wibble { Wibble(arg1: Int, arg2: Bool, arg3: Int) }\n    pub fn main() {\n        case Wibble(1, True, 2) {\n           Wibble(arg2:, arg3:, arg1:) if arg2 -> arg1 * arg3\n           _ -> 0\n        }\n    }\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Bool, Int) -> Wibble\"),\n            (\"main\", \"fn() -> Int\")\n        ],\n    );\n}\n\n#[test]\nfn infer_label_shorthand_in_record_update_arg() {\n    assert_module_infer!(\n        \"\n    pub type Wibble { Wibble(arg1: Int, arg2: Bool, arg3: Float) }\n    pub fn main() {\n        let wibble = Wibble(1, True, 2.0)\n        let arg3 = 3.0\n        let arg2 = False\n        Wibble(..wibble, arg3:, arg2:)\n    }\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, Bool, Float) -> Wibble\"),\n            (\"main\", \"fn() -> Wibble\")\n        ],\n    );\n}\n\n#[test]\nfn public_type_from_internal_module_has_internal_publicity() {\n    let module = compile_module(\"thepackage/internal\", \"pub type Wibble\", None, vec![]).unwrap();\n    let type_ = module.type_info.get_public_type(\"Wibble\").unwrap();\n    assert!(type_.publicity.is_internal());\n}\n\n#[test]\nfn internal_type_from_internal_module_has_internal_publicity() {\n    let module = compile_module(\n        \"thepackage/internal\",\n        \"@internal pub type Wibble\",\n        None,\n        vec![],\n    )\n    .unwrap();\n    let type_ = module.type_info.get_public_type(\"Wibble\").unwrap();\n    assert!(type_.publicity.is_internal());\n}\n\n#[test]\nfn private_type_from_internal_module_is_not_exposed_as_internal() {\n    let module = compile_module(\"thepackage/internal\", \"type Wibble\", None, vec![]).unwrap();\n    assert!(module.type_info.get_public_type(\"Wibble\").is_none());\n}\n\n#[test]\nfn assert_suitable_main_function_not_module_function() {\n    let value = ValueConstructor {\n        publicity: Publicity::Public,\n        deprecation: Deprecation::NotDeprecated,\n        type_: fn_(vec![], int()),\n        variant: ValueConstructorVariant::ModuleConstant {\n            documentation: None,\n            location: Default::default(),\n            module: \"module\".into(),\n            literal: Constant::Int {\n                location: Default::default(),\n                value: \"1\".into(),\n                int_value: 1.into(),\n            },\n            implementations: Implementations {\n                gleam: true,\n                uses_erlang_externals: false,\n                uses_javascript_externals: false,\n                can_run_on_erlang: true,\n                can_run_on_javascript: true,\n            },\n            name: \"main\".into(),\n        },\n    };\n    assert!(\n        assert_suitable_main_function(&value, &\"module\".into(), Origin::Src, Target::Erlang)\n            .is_err(),\n    );\n}\n\n#[test]\nfn assert_suitable_main_function_wrong_arity() {\n    let value = ValueConstructor {\n        publicity: Publicity::Public,\n        deprecation: Deprecation::NotDeprecated,\n        type_: fn_(vec![], int()),\n        variant: ValueConstructorVariant::ModuleFn {\n            name: \"name\".into(),\n            field_map: None,\n            arity: 1,\n            documentation: None,\n            location: Default::default(),\n            module: \"module\".into(),\n            external_erlang: None,\n            external_javascript: None,\n            implementations: Implementations {\n                gleam: true,\n                uses_erlang_externals: false,\n                uses_javascript_externals: false,\n                can_run_on_erlang: true,\n                can_run_on_javascript: true,\n            },\n            purity: Purity::Pure,\n        },\n    };\n    assert!(\n        assert_suitable_main_function(&value, &\"module\".into(), Origin::Src, Target::Erlang)\n            .is_err(),\n    );\n}\n\n#[test]\nfn assert_suitable_main_function_ok() {\n    let value = ValueConstructor {\n        publicity: Publicity::Public,\n        deprecation: Deprecation::NotDeprecated,\n        type_: fn_(vec![], int()),\n        variant: ValueConstructorVariant::ModuleFn {\n            name: \"name\".into(),\n            field_map: None,\n            arity: 0,\n            documentation: None,\n            location: Default::default(),\n            module: \"module\".into(),\n            external_erlang: None,\n            external_javascript: None,\n            implementations: Implementations {\n                gleam: true,\n                uses_erlang_externals: false,\n                uses_javascript_externals: false,\n                can_run_on_erlang: true,\n                can_run_on_javascript: true,\n            },\n            purity: Purity::Pure,\n        },\n    };\n    assert!(\n        assert_suitable_main_function(&value, &\"module\".into(), Origin::Src, Target::Erlang)\n            .is_ok(),\n    );\n}\n\n#[test]\nfn assert_suitable_main_function_erlang_not_supported() {\n    let value = ValueConstructor {\n        publicity: Publicity::Public,\n        deprecation: Deprecation::NotDeprecated,\n        type_: fn_(vec![], int()),\n        variant: ValueConstructorVariant::ModuleFn {\n            name: \"name\".into(),\n            field_map: None,\n            arity: 0,\n            documentation: None,\n            location: Default::default(),\n            module: \"module\".into(),\n            external_erlang: Some((\"wibble\".into(), \"wobble\".into())),\n            external_javascript: Some((\"wobble\".into(), \"wibble\".into())),\n            implementations: Implementations {\n                gleam: false,\n                uses_erlang_externals: true,\n                uses_javascript_externals: true,\n                can_run_on_erlang: false,\n                can_run_on_javascript: true,\n            },\n            purity: Purity::Impure,\n        },\n    };\n    assert!(\n        assert_suitable_main_function(&value, &\"module\".into(), Origin::Src, Target::Erlang)\n            .is_err(),\n    );\n}\n\n#[test]\nfn assert_suitable_main_function_javascript_not_supported() {\n    let value = ValueConstructor {\n        publicity: Publicity::Public,\n        deprecation: Deprecation::NotDeprecated,\n        type_: fn_(vec![], int()),\n        variant: ValueConstructorVariant::ModuleFn {\n            name: \"name\".into(),\n            field_map: None,\n            arity: 0,\n            documentation: None,\n            location: Default::default(),\n            module: \"module\".into(),\n            external_erlang: Some((\"wibble\".into(), \"wobble\".into())),\n            external_javascript: Some((\"wobble\".into(), \"wibble\".into())),\n            implementations: Implementations {\n                gleam: false,\n                uses_erlang_externals: true,\n                uses_javascript_externals: true,\n                can_run_on_erlang: true,\n                can_run_on_javascript: false,\n            },\n            purity: Purity::Impure,\n        },\n    };\n    assert!(\n        assert_suitable_main_function(&value, &\"module\".into(), Origin::Src, Target::JavaScript)\n            .is_err(),\n    );\n}\n\n#[test]\nfn pipe_with_annonymous_unannotated_functions() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x) { x.0 }\n     |> fn (x) { x }\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn pipe_with_annonymous_unannotated_functions_wrong_arity1() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x, y) { x.0 }\n     |> fn (x) { x }\n}\n\"#\n    );\n}\n\n#[test]\nfn pipe_with_annonymous_unannotated_functions_wrong_arity2() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x) { x.0 }\n     |> fn (x, y) { x }\n}\n\"#\n    );\n}\n\n#[test]\nfn pipe_with_annonymous_unannotated_functions_wrong_arity3() {\n    assert_module_error!(\n        r#\"\npub fn main() {\n  let a = 1\n     |> fn (x) { #(x, x + 1) }\n     |> fn (x) { x.0 }\n     |> fn () { x }\n}\n\"#\n    );\n}\n\n#[test]\nfn pipe_with_annonymous_mixed_functions() {\n    assert_module_infer!(\n        r#\"\npub fn main() {\n  let a = \"abc\"\n     |> fn (x) { #(x, x <> \"d\") }\n     |> fn (x) { x.0 }\n     |> fn (x: String) { x }\n}\n\"#,\n        vec![(\"main\", \"fn() -> String\")]\n    );\n}\n\n#[test]\nfn pipe_with_annonymous_functions_using_structs() {\n    // https://github.com/gleam-lang/gleam/issues/2504\n    assert_module_infer!(\n        r#\"\ntype Date {\n  Date(day: Day)\n}\ntype Day {\n  Day(year: Int)\n}\nfn now() -> Date {\n  Date(Day(2024))\n}\nfn get_day(date: Date) -> Day {\n  date.day\n}\npub fn main() {\n  now() |> get_day() |> fn (it) { it.year }\n}\n\"#,\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn labelled_argument_ordering() {\n    // https://github.com/gleam-lang/gleam/issues/3671\n    assert_module_infer!(\n        \"\ntype A { A }\ntype B { B }\ntype C { C }\ntype D { D }\n\nfn wibble(a a: A, b b: B, c c: C, d d: D) {\n  Nil\n}\n\npub fn main() {\n  wibble(A, C, D, b: B)\n  wibble(A, C, D, b: B)\n  wibble(B, C, D, a: A)\n  wibble(B, C, a: A, d: D)\n  wibble(B, C, d: D, a: A)\n  wibble(B, D, a: A, c: C)\n  wibble(B, D, c: C, a: A)\n  wibble(C, D, b: B, a: A)\n}\n\",\n        vec![(\"main\", \"fn() -> Nil\")]\n    );\n}\n\n#[test]\nfn variant_inference_allows_inference() {\n    // https://github.com/gleam-lang/gleam/pull/3647#issuecomment-2423146977\n    assert_module_infer!(\n        \"\npub type Wibble {\n  Wibble(a: Int)\n  Wobble(b: Int)\n}\n\npub fn do_a_thing(wibble) {\n  case wibble {\n    Wibble(..) -> wibble.a\n    _ -> todo\n  }\n  wibble\n}\n\",\n        vec![\n            (\"Wibble\", \"fn(Int) -> Wibble\"),\n            (\"Wobble\", \"fn(Int) -> Wibble\"),\n            (\"do_a_thing\", \"fn(Wibble) -> Wibble\")\n        ]\n    );\n}\n\n#[test]\nfn variant_inference_allows_inference2() {\n    // https://github.com/gleam-lang/gleam/pull/3647#issuecomment-2423146977\n    assert_module_infer!(\n        \"\npub type Box(a) {\n  Box(inner: a)\n  UnBox\n}\n\npub fn rebox(box) {\n  case box {\n    Box(..) -> Box(box.inner + 1)\n    UnBox -> UnBox\n  }\n}\n\",\n        vec![\n            (\"Box\", \"fn(a) -> Box(a)\"),\n            (\"UnBox\", \"Box(a)\"),\n            (\"rebox\", \"fn(Box(Int)) -> Box(Int)\")\n        ]\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3861\nfn variant_inference_on_literal_record() {\n    assert_module_error!(\n        \"\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  case Wibble, Wobble {\n    Wibble, Wibble -> todo\n  }\n}\n\"\n    );\n}\n\n#[test]\nfn variant_inference_on_prelude_types() {\n    assert_module_infer!(\n        \"\npub fn main() {\n  let always_ok = Ok(10)\n  case always_ok {\n    Ok(1) -> 1\n    Ok(2) -> 3\n    _ -> panic\n  }\n}\n\",\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn variant_inference_with_let_assert() {\n    assert_module_infer!(\n        \"\ntype Wibble {\n  Wibble(n: Int, b: Bool)\n  Wobble\n}\n\npub fn main() {\n  let wibble = wibble()\n  let assert Wibble(..) = wibble\n  wibble.n\n}\n\nfn wibble() {\n  Wibble(1, True)\n}\n\",\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn variant_inference_with_let_assert_and_alias() {\n    assert_module_infer!(\n        \"\ntype Wibble {\n  Wibble(n: Int, b: Bool)\n  Wobble\n}\n\npub fn main() {\n  let assert Wibble(..) as wibble = wibble()\n  wibble.n\n}\n\nfn wibble() {\n  Wibble(1, True)\n}\n\",\n        vec![(\"main\", \"fn() -> Int\")]\n    );\n}\n\n#[test]\nfn private_types_not_available_in_other_modules() {\n    assert_module_error!(\n        (\"wibble\", \"type Wibble\"),\n        \"\nimport wibble\n\ntype Wibble {\n  Wibble(wibble.Wibble)\n}\n\"\n    );\n}\n\n#[test]\nfn unlabelled_argument_not_allowed_after_labelled_argument() {\n    assert_module_error!(\n        \"\npub type Bad {\n  Bad(labelled: Int, Float)\n}\n\"\n    );\n}\n\n#[test]\nfn function_parameter_errors_do_not_stop_inference() {\n    assert_module_error!(\n        \"\npub fn wibble(x: NonExistent) {\n  1 + False\n}\n\"\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4287\n#[test]\nfn no_stack_overflow_for_nested_use() {\n    assert_module_infer!(\n        (\n            \"gleam/dynamic/decode\",\n            \"\npub fn string() {\n  Nil\n}\n\npub fn field(name, decoder, callback) {\n  callback(Nil)\n}\n\"\n        ),\n        r#\"\nimport gleam/dynamic/decode\n\npub fn main() {\n  use _n1 <- decode.field(\"n1\", decode.string)\n  use _n2 <- decode.field(\"n2\", decode.string)\n  use _n3 <- decode.field(\"n3\", decode.string)\n  use _n4 <- decode.field(\"n4\", decode.string)\n  use _n5 <- decode.field(\"n5\", decode.string)\n  use _n6 <- decode.field(\"n6\", decode.string)\n  use _n7 <- decode.field(\"n7\", decode.string)\n  use _n8 <- decode.field(\"n8\", decode.string)\n  use _n9 <- decode.field(\"n9\", decode.string)\n  use _n10 <- decode.field(\"n10\", decode.string)\n  use _n11 <- decode.field(\"n11\", decode.string)\n  use _n12 <- decode.field(\"n12\", decode.string)\n  use _n13 <- decode.field(\"n13\", decode.string)\n  use _n14 <- decode.field(\"n14\", decode.string)\n  use _n15 <- decode.field(\"n15\", decode.string)\n  use _n16 <- decode.field(\"n16\", decode.string)\n  use _n17 <- decode.field(\"n17\", decode.string)\n  use _n18 <- decode.field(\"n18\", decode.string)\n  use _n19 <- decode.field(\"n19\", decode.string)\n  use _n20 <- decode.field(\"n20\", decode.string)\n  use _n21 <- decode.field(\"n21\", decode.string)\n  use _n22 <- decode.field(\"n22\", decode.string)\n  use _n23 <- decode.field(\"n23\", decode.string)\n  use _n24 <- decode.field(\"n24\", decode.string)\n  use _n25 <- decode.field(\"n25\", decode.string)\n  use _n26 <- decode.field(\"n26\", decode.string)\n  use _n27 <- decode.field(\"n27\", decode.string)\n  use _n28 <- decode.field(\"n28\", decode.string)\n  use _n29 <- decode.field(\"n29\", decode.string)\n  use _n30 <- decode.field(\"n30\", decode.string)\n  use _n31 <- decode.field(\"n31\", decode.string)\n  use _n32 <- decode.field(\"n32\", decode.string)\n  use _n33 <- decode.field(\"n33\", decode.string)\n  use _n34 <- decode.field(\"n34\", decode.string)\n  use _n35 <- decode.field(\"n35\", decode.string)\n  use _n36 <- decode.field(\"n36\", decode.string)\n  use _n37 <- decode.field(\"n37\", decode.string)\n  use _n38 <- decode.field(\"n38\", decode.string)\n  use _n39 <- decode.field(\"n39\", decode.string)\n  use _n40 <- decode.field(\"n40\", decode.string)\n  use _n41 <- decode.field(\"n41\", decode.string)\n  use _n42 <- decode.field(\"n42\", decode.string)\n  use _n43 <- decode.field(\"n43\", decode.string)\n  use _n44 <- decode.field(\"n44\", decode.string)\n  use _n45 <- decode.field(\"n45\", decode.string)\n  use _n46 <- decode.field(\"n46\", decode.string)\n  use _n47 <- decode.field(\"n47\", decode.string)\n  use _n48 <- decode.field(\"n48\", decode.string)\n  use _n49 <- decode.field(\"n49\", decode.string)\n  use _n50 <- decode.field(\"n50\", decode.string)\n  use _n51 <- decode.field(\"n51\", decode.string)\n  use _n52 <- decode.field(\"n52\", decode.string)\n  use _n53 <- decode.field(\"n53\", decode.string)\n  use _n54 <- decode.field(\"n54\", decode.string)\n  use _n55 <- decode.field(\"n55\", decode.string)\n  Nil\n}\n\"#,\n        vec![(\"main\", \"fn() -> Nil\")]\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4883\n#[test]\nfn variant_inference_ignores_echo() {\n    assert_module_infer!(\n        \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: String)\n  Wobble(a: String, b: Int)\n}\n\npub fn get_int(w: Wibble) {\n  case echo w {\n    Wibble(..) -> w.wibble\n    Wobble(..) -> w.b\n  }\n}\n\",\n        vec![\n            (\"Wibble\", \"fn(Int, String) -> Wibble\"),\n            (\"Wobble\", \"fn(String, Int) -> Wibble\"),\n            (\"get_int\", \"fn(Wibble) -> Int\"),\n        ]\n    );\n}\n\n#[test]\nfn correct_type_check_for_multiple_mutually_recursive_functions() {\n    assert_module_error!(\n        r#\"\npub fn wibble(id) {\n  wobble(id, True)\n}\n\npub fn wobble(id, bool) {\n  case bool {\n    True -> wibble(id)\n    False -> wubble(id, bool)\n  }\n}\n\npub fn wubble(id, bool) {\n  case bool {\n    True -> final(id)\n    False -> wobble(id, bool)\n  }\n}\n\npub fn final(id) {\n  let #(a, b) = id\n  echo #(a, b)\n}\n\npub fn main() {\n  wibble(#(\"a\", \"b\"))\n  wibble(2)\n}\n\"#\n    );\n}\n\n#[test]\nfn prepend_constant_list() {\n    assert_module_infer!(\n        \"\nconst list = [3, 4, 5]\npub const full_list = [1, 2, ..list]\n\",\n        vec![(\"full_list\", \"List(Int)\")],\n    );\n}\n\n#[test]\nfn prepend_constant_list_from_other_module() {\n    assert_module_infer!(\n        (\"mod\", \"pub const list = [3, 4, 5]\"),\n        \"\nimport mod\n\npub const full_list = [1, 2, ..mod.list]\n\",\n        vec![(\"full_list\", \"List(Int)\")],\n    );\n}\n\n#[test]\nfn prepend_constant_list_wrong_type() {\n    assert_module_error!(\n        \"\nconst pi = 3.14\npub const full_list = [1.0, 2.0, ..pi]\n\"\n    );\n}\n\n#[test]\nfn prepend_constant_list_wrong_element_type() {\n    assert_module_error!(\n        \"\nconst list = [3, 4, 5]\npub const full_list = [1.0, 2.0, ..list]\n\"\n    );\n}\n"
  },
  {
    "path": "compiler-core/src/type_.rs",
    "content": "pub(crate) mod environment;\npub mod error;\npub(crate) mod expression;\npub(crate) mod fields;\npub(crate) mod hydrator;\npub(crate) mod pattern;\npub(crate) mod pipe;\npub(crate) mod prelude;\npub mod pretty;\npub mod printer;\n#[cfg(test)]\npub mod tests;\n\nuse camino::Utf8PathBuf;\nuse ecow::EcoString;\npub use environment::*;\npub use error::{Error, Problems, UnifyErrorSituation, Warning};\npub(crate) use expression::ExprTyper;\nuse expression::Purity;\npub use fields::FieldMap;\nuse hexpm::version::Version;\npub use prelude::*;\nuse printer::Names;\n\nuse crate::{\n    ast::{\n        ArgNames, BitArraySegment, CallArg, Constant, DefinitionLocation, Pattern, Publicity,\n        SrcSpan, TypedConstant, TypedExpr, TypedPattern, TypedPatternBitArraySegment,\n        UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg,\n    },\n    bit_array,\n    build::{Origin, Target},\n    inline::InlinableFunction,\n    line_numbers::LineNumbers,\n    reference::ReferenceMap,\n    type_::expression::Implementations,\n};\nuse error::*;\nuse hydrator::Hydrator;\nuse itertools::Itertools;\nuse std::{\n    cell::RefCell,\n    collections::{HashMap, HashSet},\n    ops::Deref,\n    sync::Arc,\n};\n\npub trait HasType {\n    fn type_(&self) -> Arc<Type>;\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Type {\n    /// A nominal (named) type such as `Int`, `Float`, or a programmer defined\n    /// custom type such as `Person`. The type can take other types as\n    /// arguments (aka \"generics\" or \"parametric polymorphism\").\n    ///\n    /// If the type is defined in the Gleam prelude the `module` field will be\n    /// the string \"gleam\", otherwise it will contain the name of the module\n    /// that defines the type.\n    ///\n    Named {\n        publicity: Publicity,\n        package: EcoString,\n        module: EcoString,\n        name: EcoString,\n        arguments: Vec<Arc<Type>>,\n\n        /// Which variant of the types this value is, if it is known from variant inference.\n        /// This allows us to permit certain operations when we know this,\n        /// such as record updates for multi-constructor types, or field access\n        /// for fields not shared between type variants. For example:\n        ///\n        /// ```gleam\n        /// type Wibble {\n        ///   Wibble(wibble: Int, other, Int)\n        ///   Wobble(wobble: Int, something: Int)\n        /// }\n        ///\n        /// fn add_one(some_wibble: Wibble) -> Wibble {\n        ///   case some_wibble {\n        ///     Wibble(..) as wibble -> Wibble(..wibble, other: wibble.other + 1)\n        ///     Wobble(..) as wobble -> Wobble(..wobble, something: wobble.something + 1)\n        ///   }\n        /// }\n        /// ```\n        ///\n        /// Here, the `wibble` variable has an inferred variant of `0`, since we know it's\n        /// of the `Wibble` variant. This means we can safely update it using the `Wibble`\n        /// constructor, and access the `other` field, which is only present in that variant.\n        ///\n        /// However, the parameter `some_wibble` has no known variant; it could be either of the variants,\n        /// so we can't allow any of that until we pattern match on it.\n        ///\n        inferred_variant: Option<u16>,\n    },\n\n    /// The type of a function. It takes arguments and returns a value.\n    ///\n    Fn {\n        arguments: Vec<Arc<Type>>,\n        return_: Arc<Type>,\n    },\n\n    /// A type variable. See the contained `TypeVar` enum for more information.\n    ///\n    Var { type_: Arc<RefCell<TypeVar>> },\n\n    /// A tuple is an ordered collection of 0 or more values, each of which\n    /// can have a different type, so the `tuple` type is the sum of all the\n    /// contained types.\n    ///\n    Tuple { elements: Vec<Arc<Type>> },\n}\n\nimpl Type {\n    pub fn is_result_constructor(&self) -> bool {\n        match self {\n            Type::Fn { return_, .. } => return_.is_result(),\n            Type::Var { type_ } => type_.borrow().is_result_constructor(),\n            Type::Named { .. } | Type::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_result(&self) -> bool {\n        match self {\n            Self::Named { name, module, .. } => \"Result\" == name && is_prelude_module(module),\n            Self::Var { type_ } => type_.borrow().is_result(),\n            Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_named(&self) -> bool {\n        match self {\n            Self::Named { .. } => true,\n            Self::Var { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn result_ok_type(&self) -> Option<Arc<Type>> {\n        match self {\n            Self::Named {\n                module,\n                name,\n                arguments,\n                ..\n            } if \"Result\" == name && is_prelude_module(module) => arguments.first().cloned(),\n            Self::Var { type_ } => type_.borrow().result_ok_type(),\n            Self::Named { .. } | Self::Tuple { .. } | Type::Fn { .. } => None,\n        }\n    }\n\n    pub fn result_types(&self) -> Option<(Arc<Type>, Arc<Type>)> {\n        match self {\n            Self::Named {\n                module,\n                name,\n                arguments,\n                ..\n            } if \"Result\" == name && is_prelude_module(module) => {\n                Some((arguments.first().cloned()?, arguments.get(1).cloned()?))\n            }\n            Self::Var { type_ } => type_.borrow().result_types(),\n            Self::Named { .. } | Self::Tuple { .. } | Type::Fn { .. } => None,\n        }\n    }\n\n    pub fn is_unbound(&self) -> bool {\n        match self {\n            Self::Var { type_ } => type_.borrow().is_unbound(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_variable(&self) -> bool {\n        match self {\n            Self::Var { type_ } => type_.borrow().is_variable(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn return_type(&self) -> Option<Arc<Self>> {\n        match self {\n            Self::Fn { return_, .. } => Some(return_.clone()),\n            Self::Var { type_ } => type_.borrow().return_type(),\n            Self::Named { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    pub fn fn_types(&self) -> Option<(Vec<Arc<Self>>, Arc<Self>)> {\n        match self {\n            Self::Fn {\n                arguments, return_, ..\n            } => Some((arguments.clone(), return_.clone())),\n            Self::Var { type_ } => type_.borrow().fn_types(),\n            Self::Named { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    /// Gets the types inside of a tuple. Returns `None` if the type is not a tuple.\n    pub fn tuple_types(&self) -> Option<Vec<Arc<Self>>> {\n        match self {\n            Self::Tuple { elements } => Some(elements.clone()),\n            Self::Var { type_, .. } => type_.borrow().tuple_types(),\n            Self::Named { .. } | Self::Fn { .. } => None,\n        }\n    }\n\n    /// Gets the argument types for a type constructor. Returns `None` if the type\n    /// does not lead to a type constructor.\n    pub fn constructor_types(&self) -> Option<Vec<Arc<Self>>> {\n        match self {\n            Self::Named { arguments, .. } => Some(arguments.clone()),\n            Self::Var { type_, .. } => type_.borrow().constructor_types(),\n            Self::Fn { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    /// If the type is a Gleam's prelude's List this will return its wrapped\n    /// type.\n    pub fn list_type(&self) -> Option<Arc<Self>> {\n        match self {\n            Type::Named {\n                publicity: Publicity::Public,\n                name,\n                module,\n                package,\n                arguments,\n                inferred_variant: _,\n            } if package == PRELUDE_PACKAGE_NAME\n                && module == PRELUDE_MODULE_NAME\n                && name == LIST =>\n            {\n                match arguments.as_slice() {\n                    [inner_type] => Some(inner_type.clone()),\n                    [] | [_, _, ..] => None,\n                }\n            }\n            Type::Named { .. } | Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => None,\n        }\n    }\n\n    pub fn list(inner_type: Arc<Self>) -> Self {\n        Type::Named {\n            publicity: Publicity::Public,\n            package: PRELUDE_PACKAGE_NAME.into(),\n            module: PRELUDE_MODULE_NAME.into(),\n            name: LIST.into(),\n            arguments: vec![inner_type],\n            inferred_variant: None,\n        }\n    }\n\n    #[must_use]\n    fn is_fun(&self) -> bool {\n        match self {\n            Self::Fn { .. } => true,\n            Self::Var { type_ } => type_.borrow().is_fun(),\n            Self::Named { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_nil(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"Nil\" == name && is_prelude_module(module) => true,\n            Self::Var { type_ } => type_.borrow().is_nil(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_bit_array(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"BitArray\" == name && is_prelude_module(module) => {\n                true\n            }\n            Self::Var { type_ } => type_.borrow().is_bit_array(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_utf_codepoint(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. }\n                if \"UtfCodepoint\" == name && is_prelude_module(module) =>\n            {\n                true\n            }\n            Self::Var { type_ } => type_.borrow().is_utf_codepoint(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_bool(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"Bool\" == name && is_prelude_module(module) => true,\n            Self::Var { type_ } => type_.borrow().is_bool(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_int(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"Int\" == name && is_prelude_module(module) => true,\n            Self::Var { type_ } => type_.borrow().is_int(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_float(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"Float\" == name && is_prelude_module(module) => {\n                true\n            }\n            Self::Var { type_ } => type_.borrow().is_float(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_string(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"String\" == name && is_prelude_module(module) => {\n                true\n            }\n            Self::Var { type_ } => type_.borrow().is_string(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn is_list(&self) -> bool {\n        match self {\n            Self::Named { module, name, .. } if \"List\" == name && is_prelude_module(module) => true,\n            Self::Var { type_ } => type_.borrow().is_list(),\n            Self::Named { .. } | Self::Fn { .. } | Self::Tuple { .. } => false,\n        }\n    }\n\n    pub fn named_type_name(&self) -> Option<(EcoString, EcoString)> {\n        match self {\n            Self::Named { module, name, .. } => Some((module.clone(), name.clone())),\n            Self::Var { type_ } => type_.borrow().named_type_name(),\n            Self::Fn { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    pub fn named_type_information(&self) -> Option<(EcoString, EcoString, Vec<Arc<Self>>)> {\n        match self {\n            Self::Named {\n                module,\n                name,\n                arguments,\n                ..\n            } => Some((module.clone(), name.clone(), arguments.clone())),\n            Self::Var { type_ } => type_.borrow().named_type_information(),\n            Self::Fn { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    pub fn set_custom_type_variant(&mut self, index: u16) {\n        match self {\n            Type::Named {\n                inferred_variant, ..\n            } => *inferred_variant = Some(index),\n            Type::Var { type_ } => type_.borrow_mut().set_custom_type_variant(index),\n            Type::Fn { .. } | Type::Tuple { .. } => {}\n        }\n    }\n\n    pub fn generalise_custom_type_variant(&mut self) {\n        match self {\n            Type::Named {\n                inferred_variant, ..\n            } => *inferred_variant = None,\n            Type::Var { type_ } => type_.borrow_mut().generalise_custom_type_variant(),\n            Type::Tuple { elements } => {\n                for element in elements {\n                    Arc::make_mut(element).generalise_custom_type_variant();\n                }\n            }\n            Type::Fn { arguments, return_ } => {\n                for argument in arguments {\n                    Arc::make_mut(argument).generalise_custom_type_variant();\n                }\n                Arc::make_mut(return_).generalise_custom_type_variant();\n            }\n        }\n    }\n\n    pub fn custom_type_inferred_variant(&self) -> Option<u16> {\n        match self {\n            Type::Named {\n                inferred_variant, ..\n            } => *inferred_variant,\n            Type::Var { type_ } => type_.borrow().custom_type_inferred_variant(),\n            Type::Fn { .. } | Type::Tuple { .. } => None,\n        }\n    }\n\n    /// Get the args for the type if the type is a specific `Type::Named`.\n    /// Returns None if the type is not a `Type::Named` or is an incorrect `Type:Named`\n    ///\n    /// This function is currently only used for finding the `List` type.\n    ///\n    // TODO: specialise this to just List.\n    pub fn named_type_arguments(\n        &self,\n        publicity: Publicity,\n        package: &str,\n        module: &str,\n        name: &str,\n        arity: usize,\n        environment: &mut Environment<'_>,\n    ) -> Option<Vec<Arc<Self>>> {\n        match self {\n            Self::Named {\n                module: m,\n                name: n,\n                arguments,\n                ..\n            } => {\n                if module == m && name == n && arguments.len() == arity {\n                    Some(arguments.clone())\n                } else {\n                    None\n                }\n            }\n\n            Self::Var { type_ } => {\n                let arguments: Vec<_> = match type_.borrow().deref() {\n                    TypeVar::Link { type_ } => {\n                        return type_.named_type_arguments(\n                            publicity,\n                            package,\n                            module,\n                            name,\n                            arity,\n                            environment,\n                        );\n                    }\n\n                    TypeVar::Unbound { .. } => {\n                        (0..arity).map(|_| environment.new_unbound_var()).collect()\n                    }\n\n                    TypeVar::Generic { .. } => return None,\n                };\n\n                // We are an unbound type variable! So convert us to a type link\n                // to the desired type.\n                *type_.borrow_mut() = TypeVar::Link {\n                    type_: Arc::new(Self::Named {\n                        name: name.into(),\n                        package: package.into(),\n                        module: module.into(),\n                        arguments: arguments.clone(),\n                        publicity,\n                        inferred_variant: None,\n                    }),\n                };\n                Some(arguments)\n            }\n\n            Self::Fn { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    pub fn find_private_type(&self) -> Option<Self> {\n        match self {\n            Self::Named {\n                publicity: Publicity::Private,\n                ..\n            } => Some(self.clone()),\n\n            Self::Named { arguments, .. } => {\n                arguments.iter().find_map(|type_| type_.find_private_type())\n            }\n\n            Self::Tuple { elements, .. } => {\n                elements.iter().find_map(|type_| type_.find_private_type())\n            }\n\n            Self::Fn {\n                return_, arguments, ..\n            } => return_\n                .find_private_type()\n                .or_else(|| arguments.iter().find_map(|type_| type_.find_private_type())),\n\n            Self::Var { type_, .. } => match type_.borrow().deref() {\n                TypeVar::Unbound { .. } => None,\n\n                TypeVar::Generic { .. } => None,\n\n                TypeVar::Link { type_, .. } => type_.find_private_type(),\n            },\n        }\n    }\n\n    pub fn find_internal_type(&self) -> Option<Self> {\n        match self {\n            Self::Named { publicity, .. } if publicity.is_internal() => Some(self.clone()),\n\n            Self::Named { arguments, .. } => arguments\n                .iter()\n                .find_map(|type_| type_.find_internal_type()),\n\n            Self::Tuple { elements, .. } => {\n                elements.iter().find_map(|type_| type_.find_internal_type())\n            }\n\n            Self::Fn {\n                return_, arguments, ..\n            } => return_.find_internal_type().or_else(|| {\n                arguments\n                    .iter()\n                    .find_map(|type_| type_.find_internal_type())\n            }),\n\n            Self::Var { type_, .. } => match type_.borrow().deref() {\n                TypeVar::Unbound { .. } | TypeVar::Generic { .. } => None,\n                TypeVar::Link { type_, .. } => type_.find_internal_type(),\n            },\n        }\n    }\n\n    pub fn fn_arity(&self) -> Option<usize> {\n        match self {\n            Self::Fn { arguments, .. } => Some(arguments.len()),\n            Self::Named { .. } | Self::Var { .. } | Self::Tuple { .. } => None,\n        }\n    }\n\n    /// If the type is named, return its publicity.\n    ///\n    pub fn named_type_publicity(&self) -> Option<Publicity> {\n        match self {\n            Type::Named { publicity, .. } => Some(*publicity),\n            Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => None,\n        }\n    }\n\n    #[must_use]\n    /// Returns `true` is the two types are the same. This differs from the\n    /// standard `Eq` implementation as it also follows all links to check if\n    /// two types are really the same.\n    ///\n    pub fn same_as(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Type::Named { .. }, Type::Fn { .. } | Type::Tuple { .. }) => false,\n            (one @ Type::Named { .. }, Type::Var { type_ }) => {\n                type_.as_ref().borrow().same_as_other_type(one)\n            }\n            // When comparing two types we don't care about the inferred variant:\n            // `True` has the same type as `False`, even if the inferred variants\n            // differ.\n            (\n                Type::Named {\n                    publicity,\n                    package,\n                    module,\n                    name,\n                    arguments,\n                    inferred_variant: _,\n                },\n                Type::Named {\n                    publicity: other_publicity,\n                    package: other_package,\n                    module: other_module,\n                    name: other_name,\n                    arguments: other_arguments,\n                    inferred_variant: _,\n                },\n            ) => {\n                publicity == other_publicity\n                    && package == other_package\n                    && module == other_module\n                    && name == other_name\n                    && arguments.len() == other_arguments.len()\n                    && arguments\n                        .iter()\n                        .zip(other_arguments)\n                        .all(|(one, other)| one.same_as(other))\n            }\n\n            (Type::Fn { .. }, Type::Named { .. } | Type::Tuple { .. }) => false,\n            (one @ Type::Fn { .. }, Type::Var { type_ }) => {\n                type_.as_ref().borrow().same_as_other_type(one)\n            }\n            (\n                Type::Fn { arguments, return_ },\n                Type::Fn {\n                    arguments: other_arguments,\n                    return_: other_return,\n                },\n            ) => {\n                arguments.len() == other_arguments.len()\n                    && arguments\n                        .iter()\n                        .zip(other_arguments)\n                        .all(|(one, other)| one.same_as(other))\n                    && return_.same_as(other_return)\n            }\n\n            (Type::Var { type_ }, other) => type_.as_ref().borrow().same_as_other_type(other),\n\n            (Type::Tuple { .. }, Type::Fn { .. } | Type::Named { .. }) => false,\n            (one @ Type::Tuple { .. }, Type::Var { type_ }) => {\n                type_.as_ref().borrow().same_as_other_type(one)\n            }\n            (\n                Type::Tuple { elements },\n                Type::Tuple {\n                    elements: other_elements,\n                },\n            ) => {\n                elements.len() == other_elements.len()\n                    && elements\n                        .iter()\n                        .zip(other_elements)\n                        .all(|(one, other)| one.same_as(other))\n            }\n        }\n    }\n}\n\nimpl TypeVar {\n    #[must_use]\n    fn same_as_other_type(&self, other: &Type) -> bool {\n        match (self, other) {\n            (TypeVar::Unbound { .. }, _) => true,\n            (TypeVar::Link { type_ }, other) => type_.same_as(other),\n\n            (\n                TypeVar::Generic { .. },\n                Type::Named { .. } | Type::Fn { .. } | Type::Tuple { .. },\n            ) => false,\n\n            (one @ TypeVar::Generic { .. }, Type::Var { type_ }) => {\n                one.same_as(&type_.as_ref().borrow())\n            }\n        }\n    }\n\n    #[must_use]\n    fn same_as(&self, other: &Self) -> bool {\n        match (self, other) {\n            (TypeVar::Unbound { .. }, _) | (_, TypeVar::Unbound { .. }) => true,\n            (TypeVar::Link { type_ }, TypeVar::Link { type_: other_type }) => {\n                type_.same_as(other_type)\n            }\n            (TypeVar::Link { type_ }, other @ TypeVar::Generic { .. }) => {\n                other.same_as_other_type(type_)\n            }\n            (TypeVar::Generic { id }, TypeVar::Generic { id: other_id }) => id == other_id,\n            (one @ TypeVar::Generic { .. }, TypeVar::Link { type_ }) => {\n                one.same_as_other_type(type_)\n            }\n        }\n    }\n}\n\npub fn collapse_links(t: Arc<Type>) -> Arc<Type> {\n    if let Type::Var { type_ } = t.deref()\n        && let TypeVar::Link { type_ } = type_.borrow().deref()\n    {\n        return collapse_links(type_.clone());\n    }\n    t\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct AccessorsMap {\n    pub publicity: Publicity,\n    pub type_: Arc<Type>,\n    pub shared_accessors: HashMap<EcoString, RecordAccessor>,\n    pub variant_specific_accessors: Vec<HashMap<EcoString, RecordAccessor>>,\n    pub variant_positional_accessors: Vec<Vec<Arc<Type>>>,\n}\n\nimpl AccessorsMap {\n    pub fn accessors_for_variant(\n        &self,\n        inferred_variant: Option<u16>,\n    ) -> &HashMap<EcoString, RecordAccessor> {\n        inferred_variant\n            .and_then(|index| self.variant_specific_accessors.get(index as usize))\n            .unwrap_or(&self.shared_accessors)\n    }\n\n    pub fn positional_accessors(&self, inferred_variant: u16) -> Option<&Vec<Arc<Type>>> {\n        self.variant_positional_accessors\n            .get(inferred_variant as usize)\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct RecordAccessor {\n    // TODO: smaller int. Doesn't need to be this big\n    pub index: u64,\n    pub label: EcoString,\n    pub type_: Arc<Type>,\n    pub documentation: Option<EcoString>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum ValueConstructorVariant {\n    /// A locally defined variable or function parameter\n    LocalVariable {\n        location: SrcSpan,\n        origin: VariableOrigin,\n    },\n\n    /// A module constant\n    ModuleConstant {\n        documentation: Option<EcoString>,\n        location: SrcSpan,\n        module: EcoString,\n        name: EcoString,\n        literal: Constant<Arc<Type>, EcoString>,\n        implementations: Implementations,\n    },\n\n    /// A function belonging to the module\n    ModuleFn {\n        name: EcoString,\n        field_map: Option<FieldMap>,\n        module: EcoString,\n        arity: usize,\n        location: SrcSpan,\n        documentation: Option<EcoString>,\n        implementations: Implementations,\n        external_erlang: Option<(EcoString, EcoString)>,\n        external_javascript: Option<(EcoString, EcoString)>,\n        purity: Purity,\n    },\n\n    /// A constructor for a custom type\n    Record {\n        name: EcoString,\n        arity: u16,\n        field_map: Option<FieldMap>,\n        location: SrcSpan,\n        module: EcoString,\n        variants_count: u16,\n        variant_index: u16,\n        documentation: Option<EcoString>,\n    },\n}\n\nimpl ValueConstructorVariant {\n    fn to_module_value_constructor(\n        &self,\n        type_: Arc<Type>,\n        module_name: &EcoString,\n        function_name: &EcoString,\n    ) -> ModuleValueConstructor {\n        match self {\n            Self::Record {\n                name,\n                arity,\n                field_map,\n                location,\n                documentation,\n                variant_index,\n                ..\n            } => ModuleValueConstructor::Record {\n                name: name.clone(),\n                variant_index: *variant_index,\n                field_map: field_map.clone(),\n                arity: *arity,\n                type_,\n                location: *location,\n                documentation: documentation.clone(),\n            },\n\n            // TODO: remove this clone with an rc clone\n            Self::ModuleConstant {\n                documentation,\n                literal,\n                location,\n                ..\n            } => ModuleValueConstructor::Constant {\n                literal: literal.clone(),\n                location: *location,\n                documentation: documentation.clone(),\n            },\n\n            Self::LocalVariable { location, .. } => ModuleValueConstructor::Fn {\n                name: function_name.clone(),\n                module: module_name.clone(),\n                external_erlang: None,\n                external_javascript: None,\n                documentation: None,\n                location: *location,\n                field_map: None,\n                purity: Purity::Impure,\n            },\n\n            Self::ModuleFn {\n                name,\n                module,\n                location,\n                documentation,\n                field_map,\n                external_erlang,\n                external_javascript,\n                purity,\n                ..\n            } => ModuleValueConstructor::Fn {\n                name: name.clone(),\n                module: module.clone(),\n                documentation: documentation.clone(),\n                external_erlang: external_erlang.clone(),\n                external_javascript: external_javascript.clone(),\n                location: *location,\n                field_map: field_map.clone(),\n                purity: *purity,\n            },\n        }\n    }\n\n    pub fn definition_location(&self) -> SrcSpan {\n        match self {\n            ValueConstructorVariant::LocalVariable { location, .. }\n            | ValueConstructorVariant::ModuleConstant { location, .. }\n            | ValueConstructorVariant::ModuleFn { location, .. }\n            | ValueConstructorVariant::Record { location, .. } => *location,\n        }\n    }\n\n    /// Returns `true` if the variant is [`LocalVariable`].\n    pub fn is_local_variable(&self) -> bool {\n        matches!(self, Self::LocalVariable { .. })\n    }\n\n    /// Returns `true` if the variant is a local variable generated by the compiler.\n    #[must_use]\n    pub fn is_generated_variable(&self) -> bool {\n        match self {\n            ValueConstructorVariant::LocalVariable { origin, .. } => {\n                matches!(origin.syntax, VariableSyntax::Generated)\n            }\n            ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::ModuleFn { .. }\n            | ValueConstructorVariant::Record { .. } => false,\n        }\n    }\n\n    /// Returns `true` if the value constructor variant is [`ModuleFn`].\n    ///\n    /// [`ModuleFn`]: ValueConstructorVariant::ModuleFn\n    #[must_use]\n    pub fn is_module_fn(&self) -> bool {\n        matches!(self, Self::ModuleFn { .. })\n    }\n\n    pub fn is_record(&self) -> bool {\n        matches!(self, Self::Record { .. })\n    }\n\n    pub fn implementations(&self) -> Implementations {\n        match self {\n            ValueConstructorVariant::Record { .. }\n            | ValueConstructorVariant::LocalVariable { .. } => Implementations {\n                gleam: true,\n                can_run_on_erlang: true,\n                can_run_on_javascript: true,\n                uses_javascript_externals: false,\n                uses_erlang_externals: false,\n            },\n\n            ValueConstructorVariant::ModuleFn {\n                implementations, ..\n            }\n            | ValueConstructorVariant::ModuleConstant {\n                implementations, ..\n            } => *implementations,\n        }\n    }\n\n    fn record_field_map(&self) -> Option<&FieldMap> {\n        match self {\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::ModuleFn { .. } => None,\n            ValueConstructorVariant::Record { field_map, .. } => field_map.as_ref(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum ModuleValueConstructor {\n    Record {\n        name: EcoString,\n        variant_index: u16,\n        arity: u16,\n        type_: Arc<Type>,\n        field_map: Option<FieldMap>,\n        location: SrcSpan,\n        documentation: Option<EcoString>,\n    },\n\n    Fn {\n        location: SrcSpan,\n        /// The name of the module and the function\n        /// This will be the module that this constructor belongs to\n        /// and the name that was used for the function.\n        module: EcoString,\n        name: EcoString,\n        /// If this is an `external` function, these will hold the name of the\n        /// external module and function.\n        ///\n        /// This function has module \"themodule\" and name \"wibble\"\n        ///     pub fn wibble() { Nil }\n        ///\n        /// This function has module \"themodule\" and name \"wibble\"\n        /// and erlang external \"other\" and \"whoop\".\n        ///     @external(erlang, \"other\", \"whoop\")\n        ///     pub fn wibble() -> Nil\n        ///\n        external_erlang: Option<(EcoString, EcoString)>,\n        external_javascript: Option<(EcoString, EcoString)>,\n        field_map: Option<FieldMap>,\n        documentation: Option<EcoString>,\n        purity: Purity,\n    },\n\n    Constant {\n        literal: TypedConstant,\n        location: SrcSpan,\n        documentation: Option<EcoString>,\n    },\n}\n\nimpl ModuleValueConstructor {\n    pub fn location(&self) -> SrcSpan {\n        match self {\n            ModuleValueConstructor::Fn { location, .. }\n            | ModuleValueConstructor::Record { location, .. }\n            | ModuleValueConstructor::Constant { location, .. } => *location,\n        }\n    }\n\n    pub fn get_documentation(&self) -> Option<&str> {\n        match self {\n            ModuleValueConstructor::Record { documentation, .. }\n            | ModuleValueConstructor::Fn { documentation, .. }\n            | ModuleValueConstructor::Constant { documentation, .. } => documentation.as_deref(),\n        }\n    }\n\n    /// Returns the purity of this value constructor if it is called as a function.\n    /// Referencing a module value by itself is always pure, but calling is as a\n    /// function might not be.\n    pub fn called_function_purity(&self) -> Purity {\n        match self {\n            // If we call a module constant or local variable as a function, we\n            // no longer have enough information to determine its purity. For\n            // example:\n            //\n            // ```gleam\n            // const function1 = io.println\n            // const function2 = function.identity\n            //\n            // pub fn main() {\n            //   function1(\"Hello\")\n            //   function2(\"Hello\")\n            // }\n            // ```\n            //\n            // At this point, we don't have any information about the purity of\n            // the `function1` and `function2` functions, and must return\n            // `Purity::Unknown`. See the documentation for the `Purity` type\n            // for more information on why this is the case.\n            ModuleValueConstructor::Constant { .. } => Purity::Unknown,\n\n            // Constructing records is always pure\n            ModuleValueConstructor::Record { .. } => Purity::Pure,\n\n            ModuleValueConstructor::Fn { purity, .. } => *purity,\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct ModuleFunction {\n    pub package: EcoString,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct ModuleInterface {\n    pub name: EcoString,\n    pub origin: Origin,\n    pub package: EcoString,\n    pub types: HashMap<EcoString, TypeConstructor>,\n    pub types_value_constructors: HashMap<EcoString, TypeVariantConstructors>,\n    pub values: HashMap<EcoString, ValueConstructor>,\n    pub accessors: HashMap<EcoString, AccessorsMap>,\n    /// Used for mapping to original source locations on disk\n    pub line_numbers: LineNumbers,\n    /// Used for determining the source path of the module on disk\n    pub src_path: Utf8PathBuf,\n    /// Whether the module is internal or not. Internal modules are technically\n    /// importable by other packages but to do so is violating the contract of\n    /// the package and as such is not recommended.\n    pub is_internal: bool,\n    /// Warnings emitted during analysis of this module.\n    pub warnings: Vec<Warning>,\n    /// The minimum Gleam version needed to use this module.\n    pub minimum_required_version: Version,\n    pub type_aliases: HashMap<EcoString, TypeAliasConstructor>,\n    pub documentation: Vec<EcoString>,\n    /// Wether there's any echo in the module.\n    pub contains_echo: bool,\n    pub references: References,\n    /// Functions which can be inlined\n    pub inline_functions: HashMap<EcoString, InlinableFunction>,\n}\n\nimpl ModuleInterface {\n    pub fn contains_todo(&self) -> bool {\n        self.warnings.iter().any(|warning| warning.is_todo())\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]\npub struct References {\n    pub imported_modules: HashSet<EcoString>,\n    pub value_references: ReferenceMap,\n    pub type_references: ReferenceMap,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum Opaque {\n    Opaque,\n    NotOpaque,\n}\n\n/// Information on the constructors of a custom type.\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct TypeVariantConstructors {\n    /// The id of the generic type variables of the generic version of the type that these\n    /// constructors belong to.\n    /// For example, if we have this type:\n    ///\n    /// ```gleam\n    /// pub type Option(a) {\n    ///   Some(a)\n    ///   None\n    /// }\n    /// ```\n    ///\n    /// and `a` is a Generic type variable with id 1, then this field will be `[1]`.\n    ///\n    pub type_parameters_ids: Vec<u64>,\n    pub opaque: Opaque,\n    pub variants: Vec<TypeValueConstructor>,\n}\n\nimpl TypeVariantConstructors {\n    pub(crate) fn new(\n        variants: Vec<TypeValueConstructor>,\n        type_parameters: &[&EcoString],\n        opaque: Opaque,\n        hydrator: Hydrator,\n    ) -> TypeVariantConstructors {\n        let named_types = hydrator.named_type_variables();\n        let type_parameters = type_parameters\n            .iter()\n            .map(|&p| {\n                let t = named_types\n                    .get(p)\n                    .expect(\"Type parameter not found in hydrator\");\n                let error = \"Hydrator must not store non generic types here\";\n                match t.type_.as_ref() {\n                    Type::Var { type_ } => match type_.borrow().deref() {\n                        TypeVar::Generic { id } => *id,\n                        TypeVar::Unbound { .. } | TypeVar::Link { .. } => panic!(\"{}\", error),\n                    },\n                    Type::Named { .. } | Type::Fn { .. } | Type::Tuple { .. } => {\n                        panic!(\"{}\", error)\n                    }\n                }\n            })\n            .collect_vec();\n        Self {\n            type_parameters_ids: type_parameters,\n            variants,\n            opaque,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct TypeValueConstructor {\n    pub name: EcoString,\n    pub parameters: Vec<TypeValueConstructorField>,\n    pub documentation: Option<EcoString>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct TypeValueConstructorField {\n    /// This type of this parameter\n    pub type_: Arc<Type>,\n    pub label: Option<EcoString>,\n    pub documentation: Option<EcoString>,\n}\n\nimpl ModuleInterface {\n    pub fn get_public_value(&self, name: &str) -> Option<&ValueConstructor> {\n        let value = self.values.get(name)?;\n        if value.publicity.is_importable() {\n            Some(value)\n        } else {\n            None\n        }\n    }\n\n    pub fn get_public_type(&self, name: &str) -> Option<&TypeConstructor> {\n        let type_ = self.types.get(name)?;\n        if type_.publicity.is_importable() {\n            Some(type_)\n        } else {\n            None\n        }\n    }\n\n    pub fn get_main_function(&self, target: Target) -> Result<ModuleFunction, crate::Error> {\n        // Module must have a value with the name \"main\"\n        let Some(value) = self.values.get(&EcoString::from(\"main\")) else {\n            return Err(crate::Error::ModuleDoesNotHaveMainFunction {\n                module: self.name.clone(),\n                origin: self.origin,\n            });\n        };\n\n        assert_suitable_main_function(value, &self.name, self.origin, target)?;\n\n        Ok(ModuleFunction {\n            package: self.package.clone(),\n        })\n    }\n\n    pub fn public_value_names(&self) -> Vec<EcoString> {\n        self.values\n            .iter()\n            .filter(|(_, v)| v.publicity.is_importable())\n            .map(|(k, _)| k)\n            .cloned()\n            .collect_vec()\n    }\n\n    pub fn public_type_names(&self) -> Vec<EcoString> {\n        self.types\n            .iter()\n            .filter(|(_, v)| v.publicity.is_importable())\n            .map(|(k, _)| k)\n            .cloned()\n            .collect_vec()\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct PatternConstructor {\n    pub name: EcoString,\n    pub field_map: Option<FieldMap>,\n    pub documentation: Option<EcoString>,\n    pub module: EcoString,\n    pub location: SrcSpan,\n    pub constructor_index: u16,\n}\n\nimpl PatternConstructor {\n    pub fn definition_location(&self) -> Option<DefinitionLocation> {\n        Some(DefinitionLocation {\n            module: Some(self.module.clone()),\n            span: self.location,\n        })\n    }\n\n    pub fn get_documentation(&self) -> Option<&str> {\n        self.documentation.as_deref()\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum TypeVar {\n    /// Unbound is an unbound variable. It is one specific type but we don't\n    /// know what yet in the inference process. It has a unique id which can be used to\n    /// identify if two unbound variable Rust values are the same Gleam type variable\n    /// instance or not.\n    ///\n    Unbound { id: u64 },\n    /// Link is type variable where it was an unbound variable but we worked out\n    /// that it is some other type and now we point to that one.\n    ///\n    Link { type_: Arc<Type> },\n    /// A Generic variable stands in for any possible type and cannot be\n    /// specialised to any one type\n    ///\n    /// # Example\n    ///\n    /// ```gleam\n    /// type Cat(a) {\n    ///   Cat(name: a)\n    /// }\n    /// // a is TypeVar::Generic\n    /// ```\n    ///\n    Generic { id: u64 },\n}\n\nimpl TypeVar {\n    pub fn is_unbound(&self) -> bool {\n        match self {\n            Self::Unbound { .. } => true,\n            Self::Link { type_ } => type_.is_unbound(),\n            Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_variable(&self) -> bool {\n        match self {\n            Self::Unbound { .. } | Self::Generic { .. } => true,\n            Self::Link { type_ } => type_.is_variable(),\n        }\n    }\n\n    pub fn return_type(&self) -> Option<Arc<Type>> {\n        match self {\n            Self::Link { type_ } => type_.return_type(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    pub fn tuple_types(&self) -> Option<Vec<Arc<Type>>> {\n        match self {\n            Self::Link { type_ } => type_.tuple_types(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    pub fn constructor_types(&self) -> Option<Vec<Arc<Type>>> {\n        match self {\n            Self::Link { type_ } => type_.constructor_types(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    pub fn custom_type_inferred_variant(&self) -> Option<u16> {\n        match self {\n            Self::Link { type_ } => type_.custom_type_inferred_variant(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    pub fn is_result(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_result(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_result_constructor(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_result_constructor(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_list(&self) -> bool {\n        match self {\n            TypeVar::Link { type_ } => type_.is_list(),\n            TypeVar::Unbound { .. } | TypeVar::Generic { .. } => false,\n        }\n    }\n\n    pub fn result_ok_type(&self) -> Option<Arc<Type>> {\n        match self {\n            TypeVar::Link { type_ } => type_.result_ok_type(),\n            TypeVar::Unbound { .. } | TypeVar::Generic { .. } => None,\n        }\n    }\n\n    pub fn result_types(&self) -> Option<(Arc<Type>, Arc<Type>)> {\n        match self {\n            TypeVar::Link { type_ } => type_.result_types(),\n            TypeVar::Unbound { .. } | TypeVar::Generic { .. } => None,\n        }\n    }\n\n    pub fn fn_types(&self) -> Option<(Vec<Arc<Type>>, Arc<Type>)> {\n        match self {\n            Self::Link { type_ } => type_.fn_types(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    #[must_use]\n    pub fn is_fun(&self) -> bool {\n        match self {\n            TypeVar::Link { type_ } => type_.is_fun(),\n            TypeVar::Unbound { .. } | TypeVar::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_nil(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_nil(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_bool(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_bool(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_int(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_int(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_float(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_float(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_string(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_string(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_bit_array(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_bit_array(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn is_utf_codepoint(&self) -> bool {\n        match self {\n            Self::Link { type_ } => type_.is_utf_codepoint(),\n            Self::Unbound { .. } | Self::Generic { .. } => false,\n        }\n    }\n\n    pub fn named_type_name(&self) -> Option<(EcoString, EcoString)> {\n        match self {\n            Self::Link { type_ } => type_.named_type_name(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    pub fn named_type_information(&self) -> Option<(EcoString, EcoString, Vec<Arc<Type>>)> {\n        match self {\n            Self::Link { type_ } => type_.named_type_information(),\n            Self::Unbound { .. } | Self::Generic { .. } => None,\n        }\n    }\n\n    pub fn set_custom_type_variant(&mut self, index: u16) {\n        match self {\n            Self::Link { type_ } => Arc::make_mut(type_).set_custom_type_variant(index),\n            Self::Unbound { .. } | Self::Generic { .. } => {}\n        }\n    }\n\n    pub fn generalise_custom_type_variant(&mut self) {\n        match self {\n            Self::Link { type_ } => Arc::make_mut(type_).generalise_custom_type_variant(),\n            Self::Unbound { .. } | Self::Generic { .. } => {}\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct TypeConstructor {\n    pub publicity: Publicity,\n    pub origin: SrcSpan,\n    pub module: EcoString,\n    pub parameters: Vec<Arc<Type>>,\n    pub type_: Arc<Type>,\n    pub deprecation: Deprecation,\n    pub documentation: Option<EcoString>,\n}\n\nimpl TypeConstructor {\n    pub(crate) fn with_location(mut self, location: SrcSpan) -> Self {\n        self.origin = location;\n        self\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct ValueConstructor {\n    pub publicity: Publicity,\n    pub deprecation: Deprecation,\n    pub variant: ValueConstructorVariant,\n    pub type_: Arc<Type>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]\npub enum Deprecation {\n    #[default]\n    NotDeprecated,\n    Deprecated {\n        message: EcoString,\n    },\n}\n\nimpl Deprecation {\n    /// Returns `true` if the deprecation is [`Deprecated`].\n    ///\n    /// [`Deprecated`]: Deprecation::Deprecated\n    #[must_use]\n    pub fn is_deprecated(&self) -> bool {\n        matches!(self, Self::Deprecated { .. })\n    }\n}\n\nimpl ValueConstructor {\n    pub fn local_variable(location: SrcSpan, origin: VariableOrigin, type_: Arc<Type>) -> Self {\n        Self {\n            publicity: Publicity::Private,\n            deprecation: Deprecation::NotDeprecated,\n            variant: ValueConstructorVariant::LocalVariable { location, origin },\n            type_,\n        }\n    }\n\n    pub fn is_local_variable(&self) -> bool {\n        self.variant.is_local_variable()\n    }\n\n    pub fn definition_location(&self) -> DefinitionLocation {\n        match &self.variant {\n            ValueConstructorVariant::Record {\n                module, location, ..\n            }\n            | ValueConstructorVariant::ModuleConstant {\n                location, module, ..\n            }\n            | ValueConstructorVariant::ModuleFn {\n                location, module, ..\n            } => DefinitionLocation {\n                module: Some(module.clone()),\n                span: *location,\n            },\n\n            ValueConstructorVariant::LocalVariable { location, .. } => DefinitionLocation {\n                module: None,\n                span: *location,\n            },\n        }\n    }\n\n    pub fn get_documentation(&self) -> Option<&str> {\n        match &self.variant {\n            ValueConstructorVariant::LocalVariable { .. } => Some(\"A locally defined variable.\"),\n\n            ValueConstructorVariant::ModuleFn { documentation, .. }\n            | ValueConstructorVariant::Record { documentation, .. }\n            | ValueConstructorVariant::ModuleConstant { documentation, .. } => {\n                Some(documentation.as_ref()?.as_str())\n            }\n        }\n    }\n\n    /// Returns the purity of this value constructor if it is called as a function.\n    /// Referencing a value constructor by itself is always pure, but calling is as a\n    /// function might not be.\n    pub fn called_function_purity(&self) -> Purity {\n        match &self.variant {\n            // If we call a module constant or local variable as a function, we\n            // no longer have enough information to determine its purity. For\n            // example:\n            //\n            // ```gleam\n            // const function1 = io.println\n            // const function2 = function.identity\n            //\n            // pub fn main() {\n            //   function1(\"Hello\")\n            //   function2(\"Hello\")\n            // }\n            // ```\n            //\n            // At this point, we don't have any information about the purity of\n            // the `function1` and `function2` functions, and must return\n            // `Purity::Unknown`. See the documentation for the `Purity` type\n            // for more information on why this is the case.\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. } => Purity::Unknown,\n\n            // Constructing records is always pure\n            ValueConstructorVariant::Record { .. } => Purity::Pure,\n\n            ValueConstructorVariant::ModuleFn { purity, .. } => *purity,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub struct TypeAliasConstructor {\n    pub publicity: Publicity,\n    pub module: EcoString,\n    pub type_: Arc<Type>,\n    pub arity: usize,\n    pub deprecation: Deprecation,\n    pub documentation: Option<EcoString>,\n    pub origin: SrcSpan,\n    pub parameters: Vec<Arc<Type>>,\n}\n\nimpl ValueConstructor {\n    pub fn field_map(&self) -> Option<&FieldMap> {\n        match &self.variant {\n            ValueConstructorVariant::ModuleFn { field_map, .. }\n            | ValueConstructorVariant::Record { field_map, .. } => field_map.as_ref(),\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. } => None,\n        }\n    }\n}\n\npub type TypedCallArg = CallArg<TypedExpr>;\n\nfn assert_no_labelled_arguments<A>(\n    arguments: &[CallArg<A>],\n    kind: UnexpectedLabelledArgKind,\n) -> Result<(), Error> {\n    for argument in arguments {\n        if let Some(label) = &argument.label {\n            return Err(Error::UnexpectedLabelledArg {\n                location: argument.location,\n                label: label.clone(),\n                kind,\n            });\n        }\n    }\n    Ok(())\n}\n\n/// This function makes sure that the type variable being unified\n/// doesn't occur within the type it is being unified with. This\n/// prevents the algorithm from inferring recursive types, which\n/// could cause naively-implemented type checking to diverge.\n/// While traversing the type tree.\n///\nfn unify_unbound_type(type_: &Type, own_id: u64) -> Result<(), UnifyError> {\n    if let Type::Var { type_ } = type_ {\n        return match type_.borrow().deref() {\n            TypeVar::Link { type_, .. } => unify_unbound_type(type_, own_id),\n\n            TypeVar::Unbound { id } => {\n                if id == &own_id {\n                    Err(UnifyError::RecursiveType)\n                } else {\n                    Ok(())\n                }\n            }\n\n            TypeVar::Generic { .. } => Ok(()),\n        };\n    }\n\n    match type_ {\n        Type::Named { arguments, .. } => {\n            for argument in arguments {\n                unify_unbound_type(argument, own_id)?\n            }\n            Ok(())\n        }\n\n        Type::Fn { arguments, return_ } => {\n            for argument in arguments {\n                unify_unbound_type(argument, own_id)?;\n            }\n            unify_unbound_type(return_, own_id)\n        }\n\n        Type::Tuple { elements, .. } => {\n            for element in elements {\n                unify_unbound_type(element, own_id)?\n            }\n            Ok(())\n        }\n\n        Type::Var { .. } => unreachable!(),\n    }\n}\n\nfn match_fun_type(\n    type_: Arc<Type>,\n    arity: usize,\n    environment: &mut Environment<'_>,\n) -> Result<(Vec<Arc<Type>>, Arc<Type>), MatchFunTypeError> {\n    if let Type::Var { type_ } = type_.deref() {\n        let new_value = match type_.borrow().deref() {\n            TypeVar::Link { type_, .. } => {\n                return match_fun_type(type_.clone(), arity, environment);\n            }\n\n            TypeVar::Unbound { .. } => {\n                let arguments: Vec<_> = (0..arity).map(|_| environment.new_unbound_var()).collect();\n                let return_ = environment.new_unbound_var();\n                Some((arguments, return_))\n            }\n\n            TypeVar::Generic { .. } => None,\n        };\n\n        if let Some((arguments, return_)) = new_value {\n            *type_.borrow_mut() = TypeVar::Link {\n                type_: fn_(arguments.clone(), return_.clone()),\n            };\n            return Ok((arguments, return_));\n        }\n    }\n\n    if let Type::Fn { arguments, return_ } = type_.deref() {\n        return if arguments.len() != arity {\n            Err(MatchFunTypeError::IncorrectArity {\n                expected: arguments.len(),\n                given: arity,\n                arguments: arguments.clone(),\n                return_type: return_.clone(),\n            })\n        } else {\n            Ok((arguments.clone(), return_.clone()))\n        };\n    }\n\n    Err(MatchFunTypeError::NotFn { type_ })\n}\n\npub fn generalise(t: Arc<Type>) -> Arc<Type> {\n    match t.deref() {\n        Type::Var { type_ } => match type_.borrow().deref() {\n            TypeVar::Unbound { id } => generic_var(*id),\n            TypeVar::Link { type_ } => generalise(type_.clone()),\n            TypeVar::Generic { .. } => Arc::new(Type::Var {\n                type_: type_.clone(),\n            }),\n        },\n\n        Type::Named {\n            publicity,\n            module,\n            package,\n            name,\n            arguments,\n            inferred_variant: _,\n        } => {\n            let arguments = arguments\n                .iter()\n                .map(|type_| generalise(type_.clone()))\n                .collect();\n            Arc::new(Type::Named {\n                publicity: *publicity,\n                module: module.clone(),\n                package: package.clone(),\n                name: name.clone(),\n                arguments,\n                inferred_variant: None,\n            })\n        }\n\n        Type::Fn { arguments, return_ } => fn_(\n            arguments\n                .iter()\n                .map(|type_| generalise(type_.clone()))\n                .collect(),\n            generalise(return_.clone()),\n        ),\n\n        Type::Tuple { elements } => tuple(\n            elements\n                .iter()\n                .map(|type_| generalise(type_.clone()))\n                .collect(),\n        ),\n    }\n}\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub enum FieldAccessUsage {\n    /// Used as `thing.field()`\n    MethodCall,\n    /// Used internally when trying to access a field when performing record updates.\n    /// The `infer_record_update` function uses this to determine which fields exist\n    /// on a certain record to know whether a certain record update updates correct fields.\n    /// Without this distinction, we get confusing error messages in certain cases.\n    ///\n    RecordUpdate,\n    /// Used as `thing.field`\n    Other,\n}\n\n/// Verify that a value is suitable to be used as a main function.\nfn assert_suitable_main_function(\n    value: &ValueConstructor,\n    module_name: &EcoString,\n    origin: Origin,\n    target: Target,\n) -> Result<(), crate::Error> {\n    // The value must be a module function\n    let ValueConstructorVariant::ModuleFn {\n        arity,\n        implementations,\n        ..\n    } = &value.variant\n    else {\n        return Err(crate::Error::ModuleDoesNotHaveMainFunction {\n            module: module_name.clone(),\n            origin,\n        });\n    };\n\n    // The target must be supported\n    if !implementations.supports(target) {\n        return Err(crate::Error::MainFunctionDoesNotSupportTarget {\n            module: module_name.clone(),\n            target,\n        });\n    }\n\n    // The function must be zero arity\n    if *arity != 0 {\n        return Err(crate::Error::MainFunctionHasWrongArity {\n            module: module_name.clone(),\n            arity: *arity,\n        });\n    }\n\n    // The function must be public, or trying to run it would result in a\n    // runtime crash\n    if !value.publicity.is_importable() {\n        return Err(crate::Error::MainFunctionIsPrivate {\n            module: module_name.clone(),\n        });\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "compiler-core/src/uid.rs",
    "content": "use std::sync::{\n    Arc,\n    atomic::{AtomicU64, Ordering},\n};\n\n/// A generator of unique ids. Only one should be used per compilation run to\n/// ensure ids do not get reused.\n#[derive(Debug, Clone, Default)]\npub struct UniqueIdGenerator {\n    id: Arc<AtomicU64>,\n}\n\nimpl UniqueIdGenerator {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn next(&self) -> u64 {\n        self.id.fetch_add(1, Ordering::Relaxed)\n    }\n}\n\n#[test]\nfn id_geneation() {\n    let ids = UniqueIdGenerator::new();\n    let ids2 = ids.clone();\n\n    assert_eq!(ids.next(), 0);\n    assert_eq!(ids.next(), 1);\n    assert_eq!(ids.next(), 2);\n\n    // Cloned ones use the same counter\n    assert_eq!(ids2.next(), 3);\n    assert_eq!(ids2.next(), 4);\n    assert_eq!(ids2.next(), 5);\n\n    // The original is updated\n    assert_eq!(ids.next(), 6);\n    assert_eq!(ids.next(), 7);\n}\n"
  },
  {
    "path": "compiler-core/src/version.rs",
    "content": "/// The current version of the gleam compiler. If this does not match what is\n/// already in the build folder we will not reuse any cached artifacts and\n/// instead build from scratch\npub const COMPILER_VERSION: &str = env!(\"CARGO_PKG_VERSION\");\n"
  },
  {
    "path": "compiler-core/src/warning.rs",
    "content": "use crate::{\n    ast::{BitArraySegmentTruncation, SrcSpan, TodoKind},\n    build::Target,\n    diagnostic::{self, Diagnostic, ExtraLabel, Location},\n    error::wrap,\n    exhaustiveness::ImpossibleBitArraySegmentPattern,\n    type_::{\n        self,\n        error::{\n            AssertImpossiblePattern, FeatureKind, LiteralCollectionKind, PanicPosition,\n            TodoOrPanic, UnreachablePatternReason,\n        },\n        expression::ComparisonOutcome,\n        pretty::Printer,\n    },\n};\nuse camino::Utf8PathBuf;\nuse debug_ignore::DebugIgnore;\nuse ecow::EcoString;\nuse itertools::Itertools;\nuse std::{\n    io::Write,\n    sync::{Arc, atomic::Ordering},\n};\nuse std::{rc::Rc, sync::atomic::AtomicUsize};\nuse termcolor::Buffer;\n\npub trait WarningEmitterIO {\n    fn emit_warning(&self, warning: Warning);\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct NullWarningEmitterIO;\n\nimpl WarningEmitterIO for NullWarningEmitterIO {\n    fn emit_warning(&self, _warning: Warning) {}\n}\n\n#[derive(Debug, Clone, Default)]\npub struct VectorWarningEmitterIO {\n    pub warnings: Arc<std::sync::RwLock<Vec<Warning>>>,\n}\n\nimpl VectorWarningEmitterIO {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn take(&self) -> Vec<Warning> {\n        let mut warnings = self.write_lock();\n        std::mem::take(&mut *warnings)\n    }\n\n    pub fn reset(&self) {\n        let mut warnings = self.write_lock();\n        warnings.clear();\n    }\n\n    pub fn pop(&self) -> Option<Warning> {\n        let mut warnings = self.write_lock();\n        warnings.pop()\n    }\n\n    fn write_lock(&self) -> std::sync::RwLockWriteGuard<'_, Vec<Warning>> {\n        self.warnings.write().expect(\"Vector lock poisoned\")\n    }\n}\n\nimpl WarningEmitterIO for VectorWarningEmitterIO {\n    fn emit_warning(&self, warning: Warning) {\n        let mut warnings = self.write_lock();\n        warnings.push(warning);\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct WarningEmitter {\n    /// The number of warnings emitted.\n    /// In the context of the project compiler this is the count for the root\n    /// package only, the count is reset back to zero after the dependencies are\n    /// compiled.\n    count: Arc<AtomicUsize>,\n    emitter: DebugIgnore<Rc<dyn WarningEmitterIO>>,\n}\n\nimpl WarningEmitter {\n    pub fn new(emitter: Rc<dyn WarningEmitterIO>) -> Self {\n        Self {\n            count: Arc::new(AtomicUsize::new(0)),\n            emitter: DebugIgnore(emitter),\n        }\n    }\n\n    pub fn null() -> Self {\n        Self::new(Rc::new(NullWarningEmitterIO))\n    }\n\n    pub fn reset_count(&self) {\n        self.count.store(0, Ordering::Relaxed);\n    }\n\n    pub fn count(&self) -> usize {\n        self.count.load(Ordering::Relaxed)\n    }\n\n    pub fn emit(&self, warning: Warning) {\n        _ = self.count.fetch_add(1, Ordering::Relaxed);\n        self.emitter.emit_warning(warning);\n    }\n\n    pub fn vector() -> (Self, Rc<VectorWarningEmitterIO>) {\n        let io = Rc::new(VectorWarningEmitterIO::default());\n        let emitter = Self::new(io.clone());\n        (emitter, Rc::clone(&io))\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct TypeWarningEmitter {\n    module_path: Utf8PathBuf,\n    module_src: EcoString,\n    emitter: WarningEmitter,\n}\n\nimpl TypeWarningEmitter {\n    pub fn new(module_path: Utf8PathBuf, module_src: EcoString, emitter: WarningEmitter) -> Self {\n        Self {\n            module_path,\n            module_src,\n            emitter,\n        }\n    }\n\n    pub fn null() -> Self {\n        Self {\n            module_path: Utf8PathBuf::new(),\n            module_src: EcoString::from(\"\"),\n            emitter: WarningEmitter::new(Rc::new(NullWarningEmitterIO)),\n        }\n    }\n\n    pub fn emit(&self, warning: type_::Warning) {\n        self.emitter.emit(Warning::Type {\n            path: self.module_path.clone(),\n            src: self.module_src.clone(),\n            warning,\n        });\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum Warning {\n    Type {\n        path: Utf8PathBuf,\n        src: EcoString,\n        warning: type_::Warning,\n    },\n\n    InvalidSource {\n        path: Utf8PathBuf,\n    },\n\n    DeprecatedSyntax {\n        path: Utf8PathBuf,\n        src: EcoString,\n        warning: DeprecatedSyntaxWarning,\n    },\n\n    EmptyModule {\n        path: Utf8PathBuf,\n        name: EcoString,\n    },\n\n    DetachedDocComment {\n        path: Utf8PathBuf,\n        src: EcoString,\n        location: SrcSpan,\n    },\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Copy)]\npub enum DeprecatedSyntaxWarning {\n    /// If someone uses the deprecated syntax to append to a list:\n    /// `[\"a\"..rest]`, notice how there's no comma!\n    DeprecatedListPrepend {\n        location: SrcSpan,\n    },\n\n    /// If someone uses the deprecated syntax to pattern match on a list:\n    /// ```gleam\n    /// case list {\n    ///   [first..rest] -> todo\n    ///   //    ^^ notice there's no comma!\n    ///   _ ->\n    /// }\n    /// ```\n    ///\n    DeprecatedListPattern {\n        location: SrcSpan,\n    },\n\n    /// If someone uses the deprecated syntax to match on all lists instead of\n    /// a common `_`:\n    /// ```gleam\n    /// case list {\n    ///   [..] -> todo\n    /// //^^^^ this matches on all lists so a `_` should be used instead!\n    ///   _ ->\n    /// }\n    /// ```\n    ///\n    DeprecatedListCatchAllPattern {\n        location: SrcSpan,\n    },\n\n    /// If a record pattern has a spread that is not preceded by a comma:\n    /// ```gleam\n    /// case wibble {\n    ///   Wibble(arg1: name ..) -> todo\n    /// //                  ^^ this should be preceded by a comma!\n    /// }\n    /// ```\n    ///\n    DeprecatedRecordSpreadPattern {\n        location: SrcSpan,\n    },\n\n    /// If a guard has an empty clause :\n    /// ```gleam\n    /// case wibble {\n    ///     big if -> True\n    ///         ^^ This can be removed.\n    /// }\n    /// ```\n    DeprecatedEmptyClauseGuard {\n        location: SrcSpan,\n    },\n\n    DeprecatedTargetShorthand {\n        target: Target,\n        location: SrcSpan,\n    },\n}\n\nimpl Warning {\n    pub fn to_diagnostic(&self) -> Diagnostic {\n        match self {\n            Warning::InvalidSource { path } => Diagnostic {\n                title: \"Invalid module name\".into(),\n                text: \"\\\nModule names must begin with a lowercase letter and contain\nonly lowercase alphanumeric characters or underscores.\"\n                    .into(),\n                level: diagnostic::Level::Warning,\n                location: None,\n                hint: Some(format!(\n                    \"Rename `{path}` to be valid, or remove this file from the project source.\"\n                )),\n            },\n\n            Warning::DeprecatedSyntax {\n                path,\n                src,\n                warning: DeprecatedSyntaxWarning::DeprecatedListPrepend { location },\n            } => Diagnostic {\n                title: \"Deprecated prepend syntax\".into(),\n                text: wrap(\n                    \"This syntax for prepending to a list is deprecated.\nWhen prepending an item to a list it should be preceded by a comma, \\\nlike this: `[item, ..list]`.\",\n                ),\n\n                hint: None,\n                level: diagnostic::Level::Warning,\n                location: Some(Location {\n                    label: diagnostic::Label {\n                        text: Some(\"This spread should be preceded by a comma\".into()),\n                        span: *location,\n                    },\n                    path: path.clone(),\n                    src: src.clone(),\n                    extra_labels: vec![],\n                }),\n            },\n\n            Warning::DeprecatedSyntax {\n                path,\n                src,\n                warning: DeprecatedSyntaxWarning::DeprecatedListPattern { location },\n            } => Diagnostic {\n                title: \"Deprecated list pattern matching syntax\".into(),\n                text: wrap(\n                    \"This syntax for pattern matching on a list is deprecated.\nWhen matching on the rest of a list it should always be preceded by a comma, \\\nlike this: `[item, ..list]`.\",\n                ),\n                hint: None,\n                level: diagnostic::Level::Warning,\n                location: Some(Location {\n                    label: diagnostic::Label {\n                        text: Some(\"This spread should be preceded by a comma\".into()),\n                        span: *location,\n                    },\n                    path: path.clone(),\n                    src: src.clone(),\n                    extra_labels: vec![],\n                }),\n            },\n\n            Warning::DeprecatedSyntax {\n                path,\n                src,\n                warning: DeprecatedSyntaxWarning::DeprecatedRecordSpreadPattern { location },\n            } => Diagnostic {\n                title: \"Deprecated record pattern matching syntax\".into(),\n                text: wrap(\"This syntax for pattern matching on a record is deprecated.\"),\n                hint: None,\n                level: diagnostic::Level::Warning,\n                location: Some(Location {\n                    label: diagnostic::Label {\n                        text: Some(\"This should be preceded by a comma\".into()),\n                        span: *location,\n                    },\n                    path: path.clone(),\n                    src: src.clone(),\n                    extra_labels: vec![],\n                }),\n            },\n\n            Warning::DeprecatedSyntax {\n                path,\n                src,\n                warning: DeprecatedSyntaxWarning::DeprecatedListCatchAllPattern { location },\n            } => Diagnostic {\n                title: \"Deprecated list pattern matching syntax\".into(),\n                text: wrap(\n                    \"This syntax for pattern matching on lists is deprecated.\nTo match on all possible lists, use the `_` catch-all pattern instead.\",\n                ),\n                hint: None,\n                level: diagnostic::Level::Warning,\n                location: Some(Location {\n                    label: diagnostic::Label {\n                        text: Some(\"This can be replaced with `_`\".into()),\n                        span: *location,\n                    },\n                    path: path.clone(),\n                    src: src.clone(),\n                    extra_labels: vec![],\n                }),\n            },\n            Warning::DeprecatedSyntax {\n                path,\n                src,\n                warning: DeprecatedSyntaxWarning::DeprecatedEmptyClauseGuard { location },\n            } => Diagnostic {\n                title: \"Deprecated empty guard syntax\".into(),\n                text: wrap(\n                    \"This syntax for an empty guard is deprecated. \\\nTo have a clause without a guard, remove this.\",\n                ),\n                hint: None,\n                level: diagnostic::Level::Warning,\n                location: Some(Location {\n                    label: diagnostic::Label {\n                        text: Some(\"This can be removed.\".into()),\n                        span: *location,\n                    },\n                    path: path.clone(),\n                    src: src.clone(),\n                    extra_labels: vec![],\n                }),\n            },\n            Warning::DeprecatedSyntax {\n                path,\n                src,\n                warning: DeprecatedSyntaxWarning::DeprecatedTargetShorthand { location, target },\n            } => {\n                let full_name = match target {\n                    Target::Erlang => \"erlang\",\n                    Target::JavaScript => \"javascript\",\n                };\n\n                Diagnostic {\n                    title: \"Deprecated target shorthand syntax\".into(),\n                    text: wrap(&format!(\n                        \"This shorthand target name is deprecated. Use the full name: `{full_name}` instead.\"\n                    )),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        label: diagnostic::Label {\n                            text: Some(format!(\"This should be replaced with `{full_name}`\")),\n                            span: *location,\n                        },\n                        path: path.clone(),\n                        src: src.clone(),\n                        extra_labels: vec![],\n                    }),\n                }\n            }\n\n            Warning::DetachedDocComment {\n                path,\n                src,\n                location,\n            } => Diagnostic {\n                title: \"Detached doc comment\".into(),\n                text: wrap(\n                    \"This doc comment is followed by a regular \\\ncomment so it is not attached to any definition.\",\n                ),\n                level: diagnostic::Level::Warning,\n                location: Some(Location {\n                    path: path.to_path_buf(),\n                    src: src.clone(),\n                    label: diagnostic::Label {\n                        text: Some(\"This is not attached to a definition\".into()),\n                        span: *location,\n                    },\n                    extra_labels: Vec::new(),\n                }),\n                hint: Some(\"Move the comment above the doc comment\".into()),\n            },\n\n            Warning::Type { path, warning, src } => match warning {\n                type_::Warning::Todo {\n                    kind,\n                    location,\n                    type_,\n                } => {\n                    let mut text = String::new();\n                    text.push_str(\n                        \"\\\nThis code will crash if it is run. Be sure to finish it before\nrunning your program.\",\n                    );\n                    let title = match kind {\n                        TodoKind::Keyword => \"Todo found\",\n                        TodoKind::EmptyBlock => {\n                            text.push_str(\n                                \"\nA block must always contain at least one expression.\",\n                            );\n                            \"Incomplete block\"\n                        }\n                        TodoKind::EmptyFunction { .. } => \"Unimplemented function\",\n                        TodoKind::IncompleteUse => {\n                            text.push_str(\n                                \"\nA use expression must always be followed by at least one expression.\",\n                            );\n                            \"Incomplete use expression\"\n                        }\n                    }\n                    .into();\n                    if !type_.is_variable() {\n                        text.push_str(&format!(\n                            \"\\n\\nHint: I think its type is `{}`.\\n\",\n                            Printer::new().pretty_print(type_, 0)\n                        ));\n                    }\n\n                    Diagnostic {\n                        title,\n                        text,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            path: path.to_path_buf(),\n                            src: src.clone(),\n                            label: diagnostic::Label {\n                                text: Some(\"This code is incomplete\".into()),\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                        hint: None,\n                    }\n                }\n\n                type_::Warning::ImplicitlyDiscardedResult { location } => Diagnostic {\n                    title: \"Unused result value\".into(),\n                    text: \"\".into(),\n                    hint: Some(\n                        \"If you are sure you don't need it you can assign it to `_`.\".into(),\n                    ),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        path: path.to_path_buf(),\n                        src: src.clone(),\n                        label: diagnostic::Label {\n                            text: Some(\"The Result value created here is unused\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedLiteral { location } => Diagnostic {\n                    title: \"Unused literal\".into(),\n                    text: \"\".into(),\n                    hint: Some(\"You can safely remove it.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        path: path.to_path_buf(),\n                        src: src.clone(),\n                        label: diagnostic::Label {\n                            text: Some(\"This value is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::NoFieldsRecordUpdate { location } => Diagnostic {\n                    title: \"Fieldless record update\".into(),\n                    text: \"\".into(),\n                    hint: Some(\n                        \"Add some fields to change or replace it with the record itself.\".into(),\n                    ),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        path: path.to_path_buf(),\n                        src: src.clone(),\n                        label: diagnostic::Label {\n                            text: Some(\"This record update doesn't change any fields\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::AllFieldsRecordUpdate { location } => Diagnostic {\n                    title: \"Redundant record update\".into(),\n                    text: \"\".into(),\n                    hint: Some(\"It is better style to use the record creation syntax.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"This record update specifies all fields\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedType {\n                    location, imported, ..\n                } => {\n                    let title = if *imported {\n                        \"Unused imported type\".into()\n                    } else {\n                        \"Unused private type\".into()\n                    };\n                    let label = if *imported {\n                        \"This imported type is never used\".into()\n                    } else {\n                        \"This private type is never used\".into()\n                    };\n                    Diagnostic {\n                        title,\n                        text: \"\".into(),\n                        hint: Some(\"You can safely remove it.\".into()),\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: Some(label),\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::UnusedConstructor {\n                    location, imported, ..\n                } => {\n                    let title = if *imported {\n                        \"Unused imported item\".into()\n                    } else {\n                        \"Unused private constructor\".into()\n                    };\n                    let label = if *imported {\n                        \"This imported constructor is never used\".into()\n                    } else {\n                        \"This private constructor is never used\".into()\n                    };\n                    Diagnostic {\n                        title,\n                        text: \"\".into(),\n                        hint: Some(\"You can safely remove it.\".into()),\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: Some(label),\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::UnusedImportedModule { location, .. } => Diagnostic {\n                    title: \"Unused imported module\".into(),\n                    text: \"\".into(),\n                    hint: Some(\"You can safely remove it.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"This imported module is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedImportedModuleAlias {\n                    location,\n                    module_name,\n                    ..\n                } => {\n                    let text = format!(\n                        \"\\\nHint: You can safely remove it.\n\n    import {module_name} as _\n\"\n                    );\n                    Diagnostic {\n                        title: \"Unused imported module alias\".into(),\n                        text,\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: Some(\"This alias is never used\".into()),\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::UnusedImportedValue { location, .. } => Diagnostic {\n                    title: \"Unused imported value\".into(),\n                    text: \"\".into(),\n                    hint: Some(\"You can safely remove it.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"This imported value is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedPrivateModuleConstant { location, .. } => Diagnostic {\n                    title: \"Unused private constant\".into(),\n                    text: \"\".into(),\n                    hint: Some(\"You can safely remove it.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"This private constant is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedPrivateFunction { location, .. } => Diagnostic {\n                    title: \"Unused private function\".into(),\n                    text: \"\".into(),\n                    hint: Some(\"You can safely remove it.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"This private function is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedVariable { location, origin } => Diagnostic {\n                    title: if origin.is_function_parameter() {\n                        \"Unused function argument\".into()\n                    } else {\n                        \"Unused variable\".into()\n                    },\n                    text: \"\".into(),\n                    hint: origin.how_to_ignore(),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: if origin.is_function_parameter() {\n                                Some(\"This argument is never used\".into())\n                            } else {\n                                Some(\"This variable is never used\".into())\n                            },\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedRecursiveArgument { location } => Diagnostic {\n                    title: \"Unused function argument\".into(),\n                    text: wrap(\n                        \"This argument is passed to the function when recursing, \\\nbut it's never used for anything.\",\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"This argument is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: vec![],\n                    }),\n                },\n\n                type_::Warning::UnnecessaryDoubleIntNegation { location } => Diagnostic {\n                    title: \"Unnecessary double negation (--) on integer\".into(),\n                    text: \"\".into(),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"You can safely remove this.\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n                type_::Warning::UnnecessaryDoubleBoolNegation { location } => Diagnostic {\n                    title: \"Unnecessary double negation (!!) on bool\".into(),\n                    text: \"\".into(),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"You can safely remove this.\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n                type_::Warning::InefficientEmptyListCheck { location, kind } => {\n                    use type_::error::EmptyListCheckKind;\n                    let text = \"The `list.length` function has to iterate across the whole\nlist to calculate the length, which is wasteful if you only\nneed to know if the list is empty or not.\n\"\n                    .into();\n                    let hint = Some(match kind {\n                        EmptyListCheckKind::Empty => \"You can use `the_list == []` instead.\".into(),\n                        EmptyListCheckKind::NonEmpty => {\n                            \"You can use `the_list != []` instead.\".into()\n                        }\n                    });\n\n                    Diagnostic {\n                        title: \"Inefficient use of `list.length`\".into(),\n                        text,\n                        hint,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::TransitiveDependencyImported {\n                    location,\n                    module,\n                    package,\n                } => {\n                    let text = wrap(&format!(\n                        \"The module `{module}` is being imported, but \\\n`{package}`, the package it belongs to, is not a direct dependency of your \\\npackage.\nIn a future version of Gleam this may become a compile error.\n\nRun this command to add it to your dependencies:\n\n    gleam add {package}\n\"\n                    ));\n                    Diagnostic {\n                        title: \"Transitive dependency imported\".into(),\n                        text,\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::DeprecatedItem {\n                    location,\n                    message,\n                    layer,\n                } => {\n                    let text = wrap(&format!(\"It was deprecated with this message: {message}\"));\n                    let (title, diagnostic_label_text) = if layer.is_value() {\n                        (\n                            \"Deprecated value used\".into(),\n                            Some(\"This value has been deprecated\".into()),\n                        )\n                    } else {\n                        (\n                            \"Deprecated type used\".into(),\n                            Some(\"This type has been deprecated\".into()),\n                        )\n                    };\n\n                    Diagnostic {\n                        title,\n                        text,\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: diagnostic_label_text,\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::UnreachableCasePattern { location, reason } => {\n                    let text = match reason {\n                        UnreachablePatternReason::DuplicatePattern => wrap(\n                            \"This pattern cannot be reached as a previous \\\npattern matches the same values.\\n\",\n                        ),\n                        UnreachablePatternReason::ImpossibleVariant => wrap(\n                            \"This pattern cannot be reached as it matches on \\\na variant of a type which is never present.\\n\",\n                        ),\n                        UnreachablePatternReason::ImpossibleSegments(_) => wrap(\n                            \"This pattern cannot be reached as it contains \\\nsegments that will never match.\\n\",\n                        ),\n                    };\n\n                    let extra_labels = match reason {\n                        UnreachablePatternReason::DuplicatePattern\n                        | UnreachablePatternReason::ImpossibleVariant => vec![],\n                        UnreachablePatternReason::ImpossibleSegments(segments) => segments\n                            .iter()\n                            .map(|segment| ExtraLabel {\n                                src_info: None,\n                                label: diagnostic::Label {\n                                    text: Some(explain_impossible_segment(segment)),\n                                    span: segment.location(),\n                                },\n                            })\n                            .collect_vec(),\n                    };\n\n                    Diagnostic {\n                        title: \"Unreachable pattern\".into(),\n                        text,\n                        hint: Some(\"It can be safely removed.\".into()),\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *location,\n                            },\n                            extra_labels,\n                        }),\n                    }\n                }\n\n                type_::Warning::CaseMatchOnLiteralCollection { kind, location } => {\n                    let kind = match kind {\n                        LiteralCollectionKind::List => \"list\",\n                        LiteralCollectionKind::Tuple => \"tuple\",\n                        LiteralCollectionKind::Record => \"record\",\n                    };\n\n                    let title = format!(\"Redundant {kind}\");\n                    let text = wrap(&format!(\n                        \"Instead of building a {kind} and matching on it, \\\nyou can match on its contents directly.\nA case expression can take multiple subjects separated by commas like this:\n\n    case one_subject, another_subject {{\n      _, _ -> todo\n    }}\n\nSee: https://tour.gleam.run/flow-control/multiple-subjects/\"\n                    ));\n\n                    Diagnostic {\n                        title,\n                        text,\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            src: src.clone(),\n                            path: path.to_path_buf(),\n                            label: diagnostic::Label {\n                                text: Some(format!(\"You can remove this {kind} wrapper\")),\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                    }\n                }\n\n                type_::Warning::CaseMatchOnLiteralValue { location } => Diagnostic {\n                    title: \"Match on a literal value\".into(),\n                    text: wrap(\n                        \"Matching on a literal value is redundant since you \\\ncan already tell which branch is going to match with this value.\",\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"There's no need to pattern match on this value\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::OpaqueExternalType { location } => Diagnostic {\n                    title: \"Opaque external type\".into(),\n                    text: \"This type has no constructors so making it opaque is redundant.\".into(),\n                    hint: Some(\"Remove the `opaque` qualifier from the type definition.\".into()),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: None,\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::UnusedValue { location } => Diagnostic {\n                    title: \"Unused value\".into(),\n                    text: wrap(\n                        \"This expression computes a value without any side \\\neffects, but then the value isn't used at all. You might want to assign it to a \\\nvariable, or delete the expression entirely if it's not needed.\",\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        path: path.to_path_buf(),\n                        src: src.clone(),\n                        label: diagnostic::Label {\n                            text: Some(\"This value is never used\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::InternalTypeLeak { location, leaked } => {\n                    let mut printer = Printer::new();\n\n                    // TODO: be more precise.\n                    // - is being returned by this public function\n                    // - is taken as an argument by this public function\n                    // - is taken as an argument by this public enum constructor\n                    // etc\n                    let text = format!(\n                        \"The following type is internal, but is being used by this public export.\n\n{}\n\nInternal types should not be used in a public facing function since they are\nhidden from the package's documentation.\",\n                        printer.pretty_print(leaked, 4),\n                    );\n                    Diagnostic {\n                        title: \"Internal type used in public interface\".into(),\n                        text,\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    }\n                }\n                type_::Warning::RedundantAssertAssignment { location } => Diagnostic {\n                    title: \"Redundant assertion\".into(),\n                    text: \"This assertion is redundant since the pattern covers all possibilities.\"\n                        .into(),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        label: diagnostic::Label {\n                            text: Some(\"You can remove this\".into()),\n                            span: *location,\n                        },\n                        path: path.clone(),\n                        src: src.clone(),\n                        extra_labels: vec![],\n                    }),\n                },\n\n                type_::Warning::AssertAssignmentOnImpossiblePattern { location, reason } => {\n                    let extra_labels = match reason {\n                        AssertImpossiblePattern::InferredVariant => vec![],\n                        AssertImpossiblePattern::ImpossibleSegments { segments } => segments\n                            .iter()\n                            .map(|segment| ExtraLabel {\n                                src_info: None,\n                                label: diagnostic::Label {\n                                    text: Some(explain_impossible_segment(segment)),\n                                    span: segment.location(),\n                                },\n                            })\n                            .collect_vec(),\n                    };\n\n                    Diagnostic {\n                        title: \"Assertion that will always fail\".into(),\n                        text: wrap(\n                            \"We can tell from the code above that the value will never match \\\nthis pattern and that this code will always crash.\n\nEither change the pattern or use `panic` to unconditionally fail.\",\n                        ),\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels,\n                        }),\n                    }\n                }\n\n                type_::Warning::TodoOrPanicUsedAsFunction {\n                    kind,\n                    location,\n                    arguments_location,\n                    arguments,\n                } => {\n                    let title = match kind {\n                        TodoOrPanic::Todo => \"Todo used as a function\".into(),\n                        TodoOrPanic::Panic => \"Panic used as a function\".into(),\n                    };\n                    let label_location = match arguments_location {\n                        None => location,\n                        Some(location) => location,\n                    };\n                    let name = match kind {\n                        TodoOrPanic::Todo => \"todo\",\n                        TodoOrPanic::Panic => \"panic\",\n                    };\n                    let mut text = format!(\"`{name}` is not a function\");\n                    match arguments {\n                        0 => text.push_str(&format!(\n                            \", you can just write `{name}` instead of `{name}()`.\"\n                        )),\n                        1 => text.push_str(\n                            \" and will crash before it can do anything with this argument.\",\n                        ),\n                        _ => text.push_str(\n                            \" and will crash before it can do anything with these arguments.\",\n                        ),\n                    };\n\n                    match arguments {\n                        0 => {}\n                        _ => text.push_str(&format!(\n                            \"\\n\\nHint: if you want to display an error message you should write\n`{name} as \\\"my error message\\\"`\nSee: https://tour.gleam.run/advanced-features/{name}/\"\n                        )),\n                    }\n\n                    Diagnostic {\n                        title,\n                        text: wrap(&text),\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *label_location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    }\n                }\n\n                type_::Warning::UnreachableCodeAfterPanic {\n                    location,\n                    panic_position: unreachable_code_kind,\n                } => {\n                    let text = match unreachable_code_kind {\n                        PanicPosition::PreviousExpression => {\n                            \"This code is unreachable because it comes after a `panic`.\"\n                        }\n                        PanicPosition::PreviousFunctionArgument => {\n                            \"This argument is unreachable because the previous one always panics. \\\nYour code will crash before reaching this point.\"\n                        }\n                        PanicPosition::LastFunctionArgument => {\n                            \"This function call is unreachable because its last argument always panics. \\\nYour code will crash before reaching this point.\"\n                        }\n                        PanicPosition::EchoExpression => {\n                            \"This `echo` won't print anything because the expression it \\\nshould be printing always panics.\"\n                        }\n                    };\n\n                    Diagnostic {\n                        title: \"Unreachable code\".into(),\n                        text: wrap(text),\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            label: diagnostic::Label {\n                                text: None,\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    }\n                }\n\n                type_::Warning::RedundantPipeFunctionCapture { location } => Diagnostic {\n                    title: \"Redundant function capture\".into(),\n                    text: wrap(\n                        \"This function capture is redundant since the value is already piped as \\\nthe first argument of this call.\n\nSee: https://tour.gleam.run/functions/pipelines/\",\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        label: diagnostic::Label {\n                            text: Some(\"You can safely remove this\".into()),\n                            span: *location,\n                        },\n                        path: path.clone(),\n                        src: src.clone(),\n                        extra_labels: vec![],\n                    }),\n                },\n                type_::Warning::FeatureRequiresHigherGleamVersion {\n                    location,\n                    minimum_required_version,\n                    wrongfully_allowed_version,\n                    feature_kind,\n                } => {\n                    let feature = match feature_kind {\n                        FeatureKind::LabelShorthandSyntax => \"The label shorthand syntax was\",\n                        FeatureKind::ConstantStringConcatenation => {\n                            \"Constant strings concatenation was\"\n                        }\n                        FeatureKind::ArithmeticInGuards => \"Arithmetic operations in guards were\",\n                        FeatureKind::ConcatenateInGuards => \"String concatenation in guards was\",\n                        FeatureKind::UnannotatedUtf8StringSegment => {\n                            \"The ability to omit the `utf8` annotation for string segments was\"\n                        }\n                        FeatureKind::UnannotatedFloatSegment => {\n                            \"The ability to omit the `float` annotation for float segments was\"\n                        }\n                        FeatureKind::NestedTupleAccess => {\n                            \"The ability to access nested tuple fields was\"\n                        }\n                        FeatureKind::InternalAnnotation => \"The `@internal` annotation was\",\n                        FeatureKind::AtInJavascriptModules => {\n                            \"The ability to have `@` in a Javascript module's name was\"\n                        }\n                        FeatureKind::RecordUpdateVariantInference => {\n                            \"Record updates for custom types when the variant is known was\"\n                        }\n                        FeatureKind::RecordAccessVariantInference => {\n                            \"Field access on custom types when the variant is known was\"\n                        }\n                        FeatureKind::LetAssertWithMessage => {\n                            \"Specifying a custom panic message when using let assert was\"\n                        }\n                        FeatureKind::VariantWithDeprecatedAnnotation => {\n                            \"Deprecating individual custom type variants was\"\n                        }\n                        FeatureKind::JavaScriptUnalignedBitArray => {\n                            \"Use of unaligned bit arrays on the JavaScript target was\"\n                        }\n                        FeatureKind::BoolAssert => \"The bool `assert` statement was\",\n                        FeatureKind::ExpressionInSegmentSize => \"Expressions in segment sizes were\",\n                        FeatureKind::ExternalCustomType => {\n                            \"The `@external` annotation on custom types was\"\n                        }\n                        FeatureKind::ConstantRecordUpdate => {\n                            \"The record update syntax for constants was\"\n                        }\n                    };\n\n                    Diagnostic {\n                        title: \"Incompatible gleam version range\".into(),\n                        text: wrap(&format!(\n                        \"{feature} introduced in version v{minimum_required_version}. But the Gleam version range \\\n                        specified in your `gleam.toml` would allow this code to run on an earlier \\\n                        version like v{wrongfully_allowed_version}, resulting in compilation errors!\",\n                    )),\n                        hint: Some(format!(\n                            \"Remove the version constraint from your `gleam.toml` or update it to be:\n\n    gleam = \\\">= {minimum_required_version}\\\"\"\n                        )),\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            label: diagnostic::Label {\n                                text: Some(format!(\n                                    \"This requires a Gleam version >= {minimum_required_version}\"\n                                )),\n                                span: *location,\n                            },\n                            path: path.clone(),\n                            src: src.clone(),\n                            extra_labels: vec![],\n                        }),\n                    }\n                }\n\n                type_::Warning::JavaScriptIntUnsafe { location } => Diagnostic {\n                    title: \"Int is outside JavaScript's safe integer range\".into(),\n                    text: wrap(\n                        \"This integer value is too large to be represented accurately by \\\nJavaScript's number type. To avoid this warning integer values must be in the range \\\n-(2^53 - 1) - (2^53 - 1).\n\nSee JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER properties for more \\\ninformation.\",\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        path: path.to_path_buf(),\n                        src: src.clone(),\n                        label: diagnostic::Label {\n                            text: Some(\"This is not a safe integer value on JavaScript\".into()),\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::BitArraySegmentTruncatedValue {\n                    location: _,\n                    truncation:\n                        BitArraySegmentTruncation {\n                            truncated_value,\n                            truncated_into,\n                            segment_bits,\n                            value_location,\n                        },\n                } => {\n                    let (unit, segment_size, taken) = if segment_bits % 8 == 0 {\n                        let bytes = segment_bits / 8;\n                        let segment_size = pluralise(format!(\"{bytes} byte\"), bytes);\n                        let taken = if bytes == 1 {\n                            \"first byte\".into()\n                        } else {\n                            format!(\"first {bytes} bytes\")\n                        };\n\n                        (\"bytes\", segment_size, taken)\n                    } else {\n                        let segment_size = pluralise(format!(\"{segment_bits} bit\"), *segment_bits);\n                        let taken = if *segment_bits == 1 {\n                            \"first bit\".into()\n                        } else {\n                            format!(\"first {segment_bits} bits\")\n                        };\n                        (\"bits\", segment_size, taken)\n                    };\n\n                    let text = format!(\n                        \"This segment is {segment_size} long, but {truncated_value} \\\ndoesn't fit in that many {unit}. It would be truncated by taking its {taken}, resulting in the value {truncated_into}.\"\n                    );\n\n                    Diagnostic {\n                        title: \"Truncated bit array segment\".into(),\n                        text: wrap(&text),\n                        hint: None,\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            path: path.to_path_buf(),\n                            src: src.clone(),\n                            label: diagnostic::Label {\n                                text: Some(format!(\n                                    \"You can safely replace this with {truncated_into}\"\n                                )),\n                                span: *value_location,\n                            },\n                            extra_labels: vec![],\n                        }),\n                    }\n                }\n\n                type_::Warning::AssertLiteralBool { location } => Diagnostic {\n                    title: \"Assertion of a literal value\".into(),\n                    text: wrap(\n                        \"Asserting on a literal bool is redundant since you \\\ncan already tell whether it will be `True` or `False`.\",\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: None,\n                            span: *location,\n                        },\n                        extra_labels: Vec::new(),\n                    }),\n                },\n\n                type_::Warning::ModuleImportedTwice {\n                    name,\n                    first,\n                    second,\n                } => Diagnostic {\n                    title: \"Duplicate import\".into(),\n                    text: format!(\"The {name} module has been imported twice.\"),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: Some(\"Reimported here\".into()),\n                            span: *second,\n                        },\n                        extra_labels: vec![ExtraLabel {\n                            src_info: None,\n                            label: diagnostic::Label {\n                                text: Some(\"First imported here\".into()),\n                                span: *first,\n                            },\n                        }],\n                    }),\n                },\n\n                type_::Warning::UnusedDiscardPattern { location, name } => Diagnostic {\n                    title: \"Unused discard pattern\".into(),\n                    text: format!(\"`_ as {name}` can be written more concisely as `{name}`\"),\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        src: src.clone(),\n                        path: path.to_path_buf(),\n                        label: diagnostic::Label {\n                            text: None,\n                            span: SrcSpan {\n                                start: location.start - \"_ as \".len() as u32,\n                                end: location.end,\n                            },\n                        },\n                        extra_labels: vec![],\n                    }),\n                    hint: None,\n                },\n\n                type_::Warning::TopLevelDefinitionShadowsImport { location, name } => {\n                    let text = format!(\n                        \"Definition of {name} shadows an imported value.\nThe imported value could not be used in this module anyway.\"\n                    );\n                    Diagnostic {\n                        title: \"Shadowed Import\".into(),\n                        text: wrap(&text),\n                        level: diagnostic::Level::Warning,\n                        location: Some(Location {\n                            path: path.clone(),\n                            src: src.clone(),\n                            label: diagnostic::Label {\n                                text: Some(wrap(&format!(\"`{name}` is defined here\"))),\n                                span: *location,\n                            },\n                            extra_labels: Vec::new(),\n                        }),\n                        hint: Some(\"Either rename the definition or remove the import.\".into()),\n                    }\n                }\n\n                type_::Warning::RedundantComparison { location, outcome } => Diagnostic {\n                    title: \"Redundant comparison\".into(),\n                    text: format!(\n                        \"This comparison is redundant since it always {}.\",\n                        match outcome {\n                            ComparisonOutcome::AlwaysSucceeds => \"succeeds\",\n                            ComparisonOutcome::AlwaysFails => \"fails\",\n                        }\n                    ),\n                    hint: None,\n                    level: diagnostic::Level::Warning,\n                    location: Some(Location {\n                        label: diagnostic::Label {\n                            text: Some(format!(\n                                \"This is always `{}`\",\n                                match outcome {\n                                    ComparisonOutcome::AlwaysSucceeds => \"True\",\n                                    ComparisonOutcome::AlwaysFails => \"False\",\n                                }\n                            )),\n                            span: *location,\n                        },\n                        path: path.clone(),\n                        src: src.clone(),\n                        extra_labels: vec![],\n                    }),\n                },\n            },\n\n            Warning::EmptyModule { path: _, name } => Diagnostic {\n                title: \"Empty module\".into(),\n                text: format!(\"Module '{name}' contains no public definitions.\"),\n                hint: Some(\"You can safely remove this module.\".into()),\n                level: diagnostic::Level::Warning,\n                location: None,\n            },\n        }\n    }\n\n    pub fn pretty(&self, buffer: &mut Buffer) {\n        self.to_diagnostic().write(buffer);\n        buffer\n            .write_all(b\"\\n\")\n            .expect(\"error pretty buffer write space after\");\n    }\n\n    pub fn to_pretty_string(&self) -> String {\n        let mut nocolor = Buffer::no_color();\n        self.pretty(&mut nocolor);\n        String::from_utf8(nocolor.into_inner()).expect(\"Warning printing produced invalid utf8\")\n    }\n}\n\nfn explain_impossible_segment(segment: &ImpossibleBitArraySegmentPattern) -> String {\n    match segment {\n        ImpossibleBitArraySegmentPattern::UnrepresentableInteger {\n            size,\n            signed,\n            value: _,\n            location: _,\n        } => {\n            let human_readable_size = match size {\n                1 => \"1 bit\".into(),\n                8 => \"1 byte\".into(),\n                n if n % 8 == 0 => format!(\"{} bytes\", n / 8),\n                n => format!(\"{n} bits\"),\n            };\n            let sign = if *signed { \"signed\" } else { \"unsigned\" };\n            format!(\"A {human_readable_size} {sign} integer will never match this value\")\n        }\n    }\n}\n\nfn pluralise(string: String, quantity: i64) -> String {\n    if quantity == 1 {\n        string\n    } else {\n        format!(\"{string}s\")\n    }\n}\n"
  },
  {
    "path": "compiler-core/templates/docs-css/index.css",
    "content": "/* karla regular latin-ext */\n@font-face {\n  font-family: \"Karla\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/karla-v23-regular-latin-ext.woff2\") format(\"woff2\");\n  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,\n    U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* karla regular latin */\n@font-face {\n  font-family: \"Karla\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/karla-v23-regular-latin.woff2\") format(\"woff2\");\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,\n    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,\n    U+FEFF, U+FFFD;\n}\n/* karla bold latin-ext */\n@font-face {\n  font-family: \"Karla\";\n  font-style: normal;\n  font-weight: 700;\n  font-display: swap;\n  src: url(\"../fonts/karla-v23-bold-latin-ext.woff2\") format(\"woff2\");\n  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,\n    U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* karla bold latin */\n@font-face {\n  font-family: \"Karla\";\n  font-style: normal;\n  font-weight: 700;\n  font-display: swap;\n  src: url(\"../fonts/karla-v23-bold-latin.woff2\") format(\"woff2\");\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,\n    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,\n    U+FEFF, U+FFFD;\n}\n/* ubuntu mono cyrillic-ext */\n@font-face {\n  font-family: \"Ubuntu Mono\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/ubuntu-mono-v15-regular-cyrillic-ext.woff2\")\n    format(\"woff2\");\n  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,\n    U+FE2E-FE2F;\n}\n/* ubuntu mono cyrillic */\n@font-face {\n  font-family: \"Ubuntu Mono\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/ubuntu-mono-v15-regular-cyrillic.woff2\") format(\"woff2\");\n  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* ubuntu mono greek-ext */\n@font-face {\n  font-family: \"Ubuntu Mono\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/ubuntu-mono-v15-regular-greek-ext.woff2\") format(\"woff2\");\n  unicode-range: U+1F00-1FFF;\n}\n/* ubuntu mono greek */\n@font-face {\n  font-family: \"Ubuntu Mono\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/ubuntu-mono-v15-regular-greek.woff2\") format(\"woff2\");\n  unicode-range: U+0370-03FF;\n}\n/* ubuntu mono latin-ext */\n@font-face {\n  font-family: \"Ubuntu Mono\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/ubuntu-mono-v15-regular-latin-ext.woff2\") format(\"woff2\");\n  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,\n    U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* ubuntu mono latin */\n@font-face {\n  font-family: \"Ubuntu Mono\";\n  font-style: normal;\n  font-weight: 400;\n  font-display: swap;\n  src: url(\"../fonts/ubuntu-mono-v15-regular-latin.woff2\") format(\"woff2\");\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,\n    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,\n    U+FEFF, U+FFFD;\n}\n\n:root {\n  /* Colours */\n  --black: #2a2020;\n  --hard-black: #000;\n  --pink: #ffaff3;\n  --hot-pink: #d900b8;\n  --white: #fff;\n  --pink-white: #fff8fe;\n  --mid-grey: #dfe2e5;\n  --light-grey: #f5f5f5;\n  --boi-blue: #a6f0fc;\n\n  /* Derived colours */\n  --text: var(--black);\n  --background: var(--white);\n  --accented-background: var(--pink-white);\n  --code-border: var(--pink);\n  --code-background: var(--light-grey);\n  --table-border: var(--mid-grey);\n  --table-background: var(--pink-white);\n  --links: var(--hot-pink);\n  --accent: var(--pink);\n\n  /* Sizes */\n  --content-width: 772px;\n  --header-height: 60px;\n  --hash-offset: calc(var(--header-height) * 1.67);\n  --sidebar-width: 240px;\n  --gap: 24px;\n  --small-gap: calc(var(--gap) / 2);\n  --tiny-gap: calc(var(--small-gap) / 2);\n  --large-gap: calc(var(--gap) * 2);\n  --sidebar-toggle-size: 33px;\n  --search-height: 4rem;\n\n  /* etc */\n  --shadow: 0 0 0 1px rgba(50, 50, 93, 0.075), 0 0 1px #e9ecef,\n    0 2px 4px -2px rgba(138, 141, 151, 0.6);\n  --nav-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1);\n}\n\n* {\n  box-sizing: border-box;\n}\n\nbody,\nhtml {\n  padding: 0;\n  margin: 0;\n  font-family: \"Karla\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica,\n    Arial, system-ui, ui-sans-serif, sans-serif, \"Apple Color Emoji\",\n    \"Segoe UI Emoji\";\n  font-size: 17px;\n  line-height: 1.4;\n  position: relative;\n  min-height: 100vh;\n  word-break: break-word;\n}\n\nhtml {\n  /* This is necessary so hash targets appear below the fixed header */\n  scroll-padding-top: var(--hash-offset);\n}\n\na,\na:visited {\n  color: var(--links);\n  text-decoration: none;\n}\n\na:hover {\n  text-decoration: underline;\n}\n\nbutton,\nselect {\n  background: transparent;\n  border: 0 none;\n  cursor: pointer;\n  font-family: inherit;\n  font-size: 100%;\n  line-height: 1.15;\n  margin: 0;\n  text-transform: none;\n}\n\nbutton::-moz-focus-inner {\n  border-style: none;\n  padding: 0;\n}\n\nbutton:-moz-focusring {\n  outline: 1px dotted ButtonText;\n}\n\nbutton {\n  -webkit-appearance: button;\n  appearance: button;\n  line-height: 1;\n  margin: 0;\n  overflow: visible;\n  padding: 0;\n}\n\nbutton:active,\nselect:active {\n  outline: 0 none;\n}\n\nli {\n  margin-bottom: 4px;\n}\n\np {\n  margin: var(--small-gap) 0;\n}\n\n.rendered-markdown h1,\n.rendered-markdown h2,\n.rendered-markdown h3,\n.rendered-markdown h4,\n.rendered-markdown h5 {\n  font-size: 1.3rem;\n}\n\nblockquote {\n  border-left: 4px solid var(--accent);\n  padding: var(--small-gap) var(--gap);\n  background-color: var(--accented-background);\n  margin: var(--small-gap) 0;\n}\n\n/* Code */\n\npre,\ncode {\n  font-family: \"Ubuntu Mono\", SFMono-Regular, \"SF Mono\", Menlo, Consolas,\n    \"Liberation Mono\", ui-monospace, monospace;\n  line-height: 1.2;\n  background-color: var(--code-background);\n}\n\npre {\n  margin: var(--gap) 0;\n  border-radius: 1px;\n  overflow: auto;\n  box-shadow: var(--shadow);\n}\n\npre > code,\ncode.hljs {\n  padding: var(--small-gap) var(--gap);\n  background: transparent;\n}\n\np code {\n  margin: 0 2px;\n  border-radius: 3px;\n  padding: 0 0.2em;\n  color: var(--inline-code);\n}\n\np a code {\n  color: var(--links);\n}\n\n/* Page layout */\n\n.page {\n  display: flex;\n}\n\n.content {\n  margin-left: var(--sidebar-width);\n  margin-bottom: var(--large-gap);\n  padding: calc(var(--header-height) + var(--gap)) var(--gap) 0 var(--gap);\n  width: calc(100% - var(--sidebar-width));\n  max-width: var(--content-width);\n}\n\n.content img {\n  max-width: 100%;\n}\n\n/* Page header */\n\n.page-header {\n  box-shadow: var(--nav-shadow);\n  height: var(--header-height);\n  color: black;\n  color: var(--hard-black);\n  background-color: var(--pink);\n  display: flex;\n  padding: var(--small-gap) var(--gap);\n  position: fixed;\n  left: 0;\n  right: 0;\n  top: 0;\n  z-index: 300;\n}\n\n.page-header h2 {\n  align-items: baseline;\n  display: flex;\n  margin: 0;\n  width: var(--sidebar-width);\n}\n\n.page-header a,\n.page-header a:visited {\n  color: black;\n  color: var(--hard-black);\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.sidebar-toggle {\n  display: none;\n  font-size: var(--sidebar-toggle-size);\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n\n.search-nav-button {\n  display: none;\n  font-size: var(--sidebar-toggle-size);\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n\n.page-header .sidebar-toggle {\n  color: white;\n  color: var(--white);\n  margin: 0 var(--small-gap) 0 0;\n}\n\n.page-header .search-nav-button {\n  color: white;\n  color: var(--white);\n  margin: 0 var(--small-gap) 0 0;\n}\n\n/* Version selector */\n\n#project-version {\n  --half-small-gap: calc(var(--small-gap) / 2);\n  --icon-size: 0.75em;\n  flex-shrink: 0;\n  font-size: 0.9rem;\n  font-weight: normal;\n  margin-left: var(--half-small-gap);\n}\n\n#project-version > span {\n  padding-left: var(--half-small-gap);\n}\n\n#project-version form {\n  align-items: center;\n  display: inline-flex;\n  justify-content: flex-end;\n}\n\n#project-version select {\n  appearance: none;\n  -webkit-appearance: none;\n  padding: 0.6rem calc(1.3 * var(--icon-size)) 0.6rem var(--half-small-gap);\n  position: relative;\n  z-index: 1;\n}\n\n#project-version option {\n  background-color: var(--code-background);\n}\n\n#project-version .icon {\n  font-size: var(--icon-size);\n  margin-left: calc(-1.65 * var(--icon-size));\n}\n\n/* Module doc */\n\n.module-name > a,\n.module-member-kind > a {\n  color: inherit;\n}\n\n.module-name > a:hover,\n.module-member-kind > a:hover {\n  text-decoration: none;\n}\n\n.module-name > .icon-gleam-chasse,\n.module-member-kind > .icon-gleam-chasse,\n.module-member-kind > .icon-gleam-chasse-2 {\n  color: var(--pink);\n  display: block;\n  font-size: 1rem;\n  margin: var(--small-gap) 0 0;\n}\n\n.module-name {\n  color: var(--hard-black);\n  margin: 0 0 var(--gap);\n  font-weight: 700;\n}\n\n/* Sidebar */\n\n.sidebar {\n  background-color: var(--background);\n  font-size: 0.95rem;\n  max-height: calc(100vh - var(--header-height));\n  overflow-y: auto;\n  overscroll-behavior: contain;\n  padding-top: var(--gap);\n  padding-bottom: calc(3 * var(--gap));\n  padding-left: var(--gap);\n  padding-right: var(--gap);\n  position: fixed;\n  top: var(--header-height);\n  transition: transform 0.5s ease;\n  width: var(--sidebar-width);\n  z-index: 100;\n}\n\n.sidebar h2 {\n  margin: 0;\n}\n\n.sidebar ul {\n  list-style: none;\n  margin: var(--small-gap) 0;\n  padding: 0;\n}\n\n.sidebar li {\n  line-height: 1.2;\n  margin-bottom: 4px;\n}\n\n.module-link {\n  display: inline-block;\n  padding-left: 0.5em;\n  text-indent: -0.5em;\n  line-height: 1.2;\n}\n\n.sidebar .sidebar-toggle {\n  color: var(--pink);\n  font-size: calc(0.8 * var(--sidebar-toggle-size));\n}\n\nbody.drawer-closed .label-open,\nbody.drawer-open .label-closed {\n  display: none;\n}\n\n.display-controls {\n  display: flex;\n  flex-wrap: wrap;\n  margin-top: var(--small-gap);\n  padding-right: var(--gap);\n}\n\n.display-controls .control {\n  margin: 0.5rem 0;\n}\n\n.display-controls .control:not(:first-child) {\n  margin-left: 1rem;\n}\n\n.toggle {\n  align-items: center;\n  display: flex;\n  font-size: 0.96rem;\n}\n\n.toggle-0 .label:not(.label-0),\n.toggle-1 .label:not(.label-1) {\n  display: none;\n}\n\n.label {\n  display: flex;\n}\n\n.label .icon {\n  margin: 0 0.28rem;\n}\n\n/* Module members (types, functions) */\n\n.module-members {\n  margin-top: var(--large-gap);\n}\n\n.module-members:last-of-type .member:last-of-type {\n  margin-bottom: 0;\n}\n\n.module-member-kind {\n  font-size: 2rem;\n  color: var(--text);\n}\n\n.member {\n  margin: var(--large-gap) 0;\n  padding-bottom: var(--gap);\n}\n\n.member-name {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  border-left: 4px solid var(--accent);\n  padding: var(--small-gap) var(--gap);\n  background-color: var(--accented-background);\n}\n\n.member-name h2 {\n  display: flex;\n  font-size: 1.5rem;\n  margin: 0;\n}\n\n.member-name h2 a {\n  color: var(--text);\n}\n\n.member-source {\n  align-self: baseline;\n  flex-shrink: 0;\n  line-height: calc(1.4 * 1.5rem);\n  margin: 0 0 0 var(--small-gap);\n}\n\n.visibility-tag {\n  background-color: var(--bg-shade-3);\n  color: var(--text);\n  padding: 0px 6px 4px;\n  border-radius: 4px;\n  font-size: 0.9em;\n  margin-left: auto;\n  line-height: normal;\n}\n\n/* Custom type constructors */\n\n.constructor-list {\n  list-style: none;\n  padding: 0;\n}\n\n.constructor-row {\n  align-items: center;\n  display: flex;\n}\n\n.constructor-item {\n  margin-bottom: var(--small-gap);\n}\n\n.constructor-argument-label {\n  font-style: italic;\n}\n\n.constructor-argument-list {\n  margin-bottom: var(--small-gap);\n}\n\n.constructor-item-docs {\n  margin-left: var(--large-gap);\n  margin-bottom: var(--gap);\n}\n\n.constructor-item .icon {\n  flex-shrink: 0;\n  font-size: 0.7rem;\n  margin: 0 0.88rem;\n}\n\n.constructor-name {\n  box-shadow: unset;\n  margin: 0;\n}\n\n.constructor-name > code {\n  padding: var(--small-gap);\n}\n\n/* Tables */\n\ntable {\n  border-spacing: 0;\n  border-collapse: collapse;\n}\n\ntable td,\ntable th {\n  padding: 6px 13px;\n  border: 1px solid var(--table-border);\n}\n\ntable tr:nth-child(2n) {\n  background-color: var(--table-background);\n}\n\n/* Footer */\n\n.pride {\n  width: 100%;\n  display: none;\n  flex-direction: row;\n  position: absolute;\n  bottom: 0;\n  z-index: 100;\n}\n\n.show-pride .pride {\n  display: flex;\n}\n\n.show-pride .sidebar {\n  margin-bottom: var(--gap);\n}\n\n.pride div {\n  flex: 1;\n  text-align: center;\n  padding: var(--tiny-gap);\n}\n\n.pride .white {\n  background-color: var(--white);\n}\n.pride .pink {\n  background-color: var(--pink);\n}\n.pride .blue {\n  background-color: var(--boi-blue);\n}\n\n.pride-button {\n  position: absolute;\n  right: 2px;\n  bottom: 2px;\n  opacity: 0.2;\n  font-size: 0.9rem;\n}\n\n.pride-button {\n  text-decoration: none;\n  cursor: default;\n}\n\n/* Icons */\n\n.svg-lib {\n  height: 0;\n  overflow: hidden;\n  position: absolute;\n  width: 0;\n}\n\n.icon {\n  display: inline-block;\n  fill: currentColor;\n  height: 1em;\n  stroke: currentColor;\n  stroke-width: 0;\n  width: 1em;\n}\n\n.icon-gleam-chasse {\n  width: 8.182em;\n}\n\n.icon-gleam-chasse-2 {\n  width: 4.909em;\n}\n\n/* Pre-Wrap Option */\n\nbody.prewrap-on code,\nbody.prewrap-on pre {\n  white-space: pre-wrap;\n}\n\n/* Dark Theme Option */\n\nbody.theme-dark {\n  /* Colour palette adapted from:\n   * https://github.com/dustypomerleau/yarra-valley\n   */\n\n  --argument-atom: #c651e5;\n  --class-module: #ff89b5;\n  --comment: #7e818b;\n  --escape: #7cdf89;\n  --function-call: #abb8c0;\n  --function-definition: #8af899;\n  --interpolation-regex: #ee37aa;\n  --keyword-operator: #ff9d35;\n  --number-boolean: #f14360;\n  --object: #99c2eb;\n  --punctuation: #4ce7ff;\n  --string: #aecc00;\n\n  --inline-code: #ff9d35;\n\n  --bg: #292d3e;\n  --bg-tint-1: #3e4251;\n  --bg-tint-2: #535664;\n  --bg-tint-3: #696c77;\n  --bg-tint-4: #7e818b;\n  --bg-shade-1: #242837;\n  --bg-shade-2: #202431;\n  --bg-shade-3: #1c1f2b;\n  --bg-mono-1: #33384d;\n  --bg-mono-2: #3d435d;\n  --bg-mono-3: #474e6c;\n  --bg-mono-4: #51597b;\n\n  --fg: #cac0a9;\n  --fg-tint-1: #fdf2d8;\n  --fg-tint-2: #fdf3dc;\n  --fg-tint-3: #fdf5e0;\n  --fg-shade-1: #e3d8be;\n  --fg-shade-2: #cac0a9;\n  --fg-shade-3: #b1a894;\n  --fg-shade-4: #97907f;\n\n  --orange-shade-1: #e58d2f;\n  --orange-shade-2: #cc7d2a;\n  --orange-shade-3: #b26d25;\n\n  --taupe-mono-1: #fdf1d4;\n  --taupe-mono-2: #fce9bc;\n  --taupe-mono-3: #fbe1a3;\n\n  /* Theme Overrides */\n\n  --accent: var(--pink);\n  --accented-background: var(--bg-shade-1);\n  --background: var(--bg);\n  --code-background: var(--bg-shade-2);\n  --table-background: var(--bg-mono-1);\n  --hard-black: var(--taupe-mono-1);\n  --links: var(--pink);\n  --text: var(--taupe-mono-1);\n\n  --shadow: 0 0 0 1px rgba(50, 50, 93, 0.075), 0 0 1px var(--fg-shade-3),\n    0 2px 4px -2px rgba(138, 141, 151, 0.2);\n  --nav-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.1);\n}\n\nbody.theme-dark {\n  background-color: var(--bg);\n  color: var(--fg-shade-1);\n}\n\nbody.theme-dark .page-header {\n  background-color: var(--bg-mono-1);\n}\n\nbody.theme-dark .page-header h2 {\n  color: var(--fg-shade-1);\n}\n\nbody.theme-dark .page-header a,\nbody.theme-dark .page-header a:visited {\n  color: var(--pink);\n}\n\nbody.theme-dark .page-header .sidebar-toggle {\n  color: var(--fg-shade-1);\n}\nbody.theme-dark .page-header .search-nav-button {\n  color: var(--fg-shade-1);\n}\n\nbody.theme-dark #project-version select,\nbody.theme-dark .control {\n  color: var(--fg-shade-1);\n}\n\nbody.theme-dark .module-name {\n  color: var(--taupe-mono-1);\n}\n\nbody.theme-dark .pride {\n  color: var(--bg-shade-3);\n}\n\nbody.theme-dark .pride .white {\n  background-color: var(--fg-shade-1);\n}\n\nbody.theme-dark .pride .pink {\n  background-color: var(--argument-atom);\n}\n\nbody.theme-dark .pride .blue {\n  background-color: var(--punctuation);\n}\n\n/* Medium and larger displays */\n@media (min-width: 680px) {\n  #prewrap-toggle {\n    display: none;\n  }\n}\n\n/* Small displays */\n@media (max-width: 920px) {\n  .page-header {\n    padding-left: var(--small-gap);\n    padding-right: var(--small-gap);\n  }\n\n  .page-header h2 {\n    width: calc(\n      100% - var(--sidebar-toggle-size) - var(--small-gap) -\n        var(--sidebar-toggle-size) - var(--small-gap)\n    );\n  }\n\n  .content {\n    width: 100%;\n    max-width: unset;\n    margin-left: unset;\n  }\n\n  .sidebar {\n    box-shadow: var(--nav-shadow);\n    height: 100vh;\n    max-height: unset;\n    top: 0;\n    transform: translate(calc(-10px - var(--sidebar-width)));\n    z-index: 500;\n  }\n\n  body.drawer-open .sidebar {\n    transform: translate(0);\n  }\n\n  .sidebar-toggle {\n    display: block;\n    opacity: 1;\n  }\n\n  .search-nav-button {\n    display: block;\n    opacity: 1;\n  }\n\n  .sidebar .sidebar-toggle {\n    height: var(--sidebar-toggle-size);\n    position: absolute;\n    right: var(--small-gap);\n    top: var(--small-gap);\n    width: var(--sidebar-toggle-size);\n  }\n}\n\n/* Search */\n\n.search {\n  display: none;\n  position: relative;\n  z-index: 2;\n  flex-grow: 1;\n  height: var(--search-height);\n  padding: 0.5rem;\n  transition: padding linear 200ms;\n}\n\n@media (min-width: 919px) {\n  .search {\n    margin-left: var(--small-gap);\n    display: block;\n    position: relative !important;\n    width: auto !important;\n    height: 100% !important;\n    padding: 0;\n    transition: none;\n  }\n}\n\n.search-input-wrap {\n  position: relative;\n  z-index: 1;\n  height: 3rem;\n  overflow: hidden;\n  border-radius: 4px;\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);\n  transition: height linear 200ms;\n}\n\n@media (min-width: 919px) {\n  .search-input-wrap {\n    position: absolute;\n    width: 100%;\n    max-width: calc(var(--content-width) - var(--gap) - var(--gap));\n    height: 100% !important;\n    border-radius: 0;\n    box-shadow: none;\n    transition: width ease 400ms;\n  }\n}\n\n.search-input {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  padding: 0.5rem 1rem;\n  font-size: 16px;\n  background-color: var(--background);\n  color: var(--text);\n  border-top: 0;\n  border-right: 0;\n  border-bottom: 0;\n  border-left: 0;\n  border-radius: 0;\n}\n\n@media (min-width: 919px) {\n  .search-input {\n    padding: 1rem;\n    font-size: 14px;\n    background-color: var(--background);\n    transition: padding-left linear 200ms;\n  }\n}\n\n.search-input:focus {\n  outline: 0;\n}\n\n.search-input:focus + .search-label .search-icon {\n  color: var(--pink);\n}\n\n.search-label {\n  position: absolute;\n  right: 0;\n  display: flex;\n  height: 100%;\n  padding-right: 1rem;\n  cursor: pointer;\n}\n\n@media (min-width: 919px) {\n  .search-label {\n    padding-right: 0.6rem;\n    transition: padding-left linear 200ms;\n  }\n}\n\n.search-label .search-icon {\n  width: 1.2rem;\n  height: 1.2rem;\n  align-self: center;\n  color: var(--text);\n}\n\n.search-results {\n  position: absolute;\n  left: 0;\n  display: none;\n  width: 100%;\n  max-height: calc(100% - var(--search-height));\n  overflow-y: auto;\n  background-color: var(--background);\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);\n}\n\n@media (min-width: 919px) {\n  .search-results {\n    top: 100%;\n    width: calc(var(--content-width) - var(--gap) - var(--gap));\n    max-height: calc(100vh - 200%) !important;\n  }\n}\n\n.search-results-list {\n  padding-left: 0;\n  margin-bottom: 0.25rem;\n  list-style: none;\n  font-size: 14px !important;\n}\n\n@media (min-width: 31.25rem) {\n  .search-results-list {\n    font-size: 16px !important;\n  }\n}\n\n@media (min-width: 919px) {\n  .search-results-list {\n    font-size: 12px !important;\n  }\n}\n\n@media (min-width: 919px) and (min-width: 31.25rem) {\n  .search-results-list {\n    font-size: 14px !important;\n  }\n}\n\n.search-results-list-item {\n  padding: 0;\n  margin: 0;\n}\n\n.search-result {\n  display: block;\n  padding-top: 0.25rem;\n  padding-right: 0.75rem;\n  padding-bottom: 0.25rem;\n  padding-left: 0.75rem;\n}\n\n.search-result:hover,\n.search-result.active {\n  background-color: var(--code-background);\n}\n\n.search-result-title {\n  display: block;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n}\n\n@media (min-width: 31.25rem) {\n  .search-result-title {\n    display: inline-block;\n    width: 40%;\n    padding-right: 0.5rem;\n    vertical-align: top;\n  }\n}\n\n.search-result-doc {\n  display: flex;\n  align-items: center;\n  word-wrap: break-word;\n}\n\n.search-result-doc.search-result-doc-parent {\n  opacity: 0.5;\n  font-size: 12px !important;\n}\n\n@media (min-width: 31.25rem) {\n  .search-result-doc.search-result-doc-parent {\n    font-size: 14px !important;\n  }\n}\n\n@media (min-width: 919px) {\n  .search-result-doc.search-result-doc-parent {\n    font-size: 11px !important;\n  }\n}\n\n@media (min-width: 919px) and (min-width: 31.25rem) {\n  .search-result-doc.search-result-doc-parent {\n    font-size: 12px !important;\n  }\n}\n\n.search-result-doc .search-result-icon {\n  width: 1rem;\n  height: 1rem;\n  margin-right: 0.5rem;\n  color: var(--pink);\n  flex-shrink: 0;\n}\n\n.search-result-doc .search-result-doc-title {\n  overflow: auto;\n}\n\n.search-result-section {\n  margin-left: 1.5rem;\n  word-wrap: break-word;\n}\n\n.search-result-rel-url {\n  display: block;\n  margin-left: 1.5rem;\n  overflow: hidden;\n  color: var(--text);\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  font-size: 9px !important;\n}\n\n@media (min-width: 31.25rem) {\n  .search-result-rel-url {\n    font-size: 10px !important;\n  }\n}\n\n.search-result-previews {\n  display: block;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n  padding-left: 1rem;\n  margin-left: 0.5rem;\n  color: var(--text);\n  word-wrap: break-word;\n  border-left: 1px solid;\n  border-left-color: #eeebee;\n  font-size: 11px !important;\n  /* TODO: fix it by not adding at the parent? */\n  white-space: initial !important;\n}\n\n@media (min-width: 31.25rem) {\n  .search-result-previews {\n    font-size: 12px !important;\n  }\n}\n\n@media (min-width: 31.25rem) {\n  .search-result-previews {\n    display: inline-block;\n    width: 60%;\n    padding-left: 0.5rem;\n    margin-left: 0;\n    vertical-align: top;\n  }\n}\n\n.search-result-preview + .search-result-preview {\n  margin-top: 0.25rem;\n}\n\n.search-result-highlight {\n  font-weight: bold;\n}\n\n.search-no-result {\n  padding-top: 0.5rem;\n  padding-right: 0.75rem;\n  padding-bottom: 0.5rem;\n  padding-left: 0.75rem;\n  font-size: 12px !important;\n}\n\n@media (min-width: 31.25rem) {\n  .search-no-result {\n    font-size: 14px !important;\n  }\n}\n\n.search-button {\n  position: fixed;\n  right: 1rem;\n  bottom: 1rem;\n  display: flex;\n  width: 3.5rem;\n  height: 3.5rem;\n  background-color: var(--background);\n  border: 1px solid rgba(114, 83, 237, 0.3);\n  border-radius: 1.75rem;\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);\n  align-items: center;\n  justify-content: center;\n}\n\n.search-overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: 101;\n  width: 0;\n  height: 0;\n  background-color: rgba(0, 0, 0, 0.3);\n  opacity: 0;\n  transition: opacity ease 400ms, width 0s 400ms, height 0s 400ms;\n}\n\n.search-active .search {\n  display: block;\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  padding: 0;\n}\n\n.search-active .search-input-wrap {\n  height: var(--search-height);\n  border-radius: 0;\n}\n\n@media (min-width: 919px) {\n  .search-active .search-input-wrap {\n    width: calc(var(--content-width) - var(--gap) - var(--gap));\n    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);\n  }\n}\n\n@media (min-width: 919px) {\n  .search-active .search-label {\n    padding-left: 0.6rem;\n  }\n}\n\n.search-active .search-results {\n  display: block;\n}\n\n.search-active .search-overlay {\n  width: 100%;\n  height: 100%;\n  opacity: 1;\n  transition: opacity ease 400ms, width 0s, height 0s;\n}\n\n@media (min-width: 919px) {\n  .search-active .main {\n    position: fixed;\n    right: 0;\n    left: 0;\n  }\n}\n\n.search-active .main-header {\n  padding-top: var(--search-height);\n}\n\n@media (min-width: 919px) {\n  .search-active .main-header {\n    padding-top: 0;\n  }\n}\n"
  },
  {
    "path": "compiler-core/templates/docs-js/highlightjs-gleam.js",
    "content": "hljs.registerLanguage(\"gleam\", function (hljs) {\n  const KEYWORDS = {\n    className: \"keyword\",\n    beginKeywords:\n      \"as assert auto case const delegate derive echo else fn if \" +\n      \"implement import let macro opaque panic pub test todo type use\",\n  };\n  const STRING = {\n    className: \"string\",\n    variants: [{ begin: /\"/, end: /\"/ }],\n    contains: [hljs.BACKSLASH_ESCAPE],\n    relevance: 0,\n  };\n  const NAME = {\n    className: \"variable\",\n    begin: \"\\\\b[a-z][a-z0-9_]*\\\\b\",\n    relevance: 0,\n  };\n  const DISCARD_NAME = {\n    className: \"comment\",\n    begin: \"\\\\b_[a-z][a-z0-9_]*\\\\b\",\n    relevance: 0,\n  };\n  const NUMBER = {\n    className: \"number\",\n    variants: [\n      {\n        // binary\n        begin: \"\\\\b0[bB](?:_?[01]+)+\",\n      },\n      {\n        // octal\n        begin: \"\\\\b0[oO](?:_?[0-7]+)+\",\n      },\n      {\n        // hex\n        begin: \"\\\\b0[xX](?:_?[0-9a-fA-F]+)+\",\n      },\n      {\n        // dec, float\n        begin: \"\\\\b\\\\d(?:_?\\\\d+)*(?:\\\\.(?:\\\\d(?:_?\\\\d+)*)*)?\",\n      },\n    ],\n    relevance: 0,\n  };\n\n  return {\n    name: \"Gleam\",\n    aliases: [\"gleam\"],\n    contains: [\n      hljs.C_LINE_COMMENT_MODE,\n      STRING,\n      {\n        // bit array\n        begin: \"<<\",\n        end: \">>\",\n        contains: [\n          {\n            className: \"keyword\",\n            beginKeywords:\n              \"binary bits bytes int float bit_string bit_array bits utf8 utf16 \" +\n              \"utf32 utf8_codepoint utf16_codepoint utf32_codepoint signed \" +\n              \"unsigned big little native unit size\",\n          },\n          KEYWORDS,\n          STRING,\n          NAME,\n          DISCARD_NAME,\n          NUMBER,\n        ],\n        relevance: 10,\n      },\n      {\n        className: \"function\",\n        beginKeywords: \"fn\",\n        end: \"\\\\(\",\n        excludeEnd: true,\n        contains: [\n          {\n            className: \"title\",\n            begin: \"[a-z][a-z0-9_]*\\\\w*\",\n            relevance: 0,\n          },\n        ],\n      },\n      {\n        className: \"attribute\",\n        begin: \"@\",\n        end: \"\\\\(\",\n        excludeEnd: true,\n      },\n      KEYWORDS,\n      {\n        // Type names and constructors\n        className: \"title\",\n        begin: \"\\\\b[A-Z][A-Za-z0-9]*\\\\b\",\n        relevance: 0,\n      },\n      {\n        className: \"operator\",\n        begin: \"[+\\\\-*/%!=<>&|.]+\",\n        relevance: 0,\n      },\n      NAME,\n      DISCARD_NAME,\n      NUMBER,\n    ],\n  };\n});\n"
  },
  {
    "path": "compiler-core/templates/docs-js/index.js",
    "content": "\"use strict\";\n\nwindow.Gleam = (function () {\n  /* Global Object */\n  const self = {};\n\n  /* Public Properties */\n\n  self.hashOffset = undefined;\n\n  /* Public Methods */\n\n  self.getProperty = function (property) {\n    let value;\n    try {\n      value = localStorage.getItem(`Gleam.${property}`);\n    } catch (_error) { }\n    if (-1 < [null, undefined].indexOf(value)) {\n      return gleamConfig[property].values[0].value;\n    }\n    return value;\n  };\n\n  self.icons = function () {\n    return Array.from(arguments).reduce(\n      (acc, name) =>\n        `${acc}\n        <svg class=\"icon icon-${name}\"><use xlink:href=\"#icon-${name}\"></use></svg>`,\n      \"\",\n    );\n  };\n\n  self.scrollToHash = function () {\n    const locationHash = arguments[0] || window.location.hash;\n    const query = locationHash ? locationHash : \"body\";\n    const hashTop = document.querySelector(query).offsetTop;\n    window.scrollTo(0, hashTop - self.hashOffset);\n    return locationHash;\n  };\n\n  self.toggleSidebar = function () {\n    const previousState = bodyClasses.contains(\"drawer-open\")\n      ? \"open\"\n      : \"closed\";\n\n    let state;\n    if (0 < arguments.length) {\n      state = false === arguments[0] ? \"closed\" : \"open\";\n    } else {\n      state = \"open\" === previousState ? \"closed\" : \"open\";\n    }\n\n    bodyClasses.remove(`drawer-${previousState}`);\n    bodyClasses.add(`drawer-${state}`);\n\n    if (\"open\" === state) {\n      document.addEventListener(\"click\", closeSidebar, false);\n    }\n  };\n\n  /* Private Properties */\n\n  const html = document.documentElement;\n  const body = document.body;\n  const bodyClasses = body.classList;\n  const sidebar = document.querySelector(\".sidebar\");\n  const sidebarToggles = document.querySelectorAll(\".sidebar-toggle\");\n  const displayControls = document.createElement(\"div\");\n\n  const isMac = navigator?.userAgentData?.platform === 'macOS'\n    || /mac/i.test(navigator.userAgent);\n\n  displayControls.classList.add(\"display-controls\");\n  sidebar.appendChild(displayControls);\n\n  /* Private Methods */\n\n  const initProperty = function (property) {\n    const config = gleamConfig[property];\n\n    displayControls.insertAdjacentHTML(\n      \"beforeend\",\n      config.values.reduce(\n        (acc, item, index) => {\n          const tooltip = item.label\n            ? `alt=\"${item.label}\" title=\"${item.label}\"`\n            : \"\";\n          let inner;\n          if (item.icons) {\n            inner = self.icons(...item.icons);\n          } else if (item.label) {\n            inner = item.label;\n          } else {\n            inner = \"\";\n          }\n          return `\n            ${acc}\n            <span class=\"label label-${index}\" ${tooltip}>\n              ${inner}\n            </span>\n          `;\n        },\n        `<button\n          id=\"${property}-toggle\"\n          class=\"control control-${property} toggle toggle-0\">\n        `,\n      ) +\n      `\n        </button>\n      `,\n    );\n\n    setProperty(null, property, function () {\n      return self.getProperty(property);\n    });\n  };\n\n  const setProperty = function (_event, property) {\n    const previousValue = self.getProperty(property);\n\n    const update =\n      2 < arguments.length ? arguments[2] : gleamConfig[property].update;\n    const value = update();\n\n    try {\n      localStorage.setItem(\"Gleam.\" + property, value);\n    } catch (_error) { }\n\n    bodyClasses.remove(`${property}-${previousValue}`);\n    bodyClasses.add(`${property}-${value}`);\n\n    const isDefault = value === gleamConfig[property].values[0].value;\n    const toggleClasses = document.querySelector(\n      `#${property}-toggle`,\n    ).classList;\n    toggleClasses.remove(`toggle-${isDefault ? 1 : 0}`);\n    toggleClasses.add(`toggle-${isDefault ? 0 : 1}`);\n\n    try {\n      gleamConfig[property].callback(value);\n    } catch (_error) { }\n\n    return value;\n  };\n\n  const setHashOffset = function () {\n    const el = document.createElement(\"div\");\n    el.style.cssText = `\n      height: var(--hash-offset);\n      pointer-events: none;\n      position: absolute;\n      visibility: hidden;\n      width: 0;\n      `;\n    body.appendChild(el);\n    self.hashOffset = parseInt(\n      getComputedStyle(el).getPropertyValue(\"height\") || \"0\",\n    );\n    body.removeChild(el);\n  };\n\n  const closeSidebar = function (event) {\n    if (!event.target.closest(\".sidebar-toggle\")) {\n      document.removeEventListener(\"click\", closeSidebar, false);\n      self.toggleSidebar(false);\n    }\n  };\n\n  const addEvent = function (el, type, handler) {\n    if (el.attachEvent) el.attachEvent(\"on\" + type, handler);\n    else el.addEventListener(type, handler);\n  };\n\n  const searchLoaded = function (index, searchItems) {\n    const preview_words_after = 10;\n    const preview_words_before = 5;\n    const previews = 3;\n\n    const searchInput = document.getElementById(\"search-input\");\n    const searchNavButton = document.getElementById(\"search-nav-button\");\n    const searchResults = document.getElementById(\"search-results\");\n    let currentInput;\n    let currentSearchIndex = 0;\n\n    // Set search input placeholder based on OS\n    searchInput.setAttribute(\"placeholder\", isMac ? \"Search ⌘ + K\" : \"Search Ctrl + K\")\n\n    function showSearch() {\n      document.documentElement.classList.add(\"search-active\");\n    }\n\n    searchNavButton.addEventListener(\"click\", function (e) {\n      e.stopPropagation();\n      showSearch();\n      setTimeout(function () {\n        searchInput.focus();\n      }, 0);\n    });\n\n    function hideSearch() {\n      document.documentElement.classList.remove(\"search-active\");\n    }\n\n    function update() {\n      currentSearchIndex++;\n\n      const input = searchInput.value;\n      showSearch();\n      if (input === currentInput) {\n        return;\n      }\n      currentInput = input;\n      searchResults.innerHTML = \"\";\n      if (input === \"\") {\n        return;\n      }\n\n      let results = index.query(function (query) {\n        const tokens = lunr.tokenizer(input);\n        query.term(tokens, {\n          boost: 10,\n        });\n        query.term(tokens, {\n          boost: 5,\n          wildcard: lunr.Query.wildcard.TRAILING,\n        });\n        query.term(tokens, {\n          wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING,\n        });\n      });\n\n      if (results.length == 0 && input.length > 2) {\n        const tokens = lunr.tokenizer(input).filter(function (token, i) {\n          return token.str.length < 20;\n        });\n        if (tokens.length > 0) {\n          results = index.query(function (query) {\n            query.term(tokens, {\n              editDistance: Math.round(Math.sqrt(input.length / 2 - 1)),\n            });\n          });\n        }\n      }\n\n      if (results.length == 0) {\n        const noResultsDiv = document.createElement(\"div\");\n        noResultsDiv.classList.add(\"search-no-result\");\n        noResultsDiv.innerText = \"No results found\";\n        searchResults.appendChild(noResultsDiv);\n      } else {\n        const resultsList = document.createElement(\"ul\");\n        resultsList.classList.add(\"search-results-list\");\n        searchResults.appendChild(resultsList);\n\n        addResults(resultsList, results, 0, 10, 100, currentSearchIndex);\n      }\n\n      function addResults(\n        resultsList,\n        results,\n        start,\n        batchSize,\n        batchMillis,\n        searchIndex,\n      ) {\n        if (searchIndex != currentSearchIndex) {\n          return;\n        }\n        for (let i = start; i < start + batchSize; i++) {\n          if (i == results.length) {\n            return;\n          }\n          addResult(resultsList, results[i]);\n        }\n        setTimeout(function () {\n          addResults(\n            resultsList,\n            results,\n            start + batchSize,\n            batchSize,\n            batchMillis,\n            searchIndex,\n          );\n        }, batchMillis);\n      }\n\n      function addResult(resultsList, result) {\n        const searchItem = searchItems[result.ref];\n        const resultsListItem = document.createElement(\"li\");\n        resultsListItem.classList.add(\"search-results-list-item\");\n        resultsList.appendChild(resultsListItem);\n        const resultLink = document.createElement(\"a\");\n        resultLink.classList.add(\"search-result\");\n        resultLink.setAttribute(\"href\", `${window.unnest}/${searchItem.ref}`);\n        resultsListItem.appendChild(resultLink);\n        const resultTitle = document.createElement(\"div\");\n        resultTitle.classList.add(\"search-result-title\");\n        resultLink.appendChild(resultTitle);\n        const resultDoc = document.createElement(\"div\");\n        resultDoc.classList.add(\"search-result-doc\");\n        resultDoc.innerHTML =\n          '<svg viewBox=\"0 0 24 24\" class=\"search-result-icon\"><use xlink:href=\"#icon-svg-doc\"></use></svg>';\n        resultTitle.appendChild(resultDoc);\n        const resultDocTitle = document.createElement(\"div\");\n        resultDocTitle.classList.add(\"search-result-doc-title\");\n        resultDocTitle.innerHTML = searchItem.parentTitle;\n        resultDoc.appendChild(resultDocTitle);\n        let resultDocOrSection = resultDocTitle;\n        if (searchItem.parentTitle != searchItem.title) {\n          resultDoc.classList.add(\"search-result-doc-parent\");\n          const resultSection = document.createElement(\"div\");\n          resultSection.classList.add(\"search-result-section\");\n          resultSection.innerHTML = searchItem.title;\n          resultTitle.appendChild(resultSection);\n          resultDocOrSection = resultSection;\n        }\n        const metadata = result.matchData.metadata;\n        const titlePositions = [];\n        const contentPositions = [];\n        for (let j in metadata) {\n          const meta = metadata[j];\n          if (meta.title) {\n            const positions = meta.title.position;\n            for (let k in positions) {\n              titlePositions.push(positions[k]);\n            }\n          }\n          if (meta.content) {\n            const positions = meta.content.position;\n            for (let k in positions) {\n              const position = positions[k];\n              let previewStart = position[0];\n              let previewEnd = position[0] + position[1];\n              let ellipsesBefore = true;\n              let ellipsesAfter = true;\n              for (let k = 0; k < preview_words_before; k++) {\n                const nextSpace = searchItem.doc.lastIndexOf(\n                  \" \",\n                  previewStart - 2,\n                );\n                const nextDot = searchItem.doc.lastIndexOf(\". \", previewStart - 2);\n                if (nextDot >= 0 && nextDot > nextSpace) {\n                  previewStart = nextDot + 1;\n                  ellipsesBefore = false;\n                  break;\n                }\n                if (nextSpace < 0) {\n                  previewStart = 0;\n                  ellipsesBefore = false;\n                  break;\n                }\n                previewStart = nextSpace + 1;\n              }\n              for (let k = 0; k < preview_words_after; k++) {\n                const nextSpace = searchItem.doc.indexOf(\" \", previewEnd + 1);\n                const nextDot = searchItem.doc.indexOf(\". \", previewEnd + 1);\n                if (nextDot >= 0 && nextDot < nextSpace) {\n                  previewEnd = nextDot;\n                  ellipsesAfter = false;\n                  break;\n                }\n                if (nextSpace < 0) {\n                  previewEnd = searchItem.doc.length;\n                  ellipsesAfter = false;\n                  break;\n                }\n                previewEnd = nextSpace;\n              }\n              contentPositions.push({\n                highlight: position,\n                previewStart: previewStart,\n                previewEnd: previewEnd,\n                ellipsesBefore: ellipsesBefore,\n                ellipsesAfter: ellipsesAfter,\n              });\n            }\n          }\n        }\n        if (titlePositions.length > 0) {\n          titlePositions.sort(function (p1, p2) {\n            return p1[0] - p2[0];\n          });\n          resultDocOrSection.innerHTML = \"\";\n          addHighlightedText(\n            resultDocOrSection,\n            searchItem.title,\n            0,\n            searchItem.title.length,\n            titlePositions,\n          );\n        }\n        if (contentPositions.length > 0) {\n          contentPositions.sort(function (p1, p2) {\n            return p1.highlight[0] - p2.highlight[0];\n          });\n          let contentPosition = contentPositions[0];\n          let previewPosition = {\n            highlight: [contentPosition.highlight],\n            previewStart: contentPosition.previewStart,\n            previewEnd: contentPosition.previewEnd,\n            ellipsesBefore: contentPosition.ellipsesBefore,\n            ellipsesAfter: contentPosition.ellipsesAfter,\n          };\n          const previewPositions = [previewPosition];\n          for (let j = 1; j < contentPositions.length; j++) {\n            contentPosition = contentPositions[j];\n            if (previewPosition.previewEnd < contentPosition.previewStart) {\n              previewPosition = {\n                highlight: [contentPosition.highlight],\n                previewStart: contentPosition.previewStart,\n                previewEnd: contentPosition.previewEnd,\n                ellipsesBefore: contentPosition.ellipsesBefore,\n                ellipsesAfter: contentPosition.ellipsesAfter,\n              };\n              previewPositions.push(previewPosition);\n            } else {\n              previewPosition.highlight.push(contentPosition.highlight);\n              previewPosition.previewEnd = contentPosition.previewEnd;\n              previewPosition.ellipsesAfter = contentPosition.ellipsesAfter;\n            }\n          }\n          const resultPreviews = document.createElement(\"div\");\n          resultPreviews.classList.add(\"search-result-previews\");\n          resultLink.appendChild(resultPreviews);\n          const content = searchItem.doc;\n          for (\n            let j = 0;\n            j < Math.min(previewPositions.length, previews);\n            j++\n          ) {\n            const position = previewPositions[j];\n            const resultPreview = document.createElement(\"div\");\n            resultPreview.classList.add(\"search-result-preview\");\n            resultPreviews.appendChild(resultPreview);\n            if (position.ellipsesBefore) {\n              resultPreview.appendChild(document.createTextNode(\"... \"));\n            }\n            addHighlightedText(\n              resultPreview,\n              content,\n              position.previewStart,\n              position.previewEnd,\n              position.highlight,\n            );\n            if (position.ellipsesAfter) {\n              resultPreview.appendChild(document.createTextNode(\" ...\"));\n            }\n          }\n        }\n        const resultRelUrl = document.createElement(\"span\");\n        resultRelUrl.classList.add(\"search-result-rel-url\");\n        resultRelUrl.innerText = searchItem.ref;\n        resultTitle.appendChild(resultRelUrl);\n      }\n\n      function addHighlightedText(parent, text, start, end, positions) {\n        let index = start;\n        for (let i in positions) {\n          const position = positions[i];\n          const span = document.createElement(\"span\");\n          span.innerHTML = text.substring(index, position[0]);\n          parent.appendChild(span);\n          index = position[0] + position[1];\n          const highlight = document.createElement(\"span\");\n          highlight.classList.add(\"search-result-highlight\");\n          highlight.innerHTML = text.substring(position[0], index);\n          parent.appendChild(highlight);\n        }\n        const span = document.createElement(\"span\");\n        span.innerHTML = text.substring(index, end);\n        parent.appendChild(span);\n      }\n    }\n\n    addEvent(document, \"keydown\", function (event) {\n      // Don't do anything when search is already in focus\n      if (document.activeElement == searchInput) {\n        return\n      }\n\n      if (\n        // Handle cmd/ctrl + k\n        ((event.metaKey || event.ctrlKey) && event.key === 'k') ||\n        // Handle s or /\n        event.key === 's' || event.key === '/'\n      ) {\n        event.preventDefault();\n\n        searchInput.focus();\n        return;\n      }\n    })\n\n    addEvent(searchInput, \"focus\", function () {\n      setTimeout(update, 0);\n    });\n\n    addEvent(searchInput, \"keyup\", function (e) {\n      switch (e.keyCode) {\n        case 27: // When esc key is pressed, hide the results and clear the field\n          searchInput.value = \"\";\n          break;\n        case 38: // arrow up\n        case 40: // arrow down\n        case 13: // enter\n          e.preventDefault();\n          return;\n      }\n      update();\n    });\n\n    addEvent(searchInput, \"keydown\", function (e) {\n      let active;\n      switch (e.keyCode) {\n        case 38: // arrow up\n          e.preventDefault();\n          active = document.querySelector(\".search-result.active\");\n          if (active) {\n            active.classList.remove(\"active\");\n            if (active.parentElement.previousSibling) {\n              const previous =\n                active.parentElement.previousSibling.querySelector(\n                  \".search-result\",\n                );\n              previous.classList.add(\"active\");\n            }\n          }\n          return;\n        case 40: // arrow down\n          e.preventDefault();\n          active = document.querySelector(\".search-result.active\");\n          if (active) {\n            if (active.parentElement.nextSibling) {\n              const next =\n                active.parentElement.nextSibling.querySelector(\n                  \".search-result\",\n                );\n              active.classList.remove(\"active\");\n              next.classList.add(\"active\");\n            }\n          } else {\n            const next = document.querySelector(\".search-result\");\n            if (next) {\n              next.classList.add(\"active\");\n            }\n          }\n          return;\n        case 13: // enter\n          e.preventDefault();\n          active = document.querySelector(\".search-result.active\");\n          if (active) {\n            active.click();\n          } else {\n            const first = document.querySelector(\".search-result\");\n            if (first) {\n              first.click();\n            }\n          }\n          return;\n      }\n    });\n\n    addEvent(document, \"click\", function (e) {\n      if (e.target != searchInput) {\n        hideSearch();\n      }\n    });\n  };\n\n  self.initSearch = function initSeach(searchData) {\n    // enable support for hyphenated search words\n    lunr.tokenizer.separator = /[\\s/]+/;\n    const index = lunr(function () {\n      this.ref(\"id\");\n      // this.field(\"type\");\n      // this.field(\"parentTitle\");\n      this.field(\"title\", { boost: 200 });\n      this.field(\"doc\", { boost: 2 });\n      this.field(\"ref\");\n      this.metadataWhitelist = [\"position\"];\n\n      for (let [i, entry] of searchData.items.entries()) {\n        this.add({\n          id: i,\n          // type: entry.type,\n          parentTitle: entry.parentTitle,\n          title: entry.title,\n          doc: entry.doc,\n          ref: `${window.unnest}/${entry.ref}`,\n        });\n      }\n    });\n    searchLoaded(index, searchData.items);\n  };\n\n  const init = function () {\n    for (let property in gleamConfig) {\n      initProperty(property);\n      const toggle = document.querySelector(`#${property}-toggle`);\n      toggle.addEventListener(\"click\", function (event) {\n        setProperty(event, property);\n      });\n    }\n\n    sidebarToggles.forEach(function (sidebarToggle) {\n      sidebarToggle.addEventListener(\"click\", function (event) {\n        event.preventDefault();\n        self.toggleSidebar();\n      });\n    });\n\n    setHashOffset();\n    window.addEventListener(\"load\", function (_event) {\n      self.scrollToHash();\n    });\n    window.addEventListener(\"hashchange\", function (_event) {\n      self.scrollToHash();\n    });\n\n    document\n      .querySelectorAll(\n        `\n      .module-name > a,\n      .member-name a[href^='#']\n    `,\n      )\n      .forEach(function (title) {\n        title.innerHTML = title.innerHTML.replace(\n          /([A-Z])|([_/])/g,\n          \"$2<wbr>$1\",\n        );\n      });\n  };\n\n  /* Initialise */\n\n  init();\n\n  return self;\n})();\n"
  },
  {
    "path": "compiler-core/templates/documentation_layout.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>{{ page_title }}</title>\n    <meta name=\"description\" content=\"{{page_meta_description}}\"/>\n    <meta name=\"theme-color\" content=\"#ffaff3\" media=\"(prefers-color-scheme: light)\"/>\n    <meta name=\"theme-color\" content=\"#33384d\" media=\"(prefers-color-scheme: dark)\"/>\n    <link rel=\"stylesheet\" href=\"{{ unnest }}/css/index.css?v={{ gleam_version }}\" type=\"text/css\"/>\n    <!-- The docs_config.js file is provided by HexDocs and shared\n         between multiple versions of the same package. -->\n    <script src=\"{{ unnest }}/docs_config.js\"></script>\n    <link id=\"syntax-theme\" rel=\"stylesheet\" href=\"{{ unnest }}/css/atom-one-light.min.css?v={{ gleam_version }}\"/>\n    {% if !host.is_empty() && !project_name.is_empty() -%}<link rel=\"canonical\" href=\"{{ host }}/{{ project_name|safe }}/{{ file_path|safe }}\" />{%- endif %}\n  </head>\n  <body class=\"prewrap-off theme-light drawer-closed\">\n    <script>\n      \"use strict\";\n\n      /* gleamConfig format:\n       * // object with one or more options\n       * {option: {\n       *   // array of values\n       *   values: [{\n       *     // this value\n       *     value: \"off\",\n       *     // optional button label\n       *     label: \"default\",\n       *     // optional array of icons\n       *     icons: [\"star\", \"toggle-left\", ...],\n       *   }, ...],\n       *\n       *   // value update function\n       *   update: () => {...},\n       *\n       *   // optional callback function\n       *   callback: (value) => {...},\n       * }, ...};\n       */\n      window.unnest = '{{ unnest }}';\n      const gleamConfig = {\n        theme: {\n          values: (() => {\n            const dark = {\n              value: \"dark\",\n              label: \"Switch to light mode\",\n              icons: [\"moon\"],\n            };\n            const light = {\n              value: \"light\",\n              label: \"Switch to dark mode\",\n              icons: [\"sun\"],\n            };\n            return (\n              window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n              ? [dark, light]\n              : [light, dark]\n            ).map((item, index) => {\n              item.icons.push(`toggle-${0 === index ? \"left\" : \"right\"}`);\n              return item;\n            });\n          })(),\n\n          update: () => \"light\" === Gleam.getProperty(\"theme\") ? \"dark\" : \"light\",\n\n          callback: function(value) {\n            const syntaxThemes = {\n              dark: \"atom-one-dark\",\n              light: \"atom-one-light\",\n            };\n            const syntaxTheme = document.querySelector(\"#syntax-theme\");\n            const hrefParts = syntaxTheme.href.match(\n              /^(.*?)([^/\\\\#?]+?)((?:\\.min)?\\.css.*)$/i\n            );\n            if (syntaxThemes[value] !== hrefParts[2]) {\n              hrefParts[2] = syntaxThemes[value];\n              hrefParts.shift();\n              syntaxTheme.href = hrefParts.join(\"\");\n            }\n          },\n        },\n        prewrap: {\n          values: [\n            {\n              value: \"off\",\n              label: \"Switch to line-wrapped snippets\",\n              icons: [\"more-horizontal\", \"toggle-left\"],\n            },\n            {\n              value: \"on\",\n              label: \"Switch to non-wrapped snippets\",\n              icons: [\"more-vertical\", \"toggle-right\"],\n            },\n          ],\n\n          update: () => \"off\" === Gleam.getProperty(\"prewrap\") ? \"on\" : \"off\",\n        },\n      };\n    </script>\n\n    <script>\n      \"use strict\";\n\n      /* Initialise options before any content loads */\n      void function() {\n        for (const property in gleamConfig) {\n          const name = `Gleam.${property}`;\n\n          let value;\n\n          try {\n            value = localStorage.getItem(name);\n            if (value.startsWith('\"') && value.endsWith('\"')) {\n              localStorage.setItem(name, value.slice(1, value.length - 1));\n            }\n          }\n          catch (_error) {}\n\n          const defaultValue = gleamConfig[property].values[0].value;\n          try {\n            value = localStorage.getItem(name);\n          }\n          catch(_error) {}\n          if (-1 < [null, undefined].indexOf(value)) {\n            value = defaultValue;\n          }\n          const bodyClasses = document.body.classList;\n          bodyClasses.remove(`${property}-${defaultValue}`);\n          bodyClasses.add(`${property}-${value}`);\n          try {\n            gleamConfig[property].callback(value);\n          }\n          catch(_error) {}\n        }\n      }();\n    </script>\n\n    <header class=\"page-header\">\n      <button class=\"sidebar-toggle\" tabindex=\"0\">\n        <svg class=\"label label-closed icon icon-menu\" alt=\"Open Menu\" title=\"Open Menu\"><use xlink:href=\"#icon-menu\"></use></svg>\n        <svg class=\"label label-open icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n      </button>\n\n      <h2>\n        <a href=\"{{ unnest }}/\">{{ project_name }}</a>\n        <span id=\"project-version\">\n          <span> - v{{ project_version }} </span>\n        </span>\n        <script>\n          \"use strict\";\n\n          if (\"undefined\" !== typeof versionNodes) {\n            const currentVersion = \"v{{ project_version }}\";\n            if (! versionNodes.find(element => element.version === currentVersion)) {\n              versionNodes.unshift({ version: currentVersion, url: \"#\" });\n            }\n            document.querySelector(\"#project-version\").innerHTML =\n              versionNodes.reduce(\n                (acc, element) => {\n                  const status =\n                    currentVersion === element.version ? \"selected disabled\" : \"\";\n                  return `\n                    ${acc}\n                      <option value=\"${element.url}\" ${status}>\n                        ${element.version}\n                      </option>\n                  `;\n                },\n                `\n                <form autocomplete=\"off\">\n                  <select onchange=\"window.location.href = this.value\">\n                `\n              ) + `\n                  </select>\n                  <svg class=\"icon icon-chevrons-down\"><use xlink:href=\"#icon-chevrons-down\"></use></svg>\n                </form>\n              `;\n          }\n        </script>\n      </h2>\n      <div class=\"search\">\n        <div class=\"search-input-wrap\">\n          <input type=\"text\" id=\"search-input\" class=\"search-input\" tabindex=\"0\" aria-label=\"Search {{ project_name }}\" autocomplete=\"off\">\n          <label for=\"search-input\" class=\"search-label\"><svg viewBox=\"0 0 24 24\" class=\"search-icon\"><use xlink:href=\"#icon-svg-search\"></use></svg></label>\n        </div>\n        <div id=\"search-results\" class=\"search-results\"></div>\n      </div>\n\n      <button class=\"search-nav-button\" id=\"search-nav-button\" tabindex=\"0\">\n        <svg class=\"label icon icon-x-circle\" alt=\"Open Search\" title=\"Open Search\"><use xlink:href=\"#icon-svg-search\"></use></svg>\n      </button>\n\n    </header>\n\n    <div class=\"page\">\n      <nav class=\"sidebar\">\n        <button class=\"sidebar-toggle\" tabindex=\"1\">\n          <svg class=\"label icon icon-x-circle\" alt=\"Close Menu\" title=\"Close Menu\"><use xlink:href=\"#icon-x-circle\"></use></svg>\n        </button>\n\n        {% if !pages.is_empty() %}\n        <h2>Pages</h2>\n        <ul>\n        {% for page in pages %}\n          <li><a href=\"{{ unnest }}/{{ page.path }}\">{{ page.name }}</a></li>\n        {% endfor %}\n        </ul>\n        {% endif %}\n\n        {% if !links.is_empty() %}\n        <h2>Links</h2>\n        <ul>\n        {% for link in links %}\n          <li><a href=\"{{ link.path }}\">{{ link.name }}</a></li>\n        {% endfor %}\n        </ul>\n        {% endif %}\n\n        <h2>Modules</h2>\n        <ul>\n        {% for module in modules %}\n          <li><a href=\"{{ unnest }}/{{ module.path }}\" class=\"module-link\">{{ module.name|safe }}</a></li>\n        {% endfor %}\n        </ul>\n\n        {% block sidebar_content %}{% endblock %}\n      </nav>\n\n      <main class=\"content\">\n        {% block content %}{% endblock %}\n      </main>\n      <div class=\"search-overlay\"></div>\n    </div>\n\n    <script>\n      \"use strict\";\n      const pride = () => document.body.classList.toggle(\"show-pride\");\n    </script>\n    <a class=\"pride-button\" onclick=\"pride()\">✨</a>\n    <footer class=\"pride\" onclick=\"pride()\">\n      <div class=\"blue\">Lucy</div>\n      <div class=\"pink\">says</div>\n      <div class=\"white\">trans</div>\n      <div class=\"pink\">rights</div>\n      <div class=\"blue\">now</div>\n    </footer>\n\n    <svg class=\"svg-lib\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <defs>\n        <symbol id=\"icon-chevrons-down\" viewBox=\"0 0 24 24\"><path d=\"M6.293 13.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM6.293 6.707l5 5c0.391 0.391 1.024 0.391 1.414 0l5-5c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-4.293 4.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse\" viewBox=\"0 0 180 22\"><path d=\"m0.00798 15.6c0.784-1.73 0.754-2.11 1.94-3.97 1.17-0.28 2.66-0.119 3.71-0.524 1.12 0.501 1.85 0.729 3.35-0.466 0.942-0.806 2.41 0.656 3.41-0.0865 2.53-1.48 0.972-1.03 5.14-0.585 1.79-0.493 3.46-0.852 6.64-1.06 3.8-0.331 0.0108-1.06 5.16-1.16 0.874-0.835 3.43-1.34 5.49-0.963 2.17-1.41 0.488-1.58 2.64-0.426 4.36-0.0592 0.83-1.08 5.39-1.22 3.27-0.264 0.843-0.471 2.82 0.187 2.13-0.254 1.36-0.525 3.67 0.709 1.77 1.66 0.962 0.181 1.9 2.32 0.26 0.593 0.304 1.71 0.814 1.74 3.67-0.833-0.0875 0.536 4.63-0.838 0.719-0.891 4.42 0.255 3.8-0.806 2.07 0.119 2.75-0.7 6.07-0.822 1.48-1.17 2.26 0.943 3.4-0.974 0.391 0.166-1.61-0.548 3.88-0.154 2.93-1.26-1.74 0.103 4.21-0.851 3.52 8e-3 0.233-0.263 3.33-0.811 1.06-1.46-0.459-1.02 5.55-0.963 2.61-2.11 0.281-1.59 4.88-0.572 0.699 0.597 3.05 1.65 3.99 3.26 0.863-0.152 2.77 0.0659 3.41-0.626 2.24-1.04-0.0635-1.05 3.37-1.34 2.1 0.115 2.2-1.21 2.77-0.679 5.91-0.778 1.96-1.63 4.89-1.49 5.47 0.212 0.204 1.22 3.99-0.265 2.14-0.0482 0.411-0.776 2.93-0.892 2.17-0.148 0.604-0.262 2.54-1.52 0.804 0.0911 1.11 0.562 1.23 1.57 0.468 1.54 0.966 3.31 1.86 4.62 2.67-0.472-0.76-0.582 4.72-0.393 3.14 0.131 3.72-0.565 6.16-0.724 4.54-0.853 1.37-0.939 5.89-0.58 10.1-1.7 2.9-0.523 10.2-1.15 4.86-0.211 4.69-0.969 7.4-1.04 3.46-0.0576 3.13 0.58 3.83 0 3.63 0.257 2.5-0.141 7.74-0.46 2.23 1.09-0.13 0.518 5.9 0.145 1.12-0.0184 2.85-6e-3 3.83-0.186 0.748 0.694 1.01 1.4 1.58 2.33-0.112 0.687-0.306 0.992-0.454 1.51 0.0805 0.459-0.0486 0.901 0.226 1.36 0.057 0.859-1.34 1.08-2.69 0.127-3.53-0.828-1.21-0.849-7.23 0.974-5.16-0.286-1.66-0.354-7.64 0.321-1.48 0.961-4.73 0.287-6.76 0.551-4.01 0.178-1.95-0.517-3.33 0.624-5.29 1.8-3.12 1.47-5.66 0.941-5.26 0.0339-2.08-0.772-4.75 0.424-6.08 2.5-3.35 1.33-7.54 2.02-6.37-0.269-3.02 1.17-6.76 0.468-0.975 0.1-2.43 0.343-3.46 0.786-1.5-0.748-1.92 0.689-3.38 0.363-0.83-0.0851-2.1-0.343-3.5-0.0239-1.28 0.81-3.87-0.666-5.67-2.17-0.131-0.478-0.106-0.902-0.403-1.69-1.63 0.392-0.668 0.395-4.29 1.14-2.71 0.289 0.131 0.495-3.22 0.964-0.638 0.331-0.998 1.17-3.15 1.04-3.09 0.469-4.48 2.1-3.66 0.577-2.95 0.347-2.9 1.82-5.86 1.85-3.3 0.815 0.192 0.978-5.2 1.66-2.81 2.66 0.0387 0.735-4.21 1.29-1.43-0.911-2.24-2.29-3.89-3.63-0.363-0.679 0.258-1.84-0.375-2.28-5.28 1.39 0.176-0.925-5.08 1.01-10.6 1.42-4.55 1.88-9.18 1.66-6.73 1.35-4.11 1.99-10.2 2.31-4.53 1.09-1.63-0.398-5.52 1.02-3.15 0.522-2.41-0.0562-4.51 1.04-0.76 0.379-0.865-0.416-2.75-0.0493-3.5-3.45-2.85-0.892-2.93-6.14-4.41 0.837 0.477 0.703-6.18 1.2-4.59 0.0171-1.93 1.02-7.41 1.04-0.815 0.505-2.55 0.453-4.13 0.791-5 0.71-5.97 2-8.46 1.61-1.39 1.09-2.58 1.53-4.22 2.62-0.919 0.756-3.45 0.596-4.48 0.492-0.525-0.406-0.751-1.2-1.82-3.28 0.149-0.902-0.325-1.44-0.248-2.8z\"></path></symbol>\n\n        <symbol id=\"icon-gleam-chasse-2\" viewBox=\"0 0 108 22\"><path d=\"m0.585 18.5c-0.578-1.54-0.65-1.33-0.543-2.64 0.271-1.19 0.153-1.06 1.27-1.71 0.993 0.124 1.94-0.662 2.94-0.869 2.48 0.119 0.772 0.443 2.99-0.366 1.66-1.91 0.764 0.783 3.36-0.992 2.37 0.314 4.26-1.5 5.16-1.26 0.387 0.627 0.202 0.412 2.52-0.776 4.89-1.57 3.91-1.47 5-0.972 2.05-1.09-0.0615-0.49 2.79-1.2 4.47-0.514 3.62 0.127 4.18-1.19 4.3-0.613 2.56-1.49 4.09-0.847 1.8-1.51 1.01 0.157 2.64-0.722 4.91-1.28 1.39 0.553 4.43-0.843 1.28-0.387 2.72-0.427 4.05-0.748 0.332-0.942 1.93 0.121 2.75-0.817 3 0.294-0.74-0.514 3.35-0.219 2.34-1.12 0.474 0.505 3.01-1.33 0.779-0.552 0.958 0.919 2.76-0.331 1.26-0.027 0.231 0.642 1.71 0.0417 1.08-0.234-0.332-0.25 1.4-0.727 1.07 0.281 0.347 0.858 2.47 1.86 1.02 2.09-0.0407 0.967 0.473 3.88-0.19 1.31 0.095 0.629-1.34 1.44-0.351 0.381-0.494 0.132-0.0505 0.773 5.7-0.865 2.24-0.0704 4.31-0.722 1.39-0.602 3.12 0.189 3.85-0.396 5.52-1.74 1.2 0.802 5.56-0.972 5.77-0.78 5.5-0.0267 5.87-0.622 1.29-0.593 0.466-0.184 2.73-0.0872 0.586-0.907-0.0863-0.919 1.23-0.644 0.471-1.23 3.03 0.227 3.86-0.234 1.2 0.319 2.27 0.00513 2.55 0.264 0.378 0.998 1.18 1.79 1.78 2.57-0.109 0.798 0.472 1.14 0.254 2.4 2.25-0.43 1.69-0.298 4.1-0.338 2.35-1.11 0.595 0.263 3.12-0.813 1.5-0.153 2.17 0.044 3.29-0.328 1.39-0.699 0.859-0.135 1.88-0.671 1.35 0.779 0.389 0.64 1.39 1.7 0.132 1.37 0.34 1.03 0.117 2.21-0.619 0.327-0.757 0.0587-1.28 0.739-2.68 0.688-0.161 0.395-2.5 0.734-1.97-0.203-0.915-0.0737-3.21 0.454-1.76 1.41-0.982 1.12-2.36 1.43-1.65 0.974 0.119-0.784-2.27 0.501-0.883 0.361-1.2 0.471-1.88 0.827-2.84 1.1-1.72-0.0496-3.18 1.37-2.38 0.689-1.82 0.324-2.65 1.27-3.52 0.658-2.07-0.49-3.27-0.419-1.85-2.19 0.14-0.414-1.87-2.62-0.551-2.06-0.527-0.977 0.131-2.63 0.366-1.44 0.369-0.627 1.15-1.88-1.79 0.433-1.64 0.163-5.6 0.781-3.59 1.82-0.592-0.17-4.29 0.729-0.705 0.598-0.369 0.995-1.59-0.0892-0.655 0.638-0.104 0.42-2.9 0.621-3.6 1.1-2.83 1.29-4.17 0.742 0.0193-1.05-1.8 1.24-2.18 0.454-2.51 0.61-1.36 0.795-3.64 0.594-0.211 0.804-4.14-0.139-5.09 0.879-3.61 0.381 0.127-0.296-3.51-1.03-1.44-1.87-1.14-0.196-1.22-3.01 0.14-1.2-0.505-0.638-0.0251-2.39-2.64 0.466-1.25-0.372-3.55 0.344-4.12 0.781-0.26 1.32-4.36 1.02-1.78 0.235 0.327 0.568-3.16 0.555-1.36 0.861-0.709 0.778-2.01 0.649-4.07 1.1-0.948 0.904-4.54 1.17-1.27 0.686-4.67 0.341-4.6 1.04-2.47 0.466-0.707 1.46-3.49 0.582-2.93 1.39-0.739 1.31-4.38 1.56-3.21 1.23-0.735 1.93-3.87 1.14-2.82 1.91-0.676 1.23-4.04 1.82-1.97 1.47 0.312 0.745-2.95 0.812-3.51 1.54 0.0965-0.473-4.27 1.39-2.68 0.382-1.75 0.682-3.32-0.585-1.65-1.61 0.361-0.307-1.37-2.31z\"></path></symbol>\n\n        <symbol id=\"icon-menu\" viewBox=\"0 0 24 24\"><path d=\"M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z\"></path></symbol>\n\n        <symbol id=\"icon-moon\" viewBox=\"0 0 24 24\"><path d=\"M21.996 12.882c0.022-0.233-0.038-0.476-0.188-0.681-0.325-0.446-0.951-0.544-1.397-0.219-0.95 0.693-2.060 1.086-3.188 1.162-1.368 0.092-2.765-0.283-3.95-1.158-1.333-0.985-2.139-2.415-2.367-3.935s0.124-3.124 1.109-4.456c0.142-0.191 0.216-0.435 0.191-0.691-0.053-0.55-0.542-0.952-1.092-0.898-2.258 0.22-4.314 1.18-5.895 2.651-1.736 1.615-2.902 3.847-3.137 6.386-0.254 2.749 0.631 5.343 2.266 7.311s4.022 3.313 6.772 3.567 5.343-0.631 7.311-2.266 3.313-4.022 3.567-6.772zM19.567 14.674c-0.49 1.363-1.335 2.543-2.416 3.441-1.576 1.309-3.648 2.016-5.848 1.813s-4.108-1.278-5.417-2.854-2.016-3.648-1.813-5.848c0.187-2.032 1.117-3.814 2.507-5.106 0.782-0.728 1.71-1.3 2.731-1.672-0.456 1.264-0.577 2.606-0.384 3.899 0.303 2.023 1.38 3.934 3.156 5.247 1.578 1.167 3.448 1.668 5.272 1.545 0.752-0.050 1.496-0.207 2.21-0.465z\"></path></symbol>\n\n        <symbol id=\"icon-more-horizontal\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM21 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM7 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-more-vertical\" viewBox=\"0 0 24 24\"><path d=\"M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z\"></path></symbol>\n\n        <symbol id=\"icon-star\" viewBox=\"0 0 24 24\"><path d=\"M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z\"></path></symbol>\n\n        <symbol id=\"icon-sun\" viewBox=\"0 0 24 24\"><path d=\"M18 12c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243 0.673 3.158 1.757 4.243 2.586 1.757 4.243 1.757 3.158-0.673 4.243-1.757 1.757-2.586 1.757-4.243zM16 12c0 1.105-0.447 2.103-1.172 2.828s-1.723 1.172-2.828 1.172-2.103-0.447-2.828-1.172-1.172-1.723-1.172-2.828 0.447-2.103 1.172-2.828 1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828zM11 1v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM11 21v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.552-0.448-1-1-1s-1 0.448-1 1zM3.513 4.927l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM17.653 19.067l1.42 1.42c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-1.42-1.42c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414zM1 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM21 13h2c0.552 0 1-0.448 1-1s-0.448-1-1-1h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4.927 20.487l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0zM19.067 6.347l1.42-1.42c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.42 1.42c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-left\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM12 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM10 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-toggle-right\" viewBox=\"0 0 24 24\"><path d=\"M8 4c-2.209 0-4.21 0.897-5.657 2.343s-2.343 3.448-2.343 5.657 0.897 4.21 2.343 5.657 3.448 2.343 5.657 2.343h8c2.209 0 4.21-0.897 5.657-2.343s2.343-3.448 2.343-5.657-0.897-4.21-2.343-5.657-3.448-2.343-5.657-2.343zM8 6h8c1.657 0 3.156 0.67 4.243 1.757s1.757 2.586 1.757 4.243-0.67 3.156-1.757 4.243-2.586 1.757-4.243 1.757h-8c-1.657 0-3.156-0.67-4.243-1.757s-1.757-2.586-1.757-4.243 0.67-3.156 1.757-4.243 2.586-1.757 4.243-1.757zM20 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM18 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-x-circle\" viewBox=\"0 0 24 24\"><path d=\"M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM8.293 9.707l2.293 2.293-2.293 2.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l2.293-2.293 2.293 2.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-2.293-2.293 2.293-2.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-2.293 2.293-2.293-2.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z\"></path></symbol>\n\n        <symbol id=\"icon-svg-search\" viewBox=\"0 0 24 24\">\n            <title>Search</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-search\">\n                <circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n            </svg>\n        </symbol>\n\n        <symbol id=\"icon-svg-doc\" viewBox=\"0 0 24 24\">\n            <title>Document</title>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-file\">\n                <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path><polyline points=\"13 2 13 9 20 9\"></polyline>\n            </svg>\n        </symbol>\n      </defs>\n    </svg>\n\n    <script src=\"{{ unnest }}/js/highlight.min.js?v={{ gleam_version }}\"></script>\n    <script src=\"{{ unnest }}/js/highlightjs-gleam.js?v={{ gleam_version }}\"></script>\n    <script src=\"{{ unnest }}/js/highlightjs-erlang.min.js?v={{ gleam_version }}\"></script>\n    <script src=\"{{ unnest }}/js/highlightjs-elixir.min.js?v={{ gleam_version }}\"></script>\n    <script src=\"{{ unnest }}/js/highlightjs-javascript.min.js?v={{ gleam_version }}\"></script>\n    <script src=\"{{ unnest }}/js/highlightjs-typescript.min.js?v={{ gleam_version }}\"></script>\n    <script>\n      document.querySelectorAll(\"pre code\").forEach((elem) => {\n        if (elem.className === \"\") {\n          elem.classList.add(\"gleam\");\n        }\n      });\n      hljs.configure({\n        cssSelector: 'pre code:not(.hljs-ignore)'\n      })\n      hljs.highlightAll();\n    </script>\n\n    <script src=\"{{ unnest }}/js/lunr.min.js?v={{ gleam_version }}\"></script>\n    <script src=\"{{ unnest }}/js/index.js?v={{ rendering_timestamp }}\"></script>\n    <script>\n      fetch(\"{{ unnest }}/search-data.json?v={{ rendering_timestamp }}\")\n        .then(response => response.json())\n        .then(data => window.Gleam.initSearch(data));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "compiler-core/templates/documentation_module.html",
    "content": "{% extends \"documentation_layout.html\" %}\n\n{% block sidebar_content %}\n{% if !types.is_empty() %}\n<h2>Types</h2>\n<ul>\n  {% for typ in types %}\n  <li><a href=\"#{{ typ.name }}\">{{ typ.name }}</a></li>\n  {% endfor %}\n</ul>\n{% endif %}\n\n{% if !values.is_empty() %}\n<h2>Values</h2>\n<ul>\n  {% for value in values %}\n  <li><a href=\"#{{ value.name }}\">{{ value.name }}</a></li>\n  {% endfor %}\n</ul>\n{% endif %}\n{% endblock %}\n\n{% block content %}\n<h1 id=\"module-name\" class=\"module-name\">\n  <a href=\"#module-name\">{{ module_name }}</a>\n  <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n</h1>\n{{ documentation|safe }}\n\n{% if !types.is_empty() %}\n<section class=\"module-members\">\n  <h1 id=\"module-types\" class=\"module-member-kind\">\n    <a href=\"#module-types\">Types</a>\n    <svg class=\"icon icon-gleam-chasse-2\"><use xlink:href=\"#icon-gleam-chasse-2\"></use></svg>\n  </h1>\n\n  {% for typ in types %}\n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"{{ typ.name }}\">\n        <a href=\"#{{ typ.name }}\">\n          {{ typ.name }}\n        </a>\n      </h2>{% if typ.opaque %} <span class=\"visibility-tag\">opaque</span> {% endif %}\n      {% if !typ.source_url.is_empty() %}\n      <a class=\"member-source\" alt=\"View Source\" title=\"View Source\" href=\"{{ typ.source_url|safe }}\">\n        &lt;/&gt;\n      </a>\n      {% endif %}\n    </div>\n    {% if !typ.deprecation_message.is_empty() %}\n    <p>\n      <b>Deprecated:</b> {{ typ.deprecation_message }}\n    </p>\n    {% endif %}\n    <div class=\"custom-type-constructors\">\n      <div class=\"rendered-markdown\">{{ typ.documentation|safe }}</div>\n      <pre><code class=\"hljs hljs-ignore\">{{ typ.definition|safe }}</code></pre>\n      {% if !typ.constructors.is_empty() %}\n      <h3>\n        Constructors\n      </h3>\n      <ul class=\"constructor-list\">\n        {% for constructor in typ.constructors %}\n        <li class=\"constructor-item\">\n          <div class=\"constructor-row\">\n            <svg class=\"icon icon-star\"><use xlink:href=\"#icon-star\"></use></svg>\n            <pre class=\"constructor-name\"><code class=\"hljs hljs-ignore\">{{ constructor.definition|safe }}</code></pre>\n          </div>\n\n          <div class=\"constructor-item-docs\">\n            {{ constructor.documentation|safe }}\n\n            {% if !constructor.arguments.is_empty() %}\n            <h4>\n              Arguments\n            </h4>\n\n            <dl class=\"constructor-argument-list\">\n            {% for argument in constructor.arguments %}\n              <dt class=\"constructor-argument-label\">\n                {{ argument.name }}\n              </dt>\n              <dd class=\"constructor-argument-doc\">\n                {{ argument.doc|safe }}\n              </dd>\n            {% endfor %}\n            </dl>\n            {% endif %}\n          </div>\n        </li>\n        {% endfor %}\n      </ul>\n      {% endif %}\n    </div>\n  </div>\n  {% endfor %}\n</section>\n{% endif %}\n\n{% if !values.is_empty() %}\n<section class=\"module-members\">\n  <h1 id=\"module-values\" class=\"module-member-kind\">\n    <a href=\"#module-values\">Values</a>\n    <svg class=\"icon icon-gleam-chasse\"><use xlink:href=\"#icon-gleam-chasse\"></use></svg>\n  </h1>\n  {% for value in values %}\n  <div class=\"member\">\n    <div class=\"member-name\">\n      <h2 id=\"{{ value.name }}\">\n        <a href=\"#{{ value.name }}\">\n          {{ value.name }}\n        </a>\n      </h2>\n      {% if !value.source_url.is_empty() %}\n      <a class=\"member-source\" alt=\"View Source\" title=\"View Source\" href=\"{{ value.source_url|safe }}\">\n        &lt;/&gt;\n      </a>\n      {% endif %}\n    </div>\n\n    <pre><code class=\"hljs hljs-ignore\">{{ value.definition|safe }}</code></pre>\n    {% if !value.deprecation_message.is_empty() %}\n    <p>\n      <b>Deprecated:</b> {{ value.deprecation_message }}\n    </p>\n    {% endif %}\n    <div class=\"rendered-markdown\">{{ value.documentation|safe }}</div>\n  </div>\n  {% endfor %}\n</section>\n{% endif %}\n{% endblock %}"
  },
  {
    "path": "compiler-core/templates/documentation_page.html",
    "content": "{% extends \"documentation_layout.html\" %}\n\n{% block title %}\n{{ title }} - {{ project_name }}\n{% endblock %}\n\n{% block content %}\n{{ content|safe }}\n{% endblock %}\n"
  },
  {
    "path": "compiler-core/templates/echo.erl",
    "content": "-define(is_lowercase_char(X),\n    (X > 96 andalso X < 123)).\n\n-define(is_underscore_char(X),\n    (X == 95)).\n\n-define(is_digit_char(X),\n    (X > 47 andalso X < 58)).\n\n-define(is_ascii_character(X),\n    (erlang:is_integer(X) andalso X >= 32 andalso X =< 126)).\n\n-define(could_be_record(Tuple),\n    erlang:is_tuple(Tuple) andalso\n        erlang:is_atom(erlang:element(1, Tuple)) andalso\n        erlang:element(1, Tuple) =/= false andalso\n        erlang:element(1, Tuple) =/= true andalso\n        erlang:element(1, Tuple) =/= nil\n).\n-define(is_atom_char(C),\n    (?is_lowercase_char(C) orelse\n        ?is_underscore_char(C) orelse\n        ?is_digit_char(C))\n).\n\n-define(grey, \"\\e[90m\").\n-define(reset_color, \"\\e[39m\").\n\necho(Value, Message, Line) ->\n    StringLine = erlang:integer_to_list(Line),\n    StringValue = echo@inspect(Value),\n    StringMessage =\n        case Message of\n            nil -> \"\";\n            M -> [\" \", M]\n        end,\n\n    io:put_chars(\n      standard_error,\n      [\n        ?grey, ?FILEPATH, $:, StringLine, ?reset_color, StringMessage, $\\n,\n        StringValue, $\\n\n      ]\n    ),\n    Value.\n\necho@inspect(Value) ->\n    case Value of\n        nil -> \"Nil\";\n        true -> \"True\";\n        false -> \"False\";\n        Int when erlang:is_integer(Int) -> erlang:integer_to_list(Int);\n        Float when erlang:is_float(Float) -> io_lib_format:fwrite_g(Float);\n        Binary when erlang:is_binary(Binary) -> inspect@binary(Binary);\n        Bits when erlang:is_bitstring(Bits) -> inspect@bit_array(Bits);\n        Atom when erlang:is_atom(Atom) -> inspect@atom(Atom);\n        List when erlang:is_list(List) -> inspect@list(List);\n        Map when erlang:is_map(Map) -> inspect@map(Map);\n        Record when ?could_be_record(Record) -> inspect@record(Record);\n        Tuple when erlang:is_tuple(Tuple) -> inspect@tuple(Tuple);\n        Function when erlang:is_function(Function) -> inspect@function(Function);\n        Any -> [\"//erl(\", io_lib:format(\"~p\", [Any]), \")\"]\n    end.\n\ninspect@bit_array(Bits) ->\n    Pieces = inspect@bit_array_pieces(Bits, []),\n    Inner = lists:join(\", \", lists:reverse(Pieces)),\n    [\"<<\", Inner, \">>\"].\n\ninspect@bit_array_pieces(Bits, Acc) ->\n    case Bits of\n        <<>> ->\n            Acc;\n        <<Byte, Rest/bitstring>> ->\n            inspect@bit_array_pieces(Rest, [erlang:integer_to_binary(Byte) | Acc]);\n        _ ->\n            Size = erlang:bit_size(Bits),\n            <<RemainingBits:Size>> = Bits,\n            SizeString = [\":size(\", erlang:integer_to_binary(Size), \")\"],\n            Piece = [erlang:integer_to_binary(RemainingBits), SizeString],\n            [Piece | Acc]\n    end.\n\ninspect@binary(Binary) ->\n    case inspect@maybe_utf8_string(Binary, <<>>) of\n        {ok, InspectedUtf8String} ->\n            InspectedUtf8String;\n        {error, not_a_utf8_string} ->\n            Segments = [erlang:integer_to_list(X) || <<X>> <= Binary],\n            [\"<<\", lists:join(\", \", Segments), \">>\"]\n    end.\n\ninspect@atom(Atom) ->\n    Binary = erlang:atom_to_binary(Atom),\n    case inspect@maybe_gleam_atom(Binary, none, <<>>) of\n        {ok, Inspected} -> Inspected;\n        {error, _} -> [\"atom.create(\\\"\", Binary, \"\\\")\"]\n    end.\n\ninspect@list(List) ->\n    case inspect@list_loop(List, true) of\n        {charlist, _} -> [\"charlist.from_string(\\\"\", erlang:list_to_binary(List), \"\\\")\"];\n        {proper, Elements} -> [\"[\", Elements, \"]\"];\n        {improper, Elements} -> [\"//erl([\", Elements, \"])\"]\n    end.\n\ninspect@map(Map) ->\n    Fields = [\n        [<<\"#(\">>, echo@inspect(Key), <<\", \">>, echo@inspect(Value), <<\")\">>]\n        || {Key, Value} <- maps:to_list(Map)\n    ],\n    [\"dict.from_list([\", lists:join(\", \", Fields), \"])\"].\n\ninspect@record(Record) ->\n    [Atom | ArgsList] = Tuple = erlang:tuple_to_list(Record),\n    case inspect@maybe_gleam_atom(Atom, none, <<>>) of\n        {ok, Tag} ->\n            Args = lists:join(\", \", lists:map(fun echo@inspect/1, ArgsList)),\n            [Tag, \"(\", Args, \")\"];\n        _ ->\n            inspect@tuple(Tuple)\n    end.\n\ninspect@tuple(Tuple) when erlang:is_tuple(Tuple) ->\n    inspect@tuple(erlang:tuple_to_list(Tuple));\ninspect@tuple(Tuple) ->\n    Elements = lists:map(fun echo@inspect/1, Tuple),\n    [\"#(\", lists:join(\", \", Elements), \")\"].\n\ninspect@function(Function) ->\n    {arity, Arity} = erlang:fun_info(Function, arity),\n    ArgsAsciiCodes = lists:seq($a, $a + Arity - 1),\n    Args = lists:join(\", \", lists:map(fun(Arg) -> <<Arg>> end, ArgsAsciiCodes)),\n    [\"//fn(\", Args, \") { ... }\"].\n\ninspect@maybe_utf8_string(Binary, Acc) ->\n    case Binary of\n        <<>> ->\n            {ok, <<$\", Acc/binary, $\">>};\n        <<First/utf8, Rest/binary>> ->\n            Escaped = inspect@escape_grapheme(First),\n            inspect@maybe_utf8_string(Rest, <<Acc/binary, Escaped/binary>>);\n        _ ->\n            {error, not_a_utf8_string}\n    end.\n\ninspect@escape_grapheme(Char) ->\n    case Char of\n        $\" -> <<$\\\\, $\">>;\n        $\\\\ -> <<$\\\\, $\\\\>>;\n        $\\r -> <<$\\\\, $r>>;\n        $\\n -> <<$\\\\, $n>>;\n        $\\t -> <<$\\\\, $t>>;\n        $\\f -> <<$\\\\, $f>>;\n        X when X > 126, X < 160 -> inspect@convert_to_u(X);\n        X when X < 32 -> inspect@convert_to_u(X);\n        Other -> <<Other/utf8>>\n    end.\n\ninspect@convert_to_u(Code) ->\n    erlang:list_to_binary(io_lib:format(\"\\\\u{~4.16.0B}\", [Code])).\n\ninspect@list_loop(List, Ascii) ->\n    case List of\n        [] ->\n            {proper, []};\n        [First] when Ascii andalso ?is_ascii_character(First) ->\n            {charlist, nil};\n        [First] ->\n            {proper, [echo@inspect(First)]};\n        [First | Rest] when erlang:is_list(Rest) ->\n            StillAscii = Ascii andalso ?is_ascii_character(First),\n            {Kind, Inspected} = inspect@list_loop(Rest, StillAscii),\n            {Kind, [echo@inspect(First), \", \" | Inspected]};\n        [First | ImproperRest] ->\n            {improper, [echo@inspect(First), \" | \", echo@inspect(ImproperRest)]}\n    end.\n\ninspect@maybe_gleam_atom(Atom, PrevChar, Acc) when erlang:is_atom(Atom) ->\n    Binary = erlang:atom_to_binary(Atom),\n    inspect@maybe_gleam_atom(Binary, PrevChar, Acc);\ninspect@maybe_gleam_atom(Atom, PrevChar, Acc) ->\n    case {Atom, PrevChar} of\n        {<<>>, none} ->\n            {error, nil};\n        {<<First, _/binary>>, none} when ?is_digit_char(First) ->\n            {error, nil};\n        {<<\"_\", _/binary>>, none} ->\n            {error, nil};\n        {<<\"_\">>, _} ->\n            {error, nil};\n        {<<\"_\", _/binary>>, $_} ->\n            {error, nil};\n        {<<First, _/binary>>, _} when not ?is_atom_char(First) ->\n            {error, nil};\n        {<<First, Rest/binary>>, none} ->\n            inspect@maybe_gleam_atom(Rest, First, <<Acc/binary, (inspect@uppercase(First))>>);\n        {<<\"_\", Rest/binary>>, _} ->\n            inspect@maybe_gleam_atom(Rest, $_, Acc);\n        {<<First, Rest/binary>>, $_} ->\n            inspect@maybe_gleam_atom(Rest, First, <<Acc/binary, (inspect@uppercase(First))>>);\n        {<<First, Rest/binary>>, _} ->\n            inspect@maybe_gleam_atom(Rest, First, <<Acc/binary, First>>);\n        {<<>>, _} ->\n            {ok, Acc};\n        _ ->\n            erlang:throw({gleam_error, echo, Atom, PrevChar, Acc})\n    end.\n\ninspect@uppercase(X) -> X - 32.\n"
  },
  {
    "path": "compiler-core/templates/echo.mjs",
    "content": "function echo(value, message, file, line) {\n  const grey = \"\\u001b[90m\";\n  const reset_color = \"\\u001b[39m\";\n  const file_line = `${file}:${line}`;\n  const inspector = new Echo$Inspector();\n  const string_value = inspector.inspect(value);\n  const string_message = message === undefined ? \"\" : \" \" + message;\n\n  if (globalThis.process?.stderr?.write) {\n    // If we're in Node.js, use `stderr`\n    const string = `${grey}${file_line}${reset_color}${string_message}\\n${string_value}\\n`;\n    globalThis.process.stderr.write(string);\n  } else if (globalThis.Deno) {\n    // If we're in Deno, use `stderr`\n    const string = `${grey}${file_line}${reset_color}${string_message}\\n${string_value}\\n`;\n    globalThis.Deno.stderr.writeSync(new TextEncoder().encode(string));\n  } else {\n    // Otherwise, use `console.log`\n    // The browser's console.log doesn't support ansi escape codes\n    const string = `${file_line}${string_message}\\n${string_value}`;\n    globalThis.console.log(string);\n  }\n\n  return value;\n}\n\nclass Echo$Inspector {\n  #references = new globalThis.Set();\n\n  #isDict(value) {\n    try {\n      // We can only check if an object is a stdlib Dict if it is one of the\n      // project's dependencies.\n      // We import the public gleam/dict module, so to check if something is a\n      // dict we compare the `constructor` field on the object with that of a\n      // new dict.\n      const empty_dict = $stdlib$dict.new$();\n      const dict_class = empty_dict.constructor;\n      return value instanceof dict_class;\n    } catch {\n      // If stdlib is not one of the project's dependencies then `$stdlib$dict`\n      // will not have been imported and the check will throw an exception meaning\n      // we can't check if something is actually a `Dict`.\n      return false;\n    }\n  }\n\n  #float(float) {\n    const string = float.toString().replace(\"+\", \"\");\n    if (string.indexOf(\".\") >= 0) {\n      return string;\n    } else {\n      const index = string.indexOf(\"e\");\n      if (index >= 0) {\n        return string.slice(0, index) + \".0\" + string.slice(index);\n      } else {\n        return string + \".0\";\n      }\n    }\n  }\n\n  inspect(v) {\n    const t = typeof v;\n    if (v === true) return \"True\";\n    if (v === false) return \"False\";\n    if (v === null) return \"//js(null)\";\n    if (v === undefined) return \"Nil\";\n    if (t === \"string\") return this.#string(v);\n    if (t === \"bigint\" || globalThis.Number.isInteger(v)) return v.toString();\n    if (t === \"number\") return this.#float(v);\n    if (v instanceof $UtfCodepoint) return this.#utfCodepoint(v);\n    if (v instanceof $BitArray) return this.#bit_array(v);\n    if (v instanceof globalThis.RegExp) return `//js(${v})`;\n    if (v instanceof globalThis.Date) return `//js(Date(\"${v.toISOString()}\"))`;\n    if (v instanceof globalThis.Error) return `//js(${v.toString()})`;\n    if (v instanceof globalThis.Function) {\n      const args = [];\n      for (const i of globalThis.Array(v.length).keys())\n        args.push(globalThis.String.fromCharCode(i + 97));\n      return `//fn(${args.join(\", \")}) { ... }`;\n    }\n\n    if (this.#references.size === this.#references.add(v).size) {\n      return \"//js(circular reference)\";\n    }\n\n    let printed;\n    if (globalThis.Array.isArray(v)) {\n      printed = `#(${v.map((v) => this.inspect(v)).join(\", \")})`;\n    } else if (v instanceof $List) {\n      printed = this.#list(v);\n    } else if (v instanceof $CustomType) {\n      printed = this.#customType(v);\n    } else if (this.#isDict(v)) {\n      printed = this.#dict(v);\n    } else if (v instanceof Set) {\n      return `//js(Set(${[...v].map((v) => this.inspect(v)).join(\", \")}))`;\n    } else {\n      printed = this.#object(v);\n    }\n    this.#references.delete(v);\n    return printed;\n  }\n\n  #object(v) {\n    const name =\n      globalThis.Object.getPrototypeOf(v)?.constructor?.name || \"Object\";\n    const props = [];\n    for (const k of globalThis.Object.keys(v)) {\n      props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`);\n    }\n    const body = props.length ? \" \" + props.join(\", \") + \" \" : \"\";\n    const head = name === \"Object\" ? \"\" : name + \" \";\n    return `//js(${head}{${body}})`;\n  }\n\n  #dict(map) {\n    let body = \"dict.from_list([\";\n    let first = true;\n\n    let key_value_pairs = $stdlib$dict.fold(map, [], (pairs, key, value) => {\n      pairs.push([key, value]);\n      return pairs;\n    });\n\n    key_value_pairs.sort();\n    key_value_pairs.forEach(([key, value]) => {\n      if (!first) body = body + \", \";\n      body = body + \"#(\" + this.inspect(key) + \", \" + this.inspect(value) + \")\";\n      first = false;\n    });\n    return body + \"])\";\n  }\n\n  #customType(record) {\n    const props = globalThis.Object.keys(record)\n      .map((label) => {\n        const value = this.inspect(record[label]);\n        return isNaN(parseInt(label)) ? `${label}: ${value}` : value;\n      })\n      .join(\", \");\n    return props\n      ? `${record.constructor.name}(${props})`\n      : record.constructor.name;\n  }\n\n  #list(list) {\n    if (list instanceof $Empty) {\n      return \"[]\";\n    }\n\n    let char_out = 'charlist.from_string(\"';\n    let list_out = \"[\";\n\n    let current = list;\n    while (current instanceof $NonEmpty) {\n      let element = current.head;\n      current = current.tail;\n\n      if (list_out !== \"[\") {\n        list_out += \", \";\n      }\n      list_out += this.inspect(element);\n\n      if (char_out) {\n        if (\n          globalThis.Number.isInteger(element) &&\n          element >= 32 &&\n          element <= 126\n        ) {\n          char_out += globalThis.String.fromCharCode(element);\n        } else {\n          char_out = null;\n        }\n      }\n    }\n\n    if (char_out) {\n      return char_out + '\")';\n    } else {\n      return list_out + \"]\";\n    }\n  }\n\n  #string(str) {\n    let new_str = '\"';\n    for (let i = 0; i < str.length; i++) {\n      const char = str[i];\n      switch (char) {\n        case \"\\n\":\n          new_str += \"\\\\n\";\n          break;\n        case \"\\r\":\n          new_str += \"\\\\r\";\n          break;\n        case \"\\t\":\n          new_str += \"\\\\t\";\n          break;\n        case \"\\f\":\n          new_str += \"\\\\f\";\n          break;\n        case \"\\\\\":\n          new_str += \"\\\\\\\\\";\n          break;\n        case '\"':\n          new_str += '\\\\\"';\n          break;\n        default:\n          if (char < \" \" || (char > \"~\" && char < \"\\u{00A0}\")) {\n            new_str +=\n              \"\\\\u{\" +\n              char.charCodeAt(0).toString(16).toUpperCase().padStart(4, \"0\") +\n              \"}\";\n          } else {\n            new_str += char;\n          }\n      }\n    }\n    new_str += '\"';\n    return new_str;\n  }\n\n  #utfCodepoint(codepoint) {\n    return `//utfcodepoint(${globalThis.String.fromCodePoint(codepoint.value)})`;\n  }\n\n  #bit_array(bits) {\n    if (bits.bitSize === 0) {\n      return \"<<>>\";\n    }\n\n    let acc = \"<<\";\n\n    for (let i = 0; i < bits.byteSize - 1; i++) {\n      acc += bits.byteAt(i).toString();\n      acc += \", \";\n    }\n\n    if (bits.byteSize * 8 === bits.bitSize) {\n      acc += bits.byteAt(bits.byteSize - 1).toString();\n    } else {\n      const trailingBitsCount = bits.bitSize % 8;\n      acc += bits.byteAt(bits.byteSize - 1) >> (8 - trailingBitsCount);\n      acc += `:size(${trailingBitsCount})`;\n    }\n\n    acc += \">>\";\n    return acc;\n  }\n}\n"
  },
  {
    "path": "compiler-core/templates/ejected.mk",
    "content": "ifndef GLEAM_NO_COMPILE\nGLEAM_INSTALLED := $(shell command -v gleam)\nendif\n\nERLANG_FILES = $(wildcard {src,build}/*.erl)\nGLEAM_FILES = $(wildcard {src,build}/**/*.gleam)\n\n.PHONY: ebin check\n\nifdef GLEAM_INSTALLED\nebin: check $(GLEAM_FILES) $(ERLANG_FILES)\n\tgleam compile-package --target erlang\nelse\nebin: check $(ERLANG_FILES)\n\t@mkdir -p ./ebin\n\t@cp build/*.app ebin/\n\t@erlc -server -o ebin $(ERLANG_FILES) || (rm -rf ebin && false)\nendif\n\ncheck:\nifndef ERL_LIBS\n\t$(error \"ERL_LIBS environment variable not set\")\nendif\n"
  },
  {
    "path": "compiler-core/templates/gleam@@main.erl",
    "content": "-module('{{ application }}@@main').\n-export([run/1]).\n\n-define(red, \"\\e[31;1m\").\n-define(grey, \"\\e[90m\").\n-define(reset_color, \"\\e[39m\").\n-define(reset_all, \"\\e[0m\").\n\nrun(Module) ->\n    io:setopts(standard_io, [binary, {encoding, utf8}]),\n    io:setopts(standard_error, [{encoding, utf8}]),\n    process_flag(trap_exit, true),\n    Pid = spawn_link(fun() -> run_module(Module) end),\n    receive\n        {'EXIT', Pid, {Reason, [First|_] = StackTrace}} when is_tuple(First) ->\n            print_error_with_stacktrace(exit, Reason, StackTrace),\n            init:stop(1);\n        {'EXIT', Pid, Reason} when Reason =/= normal ->\n            print_error(exit, Reason),\n            init:stop(1)\n    end.\n\nrun_module(Module) ->\n    try\n        {ok, _} = application:ensure_all_started('{{ application }}'),\n        erlang:process_flag(trap_exit, false),\n        Module:main(),\n        init:stop(0)\n    catch\n        Class:Reason:StackTrace ->\n            print_error_with_stacktrace(Class, Reason, StackTrace),\n            init:stop(1)\n    end.\n\nprint_error_with_stacktrace(Class, Error, Stacktrace) ->\n    Printed = [\n        ?red, \"runtime error\", ?reset_color, \": \", error_class(Class, Error), ?reset_all,\n        \"\\n\\n\",\n        error_message(Error),\n        \"\\n\\n\",\n        error_details(Class, Error),\n        \"stacktrace:\\n\",\n        [error_frame(Line) || Line <- refine_first(Error, Stacktrace)]\n    ],\n    io:format(standard_error, \"~ts~n\", [Printed]).\n\nprint_error(Class, Error) ->\n    Printed = [\n        ?red, \"runtime error\", ?reset_color, \": \", error_class(Class, Error), ?reset_all,\n        \"\\n\\n\",\n        error_message(Error),\n        \"\\n\\n\",\n        \"exit reason:\\n  \", print_term(Error), $\\n\n    ],\n    io:format(standard_error, \"~ts~n\", [Printed]).\n\nrefine_first(#{gleam_error := _, line := L}, [{M, F, A, [{file, Fi} | _]} | S]) ->\n    [{M, F, A, [{file, Fi}, {line, L}]} | S];\nrefine_first(_, S) ->\n    S.\n\nerror_class(_, #{gleam_error := panic}) -> \"panic\";\nerror_class(_, #{gleam_error := todo}) -> \"todo\";\nerror_class(_, #{gleam_error := let_assert}) -> \"let assert\";\nerror_class(_, #{gleam_error := assert}) -> \"assert\";\nerror_class(Class, _) -> [\"Erlang \", atom_to_binary(Class)].\n\nerror_message(#{gleam_error := _, message := M}) ->\n    M;\nerror_message(undef) ->\n    <<\"A function was called but it did not exist.\"/utf8 >>;\nerror_message({case_clause, _}) ->\n    <<\"No pattern matched in an Erlang case expression.\"/utf8>>;\nerror_message({badmatch, _}) ->\n    <<\"An Erlang assignment pattern did not match.\"/utf8>>;\nerror_message(function_clause) ->\n    <<\"No Erlang function clause matched the arguments it was called with.\"/utf8>>;\nerror_message(_) ->\n    <<\"An error occurred outside of Gleam.\"/utf8>>.\n\nerror_details(_, #{gleam_error := let_assert, value := V}) ->\n    [\"unmatched value:\\n  \", print_term(V), $\\n, $\\n];\nerror_details(_, {case_clause, V}) ->\n    [\"unmatched value:\\n  \", print_term(V), $\\n, $\\n];\nerror_details(_, {badmatch, V}) ->\n    [\"unmatched value:\\n  \", print_term(V), $\\n, $\\n];\nerror_details(_, #{gleam_error := _}) ->\n    [];\nerror_details(error, function_clause) ->\n    [];\nerror_details(error, undef) ->\n    [];\nerror_details(C, E) ->\n    [\"erlang:\", atom_to_binary(C), $(, print_term(E), $), $\\n, $\\n].\n\nprint_term(T) ->\n    try\n        gleam@string:inspect(T)\n    catch\n        _:_ -> io_lib:format(\"~p\", [T])\n    end.\n\nerror_frame({?MODULE, _, _, _}) -> [];\nerror_frame({erl_eval, _, _, _}) -> [];\nerror_frame({init, _, _, _}) -> [];\nerror_frame({M, F, _, O}) ->\n    M1 = string:replace(atom_to_binary(M), \"@\", \"/\", all),\n    [\"  \", M1, $., atom_to_binary(F), error_frame_end(O), $\\n].\n\nerror_frame_end([{file, Fi}, {line, L} | _]) ->\n    [?grey, $\\s, Fi, $:, integer_to_binary(L), ?reset_all];\nerror_frame_end(_) ->\n    [?grey, \" unknown source\", ?reset_all].\n"
  },
  {
    "path": "compiler-core/templates/prelude.d.mts",
    "content": "/** @deprecated */\nexport class CustomType {\n  /** @deprecated */\n  withFields<K extends keyof this>(fields: { [P in K]: this[P] }): this;\n}\n\nexport interface List<T> {\n  readonly __gleam: unique symbol;\n\n  /** @deprecated */\n  head?: T;\n  /** @deprecated */\n  tail?: List<T>;\n  /** @deprecated */\n  toArray(): Array<T>;\n  /** @deprecated */\n  atLeastLength(desired: number): boolean;\n  /** @deprecated */\n  hasLength(desired: number): boolean;\n  /** @deprecated */\n  countLength(): number;\n  /** @deprecated */\n  [Symbol.iterator](): Iterator<T>;\n}\n/** @deprecated */\nexport const List: {\n  /** @deprecated */\n  new <T>(): List<T>;\n  /** @deprecated */\n  fromArray<T>(array: Array<T>): List<T>;\n}\nexport function List$Empty<T>(): List<T>;\nexport function List$NonEmpty<T>(head: T, tail: List<T>): List<T>;\nexport function List$isEmpty(list: any): list is List<unknown>;\nexport function List$isNonEmpty(list: any): list is List<unknown>;\nexport function List$NonEmpty$first<T>(list: List<T>): T | undefined;\nexport function List$NonEmpty$rest<T>(list: List<T>): List<T> | undefined;\n/** @deprecated */\nexport class Empty<T = never> extends List<T> { }\n/** @deprecated */\nexport class NonEmpty<T> extends List<T> { }\n\nexport interface BitArray {\n  readonly __gleam: unique symbol;\n\n  /** @deprecated */\n  bitSize: number;\n  /** @deprecated */\n  byteSize: number;\n  /** @deprecated */\n  bitOffset: number;\n  /** @deprecated */\n  rawBuffer: Uint8Array;\n  /** @deprecated */\n  constructor(buffer: Uint8Array, bitSize?: number, bitOffset?: number): BitArray;\n  /** @deprecated */\n  byteAt(index: number): number;\n  /** @deprecated */\n  equals(other: BitArray): boolean;\n  /** @deprecated */\n  get buffer(): Uint8Array;\n  /** @deprecated */\n  get length(): number;\n}\n/** @deprecated */\nexport const BitArray: {\n  /** @deprecated */\n  new(buffer: Uint8Array, bitSize?: number, bitOffset?: number): BitArray;\n}\nexport function BitArray$BitArray(\n  buffer: Uint8Array,\n  bitSize?: number,\n  bitOffset?: number,\n): BitArray;\nexport function BitArray$isBitArray(value: any): value is BitArray;\nexport function BitArray$BitArray$data(value: BitArray): DataView;\n\nexport interface UtfCodepoint {\n  readonly __gleam: unique symbol;\n  /** @deprecated */\n  value: string;\n}\n/** @deprecated */\nexport const UtfCodepoint: {\n  /** @deprecated */\n  new(value: string): UtfCodepoint\n}\n\nexport interface Result<T, E> {\n  readonly __gleam: unique symbol;\n  /** @deprecated */\n  isOk(): boolean;\n}\n/** @deprecated */\nexport const Result: {\n  new <T, E>(): Result<T, E>\n}\nexport function Result$Ok<T, E>(value: T): Result<T, E>;\nexport function Result$Error<T, E>(error: E): Result<T, E>;\nexport function Result$isError(data: any): data is Result<unknown, unknown>;\nexport function Result$isOk(data: any): data is Result<unknown, unknown>;\nexport function Result$Ok$0<T, E>(result: Result<T, E>): T | undefined;\nexport function Result$Error$0<T, E>(result: Result<T, E>): E | undefined;\n/** @deprecated */\nexport class Ok<T, E> extends Result<T, E> {\n  /** @deprecated */\n  0: T;\n  /** @deprecated */\n  constructor(value: T);\n  /** @deprecated */\n  withFields<K extends keyof this>(fields: { [P in K]: this[P] }): this;\n  /** @deprecated */\n  static isResult(data: unknown): boolean;\n}\n/** @deprecated */\nexport class Error<T, E> extends Result<T, E> {\n  /** @deprecated */\n  0: E;\n  /** @deprecated */\n  constructor(value: E);\n  /** @deprecated */\n  withFields<K extends keyof this>(fields: { [P in K]: this[P] }): this;\n  /** @deprecated */\n  static isResult(data: unknown): boolean;\n}\n\n/** @deprecated */\nexport function prepend<T>(element: T, tail: List<T>): List<T>;\n/** @deprecated */\nexport function toList<T>(array: Array<T>): List<T>;\n\n/** @deprecated */\nexport function toBitArray(segments: Array<BitArray | Uint8Array | number>): BitArray;\n\n/** @deprecated */\nexport function sizedInt(\n  /** @deprecated */\n  value: number,\n  /** @deprecated */\n  size: number,\n  /** @deprecated */\n  isBigEndian: boolean\n): Uint8Array | BitArray;\n\n/** @deprecated */\nexport function stringBits(string: string): Uint8Array;\n\n/** @deprecated */\nexport function codepointBits(codepoint: UtfCodepoint): Uint8Array;\n\n/** @deprecated */\nexport function sizedFloat(\n  value: number,\n  size: number,\n  isBigEndian: boolean\n): Uint8Array;\n\n/** @deprecated */\nexport function isEqual(a: any, b: any): boolean;\n\n/** @deprecated */\nexport function remainderInt(a: number, b: number): number;\n\n/** @deprecated */\nexport function divideInt(a: number, b: number): number;\n\n/** @deprecated */\nexport function divideFloat(a: number, b: number): number;\n"
  },
  {
    "path": "compiler-core/templates/prelude.mjs",
    "content": "export class CustomType {\n  withFields(fields) {\n    let properties = Object.keys(this).map((label) =>\n      label in fields ? fields[label] : this[label],\n    );\n    return new this.constructor(...properties);\n  }\n}\n\nexport class List {\n  static fromArray(array, tail) {\n    let t = tail || new Empty();\n    for (let i = array.length - 1; i >= 0; --i) {\n      t = new NonEmpty(array[i], t);\n    }\n    return t;\n  }\n\n  [Symbol.iterator]() {\n    return new ListIterator(this);\n  }\n\n  toArray() {\n    return [...this];\n  }\n\n  atLeastLength(desired) {\n    let current = this;\n    while (desired-- > 0 && current) current = current.tail;\n    return current !== undefined;\n  }\n\n  hasLength(desired) {\n    let current = this;\n    while (desired-- > 0 && current) current = current.tail;\n    return desired === -1 && current instanceof Empty;\n  }\n\n  countLength() {\n    let current = this;\n    let length = 0;\n    while (current) {\n      current = current.tail;\n      length++;\n    }\n    return length - 1;\n  }\n}\n\nexport function prepend(element, tail) {\n  return new NonEmpty(element, tail);\n}\n\nexport function toList(elements, tail) {\n  return List.fromArray(elements, tail);\n}\n\nclass ListIterator {\n  #current;\n\n  constructor(current) {\n    this.#current = current;\n  }\n\n  next() {\n    if (this.#current instanceof Empty) {\n      return { done: true };\n    } else {\n      let { head, tail } = this.#current;\n      this.#current = tail;\n      return { value: head, done: false };\n    }\n  }\n}\n\nexport class Empty extends List {}\nexport const List$Empty = () => new Empty();\nexport const List$isEmpty = (value) => value instanceof Empty;\n\nexport class NonEmpty extends List {\n  constructor(head, tail) {\n    super();\n    this.head = head;\n    this.tail = tail;\n  }\n}\nexport const List$NonEmpty = (head, tail) => new NonEmpty(head, tail);\nexport const List$isNonEmpty = (value) => value instanceof NonEmpty;\n\nexport const List$NonEmpty$first = (value) => value.head;\nexport const List$NonEmpty$rest = (value) => value.tail;\n\n/**\n * A bit array is a contiguous sequence of bits similar to Erlang's Binary type.\n */\nexport class BitArray {\n  /**\n   * The size in bits of this bit array's data.\n   *\n   * @type {number}\n   */\n  bitSize;\n\n  /**\n   * The size in bytes of this bit array's data. If this bit array doesn't store\n   * a whole number of bytes then this value is rounded up.\n   *\n   * @type {number}\n   */\n  byteSize;\n\n  /**\n   * The number of unused high bits in the first byte of this bit array's\n   * buffer prior to the start of its data. The value of any unused high bits is\n   * undefined.\n   *\n   * The bit offset will be in the range 0-7.\n   *\n   * @type {number}\n   */\n  bitOffset;\n\n  /**\n   * The raw bytes that hold this bit array's data.\n   *\n   * If `bitOffset` is not zero then there are unused high bits in the first\n   * byte of this buffer.\n   *\n   * If `bitOffset + bitSize` is not a multiple of 8 then there are unused low\n   * bits in the last byte of this buffer.\n   *\n   * @type {Uint8Array}\n   */\n  rawBuffer;\n\n  /**\n   * Constructs a new bit array from a `Uint8Array`, an optional size in\n   * bits, and an optional bit offset.\n   *\n   * If no bit size is specified it is taken as `buffer.length * 8`, i.e. all\n   * bytes in the buffer make up the new bit array's data.\n   *\n   * If no bit offset is specified it defaults to zero, i.e. there are no unused\n   * high bits in the first byte of the buffer.\n   *\n   * @param {Uint8Array} buffer\n   * @param {number} [bitSize]\n   * @param {number} [bitOffset]\n   */\n  constructor(buffer, bitSize, bitOffset) {\n    if (!(buffer instanceof Uint8Array)) {\n      throw globalThis.Error(\n        \"BitArray can only be constructed from a Uint8Array\",\n      );\n    }\n\n    this.bitSize = bitSize ?? buffer.length * 8;\n    this.byteSize = Math.trunc((this.bitSize + 7) / 8);\n    this.bitOffset = bitOffset ?? 0;\n\n    // Validate the bit size\n    if (this.bitSize < 0) {\n      throw globalThis.Error(`BitArray bit size is invalid: ${this.bitSize}`);\n    }\n\n    // Validate the bit offset\n    if (this.bitOffset < 0 || this.bitOffset > 7) {\n      throw globalThis.Error(\n        `BitArray bit offset is invalid: ${this.bitOffset}`,\n      );\n    }\n\n    // Validate the length of the buffer\n    if (buffer.length !== Math.trunc((this.bitOffset + this.bitSize + 7) / 8)) {\n      throw globalThis.Error(\"BitArray buffer length is invalid\");\n    }\n\n    this.rawBuffer = buffer;\n  }\n\n  /**\n   * Returns a specific byte in this bit array. If the byte index is out of\n   * range then `undefined` is returned.\n   *\n   * When returning the final byte of a bit array with a bit size that's not a\n   * multiple of 8, the content of the unused low bits are undefined.\n   *\n   * @param {number} index\n   * @returns {number | undefined}\n   */\n  byteAt(index) {\n    if (index < 0 || index >= this.byteSize) {\n      return undefined;\n    }\n\n    return bitArrayByteAt(this.rawBuffer, this.bitOffset, index);\n  }\n\n  equals(other) {\n    if (this.bitSize !== other.bitSize) {\n      return false;\n    }\n\n    const wholeByteCount = Math.trunc(this.bitSize / 8);\n\n    // If both bit offsets are zero do a byte-aligned equality check which is\n    // faster\n    if (this.bitOffset === 0 && other.bitOffset === 0) {\n      // Compare any whole bytes\n      for (let i = 0; i < wholeByteCount; i++) {\n        if (this.rawBuffer[i] !== other.rawBuffer[i]) {\n          return false;\n        }\n      }\n\n      // Compare any trailing bits, excluding unused low bits\n      const trailingBitsCount = this.bitSize % 8;\n      if (trailingBitsCount) {\n        const unusedLowBitCount = 8 - trailingBitsCount;\n        if (\n          this.rawBuffer[wholeByteCount] >> unusedLowBitCount !==\n          other.rawBuffer[wholeByteCount] >> unusedLowBitCount\n        ) {\n          return false;\n        }\n      }\n    } else {\n      // Compare any whole bytes\n      for (let i = 0; i < wholeByteCount; i++) {\n        const a = bitArrayByteAt(this.rawBuffer, this.bitOffset, i);\n        const b = bitArrayByteAt(other.rawBuffer, other.bitOffset, i);\n\n        if (a !== b) {\n          return false;\n        }\n      }\n\n      // Compare any trailing bits\n      const trailingBitsCount = this.bitSize % 8;\n      if (trailingBitsCount) {\n        const a = bitArrayByteAt(\n          this.rawBuffer,\n          this.bitOffset,\n          wholeByteCount,\n        );\n        const b = bitArrayByteAt(\n          other.rawBuffer,\n          other.bitOffset,\n          wholeByteCount,\n        );\n\n        const unusedLowBitCount = 8 - trailingBitsCount;\n        if (a >> unusedLowBitCount !== b >> unusedLowBitCount) {\n          return false;\n        }\n      }\n    }\n\n    return true;\n  }\n\n  /**\n   * Returns this bit array's internal buffer.\n   *\n   * @deprecated\n   *\n   * @returns {Uint8Array}\n   */\n  get buffer() {\n    if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) {\n      throw new globalThis.Error(\n        \"BitArray.buffer does not support unaligned bit arrays\",\n      );\n    }\n\n    return this.rawBuffer;\n  }\n\n  /**\n   * Returns the length in bytes of this bit array's internal buffer.\n   *\n   * @deprecated\n   *\n   * @returns {number}\n   */\n  get length() {\n    if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) {\n      throw new globalThis.Error(\n        \"BitArray.length does not support unaligned bit arrays\",\n      );\n    }\n\n    return this.rawBuffer.length;\n  }\n}\n\nexport const BitArray$BitArray = (buffer, bitSize, bitOffset) =>\n  new BitArray(buffer, bitSize, bitOffset);\nexport const BitArray$isBitArray = (value) => value instanceof BitArray;\nexport const BitArray$BitArray$data = (bitArray) => {\n  if (bitArray.bitSize % 8 !== 0)\n    throw new Error(\"BitArray$BitArray$data called on un-aligned bit array\");\n  const array = bitArray.rawBuffer;\n  return new DataView(array.buffer, array.byteOffset, bitArray.byteSize);\n};\n\n/**\n * Returns the nth byte in the given buffer, after applying the specified bit\n * offset. If the index is out of bounds then zero is returned.\n *\n * @param {Uint8Array} buffer\n * @param {number} bitOffset\n * @param {number} index\n * @returns {number}\n */\nfunction bitArrayByteAt(buffer, bitOffset, index) {\n  if (bitOffset === 0) {\n    return buffer[index] ?? 0;\n  } else {\n    const a = (buffer[index] << bitOffset) & 0xff;\n    const b = buffer[index + 1] >> (8 - bitOffset);\n\n    return a | b;\n  }\n}\n\nexport class UtfCodepoint {\n  constructor(value) {\n    this.value = value;\n  }\n}\n\n/**\n * Slices a bit array to produce a new bit array. If `end` is not supplied then\n * all bits from `start` onward are returned.\n *\n * If the slice is out of bounds then an exception is thrown.\n *\n * @param {BitArray} bitArray\n * @param {number} start\n * @param {number} [end]\n * @returns {BitArray}\n */\nexport function bitArraySlice(bitArray, start, end) {\n  end ??= bitArray.bitSize;\n\n  bitArrayValidateRange(bitArray, start, end);\n\n  // Handle zero-length slices\n  if (start === end) {\n    return new BitArray(new Uint8Array());\n  }\n\n  // Early return for slices that cover the whole bit array\n  if (start === 0 && end === bitArray.bitSize) {\n    return bitArray;\n  }\n\n  start += bitArray.bitOffset;\n  end += bitArray.bitOffset;\n\n  const startByteIndex = Math.trunc(start / 8);\n  const endByteIndex = Math.trunc((end + 7) / 8);\n  const byteLength = endByteIndex - startByteIndex;\n\n  // Avoid creating a new Uint8Array if the view of the underlying ArrayBuffer\n  // is the same. This can occur when slicing off just the first or last bit of\n  // a bit array, i.e. when only the bit offset or bit size need to be updated.\n  let buffer;\n  if (startByteIndex === 0 && byteLength === bitArray.rawBuffer.byteLength) {\n    buffer = bitArray.rawBuffer;\n  } else {\n    buffer = new Uint8Array(\n      bitArray.rawBuffer.buffer,\n      bitArray.rawBuffer.byteOffset + startByteIndex,\n      byteLength,\n    );\n  }\n\n  return new BitArray(buffer, end - start, start % 8);\n}\n\n/**\n * Interprets a slice of this bit array as a floating point number, either\n * 32-bit or 64-bit, with the specified endianness.\n *\n * The value of `end - start` must be exactly 32 or 64, otherwise an exception\n * will be thrown.\n *\n * @param {BitArray} bitArray\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @returns {number}\n */\nexport function bitArraySliceToFloat(bitArray, start, end, isBigEndian) {\n  bitArrayValidateRange(bitArray, start, end);\n\n  const floatSize = end - start;\n\n  // Check size is valid\n  if (floatSize !== 16 && floatSize !== 32 && floatSize !== 64) {\n    const msg =\n      `Sized floats must be 16-bit, 32-bit or 64-bit, got size of ` +\n      `${floatSize} bits`;\n    throw new globalThis.Error(msg);\n  }\n\n  start += bitArray.bitOffset;\n\n  const isStartByteAligned = start % 8 === 0;\n\n  // If the bit range is byte aligned then the float can be read directly out\n  // of the existing buffer\n  if (isStartByteAligned) {\n    const view = new DataView(\n      bitArray.rawBuffer.buffer,\n      bitArray.rawBuffer.byteOffset + start / 8,\n    );\n\n    if (floatSize === 64) {\n      return view.getFloat64(0, !isBigEndian);\n    } else if (floatSize === 32) {\n      return view.getFloat32(0, !isBigEndian);\n    } else if (floatSize === 16) {\n      return fp16UintToNumber(view.getUint16(0, !isBigEndian));\n    }\n  }\n\n  // Copy the unaligned bytes into an aligned array so a DataView can be used\n  const alignedBytes = new Uint8Array(floatSize / 8);\n  const byteOffset = Math.trunc(start / 8);\n  for (let i = 0; i < alignedBytes.length; i++) {\n    alignedBytes[i] = bitArrayByteAt(\n      bitArray.rawBuffer,\n      start % 8,\n      byteOffset + i,\n    );\n  }\n\n  // Read the float out of the aligned buffer\n  const view = new DataView(alignedBytes.buffer);\n  if (floatSize === 64) {\n    return view.getFloat64(0, !isBigEndian);\n  } else if (floatSize === 32) {\n    return view.getFloat32(0, !isBigEndian);\n  } else {\n    return fp16UintToNumber(view.getUint16(0, !isBigEndian));\n  }\n}\n\n/**\n * Interprets a slice of this bit array as a signed or unsigned integer with the\n * specified endianness.\n *\n * @param {BitArray} bitArray\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @param {boolean} isSigned\n * @returns {number}\n */\nexport function bitArraySliceToInt(\n  bitArray,\n  start,\n  end,\n  isBigEndian,\n  isSigned,\n) {\n  bitArrayValidateRange(bitArray, start, end);\n\n  if (start === end) {\n    return 0;\n  }\n\n  start += bitArray.bitOffset;\n  end += bitArray.bitOffset;\n\n  const isStartByteAligned = start % 8 === 0;\n  const isEndByteAligned = end % 8 === 0;\n\n  // If the slice is byte-aligned then there is no need to handle unaligned\n  // slices, meaning a simpler and faster implementation can be used instead\n  if (isStartByteAligned && isEndByteAligned) {\n    return intFromAlignedSlice(\n      bitArray,\n      start / 8,\n      end / 8,\n      isBigEndian,\n      isSigned,\n    );\n  }\n\n  const size = end - start;\n\n  const startByteIndex = Math.trunc(start / 8);\n  const endByteIndex = Math.trunc((end - 1) / 8);\n\n  // Handle the case of the slice being completely contained in a single byte\n  if (startByteIndex == endByteIndex) {\n    const mask = 0xff >> (start % 8);\n    const unusedLowBitCount = (8 - (end % 8)) % 8;\n\n    let value =\n      (bitArray.rawBuffer[startByteIndex] & mask) >> unusedLowBitCount;\n\n    // For signed integers, if the high bit is set reinterpret as two's\n    // complement\n    if (isSigned) {\n      const highBit = 2 ** (size - 1);\n      if (value >= highBit) {\n        value -= highBit * 2;\n      }\n    }\n\n    return value;\n  }\n\n  // The integer value to be read is not aligned and crosses at least one byte\n  // boundary in the input array\n\n  if (size <= 53) {\n    return intFromUnalignedSliceUsingNumber(\n      bitArray.rawBuffer,\n      start,\n      end,\n      isBigEndian,\n      isSigned,\n    );\n  } else {\n    return intFromUnalignedSliceUsingBigInt(\n      bitArray.rawBuffer,\n      start,\n      end,\n      isBigEndian,\n      isSigned,\n    );\n  }\n}\n\n/**\n * Joins the given segments into a new bit array, tightly packing them together.\n * Each segment must be one of the following types:\n *\n * - A `number`: A single byte value in the range 0-255. Values outside this\n *   range will be wrapped.\n * - A `Uint8Array`: A sequence of byte values of any length.\n * - A `BitArray`: A sequence of bits of any length, which may not be byte\n *   aligned.\n *\n * The bit size of the returned bit array will be the sum of the size in bits\n * of the input segments.\n *\n * @param {(number | Uint8Array | BitArray)[]} segments\n * @returns {BitArray}\n */\nexport function toBitArray(segments) {\n  if (segments.length === 0) {\n    return new BitArray(new Uint8Array());\n  }\n\n  if (segments.length === 1) {\n    const segment = segments[0];\n\n    // When there is a single BitArray segment it can be returned as-is\n    if (segment instanceof BitArray) {\n      return segment;\n    }\n\n    // When there is a single Uint8Array segment, pass it directly to the bit\n    // array constructor to avoid a copy\n    if (segment instanceof Uint8Array) {\n      return new BitArray(segment);\n    }\n\n    return new BitArray(new Uint8Array(/** @type {number[]} */ (segments)));\n  }\n\n  // Count the total number of bits and check if all segments are numbers, i.e.\n  // single bytes\n  let bitSize = 0;\n  let areAllSegmentsNumbers = true;\n  for (const segment of segments) {\n    if (segment instanceof BitArray) {\n      bitSize += segment.bitSize;\n      areAllSegmentsNumbers = false;\n    } else if (segment instanceof Uint8Array) {\n      bitSize += segment.byteLength * 8;\n      areAllSegmentsNumbers = false;\n    } else {\n      bitSize += 8;\n    }\n  }\n\n  // If all segments are numbers then pass the segments array directly to the\n  // Uint8Array constructor\n  if (areAllSegmentsNumbers) {\n    return new BitArray(new Uint8Array(/** @type {number[]} */ (segments)));\n  }\n\n  // Pack the segments into a Uint8Array\n  const buffer = new Uint8Array(Math.trunc((bitSize + 7) / 8));\n\n  // The current write position in bits into the above array. Byte-aligned\n  // segments, i.e. when the cursor is a multiple of 8, are able to be processed\n  // faster due to being able to copy bytes directly.\n  let cursor = 0;\n\n  for (let segment of segments) {\n    const isCursorByteAligned = cursor % 8 === 0;\n\n    if (segment instanceof BitArray) {\n      if (isCursorByteAligned && segment.bitOffset === 0) {\n        buffer.set(segment.rawBuffer, cursor / 8);\n        cursor += segment.bitSize;\n\n        // Zero any unused bits in the last byte of the buffer. Their content is\n        // undefined and shouldn't be included in the output.\n        const trailingBitsCount = segment.bitSize % 8;\n        if (trailingBitsCount !== 0) {\n          const lastByteIndex = Math.trunc(cursor / 8);\n          buffer[lastByteIndex] >>= 8 - trailingBitsCount;\n          buffer[lastByteIndex] <<= 8 - trailingBitsCount;\n        }\n      } else {\n        appendUnalignedBits(\n          segment.rawBuffer,\n          segment.bitSize,\n          segment.bitOffset,\n        );\n      }\n    } else if (segment instanceof Uint8Array) {\n      if (isCursorByteAligned) {\n        buffer.set(segment, cursor / 8);\n        cursor += segment.byteLength * 8;\n      } else {\n        appendUnalignedBits(segment, segment.byteLength * 8, 0);\n      }\n    } else {\n      if (isCursorByteAligned) {\n        buffer[cursor / 8] = segment;\n        cursor += 8;\n      } else {\n        appendUnalignedBits(new Uint8Array([segment]), 8, 0);\n      }\n    }\n  }\n\n  function appendUnalignedBits(unalignedBits, size, offset) {\n    if (size === 0) {\n      return;\n    }\n\n    const byteSize = Math.trunc(size + 7 / 8);\n\n    const highBitsCount = cursor % 8;\n    const lowBitsCount = 8 - highBitsCount;\n\n    let byteIndex = Math.trunc(cursor / 8);\n\n    for (let i = 0; i < byteSize; i++) {\n      let byte = bitArrayByteAt(unalignedBits, offset, i);\n\n      // If this is a partial byte then zero out the trailing bits as their\n      // content is undefined and shouldn't be included in the output\n      if (size < 8) {\n        byte >>= 8 - size;\n        byte <<= 8 - size;\n      }\n\n      // Copy the high bits of the input byte to the low bits of the current\n      // output byte\n      buffer[byteIndex] |= byte >> highBitsCount;\n\n      let appendedBitsCount = size - Math.max(0, size - lowBitsCount);\n      size -= appendedBitsCount;\n      cursor += appendedBitsCount;\n\n      if (size === 0) {\n        break;\n      }\n\n      // Copy the low bits of the input byte to the high bits of the next output\n      // byte\n      buffer[++byteIndex] = byte << lowBitsCount;\n      appendedBitsCount = size - Math.max(0, size - highBitsCount);\n      size -= appendedBitsCount;\n      cursor += appendedBitsCount;\n    }\n  }\n\n  return new BitArray(buffer, bitSize);\n}\n\n/**\n * Encodes a floating point value into a `Uint8Array`. This is used to create\n * float segments that are part of bit array expressions.\n *\n * @param {number} value\n * @param {number} size\n * @param {boolean} isBigEndian\n * @returns {Uint8Array}\n */\nexport function sizedFloat(value, size, isBigEndian) {\n  if (size !== 16 && size !== 32 && size !== 64) {\n    const msg = `Sized floats must be 16-bit, 32-bit or 64-bit, got size of ${size} bits`;\n    throw new globalThis.Error(msg);\n  }\n\n  if (size === 16) {\n    return numberToFp16Uint(value, isBigEndian);\n  }\n\n  const buffer = new Uint8Array(size / 8);\n\n  const view = new DataView(buffer.buffer);\n\n  if (size == 64) {\n    view.setFloat64(0, value, !isBigEndian);\n  } else {\n    view.setFloat32(0, value, !isBigEndian);\n  }\n\n  return buffer;\n}\n\n/**\n * Encodes an integer value into a `Uint8Array`, or a `BitArray` if the size in\n * bits is not a multiple of 8. This is used to create integer segments used in\n * bit array expressions.\n *\n * @param {number} value\n * @param {number} size\n * @param {boolean} isBigEndian\n * @returns {Uint8Array | BitArray}\n */\nexport function sizedInt(value, size, isBigEndian) {\n  if (size <= 0) {\n    return new Uint8Array();\n  }\n\n  // Fast path when size is 8 bits. This relies on the rounding behavior of the\n  // Uint8Array constructor.\n  if (size === 8) {\n    return new Uint8Array([value]);\n  }\n\n  // Fast path when size is less than 8 bits: shift the value up to the high\n  // bits\n  if (size < 8) {\n    value <<= 8 - size;\n    return new BitArray(new Uint8Array([value]), size);\n  }\n\n  // Allocate output buffer\n  const buffer = new Uint8Array(Math.trunc((size + 7) / 8));\n\n  // The number of trailing bits in the final byte. Will be zero if the size is\n  // an exact number of bytes.\n  const trailingBitsCount = size % 8;\n\n  // The number of unused bits in the final byte of the buffer\n  const unusedBitsCount = 8 - trailingBitsCount;\n\n  // For output sizes not exceeding 32 bits the number type is used. For larger\n  // output sizes the BigInt type is needed.\n  //\n  // The code in each of these two paths must be kept in sync.\n  if (size <= 32) {\n    if (isBigEndian) {\n      let i = buffer.length - 1;\n\n      // Set the trailing bits at the end of the output buffer\n      if (trailingBitsCount) {\n        buffer[i--] = (value << unusedBitsCount) & 0xff;\n        value >>= trailingBitsCount;\n      }\n\n      for (; i >= 0; i--) {\n        buffer[i] = value;\n        value >>= 8;\n      }\n    } else {\n      let i = 0;\n\n      const wholeByteCount = Math.trunc(size / 8);\n      for (; i < wholeByteCount; i++) {\n        buffer[i] = value;\n        value >>= 8;\n      }\n\n      // Set the trailing bits at the end of the output buffer\n      if (trailingBitsCount) {\n        buffer[i] = value << unusedBitsCount;\n      }\n    }\n  } else {\n    const bigTrailingBitsCount = BigInt(trailingBitsCount);\n    const bigUnusedBitsCount = BigInt(unusedBitsCount);\n\n    let bigValue = BigInt(value);\n\n    if (isBigEndian) {\n      let i = buffer.length - 1;\n\n      // Set the trailing bits at the end of the output buffer\n      if (trailingBitsCount) {\n        buffer[i--] = Number(bigValue << bigUnusedBitsCount);\n        bigValue >>= bigTrailingBitsCount;\n      }\n\n      for (; i >= 0; i--) {\n        buffer[i] = Number(bigValue);\n        bigValue >>= 8n;\n      }\n    } else {\n      let i = 0;\n\n      const wholeByteCount = Math.trunc(size / 8);\n      for (; i < wholeByteCount; i++) {\n        buffer[i] = Number(bigValue);\n        bigValue >>= 8n;\n      }\n\n      // Set the trailing bits at the end of the output buffer\n      if (trailingBitsCount) {\n        buffer[i] = Number(bigValue << bigUnusedBitsCount);\n      }\n    }\n  }\n\n  // Integers that aren't a whole number of bytes are returned as a BitArray so\n  // their size in bits is tracked\n  if (trailingBitsCount) {\n    return new BitArray(buffer, size);\n  }\n\n  return buffer;\n}\n\n/**\n * Reads an aligned slice of any size as an integer.\n *\n * @param {BitArray} bitArray\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @param {boolean} isSigned\n * @returns {number}\n */\nfunction intFromAlignedSlice(bitArray, start, end, isBigEndian, isSigned) {\n  const byteSize = end - start;\n\n  if (byteSize <= 6) {\n    return intFromAlignedSliceUsingNumber(\n      bitArray.rawBuffer,\n      start,\n      end,\n      isBigEndian,\n      isSigned,\n    );\n  } else {\n    return intFromAlignedSliceUsingBigInt(\n      bitArray.rawBuffer,\n      start,\n      end,\n      isBigEndian,\n      isSigned,\n    );\n  }\n}\n\n/**\n * Reads an aligned slice up to 48 bits in size as an integer. Uses the\n * JavaScript `number` type internally.\n *\n * @param {Uint8Array} buffer\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @param {boolean} isSigned\n * @returns {number}\n */\nfunction intFromAlignedSliceUsingNumber(\n  buffer,\n  start,\n  end,\n  isBigEndian,\n  isSigned,\n) {\n  const byteSize = end - start;\n\n  let value = 0;\n\n  // Read bytes as an unsigned integer\n  if (isBigEndian) {\n    for (let i = start; i < end; i++) {\n      value *= 256;\n      value += buffer[i];\n    }\n  } else {\n    for (let i = end - 1; i >= start; i--) {\n      value *= 256;\n      value += buffer[i];\n    }\n  }\n\n  // For signed integers, if the high bit is set reinterpret as two's\n  // complement\n  if (isSigned) {\n    const highBit = 2 ** (byteSize * 8 - 1);\n    if (value >= highBit) {\n      value -= highBit * 2;\n    }\n  }\n\n  return value;\n}\n\n/**\n * Reads an aligned slice of any size as an integer. Uses the JavaScript\n * `BigInt` type internally.\n *\n * @param {Uint8Array} buffer\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @param {boolean} isSigned\n * @returns {number}\n */\nfunction intFromAlignedSliceUsingBigInt(\n  buffer,\n  start,\n  end,\n  isBigEndian,\n  isSigned,\n) {\n  const byteSize = end - start;\n\n  let value = 0n;\n\n  // Read bytes as an unsigned integer value\n  if (isBigEndian) {\n    for (let i = start; i < end; i++) {\n      value *= 256n;\n      value += BigInt(buffer[i]);\n    }\n  } else {\n    for (let i = end - 1; i >= start; i--) {\n      value *= 256n;\n      value += BigInt(buffer[i]);\n    }\n  }\n\n  // For signed integers, if the high bit is set reinterpret as two's\n  // complement\n  if (isSigned) {\n    const highBit = 1n << BigInt(byteSize * 8 - 1);\n    if (value >= highBit) {\n      value -= highBit * 2n;\n    }\n  }\n\n  // Convert the result into a JS number. This may cause quantizing/error on\n  // values outside JavaScript's safe integer range.\n  return Number(value);\n}\n\n/**\n * Reads an unaligned slice up to 53 bits in size as an integer. Uses the\n * JavaScript `number` type internally.\n *\n * This function assumes that the slice crosses at least one byte boundary in\n * the input.\n *\n * @param {Uint8Array} buffer\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @param {boolean} isSigned\n * @returns {number}\n */\nfunction intFromUnalignedSliceUsingNumber(\n  buffer,\n  start,\n  end,\n  isBigEndian,\n  isSigned,\n) {\n  const isStartByteAligned = start % 8 === 0;\n\n  let size = end - start;\n  let byteIndex = Math.trunc(start / 8);\n\n  let value = 0;\n\n  if (isBigEndian) {\n    // Read any leading bits\n    if (!isStartByteAligned) {\n      const leadingBitsCount = 8 - (start % 8);\n      value = buffer[byteIndex++] & ((1 << leadingBitsCount) - 1);\n      size -= leadingBitsCount;\n    }\n\n    // Read any whole bytes\n    while (size >= 8) {\n      value *= 256;\n      value += buffer[byteIndex++];\n      size -= 8;\n    }\n\n    // Read any trailing bits\n    if (size > 0) {\n      value *= 2 ** size;\n      value += buffer[byteIndex] >> (8 - size);\n    }\n  } else {\n    // For little endian, if the start is aligned then whole bytes can be read\n    // directly out of the input array, with the trailing bits handled at the\n    // end\n    if (isStartByteAligned) {\n      let size = end - start;\n      let scale = 1;\n\n      // Read whole bytes\n      while (size >= 8) {\n        value += buffer[byteIndex++] * scale;\n        scale *= 256;\n        size -= 8;\n      }\n\n      // Read trailing bits\n      value += (buffer[byteIndex] >> (8 - size)) * scale;\n    } else {\n      // Read little endian data where the start is not byte-aligned. This is\n      // done by reading whole bytes that cross a byte boundary in the input\n      // data, then reading any trailing bits.\n\n      const highBitsCount = start % 8;\n      const lowBitsCount = 8 - highBitsCount;\n\n      let size = end - start;\n      let scale = 1;\n\n      // Extract whole bytes\n      while (size >= 8) {\n        const byte =\n          (buffer[byteIndex] << highBitsCount) |\n          (buffer[byteIndex + 1] >> lowBitsCount);\n\n        value += (byte & 0xff) * scale;\n\n        scale *= 256;\n        size -= 8;\n        byteIndex++;\n      }\n\n      // Read any trailing bits. These trailing bits may cross a byte boundary\n      // in the input buffer.\n      if (size > 0) {\n        const lowBitsUsed = size - Math.max(0, size - lowBitsCount);\n\n        let trailingByte =\n          (buffer[byteIndex] & ((1 << lowBitsCount) - 1)) >>\n          (lowBitsCount - lowBitsUsed);\n\n        size -= lowBitsUsed;\n\n        if (size > 0) {\n          trailingByte *= 2 ** size;\n          trailingByte += buffer[byteIndex + 1] >> (8 - size);\n        }\n\n        value += trailingByte * scale;\n      }\n    }\n  }\n\n  // For signed integers, if the high bit is set reinterpret as two's\n  // complement\n  if (isSigned) {\n    const highBit = 2 ** (end - start - 1);\n    if (value >= highBit) {\n      value -= highBit * 2;\n    }\n  }\n\n  return value;\n}\n\n/**\n * Reads an unaligned slice of any size as an integer. Uses the JavaScript\n * `BigInt` type internally.\n *\n * This function assumes that the slice crosses at least one byte boundary in\n * the input.\n *\n * @param {Uint8Array} buffer\n * @param {number} start\n * @param {number} end\n * @param {boolean} isBigEndian\n * @param {boolean} isSigned\n * @returns {number}\n */\nfunction intFromUnalignedSliceUsingBigInt(\n  buffer,\n  start,\n  end,\n  isBigEndian,\n  isSigned,\n) {\n  const isStartByteAligned = start % 8 === 0;\n\n  let size = end - start;\n  let byteIndex = Math.trunc(start / 8);\n\n  let value = 0n;\n\n  if (isBigEndian) {\n    // Read any leading bits\n    if (!isStartByteAligned) {\n      const leadingBitsCount = 8 - (start % 8);\n      value = BigInt(buffer[byteIndex++] & ((1 << leadingBitsCount) - 1));\n      size -= leadingBitsCount;\n    }\n\n    // Read any whole bytes\n    while (size >= 8) {\n      value *= 256n;\n      value += BigInt(buffer[byteIndex++]);\n      size -= 8;\n    }\n\n    // Read any trailing bits\n    if (size > 0) {\n      value <<= BigInt(size);\n      value += BigInt(buffer[byteIndex] >> (8 - size));\n    }\n  } else {\n    // For little endian, if the start is aligned then whole bytes can be read\n    // directly out of the input array, with the trailing bits handled at the\n    // end\n    if (isStartByteAligned) {\n      let size = end - start;\n      let shift = 0n;\n\n      // Read whole bytes\n      while (size >= 8) {\n        value += BigInt(buffer[byteIndex++]) << shift;\n        shift += 8n;\n        size -= 8;\n      }\n\n      // Read trailing bits\n      value += BigInt(buffer[byteIndex] >> (8 - size)) << shift;\n    } else {\n      // Read little endian data where the start is not byte-aligned. This is\n      // done by reading whole bytes that cross a byte boundary in the input\n      // data, then reading any trailing bits.\n\n      const highBitsCount = start % 8;\n      const lowBitsCount = 8 - highBitsCount;\n\n      let size = end - start;\n      let shift = 0n;\n\n      // Extract whole bytes\n      while (size >= 8) {\n        const byte =\n          (buffer[byteIndex] << highBitsCount) |\n          (buffer[byteIndex + 1] >> lowBitsCount);\n\n        value += BigInt(byte & 0xff) << shift;\n\n        shift += 8n;\n        size -= 8;\n        byteIndex++;\n      }\n\n      // Read any trailing bits. These trailing bits may cross a byte boundary\n      // in the input buffer.\n      if (size > 0) {\n        const lowBitsUsed = size - Math.max(0, size - lowBitsCount);\n\n        let trailingByte =\n          (buffer[byteIndex] & ((1 << lowBitsCount) - 1)) >>\n          (lowBitsCount - lowBitsUsed);\n\n        size -= lowBitsUsed;\n\n        if (size > 0) {\n          trailingByte <<= size;\n          trailingByte += buffer[byteIndex + 1] >> (8 - size);\n        }\n\n        value += BigInt(trailingByte) << shift;\n      }\n    }\n  }\n\n  // For signed integers, if the high bit is set reinterpret as two's\n  // complement\n  if (isSigned) {\n    const highBit = 2n ** BigInt(end - start - 1);\n    if (value >= highBit) {\n      value -= highBit * 2n;\n    }\n  }\n\n  // Convert the result into a JS number. This may cause quantizing/error on\n  // values outside JavaScript's safe integer range.\n  return Number(value);\n}\n\n/**\n * Interprets a 16-bit unsigned integer value as a 16-bit floating point value.\n *\n * @param {number} intValue\n * @returns {number}\n */\nfunction fp16UintToNumber(intValue) {\n  const sign = intValue >= 0x8000 ? -1 : 1;\n  const exponent = (intValue & 0x7c00) >> 10;\n  const fraction = intValue & 0x03ff;\n\n  let value;\n  if (exponent === 0) {\n    value = 6.103515625e-5 * (fraction / 0x400);\n  } else if (exponent === 0x1f) {\n    value = fraction === 0 ? Infinity : NaN;\n  } else {\n    value = Math.pow(2, exponent - 15) * (1 + fraction / 0x400);\n  }\n\n  return sign * value;\n}\n\n/**\n * Converts a floating point number to bytes for a 16-bit floating point value.\n *\n * @param {number} intValue\n * @param {boolean} isBigEndian\n * @returns {Uint8Array}\n */\nfunction numberToFp16Uint(value, isBigEndian) {\n  const buffer = new Uint8Array(2);\n\n  if (isNaN(value)) {\n    buffer[1] = 0x7e;\n  } else if (value === Infinity) {\n    buffer[1] = 0x7c;\n  } else if (value === -Infinity) {\n    buffer[1] = 0xfc;\n  } else if (value === 0) {\n    // Both values are already zero\n  } else {\n    const sign = value < 0 ? 1 : 0;\n    value = Math.abs(value);\n\n    let exponent = Math.floor(Math.log2(value));\n    let fraction = value / Math.pow(2, exponent) - 1;\n\n    exponent += 15;\n\n    if (exponent <= 0) {\n      exponent = 0;\n      fraction = value / Math.pow(2, -14);\n    } else if (exponent >= 31) {\n      exponent = 31;\n      fraction = 0;\n    }\n\n    fraction = Math.round(fraction * 1024);\n\n    buffer[1] =\n      (sign << 7) | ((exponent & 0x1f) << 2) | ((fraction >> 8) & 0x03);\n    buffer[0] = fraction & 0xff;\n  }\n\n  if (isBigEndian) {\n    const a = buffer[0];\n    buffer[0] = buffer[1];\n    buffer[1] = a;\n  }\n\n  return buffer;\n}\n\n/**\n * Throws an exception if the given start and end values are out of bounds for\n * a bit array.\n *\n * @param {BitArray} bitArray\n * @param {number} start\n * @param {number} end\n */\nfunction bitArrayValidateRange(bitArray, start, end) {\n  if (\n    start < 0 ||\n    start > bitArray.bitSize ||\n    end < start ||\n    end > bitArray.bitSize\n  ) {\n    const msg =\n      `Invalid bit array slice: start = ${start}, end = ${end}, ` +\n      `bit size = ${bitArray.bitSize}`;\n    throw new globalThis.Error(msg);\n  }\n}\n\n/** @type {TextEncoder | undefined} */\nlet utf8Encoder;\n\n/**\n * Returns the UTF-8 bytes for a string.\n *\n * @param {string} string\n * @returns {Uint8Array}\n */\nexport function stringBits(string) {\n  utf8Encoder ??= new TextEncoder();\n  return utf8Encoder.encode(string);\n}\n\n/**\n * Returns the UTF-8 bytes for a single UTF codepoint.\n *\n * @param {UtfCodepoint} codepoint\n * @returns {Uint8Array}\n */\nexport function codepointBits(codepoint) {\n  return stringBits(String.fromCodePoint(codepoint.value));\n}\n\n/**\n * Returns the UTF-16 bytes for a string.\n *\n * @param {string} string\n * @param {boolean} isBigEndian\n * @returns {Uint8Array}\n */\nexport function stringToUtf16(string, isBigEndian) {\n  const buffer = new ArrayBuffer(string.length * 2);\n  const bufferView = new DataView(buffer);\n\n  for (let i = 0; i < string.length; i++) {\n    bufferView.setUint16(i * 2, string.charCodeAt(i), !isBigEndian);\n  }\n\n  return new Uint8Array(buffer);\n}\n\n/**\n * Returns the UTF-16 bytes for a single UTF codepoint.\n *\n * @param {UtfCodepoint} codepoint\n * @param {boolean} isBigEndian\n * @returns {Uint8Array}\n */\nexport function codepointToUtf16(codepoint, isBigEndian) {\n  return stringToUtf16(String.fromCodePoint(codepoint.value), isBigEndian);\n}\n\n/**\n * Returns the UTF-32 bytes for a string.\n *\n * @param {string} string\n * @param {boolean} isBigEndian\n * @returns {Uint8Array}\n */\nexport function stringToUtf32(string, isBigEndian) {\n  const buffer = new ArrayBuffer(string.length * 4);\n  const bufferView = new DataView(buffer);\n  let length = 0;\n\n  for (let i = 0; i < string.length; i++) {\n    const codepoint = string.codePointAt(i);\n\n    bufferView.setUint32(length * 4, codepoint, !isBigEndian);\n    length++;\n\n    if (codepoint > 0xffff) {\n      i++;\n    }\n  }\n\n  return new Uint8Array(buffer.slice(0, length * 4));\n}\n\n/**\n * Returns the UTF-32 bytes for a single UTF codepoint.\n *\n * @param {UtfCodepoint} codepoint\n * @param {boolean} isBigEndian\n * @returns {Uint8Array}\n */\nexport function codepointToUtf32(codepoint, isBigEndian) {\n  return stringToUtf32(String.fromCodePoint(codepoint.value), isBigEndian);\n}\n\nexport class Result extends CustomType {\n  static isResult(data) {\n    return data instanceof Result;\n  }\n}\n\nexport class Ok extends Result {\n  constructor(value) {\n    super();\n    this[0] = value;\n  }\n\n  isOk() {\n    return true;\n  }\n}\nexport const Result$Ok = (value) => new Ok(value);\nexport const Result$isOk = (value) => value instanceof Ok;\nexport const Result$Ok$0 = (value) => value[0];\n\nexport class Error extends Result {\n  constructor(detail) {\n    super();\n    this[0] = detail;\n  }\n\n  isOk() {\n    return false;\n  }\n}\nexport const Result$Error = (detail) => new Error(detail);\nexport const Result$isError = (value) => value instanceof Error;\nexport const Result$Error$0 = (value) => value[0];\n\nexport function isEqual(x, y) {\n  let values = [x, y];\n\n  while (values.length) {\n    let a = values.pop();\n    let b = values.pop();\n    if (a === b) continue;\n\n    if (!isObject(a) || !isObject(b)) return false;\n    let unequal =\n      !structurallyCompatibleObjects(a, b) ||\n      unequalDates(a, b) ||\n      unequalBuffers(a, b) ||\n      unequalArrays(a, b) ||\n      unequalMaps(a, b) ||\n      unequalSets(a, b) ||\n      unequalRegExps(a, b);\n    if (unequal) return false;\n\n    const proto = Object.getPrototypeOf(a);\n    if (proto !== null && typeof proto.equals === \"function\") {\n      try {\n        if (a.equals(b)) continue;\n        else return false;\n      } catch {}\n    }\n\n    let [keys, get] = getters(a);\n    const ka = keys(a);\n    const kb = keys(b);\n    if (ka.length !== kb.length) return false;\n    for (let k of ka) {\n      values.push(get(a, k), get(b, k));\n    }\n  }\n\n  return true;\n}\n\nfunction getters(object) {\n  if (object instanceof Map) {\n    return [(x) => x.keys(), (x, y) => x.get(y)];\n  } else {\n    let extra = object instanceof globalThis.Error ? [\"message\"] : [];\n    return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]];\n  }\n}\n\nfunction unequalDates(a, b) {\n  return a instanceof Date && (a > b || a < b);\n}\n\nfunction unequalBuffers(a, b) {\n  return (\n    !(a instanceof BitArray) &&\n    a.buffer instanceof ArrayBuffer &&\n    a.BYTES_PER_ELEMENT &&\n    !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i]))\n  );\n}\n\nfunction unequalArrays(a, b) {\n  return Array.isArray(a) && a.length !== b.length;\n}\n\nfunction unequalMaps(a, b) {\n  return a instanceof Map && a.size !== b.size;\n}\n\nfunction unequalSets(a, b) {\n  return (\n    a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e)))\n  );\n}\n\nfunction unequalRegExps(a, b) {\n  return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags);\n}\n\nfunction isObject(a) {\n  return typeof a === \"object\" && a !== null;\n}\n\nfunction structurallyCompatibleObjects(a, b) {\n  if (typeof a !== \"object\" && typeof b !== \"object\" && (!a || !b))\n    return false;\n\n  let nonstructural = [Promise, WeakSet, WeakMap, Function];\n  if (nonstructural.some((c) => a instanceof c)) return false;\n\n  return a.constructor === b.constructor;\n}\n\nexport function remainderInt(a, b) {\n  if (b === 0) {\n    return 0;\n  } else {\n    return a % b;\n  }\n}\n\nexport function divideInt(a, b) {\n  return Math.trunc(divideFloat(a, b));\n}\n\nexport function divideFloat(a, b) {\n  if (b === 0) {\n    return 0;\n  } else {\n    return a / b;\n  }\n}\n\nexport function makeError(variant, file, module, line, fn, message, extra) {\n  let error = new globalThis.Error(message);\n  error.gleam_error = variant;\n  error.file = file;\n  error.module = module;\n  error.line = line;\n  error.function = fn;\n  // TODO: Remove this with Gleam v2.0.0\n  error.fn = fn;\n  for (let k in extra) error[k] = extra[k];\n  return error;\n}\n"
  },
  {
    "path": "compiler-wasm/Cargo.toml",
    "content": "[package]\nname = \"gleam-wasm\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[lib]\n# This package compiles to wasm\ncrate-type = [\"cdylib\", \"rlib\"]\n\n[dependencies]\ngleam-core = { path = \"../compiler-core\" }\nconsole_error_panic_hook = \"0\"\nserde-wasm-bindgen = \"0\"\nwasm-bindgen = { version = \"0.2\", features = [\"serde-serialize\"] }\ntracing-wasm = \"*\"\ncamino.workspace = true\nhexpm = { path = \"../hexpm\" }\nim.workspace = true\nitertools.workspace = true\nserde.workspace = true\ntermcolor.workspace = true\ntracing.workspace = true\ngetrandom.workspace = true\n\n[dev-dependencies]\nwasm-bindgen-test = \"0.3.42\"\n"
  },
  {
    "path": "compiler-wasm/README.md",
    "content": "# Compiler WASM\n\n```sh\n# Install the build tool with cargo or brew etc\ncargo install wasm-pack\n\n# Build the wasm library\nwasm-pack build --release --target web\n\n# Make a tarball to attach to a release\ntar -C pkg/ -czvf gleam-v1.1.0-browser.tar.gz .\n```\n"
  },
  {
    "path": "compiler-wasm/src/lib.rs",
    "content": "#[cfg(test)]\nmod tests;\nmod wasm_filesystem;\n\nuse camino::Utf8PathBuf;\nuse gleam_core::{\n    Error,\n    analyse::TargetSupport,\n    build::{\n        Mode, NullTelemetry, PackageCompiler, StaleTracker, Target, TargetCodegenConfiguration,\n    },\n    config::PackageConfig,\n    io::{FileSystemReader, FileSystemWriter},\n    uid::UniqueIdGenerator,\n    warning::{VectorWarningEmitterIO, WarningEmitter},\n};\nuse hexpm::version::Version;\nuse im::HashMap;\nuse std::{cell::RefCell, collections::HashSet, rc::Rc};\nuse wasm_filesystem::WasmFileSystem;\n\nuse wasm_bindgen::prelude::*;\n\n#[derive(Debug, Clone, Default)]\nstruct Project {\n    fs: WasmFileSystem,\n    warnings: VectorWarningEmitterIO,\n}\n\nthread_local! {\n    static PROJECTS: RefCell<HashMap<usize, Project>> = RefCell::new(HashMap::new());\n}\n\n/// You should call this once to ensure that if the compiler crashes it gets\n/// reported in JavaScript.\n///\n#[cfg(target_arch = \"wasm32\")]\n#[wasm_bindgen]\npub fn initialise_panic_hook(debug: bool) {\n    console_error_panic_hook::set_once();\n\n    if debug {\n        let _ = tracing_wasm::try_set_as_global_default();\n    }\n}\n\n/// Reset the virtual file system to an empty state.\n///\n#[wasm_bindgen]\npub fn reset_filesystem(project_id: usize) {\n    let fs = get_filesystem(project_id);\n    fs.reset();\n}\n\n/// Delete project, freeing any memory associated with it.\n///\n#[wasm_bindgen]\npub fn delete_project(project_id: usize) {\n    PROJECTS.with(|lock| {\n        _ = lock.borrow_mut().remove(&project_id);\n    })\n}\n\nfn get_project(project_id: usize) -> Project {\n    PROJECTS.with(|lock| lock.borrow_mut().entry(project_id).or_default().clone())\n}\n\nfn get_filesystem(project_id: usize) -> WasmFileSystem {\n    get_project(project_id).fs\n}\n\nfn get_warnings(project_id: usize) -> VectorWarningEmitterIO {\n    get_project(project_id).warnings\n}\n\n/// Write a Gleam module to the `/src` directory of the virtual file system.\n///\n#[wasm_bindgen]\npub fn write_module(project_id: usize, module_name: &str, code: &str) {\n    let fs = get_filesystem(project_id);\n    let path = format!(\"/src/{module_name}.gleam\");\n    fs.write(&Utf8PathBuf::from(path), code)\n        .expect(\"writing file\")\n}\n\n/// Write a file to the virtual file system.\n///\n#[wasm_bindgen]\npub fn write_file(project_id: usize, path: &str, content: &str) {\n    let fs = get_filesystem(project_id);\n    fs.write(&Utf8PathBuf::from(path), content)\n        .expect(\"writing file\")\n}\n\n/// Write a non-text file to the virtual file system.\n///\n#[wasm_bindgen]\npub fn write_file_bytes(project_id: usize, path: &str, content: &[u8]) {\n    let fs = get_filesystem(project_id);\n    fs.write_bytes(&Utf8PathBuf::from(path), content)\n        .expect(\"writing file\")\n}\n\n/// Read a file from the virtual file system.\n///\n#[wasm_bindgen]\npub fn read_file_bytes(project_id: usize, path: &str) -> Option<Vec<u8>> {\n    let fs = get_filesystem(project_id);\n    fs.read_bytes(&Utf8PathBuf::from(path)).ok()\n}\n\n/// Run the package compiler. If this succeeds you can use\n///\n#[wasm_bindgen]\npub fn compile_package(project_id: usize, target: &str) -> Result<(), String> {\n    let target = match target.to_lowercase().as_str() {\n        \"erl\" | \"erlang\" => Target::Erlang,\n        \"js\" | \"javascript\" => Target::JavaScript,\n        _ => {\n            let msg = format!(\"Unknown target `{target}`, expected `erlang` or `javascript`\");\n            return Err(msg);\n        }\n    };\n\n    do_compile_package(get_project(project_id), target).map_err(|e| e.pretty_string())\n}\n\n/// Get the compiled JavaScript output for a given module.\n///\n/// You need to call `compile_package` before calling this function.\n///\n#[wasm_bindgen]\npub fn read_compiled_javascript(project_id: usize, module_name: &str) -> Option<String> {\n    let fs = get_filesystem(project_id);\n    let path = format!(\"/build/{module_name}.mjs\");\n    fs.read(&Utf8PathBuf::from(path)).ok()\n}\n\n/// Get the compiled Erlang output for a given module.\n///\n/// You need to call `compile_package` before calling this function.\n///\n#[wasm_bindgen]\npub fn read_compiled_erlang(project_id: usize, module_name: &str) -> Option<String> {\n    let fs = get_filesystem(project_id);\n    let path = format!(\n        \"/build/_gleam_artefacts/{}.erl\",\n        module_name.replace('/', \"@\")\n    );\n    fs.read(&Utf8PathBuf::from(path)).ok()\n}\n\n/// Clear any stored warnings. This is performed automatically when before compilation.\n///\n#[wasm_bindgen]\npub fn reset_warnings(project_id: usize) {\n    get_warnings(project_id).reset();\n}\n\n/// Pop the latest warning from the compiler.\n///\n#[wasm_bindgen]\npub fn pop_warning(project_id: usize) -> Option<String> {\n    get_warnings(project_id).pop().map(|w| w.to_pretty_string())\n}\n\nfn do_compile_package(project: Project, target: Target) -> Result<(), Error> {\n    let ids = UniqueIdGenerator::new();\n    let mut type_manifests = im::HashMap::new();\n    let mut defined_modules = im::HashMap::new();\n    #[allow(clippy::arc_with_non_send_sync)]\n    let warning_emitter = WarningEmitter::new(Rc::new(project.warnings));\n    let config = PackageConfig {\n        name: \"library\".into(),\n        version: Version::new(1, 0, 0),\n        target,\n        ..Default::default()\n    };\n\n    let target = match target {\n        Target::Erlang => TargetCodegenConfiguration::Erlang { app_file: None },\n        Target::JavaScript => TargetCodegenConfiguration::JavaScript {\n            emit_typescript_definitions: false,\n            prelude_location: Utf8PathBuf::from(\"./gleam_prelude.mjs\"),\n        },\n    };\n\n    tracing::info!(\"Compiling package\");\n\n    let lib = Utf8PathBuf::from(\"/lib\");\n    let out = Utf8PathBuf::from(\"/build\");\n    let package = Utf8PathBuf::from(\"/\");\n    let mut compiler = PackageCompiler::new(\n        &config,\n        Mode::Dev,\n        &package,\n        &out,\n        &lib,\n        &target,\n        ids,\n        project.fs,\n    );\n    compiler.write_entrypoint = false;\n    compiler.write_metadata = false;\n    compiler.compile_beam_bytecode = true;\n    compiler.target_support = TargetSupport::Enforced;\n    compiler\n        .compile(\n            &warning_emitter,\n            &mut type_manifests,\n            &mut defined_modules,\n            &mut StaleTracker::default(),\n            &mut HashSet::new(),\n            &NullTelemetry,\n        )\n        .into_result()\n        .map(|_| ())\n}\n"
  },
  {
    "path": "compiler-wasm/src/tests.rs",
    "content": "use super::*;\n\nuse wasm_bindgen_test::wasm_bindgen_test;\n\n#[wasm_bindgen_test]\nfn test_reset_filesystem() {\n    reset_filesystem(0);\n    assert_eq!(read_file_bytes(0, \"hello\"), None);\n    write_file_bytes(0, \"hello\", vec![1, 2, 3].as_slice());\n    assert_eq!(read_file_bytes(0, \"hello\"), Some(vec![1, 2, 3]));\n    reset_filesystem(0);\n    assert_eq!(read_file_bytes(0, \"hello\"), None);\n}\n\n#[wasm_bindgen_test]\nfn test_write_module() {\n    reset_filesystem(0);\n    assert_eq!(read_file_bytes(0, \"/src/some/module.gleam\"), None);\n    write_module(0, \"some/module\", \"const x = 1\");\n    assert_eq!(\n        read_file_bytes(0, \"/src/some/module.gleam\"),\n        Some(vec![99, 111, 110, 115, 116, 32, 120, 32, 61, 32, 49]),\n    );\n    reset_filesystem(0);\n    assert_eq!(read_file_bytes(0, \"/src/some/module.gleam\"), None);\n}\n\n#[wasm_bindgen_test]\nfn test_compile_package_bad_target() {\n    reset_filesystem(0);\n    assert!(compile_package(0, \"ruby\").is_err());\n}\n\n#[wasm_bindgen_test]\nfn test_compile_package_empty() {\n    reset_filesystem(0);\n    assert!(compile_package(0, \"javascript\").is_ok());\n}\n\n#[wasm_bindgen_test]\nfn test_compile_package_js() {\n    reset_filesystem(0);\n    write_module(0, \"one/two\", \"pub const x = 1\");\n    write_module(0, \"up/down\", \"import one/two pub fn go() { two.x }\");\n    assert!(compile_package(0, \"javascript\").is_ok());\n\n    assert_eq!(\n        read_compiled_javascript(0, \"one/two\"),\n        Some(\"export const x = 1;\\n\".into())\n    );\n\n    assert_eq!(\n        read_compiled_javascript(0, \"up/down\"),\n        Some(\n            r#\"import * as $two from \"../one/two.mjs\";\n\nexport function go() {\n  return $two.x;\n}\n\"#\n            .into()\n        )\n    );\n\n    // And now an error!\n    write_module(0, \"up/down\", \"import one/two/three\");\n    assert!(compile_package(0, \"javascript\").is_err());\n\n    // Let's fix that.\n    write_module(0, \"up/down\", \"pub const y = 1\");\n    assert!(compile_package(0, \"javascript\").is_ok());\n    assert_eq!(\n        read_compiled_javascript(0, \"up/down\"),\n        Some(\"export const y = 1;\\n\".into())\n    );\n}\n\n#[wasm_bindgen_test]\nfn test_compile_package_js_unsupported_feature() {\n    reset_filesystem(0);\n    write_module(\n        0,\n        \"one\",\n        r#\"\nfn wibble() { <<0:16-native>> }\npub fn main() { wibble() }\n\"#,\n    );\n\n    assert!(\n        compile_package(0, \"javascript\")\n            .unwrap_err()\n            .contains(\"The javascript target does not support\")\n    );\n}\n\n#[wasm_bindgen_test]\nfn test_warnings() {\n    reset_filesystem(0);\n    write_module(0, \"one\", \"const x = 1\");\n    assert!(pop_warning(0).is_none());\n\n    assert!(compile_package(0, \"javascript\").is_ok());\n    assert!(pop_warning(0).is_some());\n    assert!(pop_warning(0).is_none());\n}\n"
  },
  {
    "path": "compiler-wasm/src/wasm_filesystem.rs",
    "content": "use camino::{Utf8Path, Utf8PathBuf};\nuse gleam_core::{\n    Error, Result,\n    io::{\n        BeamCompiler, Command, CommandExecutor, FileSystemReader, FileSystemWriter, ReadDir, Stdio,\n        WrappedReader, memory::InMemoryFileSystem,\n    },\n};\nuse std::collections::HashSet;\n\n#[derive(Clone, Debug, Default)]\npub struct WasmFileSystem {\n    imfs: InMemoryFileSystem,\n}\n\nimpl WasmFileSystem {\n    pub fn reset(&self) {\n        self.imfs.reset();\n    }\n}\n\nimpl CommandExecutor for WasmFileSystem {\n    fn exec(&self, _command: Command) -> Result<i32, Error> {\n        Ok(0) // Always succeed.\n    }\n}\n\nimpl BeamCompiler for WasmFileSystem {\n    fn compile_beam(\n        &self,\n        _out: &Utf8Path,\n        _lib: &Utf8Path,\n        _modules: &HashSet<Utf8PathBuf>,\n        _stdio: Stdio,\n    ) -> Result<Vec<String>, Error> {\n        Ok(Vec::new()) // Always succeed.\n    }\n}\n\nimpl FileSystemWriter for WasmFileSystem {\n    fn delete_directory(&self, path: &Utf8Path) -> Result<(), Error> {\n        tracing::trace!(\"delete {:?}\", path);\n        self.imfs.delete_directory(path)\n    }\n\n    fn copy(&self, _from: &Utf8Path, _to: &Utf8Path) -> Result<(), Error> {\n        Ok(())\n    }\n    fn copy_dir(&self, _: &Utf8Path, _: &Utf8Path) -> Result<(), Error> {\n        Ok(())\n    }\n\n    fn mkdir(&self, path: &Utf8Path) -> Result<(), Error> {\n        tracing::trace!(\"mkdir {:?}\", path);\n        self.imfs.mkdir(path)\n    }\n\n    fn hardlink(&self, _: &Utf8Path, _: &Utf8Path) -> Result<(), Error> {\n        Ok(())\n    }\n\n    fn symlink_dir(&self, _: &Utf8Path, _: &Utf8Path) -> Result<(), Error> {\n        Ok(())\n    }\n\n    fn delete_file(&self, path: &Utf8Path) -> Result<(), Error> {\n        tracing::trace!(\"delete file {:?}\", path);\n        self.imfs.delete_file(path)\n    }\n\n    fn write(&self, path: &Utf8Path, content: &str) -> Result<(), Error> {\n        tracing::trace!(\"write {:?}\", path);\n        self.imfs.write(path, content)\n    }\n\n    fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<(), Error> {\n        tracing::trace!(\"write_bytes {:?}\", path);\n        self.imfs.write_bytes(path, content)\n    }\n\n    fn exists(&self, path: &Utf8Path) -> bool {\n        self.imfs.exists(path)\n    }\n}\n\nimpl FileSystemReader for WasmFileSystem {\n    fn read(&self, path: &Utf8Path) -> Result<String, Error> {\n        tracing::trace!(\"read {:?}\", path);\n        self.imfs.read(path)\n    }\n\n    fn is_file(&self, path: &Utf8Path) -> bool {\n        tracing::info!(\"is_file {:?}\", path);\n        self.imfs.is_file(path)\n    }\n\n    fn is_directory(&self, path: &Utf8Path) -> bool {\n        tracing::trace!(\"is_directory {:?}\", path);\n        self.imfs.is_directory(path)\n    }\n\n    fn reader(&self, path: &Utf8Path) -> Result<WrappedReader, Error> {\n        tracing::trace!(\"reader {:?}\", path);\n        self.imfs.reader(path)\n    }\n\n    fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir> {\n        tracing::trace!(\"read_dir {:?}\", path);\n        self.imfs.read_dir(path)\n    }\n\n    fn modification_time(&self, path: &Utf8Path) -> Result<std::time::SystemTime, Error> {\n        self.imfs.modification_time(path)\n    }\n\n    fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>, Error> {\n        self.imfs.read_bytes(path)\n    }\n\n    fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, Error> {\n        self.imfs.canonicalise(path)\n    }\n}\n"
  },
  {
    "path": "containers/elixir-alpine.dockerfile",
    "content": "FROM elixir:alpine\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/elixir-slim.dockerfile",
    "content": "FROM elixir:slim\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/elixir.dockerfile",
    "content": "FROM elixir:latest\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/erlang-alpine.dockerfile",
    "content": "FROM erlang:alpine\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/erlang-slim.dockerfile",
    "content": "FROM erlang:slim\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/erlang.dockerfile",
    "content": "FROM erlang:latest\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/node-alpine.dockerfile",
    "content": "FROM node:alpine\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/node-slim.dockerfile",
    "content": "FROM node:slim\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/node.dockerfile",
    "content": "FROM node:latest\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "containers/scratch.dockerfile",
    "content": "FROM scratch\n\nARG TARGETARCH\nCOPY gleam-${TARGETARCH} /bin/gleam\nCOPY gleam-${TARGETARCH}.sbom.spdx.json /opt/sbom/\n\nCMD [\"gleam\"]\n"
  },
  {
    "path": "deny.toml",
    "content": "# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html\n[advisories]\ndb-path = \"~/.cargo/advisory-db\"\ndb-urls = [\"https://github.com/rustsec/advisory-db\"]\nignore = [\n    \"RUSTSEC-2025-0141\"\n]\n\n# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html\n[licenses]\nallow = [\n    \"Apache-2.0 WITH LLVM-exception\",\n    \"Apache-2.0\",\n    \"BSD-3-Clause\",\n    \"BSL-1.0\",\n    \"CC0-1.0\",\n    \"CDLA-Permissive-2.0\",\n    \"ISC\",\n    \"MIT\",\n    \"MPL-2.0\",\n    \"Unicode-3.0\",\n    \"Unicode-DFS-2016\",\n    \"Zlib\",\n]\nconfidence-threshold = 0.8\n\n[[licenses.clarify]]\nname = \"ring\"\nversion = \"*\"\nexpression = \"MIT AND ISC AND OpenSSL\"\nlicense-files = [{ path = \"LICENSE\", hash = 0xbd0eed23 }]\n\n[licenses.private]\nignore = false\nregistries = []\n\n# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html\n[bans]\nmultiple-versions = \"allow\"\nwildcards = \"allow\"\nhighlight = \"all\"\nallow = []\ndeny = []\nskip = []\nskip-tree = []\n\n# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html\n[sources]\nunknown-registry = \"deny\"\nunknown-git = \"deny\"\nallow-registry = [\"https://github.com/rust-lang/crates.io-index\"]\nallow-git = [\n    # \"https://github.com/gleam-lang/hexpm-rust\",\n]\n\n[[licenses.clarify]]\nname = \"encoding_rs\"\nversion = \"*\"\nexpression = \"(Apache-2.0 OR MIT) AND BSD-3-Clause\"\nlicense-files = [\n    { path = \"COPYRIGHT\", hash = 0x39f8ad31 }\n]\n"
  },
  {
    "path": "docs/annoyances.md",
    "content": "# Annoyances\n\nThis document contains a list of issues and annoyances that we have writing\nGleam code today, so that we can devise solutions to them in future.\n\nThere are other annoyances that have known solutions that are yet to be\nimplemented. These are tracked in the Gleam issue tracker instead.\n\n## Bundling compiled JavaScript is non-obvious\n\n## Cannot shift repeated work to compile or initialise time\n\nFor example, regex compilation.\n\n## JavaScript custom type representation could be faster\n\nThere's performance improvements to be had. Would would be optimal?\n"
  },
  {
    "path": "docs/compiler/README.md",
    "content": "# Compiler documentation\n\nHello! Welcome to the documentation for the Gleam compiler. I hope you have fun\nwith the project!\n\n<!-- vscode-markdown-toc -->\n* [Project structure](#project-structure)\n* [Compilation flow](#compilation-flow)\n* [Testing](#testing)\n\t* [Running the tests](#running-the-tests)\n\t* [Snapshot testing](#snapshot-testing)\n\n<!-- vscode-markdown-toc-config\n\tnumbering=false\n\tautoSave=true\n\t/vscode-markdown-toc-config -->\n<!-- /vscode-markdown-toc -->\n\n## <a name='Projectstructure'></a>Project structure\n\nThe project is made up of several Rust crates (projects):\n\n- `compiler-core`: This project parses, analyses, and compiles Gleam projects.\n  It is entirely pure and has no IO so that is provided by the other Rust crates\n  that wrap this one.\n- `language-server`: This project contains code for the Gleam language server,\n  including autocomplete, code actions, hover and other features.\n- `compiler-cli`: A command line interface that wraps the core compiler and\n  language server, providing IO to files and to the console.\n- `compiler-wasm`: A JavaScript interface to the core compiler via web assembly.\n  Suitable for running in a web browser.\n\nIn addition to the Rust code there are these components:\n\n- `Makefile`: A makefile that defines shortcut commands for common tasks when\n  working in the Gleam codebase. Run `make help` to view them.\n- `test`: A collection of (mostly) Gleam projects that serve as integration tests for the\n  compiler.\n- `deny.toml`: Configuration for the `cargo-deny` tool which is used to ensure\n  that the Rust libraries the compiler depends on adhere to our expectations.\n- `containers`: A collection of docker-files used to produce OCI containers for\n  each Gleam release.\n- `.github/workflows`: GitHub Actions workflow definitions, used to build, test,\n  and release new versions of the project.\n- `docs`: You're looking at it pal.\n\n## <a name='Compilationflow'></a>Compilation flow\n\nThe process for compiling Gleam modules within the compiler looks roughly like\nthis:\n\n```txt\n  Gleam source code       .cache binaries\n          ▼                         ▼\n┌────────────────────┐ ┌───────────────────────┐\n│       Parser       │ │ Metadata deserializer │\n└────────────────────┘ └───────────────────────┘\n          │                         │\n      Untyped AST            Module metadata\n          └─────────┐   ┌────────┘     │\n                    ▼   ▼              │\n           ┌─────────────────────┐     │\n           │  Dependency sorter  │     │\n           └─────────────────────┘     │\n                      │                │\n                 Untyped AST           │\n              (sorted by deps)         │\n                      ▼                │\n            ┌───────────────────┐      │\n            │   Type checker    │◄─────┘\n            └───────────────────┘\n                      │\n          ┌────── Typed AST ──────┐\n          ▼                       ▼\n┌────────────────────┐ ┌─────────────────────┐\n│   Code generator   │ │ Metadata serializer │\n└────────────────────┘ └─────────────────────┘\n          │                       │\n          │                       ▼\n Erlang or JavaScript   .cache binaries\n   printing algebra\n          ▼\n┌────────────────────┐\n│   Pretty printer   │\n└────────────────────┘\n          │\n          ▼\n Erlang or JavaScript\n     source code\n```\n\n## <a name='Testing'></a>Testing\n\nWe like automated tests! They're a great way to verify that the compiler is\ndoing what we expect it do as we make changes.\n\n### <a name='Runningthetests'></a>Running the tests\n\n- `make test`: Run all the tests. Worth doing before committing any changes.\n- `make test-watch`: Run the Rust unit tests when files are saved.\n- `make language-test`: Run the cross-platform language integration tests in\n  `test/language`.\n- `make language-test-watch`: Run said tests when files are saved.\n- `make javascript-prelude-test`: Run the unit tests for the JavaScript code\n  that implements the Gleam prelude when compiling to JavaScript.\n- `make javascript-prelude-test-watch`: Run said tests when files are saved.\n\nThe `*-watch` commands require the [`watchexec`][watchexec] program to be\ninstalled.\n\n### <a name='Snapshottesting'></a>Snapshot testing\n\nThe compiler makes heavy use of snapshot testing using the\n[`cargo-insta`][cargo-insta] tool.\n\n[cargo-insta]: https://github.com/mitsuhiko/insta\n[watchexec]: https://github.com/watchexec/watchexec\n\nIf you're not familiar with snapshot testing instead of writing an input and an\nexpected output (as in normal example based tests) you write only the input. The\nsnapshot testing tool can then be used to mark any new outputs as accepted and\nsaved into the repository as snap files. If an output for one of the tests\nchanges then it is considered a failed test and the programmer has the option to\neither reject the new version (as it is an incorrect result) or accept it as the\nnew correct output.\n\nThis style of testing saves us huge amounts of time as manually updating all the\nexpected output when we make changes to the output format of the compiler or\nerror messaging is time-consuming and very dull. With snapshot testing it takes\nseconds.\n\n```sh\n# Run the tests\nmake test\n\n# Interactively verify changes to the snapshots\ncargo insta review\n```\n"
  },
  {
    "path": "docs/runtime-errors.md",
    "content": "# Runtime errors\n\nThere are several runtime errors that Gleam code can throw. This documentation\nlists them and their runtime properties.\n\nOn Erlang runtime errors are Erlang maps thrown with `erlang:error/1`, having at\nleast these properties:\n\n| Key         | Type   | Value                                       |\n| ---         | ----   | -----                                       |\n| gleam_error | Atom   | See individual errors                       |\n| message     | String | See individual errors                       |\n| file        | String | A path to the original source file location |\n| module      | String | The module the error occurred in            |\n| function    | String | The function the error occurred in          |\n| line        | Int    | The line number the error occurred on       |\n\nOn JavaScript runtime errors are instances of the JavaScript `Error` class,\nhaving at least these properties added to them:\n\n| Key         | Type   | Value                                 |\n| ---         | ----   | -----                                 |\n| gleam_error | String | See individual errors                 |\n| message     | String | See individual errors                 |\n| module      | String | The module the error occurred in      |\n| function    | String | The function the error occurred in    |\n| line        | Number | The line number the error occurred on |\n\n## Todo\n\nA panic that indicates that the code has not yet been completed, intended for\nuse in development.\n\n```gleam\ntodo\ntodo as \"some message\"\n```\n| Key         | Erlang Value      | JavaScript Value  |\n| ---         | ------------      | ----------------  |\n| gleam_error | `todo`            | `\"todo\"`          |\n| message     | The given message | The given message |\n\n## Panic\n\nAn explicit panic to unconditionally error.\n\n```gleam\npanic\npanic as \"some message\"\n```\n| Key         | Erlang Value      | JavaScript Value  |\n| ---         | ------------      | ----------------  |\n| gleam_error | `panic`           | `\"panic\"`         |\n| message     | The given message | The given message |\n\n## Let assert\n\nAn inexhaustive pattern match, erroring if the pattern does not match.\n\n```gleam\nlet assert Ok(x) = something()\nlet assert Error(e) = something() as \"This should fail\"\n```\n| Key                  | Erlang Value                                               | JavaScript Value                                          |\n| ---                  | ------------                                               | ----------------                                          |\n| gleam_error          | `let_assert`                                               | `\"let_assert\"`                                            |\n| message              | The given message                                          | The given message                                         |\n| value                | The unmatched value                                        | The unmatched value                                       |\n| start                | The byte-index of the start of the `let assert` statement  | The byte-index of the start of the `let assert` statement |\n| end                  | The byte-index of the end of the `let assert` statement    | The byte-index of the end of the `let assert` statement   |\n| pattern_start        | The byte-index of the start of the asserted pattern        | The byte-index of the start of the asserted pattern       |\n| pattern_end          | The byte-index of the end of the asserted pattern          | The byte-index of the end of the asserted pattern         |\n\n## Assert\n\nAn assertion of a boolean value.\n\nThe error format of `assert` differs based on the expression that is asserted.\nIt always has these fields:\n\n| Key              | Erlang Value                                           | JavaScript Value                                       |\n| ---              | ------------                                           | ----------------                                       |\n| gleam_error      | `assert`                                               | `\"assert\"`                                             |\n| message          | The given message                                      | The given message                                      |\n| kind             | The kind of asserted expression                        | The kind of asserted expression                        |\n| start            | The byte-index of the start of the `assert` statement  | The byte-index of the start of the `assert` statement  |\n| end              | The byte-index of the end of the `assert` expression   | The byte-index of the end of the `assert` expression   |\n| expression_start | The byte-index of the start of the asserted expression | The byte-index of the start of the asserted expression |\n\nBut, depending on the expression that was asserted, it contains additional\ninformation which can be used to diagnose the error.\n\n### Binary operators\n\n```gleam\nassert level >= 30\n```\n\n| Key       | Erlang Type  | JavaScript Type  | Value                              |\n| ---       | -----------  | ---------------  | -----                              |\n| kind      | Atom         | String           | `binary_operator`                  |\n| operator  | Atom         | String           | The binary operator that was used  |\n| left      | Map          | Object           | The left hand side of the operator |\n| right     | Map          | Object           | The left hand side of the operator |\n\n### Function calls\n\n```gleam\nassert check_some_property(a, b, c)\n```\n\n| Key       | Erlang Type  | JavaScript Type  | Value                                  |\n| ---       | -----------  | ---------------  | -----                                  |\n| kind      | Atom         | String           | `function_call`                        |\n| arguments | List of map  | Array of objects | The arguments of the asserted function |\n\n### Other expressions\n\n```gleam\nassert other_expression\n```\n\n| Key        | Erlang Type  | JavaScript Type  | Value                                |\n| ---        | -----------  | ---------------  | -----                                |\n| kind       | Atom         | String           | `expression`                         |\n| expression | Map          | Object           | The value of the asserted expression |\n\nThe expression maps have this structure:\n\n| Key    | Erlang Type  | JavaScript Type  | Value                                                             |\n| ---    | -----------  | ---------------  | -----                                                             |\n| value  | any          | any              | the value the expression evaluated to at runtime                  |\n| kind   | Atom         | String           | `literal` or `expression` or `unevaluated`                        |\n| start  | Int          | Number           | The byte-index of the start of this expression in the source code |\n| end    | Int          | Number           | The byte-index of the end of this expression in the source code   |\n\nIf the expression is a literal, such as `True` or `15`, it will have the `literal`\nkind. This signals that its value is not runtime dependent, and may not need to\nbe printed.\n\nIf the expression is on the right hand side of a short-circuiting operator, like\n`||` or `&&`, it might not be evaluated. If the operator short-circuits, the right\nhand side expression will have kind `unevaluated`.\n"
  },
  {
    "path": "docs/v2.md",
    "content": "# Breaking changes to make for v2\n\n## `[1 ..]` syntax\n\nDue to a bug in the parser we accept `[1, ..]` as a valid list value.\n\n- [x] Emits warning when used.\n- [x] Formatter rewrites it to desired syntax.\n\n## `_ as a` syntax\n\nThis pattern doesn't make sense as one could write `a` instead. We don't want\ntwo ways of doing the same thing.\n\n- [x] Emits warning when used.\n- [x] Formatter rewrites it to desired syntax.\n\n## Shadowing imported values\n\nDo not allow shadowing an imported value, the same way one can't define two\ntop level functions with the same name.\n\n- [x] Emits warning when used.\n\n## Import one module multiple times\n\nDo not allow one module to be imported multiple times. This is currently\naccepted so long as each import uses a different alias.\n\n- [x] Emits warning when used.\n\n## JavaScript runtime error `fn` property\n\nOn JavaScript there is a deprecated `fn` property. This was a mistake, it\nshould have been `function`. It still exists today due to backwards\ncompatibility.\n\n## Do not allow guard with no condition\n\nIt doesn't make sense to have an `if` guard followed by no condition, but the\ncompiler allows this: `case wibble { big if -> True }`\n\n- [x] Emits warning when used.\n- [x] Formatter rewrites it to desired syntax.\n"
  },
  {
    "path": "gleam-bin/.cargo/config.toml",
    "content": "# Statically link the CRT on Windows with MSVC toolchain\n# (only in release mode)\n[target.'cfg(all(windows, target_env = \"msvc\"))']\nrustflags = [\"-C\", \"target-feature=+crt-static\"]\n"
  },
  {
    "path": "gleam-bin/Cargo.toml",
    "content": "[package]\nname = \"gleam\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\ngleam-cli = { path = \"../compiler-cli\" }\n\n[target.'cfg(windows)'.build-dependencies]\n# For statically linking the VCRuntime on Windows when\n# using the MSVC toolchain\nstatic_vcruntime = \"3\"\n"
  },
  {
    "path": "gleam-bin/build.rs",
    "content": "fn main() {\n    #[cfg(windows)]\n    static_vcruntime::metabuild();\n}\n"
  },
  {
    "path": "gleam-bin/src/main.rs",
    "content": "pub fn main() {\n    gleam_cli::main();\n}\n"
  },
  {
    "path": "hexpm/.github/workflows/ci.yml",
    "content": "name: ci\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    name: test\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        toolchain: [stable]\n        build: [linux-amd64, macos, windows]\n        include:\n          - build: linux-amd64\n            os: ubuntu-latest\n            target: x86_64-unknown-linux-gnu\n          - build: macos\n            os: macos-latest\n            target: x86_64-apple-darwin\n          - build: windows\n            os: windows-latest\n            target: x86_64-pc-windows-msvc\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: ${{ matrix.toolchain }}\n          target: ${{ matrix.target }}\n\n      - name: Run tests\n        uses: clechasseur/rs-cargo@v2\n        with:\n          command: test\n          args: --workspace --target ${{ matrix.target }}\n\n  format-lint:\n    name: format-lint\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: stable\n          components: clippy, rustfmt\n\n      - name: Check formatting\n        run: cargo fmt --all -- --check\n\n      - name: Run linter\n        run: cargo clippy --workspace\n"
  },
  {
    "path": "hexpm/.gitignore",
    "content": "/target\nCargo.lock\n"
  },
  {
    "path": "hexpm/CHANGELOG.md",
    "content": "# Changelog\n\n## v5.1.1 - 2025-12-01\n\n- Fixed a bug with request path construction.\n\n## v5.1.0 - 2025-11-06\n\n- Updated dependencies.\n\n## v5.0.1 - 2025-11-06\n\n- Fixed a bug where ranges with `~>` and `and` or `or` would fail to parse.\n\n## v5.0.0 - 2025-09-19\n\n- Functions renamed to make it more clear if the JSON API is used or if the\n  repository endpoints are used.\n- Added `repository_v2_package_parse_body`, and `repository_v2_get_versions_body`,\n\n## v4.2.0 - 2025-08-27\n\n- `Version`'s serde deserializer can now work with `String` as well as `str`.\n\n## v4.1.0 - 2025-06-03\n\n- Added `impl From<Range> for pubgrub::Range<Version>`\n\n## v4.0.0 - 2025-05-09\n\n- Removed `version::{pubgrub_report, Version::bump, PackageVersions, resolve_versions, PackageFetcher}`.\n\n## v3.3.0 - 2025-03-10\n\n- Replaced protobuf dependency with prost to avoid a security vulnerability.\n\n## v3.2.0 - 2025-03-07\n\n- Updated protobuf to 3.7.1 and regenerated code from .proto files\n\n## v3.1.0 - 2024-06-23\n\n- Added specific errors for missing minor or patch versions.\n\n## v3.0.0 - 2024-05-30\n\n- Added `add_owner_request`, `add_owner_response`\n  `transfer_owner_request`, `transfer_owner_response`,\n\n- `revert_package_request`, and `revert_package_response`\n  are renamed to `remove_package_request`, and `remove_package_response`\n  to accurately describe what they do.\n\n## v2.4.1 - 2024-05-01\n\n- Fixed a bug where prerelease versions would not `bump` correctly. This caused\n  a panic in the Gleam compiler.\n\n## v2.4.0 - 2024-05-01\n\n- Added the `revert_release_request`, `revert_release_response`,\n  `revert_package_request`, and `revert_package_response` functions.\n\n## v2.3.0 - 2024-04-26\n\n- Updated all dependencies.\n\n## v2.2.0 - 2024-04-10\n\n- Updated for latest version of Reqwest.\n\n## v2.1.1 - 2023-11-02\n\n- Fixed a bug where the package name validation regex was too strict.\n\n## v2.1.0 - 2023-08-30\n\n- Updated for latest Hex API.\n\n## v2.0.0 - 2022-04-12\n\n- The `publish_package_request` now takes an additional argument signifying\n  whether an existing package can be replaced for now.\n\n## v1.4.1 - 2021-12-03\n\n- Fixed a bug where locked versions would discard incompatible requirements\n  during version resolution.\n\n## v1.4.0 - 2021-11-25\n\n- The HTTP client has been removed from this library in favour of request\n  building and response parsing functions. Bring your own HTTP client of choice.\n- `Version` and `Requirement` structs have been added for representing\n  information about requests versions of packages.\n- Protobuf code updated to use `cfg_attr` rather than deprecated attributes.\n- The `get_repository_versions` method returngit@github.com:gleam-lang/hexpm-rust.gits `Version`s rather than strings.\n- The `get_package` uses the `version::Range` type to represent `requirement`s.\n- A pubgrub based dependency resolver has been added.\n- Fixed a bug where a forbidden error was returned for a not-found package by\n  the get-package API.\n- Swapped the word \"token\" for \"key\" to match Hex.\n- Added `unretire_release_*`, `retire_release_*`, `remove_api_key_*` and\n  `publish_package_*` functions.\n\n## v1.3.0 - 2020-03-30\n\n- The `get_package_tarball` method has been added.\n\n## v1.2.0 - 2020-01-17\n\n- The `get_package` method has been added.\n- Update tokio to 1.0\n- Update reqwest to 0.11\n- Update url to 2.2\n- Update bytes to 1.0\n- The generated protobuf code has been regenerated.\n\n## v1.1.1 - 2020-07-20\n\n- Updated generated protobuffer deserialisation code.\n\n## v1.1.0 - 2020-07-20\n\n- The `get_repository_versions` method has been added.\n- The `repository_base` field has been added to both authenticated and\n  unauthenticated clients.\n\n## v1.0.0 - 2020-05-03\n\n- Initial release\n"
  },
  {
    "path": "hexpm/CONTRIBUTING.md",
    "content": "# How to Contribute\n\n## Adding a New API Function\n\n1. Figure out what you want to do\n    - Go to https://hexdocs.pm/hex/Mix.Tasks.Hex.html and find what you want to do\n2. Once you find the page, click on the code icon on the top-right to go to the corresponding source code like so: https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.owner.ex#L125\n```elixir\n  defp transfer_owner(organization, package, owner) do\n    auth = Mix.Tasks.Hex.auth_info(:write)\n    Hex.Shell.info(\"Transferring ownership to #{owner} for #{package}\")\n\n    case Hex.API.Package.Owner.add(organization, package, owner, \"full\", true, auth) do\n      {:ok, {code, _body, _headers}} when code in 200..299 ->\n        :ok\n\n      other ->\n        Hex.Shell.error(\"Transferring ownership failed\")\n        Hex.Utils.print_error_result(other)\n    end\n  end\n```\n\n3. The API function this is calling is `Hex.API.Package.Owner.add` so we go to https://github.com/hexpm/hex/blob/main/lib/hex/api/package.ex, scroll down to the defmodule for Owner and then find the `add` function:\n```elixir\n    def add(repo, package, owner, level, transfer, auth) when package != \"\" do\n      Hex.API.check_write_api()\n\n      owner = URI.encode_www_form(owner)\n      path = \"packages/#{URI.encode(package)}/owners/#{URI.encode(owner)}\"\n      params = %{level: level, transfer: transfer}\n      API.erlang_put_request(repo, path, params, auth)\n    end\n```\n`path` tells us what path and variables we will be using while `params` tells us what the body of the request should contain. The `API.erlang_put_request` at the bottom of this tells us the method of our request needs to be `PUT`. Now we have all of the information we need to create our request function like so:\n```elixir\npub fn transfer_owner_request(\n    package_name: &str,\n    owner: &str,\n    api_key: &str,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"level\": OwnerLevel::Full.to_string(),\n        \"transfer\": true,\n    });\n\n    config\n        .api_request(\n            Method::PUT,\n            &format!(\"packages/{}/owners/{}\", package_name, owner),\n            Some(api_key),\n        )\n        .body(body.to_string().into_bytes())\n        .expect(\"transfer_owner_request request\")\n}\n```\nNote that the `api_key` and `config` fields will always be present in these request functions while the other fields are tailored to the specific request we want to make.\n\n4. TODO: How to figure out what to write for the response function?"
  },
  {
    "path": "hexpm/Cargo.toml",
    "content": "[package]\nname = \"hexpm\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\nreadme = \"README.md\"\nrepository = \"https://github.com/gleam-lang/hexpm-rust\"\ndescription = \"A Rust client for the Hex package manager\"\nkeywords = [\"erlang\", \"gleam\", \"elixir\", \"hex\", \"api-client\"]\ncategories = [\"api-bindings\"]\n\n[dependencies]\n# HTTP types\nurl = \"2.2\"\n# Byte collections\nbytes = \"1\"\n# gzip (de)compression\nflate2 = \"1.0\"\n# RSA signature and SHA256 checksum verification\nring = \"0.17\"\n# PEM -> DER conversion\nx509-parser = \"0.18\"\n# Basic auth HTTP helper\nhttp-auth-basic = \"0.3\"\n# Protobuf runtime\nprost = \"0.13.5\"\n\nbase16 = { workspace = true, features = [\"alloc\"] }\necow = { workspace = true, features = [\"serde\"] }\nhttp.workspace = true\npubgrub.workspace = true\nregex.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nthiserror.workspace = true\n\n[dev-dependencies]\n# toml encoding\ntoml = \"0.8\"\n\n[build-dependencies]\n# Protobuf codegen\nprost-build = \"0\"\n"
  },
  {
    "path": "hexpm/LICENCE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n    1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n    2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n    3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n    4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n    5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n    6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n    7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n    8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n    9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n    END OF TERMS AND CONDITIONS\n\n    APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n    Copyright 2020 - present Louis Pilfold\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n\n## Runtime Library Exception to the Apache 2.0 License: ##\n\n\n    As an exception, if you use this Software to compile your source code and\n    portions of this Software are embedded into the binary product as a result,\n    you may redistribute such product without providing attribution as would\n    otherwise be required by Sections 4(a), 4(b) and 4(d) of the License.\n"
  },
  {
    "path": "hexpm/README.md",
    "content": "# hexpm-rust\n\n![license](https://img.shields.io/crates/l/hexpm.svg)\n[![crates.io](https://img.shields.io/crates/v/hexpm.svg?logo=rust)][crates]\n[![docs.rs](https://img.shields.io/badge/docs.rs-hexpm-blue)][docs]\n\nA Rust client for [Hex][hex], the package manager for the Erlang ecosystem.\n\nThis library was created for use in the [Gleam programming language][gleam]\ncompiler. The API is not overly well considered and breaking API changes may\noccur depending on the needs of the Gleam compiler.\n\n[hex]: https://hex.pm/\n[gleam]: https://gleam.run/\n[crates]: https://crates.io/crates/hexpm\n[docs]: https://docs.rs/hexpm\n"
  },
  {
    "path": "hexpm/build.rs",
    "content": "/// `prost_build` generates files in the output directory, which means that if we want\n/// to use it, we would need the protoc compiler as a build dependency.\n/// To get around this, we need run the build script and manually copy the generated files\n/// into the `src` folder. To do so, uncomment the below lines, then copy the files from the\n/// output directory into the `src/proto` folder. The path to the output directory\n/// will be printed in the terminal.\n///\nfn main() {\n    // prost_build::compile_protos(\n    //     &[\n    //         \"proto/signed.proto\",\n    //         \"proto/package.proto\",\n    //         \"proto/versions.proto\",\n    //     ],\n    //     &[\"proto/\"],\n    // )\n    // .expect(\"Failed to generate prost code from .proto files\");\n\n    // println!(\n    //     \"cargo::warning=Regenerated proto files, which must be manually copied into the `src` directory. Generated files can be found in {}\",\n    //     std::env::var(\"OUT_DIR\").unwrap_or_default()\n    // );\n}\n"
  },
  {
    "path": "hexpm/proto/names.proto",
    "content": "syntax = \"proto2\";\n\npackage names;\n\nmessage Names {\n  // All packages in the repository\n  repeated Package packages = 1;\n  // Name of repository\n  required string repository = 2;\n}\n\nmessage Package {\n  // Package name\n  required string name = 1;\n\n  // If set, the name of the package repository (NEVER USED, DEPRECATED)\n  // string repository = 2;\n}\n"
  },
  {
    "path": "hexpm/proto/package.proto",
    "content": "syntax = \"proto2\";\n\npackage package;\n\nmessage Package {\n  // All releases of the package\n  repeated Release releases = 1;\n  // Name of package\n  required string name = 2;\n  // Name of repository\n  required string repository = 3;\n}\n\nmessage Release {\n  // Release version\n  required string version = 1;\n  // sha256 checksum of \"inner\" package tarball\n  // deprecated in favor of outer_checksum\n  required bytes inner_checksum = 2;\n  // All dependencies of the release\n  repeated Dependency dependencies = 3;\n  // If set the release is retired, a retired release should only be\n  // resolved if it has already been locked in a project\n  optional RetirementStatus retired = 4;\n  // sha256 checksum of outer package tarball\n  // required when encoding but optional when decoding\n  optional bytes outer_checksum = 5;\n}\n\nmessage RetirementStatus {\n  required RetirementReason reason = 1;\n  optional string message = 2;\n}\n\nenum RetirementReason {\n  RETIRED_OTHER = 0;\n  RETIRED_INVALID = 1;\n  RETIRED_SECURITY = 2;\n  RETIRED_DEPRECATED = 3;\n  RETIRED_RENAMED = 4;\n}\n\nmessage Dependency {\n  // Package name of dependency\n  required string package = 1;\n  // Version requirement of dependency\n  required string requirement = 2;\n  // If set and true the package is optional (see dependency resolution)\n  optional bool optional = 3;\n  // If set is the OTP application name of the dependency, if not set the\n  // application name is the same as the package name\n  optional string app = 4;\n  // If set, the repository where the dependency is located\n  optional string repository = 5;\n}\n"
  },
  {
    "path": "hexpm/proto/signed.proto",
    "content": "syntax = \"proto2\";\n\npackage signed;\n\nmessage Signed {\n  // Signed contents\n  required bytes payload = 1;\n  // The signature\n  optional bytes signature = 2;\n}\n"
  },
  {
    "path": "hexpm/proto/versions.proto",
    "content": "syntax = \"proto2\";\n\npackage versions;\n\nmessage Versions {\n  // All packages in the repository\n  repeated VersionsPackage packages = 1;\n  // Name of repository\n  required string repository = 2;\n}\n\nmessage VersionsPackage {\n  // Package name\n  required string name = 1;\n  // All released versions of the package\n  repeated string versions = 2;\n  // Zero-based indexes of retired versions in the versions field, see package.proto\n  repeated int32 retired = 3 [packed=true];\n  // If set, the name of the package repository (NEVER USED, DEPRECATED)\n  // string repository = 4;\n}\n"
  },
  {
    "path": "hexpm/src/lib.rs",
    "content": "mod proto;\n\n#[cfg(test)]\nmod tests;\n\npub mod version;\n\nuse crate::proto::{signed::Signed, versions::Versions};\nuse bytes::buf::Buf;\nuse ecow::EcoString;\nuse flate2::read::GzDecoder;\nuse http::{Method, StatusCode};\nuse prost::Message;\nuse regex::Regex;\nuse ring::digest::{Context, SHA256};\nuse serde::{Deserialize, Serialize};\nuse serde_json::json;\nuse std::sync::OnceLock;\nuse std::time::{Duration, Instant};\nuse std::{\n    collections::HashMap,\n    convert::{TryFrom, TryInto},\n    fmt::Display,\n    io::{BufReader, Read},\n};\nuse thiserror::Error;\nuse version::{Range, Version};\nuse x509_parser::prelude::FromDer;\n\n#[derive(Debug, Clone)]\npub struct Config {\n    /// Defaults to https://hex.pm/api/\n    pub api_base: http::Uri,\n    /// Defaults to https://repo.hex.pm/\n    pub repository_base: http::Uri,\n}\n\nimpl Config {\n    pub fn new() -> Self {\n        Self {\n            api_base: http::Uri::from_static(\"https://hex.pm/api/\"),\n            repository_base: http::Uri::from_static(\"https://repo.hex.pm/\"),\n        }\n    }\n\n    fn api_request(&self, method: http::Method, path_suffix: &str) -> RequestBuilder {\n        RequestBuilder {\n            builder: make_request(self.api_base.clone(), method, path_suffix)\n                .header(\"content-type\", \"application/json\")\n                .header(\"accept\", \"application/json\"),\n        }\n    }\n\n    fn repository_request(\n        &self,\n        method: http::Method,\n        path_suffix: &str,\n        credentials: Option<&Credentials>,\n    ) -> http::request::Builder {\n        RequestBuilder {\n            builder: make_request(self.repository_base.clone(), method, path_suffix),\n        }\n        .read_credentials(credentials)\n    }\n}\n\nimpl Default for Config {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nstruct RequestBuilder {\n    builder: http::request::Builder,\n}\n\nimpl RequestBuilder {\n    pub fn read_credentials(self, credentials: Option<&Credentials>) -> http::request::Builder {\n        let mut builder = self.builder;\n        match credentials {\n            Some(Credentials::OAuthAccessToken(token)) => {\n                builder = builder.header(\"authorization\", format!(\"Bearer {token}\"));\n            }\n            Some(Credentials::ApiKey(key)) => {\n                builder = builder.header(\"authorization\", key.to_string());\n            }\n            None => (),\n        }\n        builder\n    }\n\n    pub fn write_credentials(self, credentials: &WriteActionCredentials) -> http::request::Builder {\n        let mut builder = self.builder;\n        match credentials {\n            WriteActionCredentials::OAuthAccessToken {\n                access_token,\n                one_time_password,\n            } => {\n                builder = builder.header(\"authorization\", format!(\"Bearer {access_token}\"));\n                builder = builder.header(\"x-hex-otp\", one_time_password.to_string());\n            }\n            WriteActionCredentials::ApiKey(key) => {\n                builder = builder.header(\"authorization\", key.to_string());\n            }\n        }\n        builder\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum Credentials {\n    // Short lived credential from OAuth\n    OAuthAccessToken(EcoString),\n    // Long lived API key\n    ApiKey(EcoString),\n}\n\n#[derive(Debug, Clone)]\npub enum WriteActionCredentials {\n    // Short lived credential from OAuth.\n    // A one-time-password is required for write actions when using OAuth\n    OAuthAccessToken {\n        access_token: EcoString,\n        one_time_password: EcoString,\n    },\n    // Long lived API key\n    ApiKey(EcoString),\n}\n\nfn make_request(\n    base: http::Uri,\n    method: http::Method,\n    path_suffix: &str,\n) -> http::request::Builder {\n    let mut parts = base.into_parts();\n    parts.path_and_query = Some(\n        match parts.path_and_query {\n            Some(path_and_query) => {\n                let mut path = path_and_query.path().to_owned();\n                if !path.ends_with('/') {\n                    path.push('/');\n                }\n                path += path_suffix;\n\n                // Drop query parameters\n                path.try_into()\n            }\n            None => path_suffix.try_into(),\n        }\n        .expect(\"api_uri path\"),\n    );\n    let uri = http::Uri::from_parts(parts).expect(\"api_uri building\");\n    http::Request::builder()\n        .method(method)\n        .uri(uri)\n        .header(\"user-agent\", USER_AGENT)\n}\n\n/// Create a request that deletes an Hex API key.\n///\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.user.ex#L291\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/key.ex#L15\npub fn api_remove_api_key_request(\n    name_of_key_to_delete: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let path = format!(\"keys/{name_of_key_to_delete}\");\n    config\n        .api_request(Method::DELETE, &path)\n        .write_credentials(credentials)\n        .body(vec![])\n        .expect(\"remove_api_key_request request\")\n}\n\n/// Parses a request that deleted a Hex API key.\npub fn api_remove_api_key_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        // Key was removed\n        StatusCode::NO_CONTENT | StatusCode::OK => Ok(()),\n        // Key has already been removed\n        StatusCode::NOT_FOUND => Ok(()),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\nfn unauthorised_response(headers: &http::HeaderMap) -> ApiError {\n    let authenticate_header = headers\n        .get(\"www-authenticate\")\n        .and_then(|header| header.to_str().ok())\n        .unwrap_or_default();\n\n    if authenticate_header.starts_with(\"Bearer realm=\\\"hex\\\", error=\\\"invalid_totp\\\"\") {\n        return ApiError::IncorrectOneTimePassword;\n    }\n\n    ApiError::InvalidCredentials\n}\n\n/// Retire an existing package release from Hex.\n///\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.retire.ex#L75\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/release.ex#L28\npub fn api_retire_release_request(\n    package: &str,\n    version: &str,\n    reason: RetirementReason,\n    message: Option<&str>,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"reason\": reason.to_str(),\n        \"message\": message,\n    });\n    let path = format!(\"packages/{package}/releases/{version}/retire\");\n    config\n        .api_request(Method::POST, &path)\n        .write_credentials(credentials)\n        .body(body.to_string().into_bytes())\n        .expect(\"retire_release_request request\")\n}\n\n/// Parses a request that retired a release.\npub fn api_retire_release_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT | StatusCode::OK => Ok(()),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// Un-retire an existing retired package release from Hex.\n///\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.retire.ex#L89\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/release.ex#L35\npub fn api_unretire_release_request(\n    package: &str,\n    version: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let path = format!(\"packages/{package}/releases/{version}/retire\");\n    config\n        .api_request(Method::DELETE, &path)\n        .write_credentials(credentials)\n        .body(vec![])\n        .expect(\"unretire_release_request request\")\n}\n\n/// Parses a request that un-retired a package version.\npub fn api_unretire_release_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT | StatusCode::OK => Ok(()),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// Create a request that get the names and versions of all of the packages on\n/// the package registry.\n///\n/// https://github.com/hexpm/specifications/blob/main/registry-v2.md\n///\n/// TODO: Where are the API docs for this?\npub fn repository_v2_get_versions_request(\n    credentials: Option<&Credentials>,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    config\n        .repository_request(Method::GET, \"versions\", credentials)\n        .header(\"accept\", \"application/json\")\n        .body(vec![])\n        .expect(\"get_repository_versions_request request\")\n}\n\n/// Parse a request that gets the names and versions of all of the packages on\n/// the package registry.\npub fn repository_v2_get_versions_response(\n    response: http::Response<Vec<u8>>,\n    public_key: &[u8],\n) -> Result<HashMap<String, Vec<Version>>, ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        StatusCode::OK => (),\n        status => return Err(ApiError::unexpected_response(status, body)),\n    };\n\n    let mut decoder = GzDecoder::new(body.reader());\n    let mut body = Vec::new();\n    decoder.read_to_end(&mut body)?;\n\n    repository_v2_get_versions_body(&body, public_key)\n}\n\n/// Parse a signed binary message containing all of the packages on the package registry.\npub fn repository_v2_get_versions_body(\n    protobuf_bytes: &Vec<u8>,\n    public_key: &[u8],\n) -> Result<HashMap<String, Vec<Version>>, ApiError> {\n    let signed = Signed::decode(protobuf_bytes.as_slice())?;\n\n    let payload =\n        verify_payload(signed, public_key).map_err(|_| ApiError::IncorrectPayloadSignature)?;\n\n    let versions = Versions::decode(payload.as_slice())?\n        .packages\n        .into_iter()\n        .map(|n| {\n            let parse_version = |v: &str| {\n                let err = |_| ApiError::InvalidVersionFormat(v.to_string());\n                Version::parse(v).map_err(err)\n            };\n            let versions = n\n                .versions\n                .iter()\n                .map(|v| parse_version(v.as_str()))\n                .collect::<Result<Vec<Version>, ApiError>>()?;\n            Ok((n.name, versions))\n        })\n        .collect::<Result<HashMap<_, _>, ApiError>>()?;\n\n    Ok(versions)\n}\n\n/// Create a request to get the information for a package in the repository.\n///\n/// https://github.com/hexpm/specifications/blob/main/registry-v2.md\n///\npub fn repository_v2_get_package_request(\n    name: &str,\n    credentials: Option<&Credentials>,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    config\n        .repository_request(Method::GET, &format!(\"packages/{name}\"), credentials)\n        .header(\"accept\", \"application/json\")\n        .body(vec![])\n        .expect(\"get_package_request request\")\n}\n\n/// Parse a response to get the information for a package in the repository.\n///\npub fn repository_v2_get_package_response(\n    response: http::Response<Vec<u8>>,\n    public_key: &[u8],\n) -> Result<Package, ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        StatusCode::OK => (),\n        StatusCode::FORBIDDEN => return Err(ApiError::NotFound),\n        StatusCode::NOT_FOUND => return Err(ApiError::NotFound),\n        status => {\n            return Err(ApiError::unexpected_response(status, body));\n        }\n    };\n\n    let mut decoder = GzDecoder::new(body.reader());\n    let mut body = Vec::new();\n    decoder.read_to_end(&mut body)?;\n\n    repository_v2_package_parse_body(&body, public_key)\n}\n\n/// Parse a signed binary message containing the information for a package in the repository.\npub fn repository_v2_package_parse_body(\n    protobuf_bytes: &Vec<u8>,\n    public_key: &[u8],\n) -> Result<Package, ApiError> {\n    let signed = Signed::decode(protobuf_bytes.as_slice())?;\n\n    let payload =\n        verify_payload(signed, public_key).map_err(|_| ApiError::IncorrectPayloadSignature)?;\n\n    let package = proto::package::Package::decode(payload.as_slice())?;\n    let releases = package\n        .releases\n        .clone()\n        .into_iter()\n        .map(proto_to_release)\n        .collect::<Result<Vec<_>, _>>()?;\n    let package = Package {\n        name: package.name,\n        repository: package.repository,\n        releases,\n    };\n\n    Ok(package)\n}\n\n/// Create a request to download a version of a package as a tarball\n/// TODO: Where are the API docs for this?\npub fn repository_get_package_tarball_request(\n    name: &str,\n    version: &str,\n    credentials: Option<&Credentials>,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    config\n        .repository_request(\n            Method::GET,\n            &format!(\"tarballs/{name}-{version}.tar\"),\n            credentials,\n        )\n        .header(\"accept\", \"application/x-tar\")\n        .body(vec![])\n        .expect(\"get_package_tarball_request request\")\n}\n\n/// Parse a response to download a version of a package as a tarball\n///\npub fn repository_get_package_tarball_response(\n    response: http::Response<Vec<u8>>,\n    checksum: &[u8],\n) -> Result<Vec<u8>, ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::OK => (),\n        StatusCode::FORBIDDEN => return Err(ApiError::NotFound),\n        StatusCode::NOT_FOUND => return Err(ApiError::NotFound),\n        status => {\n            return Err(ApiError::unexpected_response(status, body));\n        }\n    };\n    let body = read_and_check_body(body.reader(), checksum)?;\n    Ok(body)\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.publish.ex#L384\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/release_docs.ex#L19\npub fn api_remove_docs_request(\n    package_name: &str,\n    version: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> Result<http::Request<Vec<u8>>, ApiError> {\n    validate_package_and_version(package_name, version)?;\n    let path = format!(\"packages/{package_name}/releases/{version}/docs\");\n    Ok(config\n        .api_request(Method::DELETE, &path)\n        .write_credentials(credentials)\n        .body(vec![])\n        .expect(\"remove_docs_request request\"))\n}\n\npub fn api_remove_docs_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.publish.ex#L429\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/release_docs.ex#L11\npub fn api_publish_docs_request(\n    package_name: &str,\n    version: &str,\n    gzipped_tarball: Vec<u8>,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> Result<http::Request<Vec<u8>>, ApiError> {\n    validate_package_and_version(package_name, version)?;\n    let path = format!(\"packages/{package_name}/releases/{version}/docs\");\n    let mut builder = config\n        .api_request(Method::POST, &path)\n        .write_credentials(credentials);\n    let headers = builder.headers_mut().expect(\"headers\");\n    headers.insert(\"content-encoding\", \"x-gzip\".parse().unwrap());\n    headers.insert(\"content-type\", \"application/x-tar\".parse().unwrap());\n    Ok(builder\n        .body(gzipped_tarball)\n        .expect(\"publish_docs_request request\"))\n}\n\npub fn api_publish_docs_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::CREATED => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.publish.ex#L512\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/release.ex#L13\npub fn api_publish_package_request(\n    release_tarball: Vec<u8>,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n    replace: bool,\n) -> http::Request<Vec<u8>> {\n    let path = format!(\"publish?replace={replace}\");\n    let mut builder = config\n        .api_request(Method::POST, &path)\n        .write_credentials(credentials);\n    builder\n        .headers_mut()\n        .expect(\"headers\")\n        .insert(\"content-type\", \"application/x-tar\".parse().unwrap());\n    builder\n        .body(release_tarball)\n        .expect(\"publish_package_request request\")\n}\n\npub fn api_publish_package_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::OK | StatusCode::CREATED => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        StatusCode::UNPROCESSABLE_ENTITY => {\n            let body = &String::from_utf8_lossy(&body).to_string();\n            if body.contains(\"--replace\") {\n                return Err(ApiError::NotReplacing);\n            }\n            Err(ApiError::LateModification)\n        }\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.publish.ex#L371\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/release.ex#L21\npub fn api_revert_release_request(\n    package_name: &str,\n    version: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> Result<http::Request<Vec<u8>>, ApiError> {\n    validate_package_and_version(package_name, version)?;\n    let path = format!(\"packages/{package_name}/releases/{version}\");\n    Ok(config\n        .api_request(Method::DELETE, &path)\n        .write_credentials(credentials)\n        .body(vec![])\n        .expect(\"publish_package_request request\"))\n}\n\npub fn api_revert_release_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// See: https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.owner.ex#L47\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]\npub enum OwnerLevel {\n    /// Has every package permission EXCEPT the ability to change who owns the package\n    Maintainer,\n    /// Has every package permission including the ability to change who owns the package\n    Full,\n}\n\nimpl Display for OwnerLevel {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            OwnerLevel::Maintainer => write!(f, \"maintainer\"),\n            OwnerLevel::Full => write!(f, \"full\"),\n        }\n    }\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.owner.ex#L107\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/package.ex#L19\npub fn api_add_owner_request(\n    package_name: &str,\n    owner: &str,\n    level: OwnerLevel,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"level\": level.to_string(),\n        \"transfer\": false,\n    });\n    let path = format!(\"packages/{package_name}/owners/{owner}\");\n    config\n        .api_request(Method::PUT, &path)\n        .write_credentials(credentials)\n        .body(body.to_string().into_bytes())\n        .expect(\"add_owner_request request\")\n}\n\npub fn api_add_owner_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.owner.ex#L125\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/package.ex#L19\npub fn api_transfer_owner_request(\n    package_name: &str,\n    owner: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"level\": OwnerLevel::Full.to_string(),\n        \"transfer\": true,\n    });\n    let path = format!(\"packages/{package_name}/owners/{owner}\");\n    config\n        .api_request(Method::PUT, &path)\n        .write_credentials(credentials)\n        .body(body.to_string().into_bytes())\n        .expect(\"transfer_owner_request request\")\n}\n\npub fn api_transfer_owner_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// API Docs:\n///\n/// https://github.com/hexpm/hex/blob/main/lib/mix/tasks/hex.owner.ex#L139\n///\n/// https://github.com/hexpm/hex/blob/main/lib/hex/api/package.ex#L28\npub fn api_remove_owner_request(\n    package_name: &str,\n    owner: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let path = format!(\"packages/{package_name}/owners/{owner}\");\n    config\n        .api_request(Method::DELETE, &path)\n        .write_credentials(credentials)\n        .body(vec![])\n        .expect(\"remove_owner_request request\")\n}\n\npub fn api_remove_owner_response(response: http::Response<Vec<u8>>) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::NO_CONTENT => Ok(()),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n#[derive(Error, Debug)]\npub enum ApiError {\n    #[error(transparent)]\n    Json(#[from] serde_json::Error),\n\n    #[error(transparent)]\n    Io(#[from] std::io::Error),\n\n    #[error(\"The rate limit for the Hex API has been exceeded for this IP\")]\n    RateLimited,\n\n    #[error(\"Invalid authentication credentials\")]\n    InvalidCredentials,\n\n    #[error(\"An unexpected response was sent by Hex: {0}: {1}\")]\n    UnexpectedResponse(StatusCode, String),\n\n    #[error(\"The given package name {0} is not valid\")]\n    InvalidPackageNameFormat(String),\n\n    #[error(\"The payload signature does not match the downloaded payload\")]\n    IncorrectPayloadSignature,\n\n    #[error(transparent)]\n    InvalidProtobuf(#[from] prost::DecodeError),\n\n    #[error(\"Unexpected version format {0}\")]\n    InvalidVersionFormat(String),\n\n    #[error(\"Resource was not found\")]\n    NotFound,\n\n    #[error(\"The version requirement format {0} is not valid\")]\n    InvalidVersionRequirementFormat(String),\n\n    #[error(\"The downloaded data did not have the expected checksum\")]\n    IncorrectChecksum,\n\n    #[error(\"This account is not authorized for this action\")]\n    Forbidden,\n\n    #[error(\"Must explicitly express your intention to replace the release\")]\n    NotReplacing,\n\n    #[error(\"Can only modify a release up to one hour after publication\")]\n    LateModification,\n\n    #[error(\"The oauth request wasn't approved in time\")]\n    OAuthTimeout,\n\n    #[error(\"The oauth request was rejected\")]\n    OAuthAccessDenied,\n\n    #[error(\"The oauth token expired before the request was approved\")]\n    ExpiredToken,\n\n    #[error(\"The oauth refresh token was expired, revoked, or already used\")]\n    OAuthRefreshTokenRejected,\n\n    #[error(\"The supplied one-time-password was not correct\")]\n    IncorrectOneTimePassword,\n}\n\nimpl ApiError {\n    fn unexpected_response(status: StatusCode, body: Vec<u8>) -> Self {\n        ApiError::UnexpectedResponse(status, String::from_utf8_lossy(&body).to_string())\n    }\n\n    /// Returns `true` if the api error is [`NotFound`].\n    ///\n    /// [`NotFound`]: ApiError::NotFound\n    pub fn is_not_found(&self) -> bool {\n        matches!(self, Self::NotFound)\n    }\n\n    pub fn is_invalid_protobuf(&self) -> bool {\n        matches!(self, Self::InvalidProtobuf(_))\n    }\n}\n\n/// Read a body and ensure it has the given sha256 digest.\nfn read_and_check_body(reader: impl std::io::Read, checksum: &[u8]) -> Result<Vec<u8>, ApiError> {\n    use std::io::Read;\n    let mut reader = BufReader::new(reader);\n    let mut context = Context::new(&SHA256);\n    let mut buffer = [0; 1024];\n    let mut body = Vec::new();\n\n    loop {\n        let count = reader.read(&mut buffer)?;\n        if count == 0 {\n            break;\n        }\n        let bytes = &buffer[..count];\n        context.update(bytes);\n        body.extend_from_slice(bytes);\n    }\n\n    let digest = context.finish();\n    if digest.as_ref() == checksum {\n        Ok(body)\n    } else {\n        Err(ApiError::IncorrectChecksum)\n    }\n}\n\nfn proto_to_retirement_status(\n    status: Option<proto::package::RetirementStatus>,\n) -> Option<RetirementStatus> {\n    status.map(|stat| RetirementStatus {\n        message: stat.message().into(),\n        reason: proto_to_retirement_reason(stat.reason()),\n    })\n}\n\nfn proto_to_retirement_reason(reason: proto::package::RetirementReason) -> RetirementReason {\n    use proto::package::RetirementReason::*;\n    match reason {\n        RetiredOther => RetirementReason::Other,\n        RetiredInvalid => RetirementReason::Invalid,\n        RetiredSecurity => RetirementReason::Security,\n        RetiredDeprecated => RetirementReason::Deprecated,\n        RetiredRenamed => RetirementReason::Renamed,\n    }\n}\n\nfn proto_to_dep(dep: proto::package::Dependency) -> Result<(String, Dependency), ApiError> {\n    let app = dep.app;\n    let repository = dep.repository;\n    let requirement = Range::new(dep.requirement.clone())\n        .map_err(|_| ApiError::InvalidVersionFormat(dep.requirement))?;\n    Ok((\n        dep.package,\n        Dependency {\n            requirement,\n            optional: dep.optional.is_some(),\n            app,\n            repository,\n        },\n    ))\n}\n\nfn proto_to_release(release: proto::package::Release) -> Result<Release<()>, ApiError> {\n    let dependencies = release\n        .dependencies\n        .clone()\n        .into_iter()\n        .map(proto_to_dep)\n        .collect::<Result<HashMap<_, _>, _>>()?;\n    let version = Version::try_from(release.version.as_str())\n        .expect(\"Failed to parse version format from Hex\");\n    Ok(Release {\n        version,\n        outer_checksum: release.outer_checksum.unwrap_or_default(),\n        retirement_status: proto_to_retirement_status(release.retired),\n        requirements: dependencies,\n        meta: (),\n    })\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct Package {\n    pub name: String,\n    pub repository: String,\n    pub releases: Vec<Release<()>>,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize)]\npub struct Release<Meta> {\n    /// Release version\n    pub version: Version,\n    /// All dependencies of the release\n    pub requirements: HashMap<String, Dependency>,\n    /// If set the release is retired, a retired release should only be\n    /// resolved if it has already been locked in a project\n    pub retirement_status: Option<RetirementStatus>,\n    /// sha256 checksum of outer package tarball\n    /// required when encoding but optional when decoding\n    #[serde(alias = \"checksum\", deserialize_with = \"deserialize_checksum\")]\n    pub outer_checksum: Vec<u8>,\n    /// This is not present in all API endpoints so may be absent sometimes.\n    pub meta: Meta,\n}\n\nfn deserialize_checksum<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>\nwhere\n    D: serde::Deserializer<'de>,\n{\n    let s: &str = serde::de::Deserialize::deserialize(deserializer)?;\n    base16::decode(s).map_err(serde::de::Error::custom)\n}\n\nimpl<Meta> Release<Meta> {\n    pub fn is_retired(&self) -> bool {\n        self.retirement_status.is_some()\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize)]\npub struct ReleaseMeta {\n    pub app: String,\n    pub build_tools: Vec<String>,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize)]\npub struct RetirementStatus {\n    pub reason: RetirementReason,\n    pub message: String,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum RetirementReason {\n    Other,\n    Invalid,\n    Security,\n    Deprecated,\n    Renamed,\n}\n\nimpl<'de> serde::Deserialize<'de> for RetirementReason {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        let s: &str = serde::de::Deserialize::deserialize(deserializer)?;\n        match s {\n            \"other\" => Ok(RetirementReason::Other),\n            \"invalid\" => Ok(RetirementReason::Invalid),\n            \"security\" => Ok(RetirementReason::Security),\n            \"deprecated\" => Ok(RetirementReason::Deprecated),\n            \"renamed\" => Ok(RetirementReason::Renamed),\n            _ => Err(serde::de::Error::custom(\"unknown retirement reason type\")),\n        }\n    }\n}\n\nimpl RetirementReason {\n    pub fn to_str(&self) -> &'static str {\n        match self {\n            RetirementReason::Other => \"other\",\n            RetirementReason::Invalid => \"invalid\",\n            RetirementReason::Security => \"security\",\n            RetirementReason::Deprecated => \"deprecated\",\n            RetirementReason::Renamed => \"renamed\",\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize)]\npub struct Dependency {\n    /// Version requirement of dependency\n    pub requirement: Range,\n    /// If true the package is optional and does not need to be resolved\n    /// unless another package has specified it as a non-optional dependency.\n    pub optional: bool,\n    /// If set is the OTP application name of the dependency, if not set the\n    /// application name is the same as the package name\n    pub app: Option<String>,\n    /// If set, the repository where the dependency is located\n    pub repository: Option<String>,\n}\n\nstatic USER_AGENT: &str = concat!(\"Gleam v\", env!(\"CARGO_PKG_VERSION\"));\n\nfn validate_package_and_version(package: &str, version: &str) -> Result<(), ApiError> {\n    static PACKAGE_PATTERN: OnceLock<Regex> = OnceLock::new();\n    static VERSION_PATTERN: OnceLock<Regex> = OnceLock::new();\n\n    let package_pattern = PACKAGE_PATTERN.get_or_init(|| Regex::new(r\"^[a-z]\\w*$\").unwrap());\n    let version_pattern =\n        VERSION_PATTERN.get_or_init(|| Regex::new(r\"^[a-zA-Z-0-9\\._-]+$\").unwrap());\n\n    if !package_pattern.is_match(package) {\n        return Err(ApiError::InvalidPackageNameFormat(package.to_string()));\n    }\n    if !version_pattern.is_match(version) {\n        return Err(ApiError::InvalidVersionFormat(version.to_string()));\n    }\n    Ok(())\n}\n\n// To quote the docs:\n//\n// > All resources will be signed by the repository's private key.\n// > A signed resource is wrapped in a Signed message. The data under\n// > the payload field is signed by the signature field.\n// >\n// > The signature is an (unencoded) RSA signature of the (unencoded)\n// > SHA-512 digest of the payload.\n//\n// https://github.com/hexpm/specifications/blob/master/registry-v2.md#signing\n//\nfn verify_payload(mut signed: Signed, pem_public_key: &[u8]) -> Result<Vec<u8>, ApiError> {\n    let (_, pem) = x509_parser::pem::parse_x509_pem(pem_public_key)\n        .map_err(|_| ApiError::IncorrectPayloadSignature)?;\n    let (_, spki) = x509_parser::prelude::SubjectPublicKeyInfo::from_der(&pem.contents)\n        .map_err(|_| ApiError::IncorrectPayloadSignature)?;\n    let payload = std::mem::take(&mut signed.payload);\n    let verification = ring::signature::UnparsedPublicKey::new(\n        &ring::signature::RSA_PKCS1_2048_8192_SHA512,\n        &spki.subject_public_key,\n    )\n    .verify(payload.as_slice(), signed.signature());\n\n    if verification.is_ok() {\n        Ok(payload)\n    } else {\n        Err(ApiError::IncorrectPayloadSignature)\n    }\n}\n\n/// Create a request to get the information for a package release.\n///\npub fn api_get_package_release_request(\n    name: &str,\n    version: &str,\n    credentials: Option<&Credentials>,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let path = format!(\"packages/{name}/releases/{version}\");\n    config\n        .api_request(Method::GET, &path)\n        .read_credentials(credentials)\n        .header(\"accept\", \"application/json\")\n        .body(vec![])\n        .expect(\"get_package_release request\")\n}\n\n/// Parse a response to get the information for a package release.\n///\npub fn api_get_package_release_response(\n    response: http::Response<Vec<u8>>,\n) -> Result<Release<ReleaseMeta>, ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        StatusCode::OK => Ok(serde_json::from_slice(&body)?),\n        StatusCode::NOT_FOUND => Err(ApiError::NotFound),\n        StatusCode::TOO_MANY_REQUESTS => Err(ApiError::RateLimited),\n        StatusCode::UNAUTHORIZED => Err(unauthorised_response(&parts.headers)),\n        StatusCode::FORBIDDEN => Err(ApiError::Forbidden),\n        status => Err(ApiError::unexpected_response(status, body)),\n    }\n}\n\n/// Create a device authorisation, kicking off the Hex oauth flow.\npub fn oauth_device_authorisation_request(\n    hex_oauth_client_id: &str,\n    client_name: &str,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"client_id\": hex_oauth_client_id,\n        \"scope\": \"api:write\",\n        \"name\": client_name,\n    })\n    .to_string()\n    .into_bytes();\n    config\n        .api_request(Method::POST, \"oauth/device_authorization\")\n        .builder\n        .body(body)\n        .expect(\"oauth_device_authorisation_request\")\n}\n\n/// Parse the response of creating a device authorisation, kicking off the Hex oauth flow.\npub fn oauth_device_authorisation_response(\n    hex_oauth_client_id: String,\n    response: http::Response<Vec<u8>>,\n) -> Result<OAuthDeviceAuthorisation, ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        StatusCode::OK => (),\n        StatusCode::TOO_MANY_REQUESTS => return Err(ApiError::RateLimited),\n        status => return Err(ApiError::unexpected_response(status, body)),\n    };\n\n    let data: DeviceAuthorisationResponseBody = serde_json::from_slice(&body)?;\n    let poll_interval = Duration::from_secs(data.poll_interval_seconds);\n    let verification_uri = data\n        .verification_uri_complete\n        .unwrap_or(data.verification_uri);\n\n    Ok(OAuthDeviceAuthorisation {\n        user_code: data.user_code,\n        device_code: data.device_code,\n        start_time: Instant::now(),\n        client_id: hex_oauth_client_id,\n        poll_interval,\n        verification_uri,\n    })\n}\n\n#[derive(Debug)]\npub struct OAuthDeviceAuthorisation {\n    /// Show this code to the user for them to match against the one in the Hex UI.\n    pub user_code: String,\n    /// Send the user to this URI after showing them the code.\n    pub verification_uri: String,\n    client_id: String,\n    device_code: String,\n    poll_interval: Duration,\n    start_time: Instant,\n}\n\nimpl OAuthDeviceAuthorisation {\n    pub fn poll_token_request(&self, config: &Config) -> http::Request<Vec<u8>> {\n        let body = json!({\n            \"grant_type\": \"urn:ietf:params:oauth:grant-type:device_code\",\n            \"client_id\": &self.client_id,\n            \"device_code\": &self.device_code,\n        })\n        .to_string()\n        .into_bytes();\n        config\n            .api_request(Method::POST, \"oauth/token\")\n            .builder\n            .body(body)\n            .expect(\"poll_token_request\")\n    }\n\n    pub fn poll_token_response(\n        &mut self,\n        response: http::Response<Vec<u8>>,\n    ) -> Result<PollStep, ApiError> {\n        if self.start_time.elapsed() > Duration::from_mins(10) {\n            return Err(ApiError::OAuthTimeout);\n        }\n\n        let (parts, body) = response.into_parts();\n\n        match parts.status {\n            StatusCode::OK | StatusCode::BAD_REQUEST | StatusCode::FORBIDDEN => (),\n            status => return Err(ApiError::unexpected_response(status, body)),\n        };\n\n        let data: PollResponseBody = serde_json::from_slice(&body)?;\n        match data.into_result() {\n            Ok(tokens) => Ok(PollStep::Done(tokens)),\n\n            Err(PollResponseBodyError::AuthorizationPending) => {\n                Ok(PollStep::SleepThenPollAgain(self.poll_interval))\n            }\n\n            Err(PollResponseBodyError::SlowDown) => {\n                let max_interval = Duration::from_secs(30);\n                self.poll_interval = self.poll_interval.saturating_mul(2).min(max_interval);\n                Ok(PollStep::SleepThenPollAgain(self.poll_interval))\n            }\n\n            Err(PollResponseBodyError::AccessDenied) => Err(ApiError::OAuthAccessDenied),\n\n            Err(PollResponseBodyError::ExpiredToken) => Err(ApiError::ExpiredToken),\n        }\n    }\n}\n\n#[derive(Debug)]\npub enum PollStep {\n    Done(OAuthTokens),\n    SleepThenPollAgain(Duration),\n}\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct OAuthTokens {\n    pub access_token: EcoString,\n    pub refresh_token: EcoString,\n}\n\nimpl OAuthTokens {\n    pub fn as_credentials(&self) -> Credentials {\n        Credentials::OAuthAccessToken(self.access_token.clone())\n    }\n}\n\n#[derive(Debug, Deserialize)]\nstruct DeviceAuthorisationResponseBody {\n    #[serde(default = \"default_poll_interval_seconds\", rename = \"interval\")]\n    poll_interval_seconds: u64,\n    device_code: String,\n    user_code: String,\n    verification_uri: String,\n    verification_uri_complete: Option<String>,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(untagged)]\nenum PollResponseBody {\n    Success {\n        access_token: EcoString,\n        refresh_token: EcoString,\n    },\n    Fail {\n        error: PollResponseBodyError,\n    },\n}\n\nimpl PollResponseBody {\n    pub fn into_result(self) -> Result<OAuthTokens, PollResponseBodyError> {\n        match self {\n            PollResponseBody::Success {\n                access_token,\n                refresh_token,\n            } => Ok(OAuthTokens {\n                access_token,\n                refresh_token,\n            }),\n            PollResponseBody::Fail { error } => Err(error),\n        }\n    }\n}\n\n#[derive(Debug, Deserialize)]\nenum PollResponseBodyError {\n    #[serde(rename = \"authorization_pending\")]\n    AuthorizationPending,\n    #[serde(rename = \"slow_down\")]\n    SlowDown,\n    #[serde(rename = \"access_denied\")]\n    AccessDenied,\n    #[serde(rename = \"expired_token\")]\n    ExpiredToken,\n}\n\nfn default_poll_interval_seconds() -> u64 {\n    5\n}\n\n/// Use a refresh token to get an access token that can be used to\n/// authenticate with the API.\npub fn oauth_refresh_token_request(\n    hex_oauth_client_id: &str,\n    refresh_token: &str,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"grant_type\": \"refresh_token\",\n        \"client_id\": hex_oauth_client_id,\n        \"refresh_token\": refresh_token,\n    })\n    .to_string()\n    .into_bytes();\n    config\n        .api_request(Method::POST, \"oauth/token\")\n        .builder\n        .body(body)\n        .expect(\"oauth_refresh_token_request\")\n}\n\npub fn oauth_refresh_token_response(\n    response: http::Response<Vec<u8>>,\n) -> Result<OAuthTokens, ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        StatusCode::OK => (),\n        StatusCode::TOO_MANY_REQUESTS => return Err(ApiError::RateLimited),\n        StatusCode::BAD_REQUEST => return Err(ApiError::OAuthRefreshTokenRejected),\n        status => return Err(ApiError::unexpected_response(status, body)),\n    };\n\n    Ok(serde_json::from_slice(&body)?)\n}\n\n/// Get information about the currently authenticated user.\npub fn get_me_request(credentials: &Credentials, config: &Config) -> http::Request<Vec<u8>> {\n    config\n        .api_request(Method::GET, \"users/me\")\n        .read_credentials(Some(credentials))\n        .body(vec![])\n        .expect(\"me_request\")\n}\n\n/// Get information about the currently authenticated user.\npub fn get_me_response(response: http::Response<Vec<u8>>) -> Result<Me, ApiError> {\n    let (parts, body) = response.into_parts();\n\n    match parts.status {\n        StatusCode::OK => (),\n        status => return Err(ApiError::unexpected_response(status, body)),\n    };\n\n    Ok(serde_json::from_slice(&body)?)\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize)]\npub struct Me {\n    pub username: String,\n}\n\n/// Create a request to revoke an OAuth token.\n///\npub fn revoke_oauth_token_by_hash_request(\n    refresh_token_hash: &str,\n    credentials: &WriteActionCredentials,\n    config: &Config,\n) -> http::Request<Vec<u8>> {\n    let body = json!({\n        \"token_hash\": refresh_token_hash,\n    })\n    .to_string()\n    .into_bytes();\n    config\n        .api_request(Method::POST, \"oauth/revoke_by_hash\")\n        .write_credentials(credentials)\n        .header(\"accept\", \"application/json\")\n        .body(body)\n        .expect(\"api_get_package_release_request request\")\n}\n\n/// Parse a response to revoke an OAuth token.\n///\npub fn revoke_oauth_token_by_hash_response(\n    response: http::Response<Vec<u8>>,\n) -> Result<(), ApiError> {\n    let (parts, body) = response.into_parts();\n    match parts.status {\n        StatusCode::OK => (),\n        status => return Err(ApiError::unexpected_response(status, body)),\n    };\n    Ok(())\n}\n"
  },
  {
    "path": "hexpm/src/proto/package.rs",
    "content": "// This file is @generated by prost-build.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Package {\n    /// All releases of the package\n    #[prost(message, repeated, tag = \"1\")]\n    pub releases: ::prost::alloc::vec::Vec<Release>,\n    /// Name of package\n    #[prost(string, required, tag = \"2\")]\n    pub name: ::prost::alloc::string::String,\n    /// Name of repository\n    #[prost(string, required, tag = \"3\")]\n    pub repository: ::prost::alloc::string::String,\n}\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Release {\n    /// Release version\n    #[prost(string, required, tag = \"1\")]\n    pub version: ::prost::alloc::string::String,\n    /// sha256 checksum of \"inner\" package tarball\n    /// deprecated in favor of outer_checksum\n    #[prost(bytes = \"vec\", required, tag = \"2\")]\n    pub inner_checksum: ::prost::alloc::vec::Vec<u8>,\n    /// All dependencies of the release\n    #[prost(message, repeated, tag = \"3\")]\n    pub dependencies: ::prost::alloc::vec::Vec<Dependency>,\n    /// If set the release is retired, a retired release should only be\n    /// resolved if it has already been locked in a project\n    #[prost(message, optional, tag = \"4\")]\n    pub retired: ::core::option::Option<RetirementStatus>,\n    /// sha256 checksum of outer package tarball\n    /// required when encoding but optional when decoding\n    #[prost(bytes = \"vec\", optional, tag = \"5\")]\n    pub outer_checksum: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,\n}\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct RetirementStatus {\n    #[prost(enumeration = \"RetirementReason\", required, tag = \"1\")]\n    pub reason: i32,\n    #[prost(string, optional, tag = \"2\")]\n    pub message: ::core::option::Option<::prost::alloc::string::String>,\n}\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Dependency {\n    /// Package name of dependency\n    #[prost(string, required, tag = \"1\")]\n    pub package: ::prost::alloc::string::String,\n    /// Version requirement of dependency\n    #[prost(string, required, tag = \"2\")]\n    pub requirement: ::prost::alloc::string::String,\n    /// If set and true the package is optional (see dependency resolution)\n    #[prost(bool, optional, tag = \"3\")]\n    pub optional: ::core::option::Option<bool>,\n    /// If set is the OTP application name of the dependency, if not set the\n    /// application name is the same as the package name\n    #[prost(string, optional, tag = \"4\")]\n    pub app: ::core::option::Option<::prost::alloc::string::String>,\n    /// If set, the repository where the dependency is located\n    #[prost(string, optional, tag = \"5\")]\n    pub repository: ::core::option::Option<::prost::alloc::string::String>,\n}\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]\n#[repr(i32)]\npub enum RetirementReason {\n    RetiredOther = 0,\n    RetiredInvalid = 1,\n    RetiredSecurity = 2,\n    RetiredDeprecated = 3,\n    RetiredRenamed = 4,\n}\nimpl RetirementReason {\n    /// String value of the enum field names used in the ProtoBuf definition.\n    ///\n    /// The values are not transformed in any way and thus are considered stable\n    /// (if the ProtoBuf definition does not change) and safe for programmatic use.\n    pub fn as_str_name(&self) -> &'static str {\n        match self {\n            Self::RetiredOther => \"RETIRED_OTHER\",\n            Self::RetiredInvalid => \"RETIRED_INVALID\",\n            Self::RetiredSecurity => \"RETIRED_SECURITY\",\n            Self::RetiredDeprecated => \"RETIRED_DEPRECATED\",\n            Self::RetiredRenamed => \"RETIRED_RENAMED\",\n        }\n    }\n    /// Creates an enum from field names used in the ProtoBuf definition.\n    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {\n        match value {\n            \"RETIRED_OTHER\" => Some(Self::RetiredOther),\n            \"RETIRED_INVALID\" => Some(Self::RetiredInvalid),\n            \"RETIRED_SECURITY\" => Some(Self::RetiredSecurity),\n            \"RETIRED_DEPRECATED\" => Some(Self::RetiredDeprecated),\n            \"RETIRED_RENAMED\" => Some(Self::RetiredRenamed),\n            _ => None,\n        }\n    }\n}\n"
  },
  {
    "path": "hexpm/src/proto/signed.rs",
    "content": "// This file is @generated by prost-build.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Signed {\n    /// Signed contents\n    #[prost(bytes = \"vec\", required, tag = \"1\")]\n    pub payload: ::prost::alloc::vec::Vec<u8>,\n    /// The signature\n    #[prost(bytes = \"vec\", optional, tag = \"2\")]\n    pub signature: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,\n}\n"
  },
  {
    "path": "hexpm/src/proto/versions.rs",
    "content": "// This file is @generated by prost-build.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Versions {\n    /// All packages in the repository\n    #[prost(message, repeated, tag = \"1\")]\n    pub packages: ::prost::alloc::vec::Vec<VersionsPackage>,\n    /// Name of repository\n    #[prost(string, required, tag = \"2\")]\n    pub repository: ::prost::alloc::string::String,\n}\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct VersionsPackage {\n    /// Package name\n    #[prost(string, required, tag = \"1\")]\n    pub name: ::prost::alloc::string::String,\n    /// All released versions of the package\n    #[prost(string, repeated, tag = \"2\")]\n    pub versions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,\n    /// Zero-based indexes of retired versions in the versions field, see package.proto\n    ///\n    /// If set, the name of the package repository (NEVER USED, DEPRECATED)\n    /// string repository = 4;\n    #[prost(int32, repeated, tag = \"3\")]\n    pub retired: ::prost::alloc::vec::Vec<i32>,\n}\n"
  },
  {
    "path": "hexpm/src/proto.rs",
    "content": "#![allow(clippy::enum_variant_names)]\n\npub mod package;\npub mod signed;\npub mod versions;\n"
  },
  {
    "path": "hexpm/src/tests.rs",
    "content": "use std::{convert::TryFrom, io::Cursor};\n\nuse super::*;\nuse serde_json::json;\n\nfn make_response(status: u16, body: Vec<u8>) -> http::Response<Vec<u8>> {\n    http::Response::builder().status(status).body(body).unwrap()\n}\n\nfn make_json_response(status: u16, body: serde_json::Value) -> http::Response<Vec<u8>> {\n    make_response(status, body.to_string().into_bytes())\n}\n\n#[test]\nfn remove_docs_request() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"gleam_experimental_stdlib\";\n    let version = \"0.8.0\";\n\n    let config = Config::new();\n    let request = crate::api_remove_docs_request(package, version, &key, &config).unwrap();\n\n    assert_eq!(request.method(), http::Method::DELETE);\n    assert_eq!(\n        request.uri().path(),\n        \"/api/packages/gleam_experimental_stdlib/releases/0.8.0/docs\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n}\n\n#[test]\nfn remove_docs_response_success() {\n    let response = make_response(204, vec![]);\n    let result = crate::api_remove_docs_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn revert_release_request() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"gleam_experimental_stdlib\";\n    let version = \"0.8.0\";\n\n    let config = Config::new();\n    let request = crate::api_revert_release_request(package, version, &key, &config).unwrap();\n\n    assert_eq!(request.method(), http::Method::DELETE);\n    assert_eq!(\n        request.uri().path(),\n        \"/api/packages/gleam_experimental_stdlib/releases/0.8.0\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n}\n\n#[test]\nfn revert_release_response_success() {\n    let response = make_response(204, vec![]);\n    let result = crate::api_revert_release_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn add_owner_request() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"gleam_experimental_stdlib\";\n    let owner = \"lpil\";\n    let level = OwnerLevel::Maintainer;\n\n    let config = Config::new();\n    let request = crate::api_add_owner_request(package, owner, level, &key, &config);\n\n    assert_eq!(request.method(), http::Method::PUT);\n    assert_eq!(\n        request.uri().path(),\n        \"/api/packages/gleam_experimental_stdlib/owners/lpil\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n\n    let body: serde_json::Value = serde_json::from_slice(request.body()).unwrap();\n    assert_eq!(body[\"level\"], \"maintainer\");\n    assert_eq!(body[\"transfer\"], false);\n}\n\n#[test]\nfn add_owner_response_success() {\n    let response = make_response(204, vec![]);\n    let result = crate::api_add_owner_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn transfer_owner_request() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"gleam_experimental_stdlib\";\n    let owner = \"lpil\";\n\n    let config = Config::new();\n    let request = crate::api_transfer_owner_request(package, owner, &key, &config);\n\n    assert_eq!(request.method(), http::Method::PUT);\n    assert_eq!(\n        request.uri().path(),\n        \"/api/packages/gleam_experimental_stdlib/owners/lpil\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n\n    let body: serde_json::Value = serde_json::from_slice(request.body()).unwrap();\n    assert_eq!(body[\"level\"], \"full\");\n    assert_eq!(body[\"transfer\"], true);\n}\n\n#[test]\nfn transfer_owner_response_success() {\n    let response = make_response(204, vec![]);\n    let result = crate::api_transfer_owner_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn remove_owner_request() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"gleam_experimental_stdlib\";\n    let owner = \"lpil\";\n\n    let config = Config::new();\n    let request = crate::api_remove_owner_request(package, owner, &key, &config);\n\n    assert_eq!(request.method(), http::Method::DELETE);\n    assert_eq!(\n        request.uri().path(),\n        \"/api/packages/gleam_experimental_stdlib/owners/lpil\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n}\n\n#[test]\nfn remove_owner_response_success() {\n    let response = make_response(204, vec![]);\n    let result = crate::api_remove_owner_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn remove_key_request() {\n    let name = \"some-key-name\";\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n\n    let config = Config::new();\n    let request = crate::api_remove_api_key_request(name, &key, &config);\n\n    assert_eq!(request.method(), http::Method::DELETE);\n    assert_eq!(request.uri().path(), \"/api/keys/some-key-name\");\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n}\n\n#[test]\nfn remove_key_response_success_204() {\n    let response = make_response(204, vec![]);\n    let result = crate::api_remove_api_key_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn remove_key_response_success_200() {\n    let response = make_response(200, vec![]);\n    let result = crate::api_remove_api_key_response(response).unwrap();\n    assert_eq!(result, ());\n}\n\n#[test]\nfn remove_docs_response_not_found() {\n    let response = make_response(404, vec![]);\n    let result = crate::api_remove_docs_response(response).unwrap_err();\n\n    match result {\n        ApiError::NotFound => (),\n        result => panic!(\"expected ApiError::NotFound got {result:?}\"),\n    }\n}\n\n#[test]\nfn remove_docs_response_rate_limited() {\n    let response = make_response(429, vec![]);\n    let result = crate::api_remove_docs_response(response).unwrap_err();\n\n    match result {\n        ApiError::RateLimited => (),\n        result => panic!(\"expected ApiError::RateLimited got {result:?}\"),\n    }\n}\n\n#[test]\nfn remove_docs_response_invalid_key() {\n    let resp_body = json!({\n        \"message\": \"invalid API key\",\n        \"status\": 401,\n    });\n    let response = make_json_response(401, resp_body);\n    let result = crate::api_remove_docs_response(response).unwrap_err();\n\n    match result {\n        ApiError::InvalidCredentials => (),\n        result => panic!(\"expected ApiError::InvalidApiKey got {result:?}\"),\n    }\n}\n\n#[test]\nfn remove_docs_response_forbidden() {\n    let resp_body = json!({\n        \"message\": \"account is not authorized for this action\",\n        \"status\": 403,\n    });\n    let response = make_json_response(403, resp_body);\n    let result = crate::api_remove_docs_response(response).unwrap_err();\n\n    match result {\n        ApiError::Forbidden => (),\n        result => panic!(\"expected ApiError::Forbidden got {result:?}\"),\n    }\n}\n\n#[test]\nfn remove_docs_bad_package_name() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"not valid\";\n    let version = \"1.2.0\";\n\n    let config = Config::new();\n\n    match crate::api_remove_docs_request(package, version, &key, &config).unwrap_err() {\n        ApiError::InvalidPackageNameFormat(p) if p == package => (),\n        result => panic!(\"expected Err(ApiError::BadPackage), got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_request() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"gleam_experimental_stdlib_123\";\n    let version = \"0.8.0\";\n    let tarball = std::include_bytes!(\"../test/example.tar.gz\").to_vec();\n\n    let config = Config::new();\n    let request =\n        crate::api_publish_docs_request(package, version, tarball.clone(), &key, &config).unwrap();\n\n    assert_eq!(request.method(), http::Method::POST);\n    assert_eq!(\n        request.uri().path(),\n        \"/api/packages/gleam_experimental_stdlib_123/releases/0.8.0/docs\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        &\"Bearer my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n    assert_eq!(\n        request.headers().get(\"content-type\").unwrap(),\n        \"application/x-tar\"\n    );\n    assert_eq!(request.headers().get(\"content-encoding\").unwrap(), \"x-gzip\");\n    assert_eq!(request.body(), &tarball);\n}\n\n#[test]\nfn publish_docs_response_success() {\n    let response = make_response(201, vec![]);\n    let result = crate::api_publish_docs_response(response);\n\n    match result {\n        Ok(()) => (),\n        result => panic!(\"expected Ok(()), got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_bad_package_name() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"not valid\";\n    let version = \"1.2.0\";\n    let tarball = std::include_bytes!(\"../test/example.tar.gz\").to_vec();\n\n    let config = Config::new();\n\n    match crate::api_publish_docs_request(package, version, tarball, &key, &config).unwrap_err() {\n        ApiError::InvalidPackageNameFormat(p) if p == package => (),\n        result => panic!(\"expected Err(ApiError::BadPackage), got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_bad_package_version() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let package = \"name\";\n    let version = \"invalid version\";\n    let tarball = std::include_bytes!(\"../test/example.tar.gz\").to_vec();\n\n    let config = Config::new();\n\n    match crate::api_publish_docs_request(package, version, tarball, &key, &config).unwrap_err() {\n        ApiError::InvalidVersionFormat(v) if v == version => (),\n        result => panic!(\"expected ApiError::BadPackage, got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_response_not_found() {\n    let response = make_response(404, vec![]);\n    let result = crate::api_publish_docs_response(response);\n\n    match result {\n        Err(ApiError::NotFound) => (),\n        result => panic!(\"expected ApiError::NotFound, got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_response_rate_limit() {\n    let response = make_response(429, vec![]);\n    let result = crate::api_publish_docs_response(response);\n\n    match result {\n        Err(ApiError::RateLimited) => (),\n        result => panic!(\"expected ApiError::RateLimited, got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_response_invalid_api_key() {\n    let resp_body = json!({\n        \"message\": \"invalid API key\",\n        \"status\": 401,\n    });\n    let response = make_json_response(401, resp_body);\n    let result = crate::api_publish_docs_response(response);\n\n    match result {\n        Err(ApiError::InvalidCredentials) => (),\n        result => panic!(\"expected Err(ApiError::InvalidApiKey), got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_response_incorrect_totp_key() {\n    let resp_body = json!({\n        \"status\": 401,\n    });\n    let mut response = make_json_response(401, resp_body);\n    response.headers_mut().insert(\n        \"www-authenticate\",\n        \"Bearer realm=\\\"hex\\\", error=\\\"invalid_totp\\\"\"\n            .try_into()\n            .expect(\"Header value\"),\n    );\n    let result = crate::api_publish_docs_response(response);\n\n    match result {\n        Err(ApiError::IncorrectOneTimePassword) => (),\n        result => panic!(\"expected Err(ApiError::IncorrectOneTimePassword), got {result:?}\"),\n    }\n}\n\n#[test]\nfn publish_docs_response_forbidden() {\n    let resp_body = json!({\n        \"message\": \"account is not authorized for this action\",\n        \"status\": 403,\n    });\n    let response = make_json_response(403, resp_body);\n    let result = crate::api_publish_docs_response(response);\n\n    match result {\n        Err(ApiError::Forbidden) => (),\n        result => panic!(\"expected Err(ApiError::Forbidden), got {result:?}\"),\n    }\n}\n\nfn expected_package_exfmt() -> Package {\n    Package {\n        name: \"exfmt\".to_string(),\n        repository: \"hexpm\".to_string(),\n        releases: vec![\n            Release {\n                version: Version::try_from(\"0.0.0\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    82, 48, 191, 145, 92, 172, 0, 108, 238, 71, 57, 23, 101, 177, 161, 83, 91, 182,\n                    18, 232, 249, 225, 29, 12, 246, 5, 215, 165, 32, 57, 179, 110,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.1.0\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    111, 246, 240, 176, 118, 229, 12, 15, 164, 61, 186, 3, 89, 106, 153, 225, 247,\n                    52, 245, 8, 216, 139, 21, 232, 200, 16, 214, 59, 241, 188, 9, 6,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.2.0\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    149, 9, 192, 229, 84, 162, 110, 207, 161, 43, 31, 0, 126, 168, 14, 243, 31, 43,\n                    195, 238, 100, 91, 78, 100, 213, 181, 101, 154, 106, 168, 170, 107,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.2.1\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    157, 229, 28, 212, 92, 249, 14, 240, 235, 104, 31, 12, 160, 199, 83, 195, 154,\n                    105, 222, 37, 221, 80, 181, 183, 113, 240, 234, 107, 144, 85, 255, 65,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.2.2\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    112, 250, 133, 189, 183, 192, 54, 218, 115, 55, 216, 97, 204, 201, 191, 168,\n                    250, 133, 138, 252, 202, 240, 74, 197, 228, 235, 81, 18, 241, 7, 155, 38,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.2.3\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    131, 20, 29, 160, 171, 124, 7, 125, 210, 88, 17, 189, 199, 49, 191, 190, 14,\n                    162, 38, 247, 52, 176, 189, 17, 7, 188, 151, 152, 24, 64, 170, 29,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.2.4\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    109, 162, 185, 169, 26, 4, 62, 60, 167, 54, 182, 161, 140, 197, 75, 113, 183,\n                    117, 247, 201, 218, 228, 14, 160, 115, 157, 196, 51, 108, 16, 96, 217,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.3.0\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    97, 50, 95, 212, 242, 59, 245, 177, 140, 78, 79, 180, 108, 174, 119, 176, 24,\n                    80, 218, 152, 178, 227, 152, 242, 32, 126, 72, 67, 222, 0, 173, 170,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.4.0\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    246, 178, 237, 214, 217, 158, 143, 52, 130, 186, 64, 50, 94, 175, 161, 81, 68,\n                    186, 4, 73, 53, 226, 235, 144, 209, 84, 231, 136, 165, 119, 122, 126,\n                ],\n                meta: (),\n            },\n            Release {\n                version: Version::try_from(\"0.5.0\").unwrap(),\n                requirements: [].into(),\n                retirement_status: None,\n                outer_checksum: vec![\n                    151, 86, 157, 218, 218, 131, 240, 119, 198, 216, 202, 240, 65, 17, 57, 228, 84,\n                    252, 59, 207, 246, 49, 22, 21, 52, 47, 51, 139, 190, 9, 95, 109,\n                ],\n                meta: (),\n            },\n        ],\n    }\n}\n\n#[test]\nfn get_package_request() {\n    let config = Config::new();\n    let request = crate::repository_v2_get_package_request(\"exfmt\", None, &config);\n\n    assert_eq!(request.method(), http::Method::GET);\n    assert_eq!(request.uri().path(), \"/packages/exfmt\");\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n}\n\n#[test]\nfn get_package_response_ok() {\n    let response_body = std::include_bytes!(\"../test/package_exfmt\");\n    let response = make_response(200, response_body.to_vec());\n\n    let package = crate::repository_v2_get_package_response(\n        response,\n        std::include_bytes!(\"../test/public_key\"),\n    )\n    .unwrap();\n\n    assert_eq!(expected_package_exfmt(), package);\n}\n\n#[test]\nfn get_package_response_not_found() {\n    let response = make_response(404, vec![]);\n    let error = crate::repository_v2_get_package_response(\n        response,\n        std::include_bytes!(\"../test/public_key\"),\n    )\n    .unwrap_err();\n\n    assert!(error.is_not_found());\n}\n\n#[test]\nfn get_package_from_bytes_ok() {\n    let response_body = std::include_bytes!(\"../test/package_exfmt\");\n    let mut uncompressed = Vec::new();\n    let mut decoder = GzDecoder::new(Cursor::new(response_body));\n    let _ = decoder\n        .read_to_end(&mut uncompressed)\n        .expect(\"failed to decompress body\");\n\n    let package = crate::repository_v2_package_parse_body(\n        &uncompressed,\n        std::include_bytes!(\"../test/public_key\"),\n    )\n    .expect(\"package failed to parse\");\n\n    assert_eq!(expected_package_exfmt(), package);\n}\n\n#[test]\nfn get_package_from_bytes_malformed() {\n    // public key should not be a valid protobuf and should therefore fail\n    let bytes = std::include_bytes!(\"../test/public_key\").to_vec();\n    let package_error = crate::repository_v2_package_parse_body(&bytes, &bytes)\n        .expect_err(\"parsing failed to fail\");\n\n    assert!(package_error.is_invalid_protobuf());\n}\n\n#[test]\nfn get_repository_versions_request() {\n    let config = Config::new();\n    let request = crate::repository_v2_get_versions_request(None, &config);\n\n    assert_eq!(request.method(), http::Method::GET);\n    assert_eq!(request.uri().path(), \"/versions\");\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n}\n\n#[test]\nfn get_repository_versions_response_ok() {\n    let response_body = std::include_bytes!(\"../test/versions\");\n    let response = make_response(200, response_body.to_vec());\n\n    let versions = crate::repository_v2_get_versions_response(\n        response,\n        std::include_bytes!(\"../test/public_key\"),\n    );\n\n    assert_eq!(\n        &vec![\n            Version::parse(\"0.0.0\").unwrap(),\n            Version::parse(\"0.1.0\").unwrap(),\n            Version::parse(\"0.2.0\").unwrap(),\n            Version::parse(\"0.2.1\").unwrap(),\n            Version::parse(\"0.2.2\").unwrap(),\n            Version::parse(\"0.2.3\").unwrap(),\n            Version::parse(\"0.2.4\").unwrap(),\n            Version::parse(\"0.3.0\").unwrap(),\n            Version::parse(\"0.4.0\").unwrap(),\n            Version::parse(\"0.5.0\").unwrap(),\n        ],\n        versions.unwrap().get(\"exfmt\").unwrap(),\n    );\n}\n\n#[test]\nfn get_repository_versions_from_bytes_ok() {\n    let response_body = std::include_bytes!(\"../test/versions\");\n    let mut uncompressed = Vec::new();\n    let mut decoder = GzDecoder::new(Cursor::new(response_body));\n    let _ = decoder\n        .read_to_end(&mut uncompressed)\n        .expect(\"failed to decompress body\");\n\n    let versions = crate::repository_v2_get_versions_body(\n        &uncompressed,\n        std::include_bytes!(\"../test/public_key\"),\n    )\n    .expect(\"versions failed to parse\");\n\n    assert_eq!(\n        &vec![\n            Version::parse(\"0.0.0\").unwrap(),\n            Version::parse(\"0.1.0\").unwrap(),\n            Version::parse(\"0.2.0\").unwrap(),\n            Version::parse(\"0.2.1\").unwrap(),\n            Version::parse(\"0.2.2\").unwrap(),\n            Version::parse(\"0.2.3\").unwrap(),\n            Version::parse(\"0.2.4\").unwrap(),\n            Version::parse(\"0.3.0\").unwrap(),\n            Version::parse(\"0.4.0\").unwrap(),\n            Version::parse(\"0.5.0\").unwrap(),\n        ],\n        versions.get(\"exfmt\").unwrap(),\n    );\n}\n\n#[test]\nfn get_repository_versions_from_bytes_malformed() {\n    // public key should not be a valid protobuf and should therefore fail\n    let bytes = std::include_bytes!(\"../test/public_key\").to_vec();\n    let versions_error =\n        crate::repository_v2_get_versions_body(&bytes, &bytes).expect_err(\"parsing failed to fail\");\n\n    assert!(versions_error.is_invalid_protobuf());\n}\n\n#[test]\nfn get_repository_tarball_request() {\n    let config = Config::new();\n    let request =\n        crate::repository_get_package_tarball_request(\"gleam_stdlib\", \"0.14.0\", None, &config);\n\n    assert_eq!(request.method(), http::Method::GET);\n    assert_eq!(request.uri().path(), \"/tarballs/gleam_stdlib-0.14.0.tar\");\n    assert_eq!(\n        request.headers().get(\"accept\").unwrap(),\n        \"application/x-tar\"\n    );\n}\n\n#[test]\nfn get_repository_tarball_response_ok() {\n    let tarball_bytes = std::include_bytes!(\"../test/gleam_stdlib-0.14.0.tar\");\n    let checksum =\n        base16::decode(\"9107f6a859cb96945ad9a099085db028ca2bebb3c8ea42eec227b51c614cc2e0\").unwrap();\n\n    let response = make_response(200, tarball_bytes.to_vec());\n    let downloaded = crate::repository_get_package_tarball_response(response, &checksum).unwrap();\n\n    assert_eq!(&downloaded, tarball_bytes);\n}\n\n#[test]\nfn get_repository_tarball_response_bad_checksum() {\n    let tarball_bytes = std::include_bytes!(\"../test/gleam_stdlib-0.14.0.tar\");\n    let checksum = vec![1, 2, 3, 4, 5];\n\n    let response = make_response(200, tarball_bytes.to_vec());\n    let err = crate::repository_get_package_tarball_response(response, &checksum).unwrap_err();\n\n    assert_eq!(\n        err.to_string(),\n        \"The downloaded data did not have the expected checksum\"\n    );\n}\n\n#[test]\nfn get_repository_tarball_response_not_found() {\n    let checksum = vec![1, 2, 3, 4, 5];\n\n    let response = make_response(404, vec![]);\n    let err = crate::repository_get_package_tarball_response(response, &checksum).unwrap_err();\n\n    assert_eq!(err.to_string(), \"Resource was not found\");\n}\n\n#[test]\nfn publish_package_request() {\n    let key = WriteActionCredentials::ApiKey(EcoString::from(\"my-api-key-here\"));\n    let tarball = std::include_bytes!(\"../test/example.tar.gz\").to_vec();\n\n    let config = Config::new();\n    let request = crate::api_publish_package_request(tarball.clone(), &key, &config, false);\n\n    assert_eq!(request.method(), http::Method::POST);\n    assert_eq!(\n        request.uri().path_and_query().unwrap(),\n        \"/api/publish?replace=false\"\n    );\n    assert_eq!(\n        request.headers().get(\"authorization\").unwrap(),\n        \"my-api-key-here\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n    assert_eq!(\n        request.headers().get(\"content-type\").unwrap(),\n        \"application/x-tar\"\n    );\n    assert_eq!(request.body(), &tarball);\n}\n\n#[test]\nfn publish_package_request_replace() {\n    let key = WriteActionCredentials::OAuthAccessToken {\n        access_token: EcoString::from(\"my-api-key-here\"),\n        one_time_password: EcoString::from(\"test-otp\"),\n    };\n    let tarball = std::include_bytes!(\"../test/example.tar.gz\").to_vec();\n\n    let config = Config::new();\n    let request = crate::api_publish_package_request(tarball.clone(), &key, &config, true);\n\n    assert_eq!(\n        request.uri().path_and_query().unwrap(),\n        \"/api/publish?replace=true\"\n    );\n    assert_eq!(request.headers().get(\"x-hex-otp\").unwrap(), \"test-otp\");\n}\n\n#[test]\nfn publish_package_response_success() {\n    let response = make_response(201, vec![]);\n    let result = crate::api_publish_package_response(response);\n\n    match result {\n        Ok(()) => (),\n        result => panic!(\"expected Ok(()), got {result:?}\"),\n    }\n}\n\n#[test]\nfn modify_package_late() {\n    let resp_body = json!({\n        \"errors\": {\"inserted_at\": \"can only modify a release up to one hour after publication\"},\n        \"message\": \"Validation error(s)\",\n        \"status\": 422,\n    });\n    let response = make_json_response(422, resp_body);\n    let result = crate::api_publish_package_response(response);\n\n    match result {\n        Err(ApiError::LateModification) => (),\n        result => panic!(\"expected Err(ApiError::LateModification), got {result:?}\"),\n    }\n}\n\n#[test]\nfn not_replacing() {\n    let resp_body = json!({\n        \"errors\": {\"inserted_at\": \"must include the --replace flag to update an existing release\"},\n        \"message\": \"Validation error(s)\",\n        \"status\": 422,\n    });\n    let response = make_json_response(422, resp_body);\n    let result = crate::api_publish_package_response(response);\n\n    match result {\n        Err(ApiError::NotReplacing) => (),\n        result => panic!(\"expected Err(ApiError::NotReplacing), got {result:?}\"),\n    }\n}\n\n#[test]\nfn get_package_release_request() {\n    let config = Config::new();\n    let request = crate::api_get_package_release_request(\"clint\", \"0.0.1\", None, &config);\n\n    assert_eq!(request.method(), http::Method::GET);\n    assert_eq!(request.uri().path(), \"/api/packages/clint/releases/0.0.1\");\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n}\n\n#[test]\nfn get_package_release_response_not_found() {\n    let response = make_response(404, vec![]);\n    let error = crate::api_get_package_release_response(response).unwrap_err();\n\n    assert!(error.is_not_found());\n}\n\n#[test]\nfn get_package_release_response_ok() {\n    let resp_body = json!({\n        \"version\": \"0.0.1\",\n        \"checksum\": \"41C6781B5F4B986BCE14C3578D39C497BCB8427F1D36D8CDE5FCAA6E03CAE2B1\",\n        \"requirements\": {\n            \"plug\": {\n                \"requirement\": \"~>0.11.0\",\n                \"optional\": false,\n                \"app\": \"plug\"\n            },\n            \"cowboy\": {\n                \"requirement\": \"~>1.0.0\",\n                \"optional\": false,\n                \"app\": \"cowboy\"\n            }\n        },\n        \"meta\": {\n            \"app\": \"clint\",\n            \"build_tools\": [\"mix\"]\n        }\n    });\n    let response = make_json_response(200, resp_body);\n    let resp = crate::api_get_package_release_response(response).unwrap();\n\n    assert_eq!(\n        resp,\n        Release {\n            version: Version::new(0, 0, 1),\n            requirements: [\n                (\n                    \"plug\".into(),\n                    Dependency {\n                        requirement: Range::new(\"~>0.11.0\".into()).unwrap(),\n                        optional: false,\n                        app: Some(\"plug\".into()),\n                        repository: None\n                    }\n                ),\n                (\n                    \"cowboy\".into(),\n                    Dependency {\n                        requirement: Range::new(\"~>1.0.0\".into()).unwrap(),\n                        optional: false,\n                        app: Some(\"cowboy\".into()),\n                        repository: None\n                    }\n                )\n            ]\n            .into(),\n            retirement_status: None,\n            outer_checksum: vec![\n                65, 198, 120, 27, 95, 75, 152, 107, 206, 20, 195, 87, 141, 57, 196, 151, 188, 184,\n                66, 127, 29, 54, 216, 205, 229, 252, 170, 110, 3, 202, 226, 177\n            ],\n            meta: ReleaseMeta {\n                app: \"clint\".into(),\n                build_tools: vec![\"mix\".into()]\n            }\n        }\n    )\n}\n\n#[test]\nfn make_request_base_trailing_slash_is_optional() {\n    let slash = http::Uri::from_static(\"http://host/path/\");\n    let no_slash = http::Uri::from_static(\"http://host/path\");\n    let suffix = \"suffix\";\n    let expect = \"/path/suffix\";\n\n    let slash = make_request(slash, http::Method::GET, suffix);\n    assert_eq!(slash.uri_ref().unwrap().path(), expect);\n\n    let no_slash = make_request(no_slash, http::Method::GET, suffix);\n    assert_eq!(no_slash.uri_ref().unwrap().path(), expect);\n}\n\n#[test]\nfn oauth_device_authorisation_request() {\n    let client_id = \"test-client-id\";\n\n    let config = Config::new();\n    let request = crate::oauth_device_authorisation_request(client_id, \"My client\", &config);\n\n    assert_eq!(request.method(), http::Method::POST);\n    assert_eq!(request.uri().path(), \"/api/oauth/device_authorization\");\n    assert_eq!(\n        request.headers().get(\"content-type\").unwrap(),\n        \"application/json\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n\n    let body: serde_json::Value = serde_json::from_slice(request.body()).unwrap();\n    assert_eq!(body[\"client_id\"], \"test-client-id\");\n    assert_eq!(body[\"scope\"], \"api:write\");\n    assert_eq!(body[\"name\"], \"My client\");\n}\n\n#[test]\nfn oauth_device_authorisation_response_success() {\n    let client_id = \"test-client-id\".to_string();\n    let resp_body = json!({\n        \"device_code\": \"device-code-123\",\n        \"user_code\": \"USER-CODE\",\n        \"verification_uri\": \"https://hex.pm/oauth/device\",\n        \"interval\": 5\n    });\n\n    let response = make_json_response(200, resp_body);\n    let auth = crate::oauth_device_authorisation_response(client_id, response).unwrap();\n\n    assert_eq!(auth.user_code, \"USER-CODE\");\n    assert_eq!(auth.verification_uri, \"https://hex.pm/oauth/device\");\n}\n\n#[test]\nfn oauth_device_authorisation_response_success_with_complete_uri() {\n    let client_id = \"test-client-id\".to_string();\n    let resp_body = json!({\n        \"device_code\": \"device-code-123\",\n        \"user_code\": \"USER-CODE\",\n        \"verification_uri\": \"https://hex.pm/oauth/device\",\n        \"verification_uri_complete\": \"https://hex.pm/oauth/device?user_code=USER-CODE\",\n        \"interval\": 5\n    });\n\n    let response = make_json_response(200, resp_body);\n    let auth = crate::oauth_device_authorisation_response(client_id, response).unwrap();\n\n    assert_eq!(auth.user_code, \"USER-CODE\");\n    // When verification_uri_complete is present, it should be used instead\n    assert_eq!(\n        auth.verification_uri,\n        \"https://hex.pm/oauth/device?user_code=USER-CODE\"\n    );\n}\n\n#[test]\nfn oauth_device_authorisation_response_default_interval() {\n    let client_id = \"test-client-id\".to_string();\n    // Response without \"interval\" field - should use default of 5 seconds\n    let resp_body = json!({\n        \"device_code\": \"device-code-123\",\n        \"user_code\": \"USER-CODE\",\n        \"verification_uri\": \"https://hex.pm/oauth/device\"\n    });\n\n    let response = make_json_response(200, resp_body);\n    let auth = crate::oauth_device_authorisation_response(client_id, response).unwrap();\n\n    assert_eq!(auth.user_code, \"USER-CODE\");\n    assert_eq!(auth.verification_uri, \"https://hex.pm/oauth/device\");\n}\n\n#[test]\nfn oauth_device_authorisation_response_rate_limited() {\n    let client_id = \"test-client-id\".to_string();\n    let response = make_response(429, vec![]);\n    let result = crate::oauth_device_authorisation_response(client_id, response).unwrap_err();\n\n    match result {\n        ApiError::RateLimited => (),\n        result => panic!(\"expected RateLimited, got {:?}\", result),\n    }\n}\n\n#[test]\nfn oauth_device_authorisation_response_unexpected_status() {\n    let client_id = \"test-client-id\".to_string();\n    let resp_body = json!({\n        \"message\": \"Internal server error\",\n        \"status\": 500,\n    });\n    let response = make_json_response(500, resp_body);\n    let result = crate::oauth_device_authorisation_response(client_id, response).unwrap_err();\n\n    match result {\n        ApiError::UnexpectedResponse(status, _) => {\n            assert_eq!(status, http::StatusCode::INTERNAL_SERVER_ERROR);\n        }\n        result => panic!(\"expected UnexpectedResponse, got {:?}\", result),\n    }\n}\n\nfn make_device_authorisation() -> crate::OAuthDeviceAuthorisation {\n    let client_id = \"test-client-id\".to_string();\n    let resp_body = json!({\n        \"device_code\": \"device-code-123\",\n        \"user_code\": \"USER-CODE\",\n        \"verification_uri\": \"https://hex.pm/oauth/device\",\n        \"interval\": 5\n    });\n    let response = make_json_response(200, resp_body);\n    crate::oauth_device_authorisation_response(client_id, response).unwrap()\n}\n\n#[test]\nfn poll_token_request() {\n    let auth = make_device_authorisation();\n    let config = Config::new();\n    let request = auth.poll_token_request(&config);\n\n    assert_eq!(request.method(), http::Method::POST);\n    assert_eq!(request.uri().path(), \"/api/oauth/token\");\n    assert_eq!(\n        request.headers().get(\"content-type\").unwrap(),\n        \"application/json\"\n    );\n    assert_eq!(request.headers().get(\"accept\").unwrap(), \"application/json\");\n\n    let body: serde_json::Value = serde_json::from_slice(request.body()).unwrap();\n    assert_eq!(\n        body[\"grant_type\"],\n        \"urn:ietf:params:oauth:grant-type:device_code\"\n    );\n    assert_eq!(body[\"client_id\"], \"test-client-id\");\n    assert_eq!(body[\"device_code\"], \"device-code-123\");\n}\n\n#[test]\nfn poll_token_response_success() {\n    let mut auth = make_device_authorisation();\n    let resp_body = json!({\n        \"access_token\": \"access-token-abc\",\n        \"refresh_token\": \"refresh-token-xyz\"\n    });\n    let response = make_json_response(200, resp_body);\n\n    let result = auth.poll_token_response(response).unwrap();\n\n    match result {\n        crate::PollStep::Done(tokens) => {\n            assert_eq!(tokens.access_token, \"access-token-abc\");\n            assert_eq!(tokens.refresh_token, \"refresh-token-xyz\");\n        }\n        result => panic!(\"expected PollStep::Done, got {:?}\", result),\n    }\n}\n\n#[test]\nfn poll_token_response_authorization_pending() {\n    let mut auth = make_device_authorisation();\n    let resp_body = json!({\n        \"error\": \"authorization_pending\"\n    });\n    let response = make_json_response(200, resp_body);\n\n    let result = auth.poll_token_response(response).unwrap();\n\n    match result {\n        crate::PollStep::SleepThenPollAgain(duration) => {\n            assert_eq!(duration, std::time::Duration::from_secs(5));\n        }\n        result => panic!(\"expected PollStep::SleepThenPollAgain, got {:?}\", result),\n    }\n}\n\n#[test]\nfn poll_token_response_slow_down() {\n    let mut auth = make_device_authorisation();\n    let resp_body = json!({\n        \"error\": \"slow_down\"\n    });\n    let response = make_json_response(200, resp_body);\n\n    let result = auth.poll_token_response(response).unwrap();\n\n    match result {\n        crate::PollStep::SleepThenPollAgain(duration) => {\n            // Interval should be doubled from 5 to 10 seconds\n            assert_eq!(duration, std::time::Duration::from_secs(10));\n        }\n        result => panic!(\"expected PollStep::SleepThenPollAgain, got {:?}\", result),\n    }\n}\n\n#[test]\nfn poll_token_response_unexpected_status() {\n    let mut auth = make_device_authorisation();\n    let resp_body = json!({\n        \"message\": \"Internal server error\",\n        \"status\": 500,\n    });\n    let response = make_json_response(500, resp_body);\n\n    let result = auth.poll_token_response(response).unwrap_err();\n\n    match result {\n        ApiError::UnexpectedResponse(status, _) => {\n            assert_eq!(status, http::StatusCode::INTERNAL_SERVER_ERROR);\n        }\n        result => panic!(\"expected UnexpectedResponse, got {:?}\", result),\n    }\n}\n"
  },
  {
    "path": "hexpm/src/version/lexer.rs",
    "content": "//! Lexer for semver ranges.\n//!\n//! Breaks a string of input into an iterator of tokens that can be used with a parser.\n//!\n//! Based off https://github.com/steveklabnik/semver-parser/blob/bee9de80aaa9653c5eb46a83658606cb21151e65/src/lexer.rs\n//!\nuse self::Error::*;\nuse self::Token::*;\nuse std::str;\n\nmacro_rules! scan_while {\n    ($slf:expr, $start:expr, $first:pat_param $(| $rest:pat)*) => {{\n        let mut __end = $start;\n\n        loop {\n            if let Some((idx, c)) = $slf.one() {\n                __end = idx;\n\n                match c {\n                    $first $(| $rest)* => $slf.step(),\n                    _ => break,\n                }\n\n                continue;\n            } else {\n                __end = $slf.input.len();\n            }\n\n            break;\n        }\n\n        __end\n    }}\n}\n\n/// Semver tokens.\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\npub enum Token<'input> {\n    /// `==`\n    Eq,\n    /// `!=`\n    NotEq,\n    /// `>`\n    Gt,\n    /// `<`\n    Lt,\n    /// `<=`\n    LtEq,\n    /// `>=`\n    GtEq,\n    /// '~>`\n    Pessimistic,\n    /// `.`\n    Dot,\n    /// `-`\n    Hyphen,\n    /// `+`\n    Plus,\n    /// 'or'\n    Or,\n    /// 'and'\n    And,\n    /// any number of whitespace (`\\t\\r\\n `) and its span.\n    Whitespace(usize, usize),\n    /// Numeric component, like `0` or `42`.\n    Numeric(u32),\n    /// Alphanumeric component, like `alpha1` or `79deadbe`.\n    AlphaNumeric(&'input str),\n    /// An alphanumeric component with a leading zero, like `0alpha1` or `079deadbe`.\n    LeadingZero(&'input str),\n}\n\n#[cfg(test)]\nimpl<'input> Token<'input> {\n    /// Check if the current token is a whitespace token.\n    pub fn is_whitespace(&self) -> bool {\n        match *self {\n            Whitespace(..) => true,\n            _ => false,\n        }\n    }\n}\n\nimpl std::fmt::Display for Token<'_> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Eq => write!(f, \"==\"),\n            NotEq => write!(f, \"!=\"),\n            Gt => write!(f, \">\"),\n            Lt => write!(f, \"<\"),\n            LtEq => write!(f, \"<=\"),\n            GtEq => write!(f, \"<=\"),\n            Pessimistic => write!(f, \"~>\"),\n            Dot => write!(f, \".\"),\n            Hyphen => write!(f, \"-\"),\n            Plus => write!(f, \"+\"),\n            Or => write!(f, \"or\"),\n            And => write!(f, \"and\"),\n            Whitespace(_, _) => write!(f, \" \"),\n            Numeric(i) => write!(f, \"{i}\"),\n            AlphaNumeric(a) => write!(f, \"{a}\"),\n            LeadingZero(z) => write!(f, \"{z}\"),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, thiserror::Error)]\npub enum Error {\n    #[error(\"Unexpected character {0}\")]\n    UnexpectedChar(char),\n}\n\n/// Lexer for semver tokens belonging to a range.\n#[derive(Debug)]\npub struct Lexer<'input> {\n    input: &'input str,\n    chars: str::CharIndices<'input>,\n    // lookahead\n    c1: Option<(usize, char)>,\n    c2: Option<(usize, char)>,\n}\n\nimpl<'input> Lexer<'input> {\n    /// Construct a new lexer for the given input.\n    pub fn new(input: &str) -> Lexer<'_> {\n        let mut chars = input.char_indices();\n        let c1 = chars.next();\n        let c2 = chars.next();\n\n        Lexer {\n            input,\n            chars,\n            c1,\n            c2,\n        }\n    }\n\n    /// Shift all lookahead storage by one.\n    fn step(&mut self) {\n        self.c1 = self.c2;\n        self.c2 = self.chars.next();\n    }\n\n    fn step_n(&mut self, n: usize) {\n        for _ in 0..n {\n            self.step();\n        }\n    }\n\n    /// Access the one character, or set it if it is not set.\n    fn one(&mut self) -> Option<(usize, char)> {\n        self.c1\n    }\n\n    /// Access two characters.\n    fn two(&mut self) -> Option<(usize, char, char)> {\n        self.c1\n            .and_then(|(start, c1)| self.c2.map(|(_, c2)| (start, c1, c2)))\n    }\n\n    /// Consume a component.\n    ///\n    /// A component can either be an alphanumeric or numeric.\n    /// Does not permit leading zeroes.\n    fn component(&mut self, start: usize) -> Result<Token<'input>, Error> {\n        let end = scan_while!(self, start, '0'..='9' | 'A'..='Z' | 'a'..='z');\n        let input = &self.input[start..end];\n\n        let mut it = input.chars();\n        let (a, b) = (it.next(), it.next());\n\n        // exactly zero\n        if a == Some('0') && b.is_none() {\n            return Ok(Numeric(0));\n        }\n\n        if let Ok(numeric) = input.parse::<u32>() {\n            // Only parse as a number if there is no leading zero\n            if a != Some('0') {\n                return Ok(Numeric(numeric));\n            } else {\n                return Ok(LeadingZero(input));\n            }\n        }\n\n        Ok(AlphaNumeric(input))\n    }\n\n    fn and(&mut self, start: usize) -> Result<Token<'input>, Error> {\n        match self.one() {\n            Some((_, 'd')) => {\n                self.step();\n                Ok(And)\n            }\n            _ => self.component(start),\n        }\n    }\n\n    /// Consume whitespace.\n    fn whitespace(&mut self, start: usize) -> Result<Token<'input>, Error> {\n        let end = scan_while!(self, start, ' ' | '\\t' | '\\n' | '\\r');\n        Ok(Whitespace(start, end))\n    }\n}\n\nimpl<'input> Iterator for Lexer<'input> {\n    type Item = Result<Token<'input>, Error>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        #[allow(clippy::never_loop)]\n        loop {\n            // two subsequent char tokens.\n            if let Some((start, a, b)) = self.two() {\n                let two = match (a, b) {\n                    ('~', '>') => Some(Pessimistic),\n                    ('!', '=') => Some(NotEq),\n                    ('<', '=') => Some(LtEq),\n                    ('>', '=') => Some(GtEq),\n                    ('=', '=') => Some(Eq),\n                    ('o', 'r') => Some(Or),\n                    ('a', 'n') => {\n                        self.step_n(2);\n                        return Some(self.and(start));\n                    }\n                    _ => None,\n                };\n\n                if let Some(two) = two {\n                    self.step_n(2);\n                    return Some(Ok(two));\n                }\n            }\n\n            // single char and start of numeric tokens.\n            if let Some((start, c)) = self.one() {\n                let tok = match c {\n                    ' ' | '\\t' | '\\n' | '\\r' => {\n                        self.step();\n                        return Some(self.whitespace(start));\n                    }\n                    '>' => Gt,\n                    '<' => Lt,\n                    '.' => Dot,\n                    '-' => Hyphen,\n                    '+' => Plus,\n                    '0'..='9' | 'a'..='z' | 'A'..='Z' => {\n                        self.step();\n                        return Some(self.component(start));\n                    }\n                    c => return Some(Err(UnexpectedChar(c))),\n                };\n\n                self.step();\n                return Some(Ok(tok));\n            };\n\n            return None;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn lex(input: &str) -> Vec<Token<'_>> {\n        Lexer::new(input).map(Result::unwrap).collect::<Vec<_>>()\n    }\n\n    #[test]\n    pub fn simple_tokens() {\n        assert_eq!(\n            lex(\"!===><<=>=~>.-+orand\"),\n            vec![\n                NotEq,\n                Eq,\n                Gt,\n                Lt,\n                LtEq,\n                GtEq,\n                Pessimistic,\n                Dot,\n                Hyphen,\n                Plus,\n                Or,\n                And\n            ]\n        );\n    }\n\n    #[test]\n    pub fn whitespace() {\n        assert_eq!(\n            lex(\"  foo \\t\\n\\rbar\"),\n            vec![\n                Whitespace(0, 2),\n                AlphaNumeric(\"foo\"),\n                Whitespace(5, 9),\n                AlphaNumeric(\"bar\"),\n            ]\n        );\n    }\n\n    #[test]\n    pub fn components() {\n        assert_eq!(lex(\"42\"), vec![Numeric(42)]);\n        assert_eq!(lex(\"0\"), vec![Numeric(0)]);\n        assert_eq!(lex(\"5885644aa\"), vec![AlphaNumeric(\"5885644aa\")]);\n        assert_eq!(lex(\"beta2\"), vec![AlphaNumeric(\"beta2\")]);\n        assert_eq!(lex(\"beta.2\"), vec![AlphaNumeric(\"beta\"), Dot, Numeric(2)]);\n    }\n\n    #[test]\n    pub fn empty() {\n        assert_eq!(lex(\"\"), vec![]);\n    }\n\n    #[test]\n    pub fn numeric_all_numbers() {\n        let expected: Vec<Token> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n            .into_iter()\n            .map(Numeric)\n            .collect::<Vec<_>>();\n\n        let actual: Vec<_> = lex(\"0 1 2 3 4 5 6 7 8 9\")\n            .into_iter()\n            .filter(|t| !t.is_whitespace())\n            .collect();\n\n        assert_eq!(actual, expected);\n    }\n}\n"
  },
  {
    "path": "hexpm/src/version/parser.rs",
    "content": "// Based off of https://github.com/steveklabnik/semver-parser/blob/bee9de80aaa9653c5eb46a83658606cb21151e65/src/parser.rs\n\nuse std::fmt;\nuse std::mem;\n\nuse self::Error::*;\nuse super::lexer::{self, Lexer, Token};\nuse crate::version::{Identifier, Version};\nuse thiserror::Error;\n\ntype PubgrubRange = pubgrub::Range<Version>;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Error)]\npub enum Error {\n    /// Needed more tokens for parsing, but none are available.\n    UnexpectedEnd,\n    /// Unexpected token.\n    UnexpectedToken(String),\n    /// An error occurred in the lexer.\n    Lexer(lexer::Error),\n    /// More input available.\n    MoreInput(String),\n    /// Encountered empty predicate in a set of predicates.\n    EmptyPredicate,\n    /// Encountered an empty range.\n    EmptyRange,\n    /// Encountered a semver that's missing the minor and patch version.\n    MinorVersionMissing(u32),\n    /// Encountered a semver that's missing the patch version.\n    PatchVersionMissing(u32, u32),\n}\n\nimpl From<lexer::Error> for Error {\n    fn from(value: lexer::Error) -> Self {\n        Error::Lexer(value)\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\n        use self::Error::*;\n\n        match *self {\n            UnexpectedEnd => write!(fmt, \"expected more input\"),\n            UnexpectedToken(ref token) => write!(fmt, \"encountered unexpected token: {token:?}\"),\n            Lexer(ref error) => write!(fmt, \"lexer error: {error:?}\"),\n            MoreInput(ref tokens) => write!(fmt, \"expected end of input, but got: {tokens:?}\"),\n            EmptyPredicate => write!(fmt, \"encountered empty predicate\"),\n            EmptyRange => write!(fmt, \"encountered empty range\"),\n            MinorVersionMissing(major) => {\n                write!(fmt, \"missing minor and patch versions: {major:?}\")\n            }\n            PatchVersionMissing(major, minor) => {\n                write!(fmt, \"missing patch version: {major:?}.{minor:?}\")\n            }\n        }\n    }\n}\n\n/// impl for backwards compatibility.\nimpl From<Error> for String {\n    fn from(value: Error) -> Self {\n        value.to_string()\n    }\n}\n\n/// A recursive-descent parser for parsing version requirements.\npub struct Parser<'input> {\n    /// Source of token.\n    lexer: Lexer<'input>,\n    /// Lookaehead.\n    c1: Option<Token<'input>>,\n}\n\nimpl<'input> Parser<'input> {\n    /// Construct a new parser for the given input.\n    pub fn new(input: &'input str) -> Result<Parser<'input>, Error> {\n        let mut lexer = Lexer::new(input);\n\n        let c1 = if let Some(c1) = lexer.next() {\n            Some(c1?)\n        } else {\n            None\n        };\n\n        Ok(Parser { lexer, c1 })\n    }\n\n    /// Pop one token.\n    #[inline(always)]\n    fn pop(&mut self) -> Result<Token<'input>, Error> {\n        let c1 = if let Some(c1) = self.lexer.next() {\n            Some(c1?)\n        } else {\n            None\n        };\n\n        mem::replace(&mut self.c1, c1).ok_or(UnexpectedEnd)\n    }\n\n    /// Peek one token.\n    #[inline(always)]\n    fn peek(&mut self) -> Option<&Token<'input>> {\n        self.c1.as_ref()\n    }\n\n    /// Skip whitespace if present.\n    fn skip_whitespace(&mut self) -> Result<(), Error> {\n        match self.peek() {\n            Some(&Token::Whitespace(_, _)) => self.pop().map(|_| ()),\n            _ => Ok(()),\n        }\n    }\n\n    /// Check that some whitespace is next and then discard it\n    fn expect_whitespace(&mut self) -> Result<(), Error> {\n        match self.pop()? {\n            Token::Whitespace(_, _) => Ok(()),\n            token => Err(UnexpectedToken(token.to_string())),\n        }\n    }\n\n    /// Parse a single numeric.\n    pub fn numeric(&mut self) -> Result<u32, Error> {\n        match self.pop()? {\n            Token::Numeric(number) => Ok(number),\n            token => Err(UnexpectedToken(token.to_string())),\n        }\n    }\n\n    fn dot(&mut self) -> Result<(), Error> {\n        match self.pop()? {\n            Token::Dot => Ok(()),\n            token => Err(UnexpectedToken(token.to_string())),\n        }\n    }\n\n    /// Parse a dot, then a numeric.\n    fn dot_numeric(&mut self) -> Result<u32, Error> {\n        self.dot()?;\n        self.numeric()\n    }\n\n    /// Parse an string identifier.\n    ///\n    /// Like, `foo`, or `bar`, or `beta-1`.\n    pub fn identifier(&mut self) -> Result<Identifier, Error> {\n        let identifier = match self.pop()? {\n            Token::AlphaNumeric(identifier) => {\n                // TODO: Borrow?\n                Identifier::AlphaNumeric(identifier.to_string())\n            }\n            Token::Numeric(n) => Identifier::Numeric(n),\n            tok => return Err(UnexpectedToken(tok.to_string())),\n        };\n\n        if let Some(&Token::Hyphen) = self.peek() {\n            // pop the peeked hyphen\n            self.pop()?;\n            // concat with any following identifiers\n            Ok(identifier\n                .concat(\"-\")\n                .concat(&self.identifier()?.to_string()))\n        } else {\n            Ok(identifier)\n        }\n    }\n\n    /// Parse all pre-release identifiers, separated by dots.\n    ///\n    /// Like, `abcdef.1234`.\n    fn pre(&mut self) -> Result<Vec<Identifier>, Error> {\n        match self.peek() {\n            Some(&Token::Hyphen) => {}\n            _ => return Ok(vec![]),\n        }\n\n        // pop the peeked hyphen.\n        self.pop()?;\n        self.parts()\n    }\n\n    /// Parse a dot-separated set of identifiers.\n    fn parts(&mut self) -> Result<Vec<Identifier>, Error> {\n        let mut parts = Vec::new();\n\n        parts.push(self.identifier()?);\n\n        while let Some(&Token::Dot) = self.peek() {\n            self.pop()?;\n\n            parts.push(self.identifier()?);\n        }\n\n        Ok(parts)\n    }\n\n    /// Parse optional build metadata.\n    ///\n    /// Like, `` (empty), or `+abcdef`.\n    fn plus_build_metadata(&mut self) -> Result<Option<String>, Error> {\n        match self.peek() {\n            Some(&Token::Plus) => self.pop()?,\n            _ => return Ok(None),\n        };\n\n        let mut buffer = String::new();\n\n        loop {\n            match self.pop() {\n                Err(UnexpectedEnd) => break,\n                Ok(Token::LeadingZero(s)) => buffer.push_str(s),\n                Ok(Token::AlphaNumeric(s)) => buffer.push_str(s),\n                Ok(Token::Numeric(s)) => buffer.push_str(&s.to_string()),\n                Ok(Token::Dot) => buffer.push('.'),\n                Ok(token) => return Err(UnexpectedToken(token.to_string())),\n                Err(error) => return Err(error),\n            }\n        }\n\n        if buffer.is_empty() {\n            Err(UnexpectedEnd)\n        } else {\n            Ok(Some(buffer))\n        }\n    }\n\n    /// Parse a version.\n    ///\n    /// Like, `1.0.0` or `3.0.0-beta.1`.\n    pub fn version(&mut self) -> Result<Version, Error> {\n        self.skip_whitespace()?;\n\n        let major = self.numeric()?;\n        let minor = self\n            .dot_numeric()\n            .map_err(|_| Error::MinorVersionMissing(major))?;\n        let patch = self\n            .dot_numeric()\n            .map_err(|_| Error::PatchVersionMissing(major, minor))?;\n        let pre = self.pre()?;\n        let build = self.plus_build_metadata()?;\n\n        self.skip_whitespace()?;\n\n        Ok(Version {\n            major,\n            minor,\n            patch,\n            pre,\n            build,\n        })\n    }\n\n    /// Parse a version range requirement.\n    ///\n    /// Like, `~> 1.0.0` or `3.0.0-beta.1 or < 1.0 and > 0.2.3`.\n    pub fn range(&mut self) -> Result<PubgrubRange, Error> {\n        let mut range: Option<PubgrubRange> = None;\n\n        loop {\n            let constraint = self.range_ands_section()?;\n            range = Some(match range {\n                None => constraint,\n                Some(range) => range.union(&constraint),\n            });\n            if self.peek() == Some(&Token::Or) {\n                self.pop()?;\n                self.expect_whitespace()?;\n            } else {\n                break;\n            }\n        }\n\n        self.skip_whitespace()?;\n        range.ok_or(UnexpectedEnd)\n    }\n\n    fn pessimistic_version_constraint(&mut self) -> Result<PubgrubRange, Error> {\n        let mut included_patch = false;\n        let major = self.numeric()?;\n        let minor = self.dot_numeric()?;\n        let patch = match self.peek() {\n            Some(Token::Dot) => {\n                included_patch = true;\n                self.pop()?;\n                self.numeric()?\n            }\n            _ => 0,\n        };\n        let pre = self.pre()?;\n        let build = self.plus_build_metadata()?;\n\n        let lower = Version {\n            major,\n            minor,\n            patch,\n            pre,\n            build,\n        };\n        let upper = if included_patch {\n            lower.bump_minor()\n        } else {\n            lower.bump_major()\n        };\n        Ok(\n            PubgrubRange::higher_than(lower)\n                .intersection(&PubgrubRange::strictly_lower_than(upper)),\n        )\n    }\n\n    fn range_ands_section(&mut self) -> Result<PubgrubRange, Error> {\n        use Token::*;\n        let mut range = None;\n        let and = |range: Option<PubgrubRange>, constraint: PubgrubRange| {\n            Some(match range {\n                None => constraint,\n                Some(range) => range.intersection(&constraint),\n            })\n        };\n        loop {\n            self.skip_whitespace()?;\n            match self.peek() {\n                None => break,\n                Some(Numeric(_)) => range = and(range, PubgrubRange::singleton(self.version()?)),\n\n                Some(Eq) => {\n                    self.pop()?;\n                    range = and(range, PubgrubRange::singleton(self.version()?));\n                }\n\n                Some(NotEq) => {\n                    self.pop()?;\n                    let version = self.version()?;\n                    let bumped = version.bump_patch();\n                    let below = PubgrubRange::strictly_lower_than(version);\n                    let above = PubgrubRange::higher_than(bumped);\n                    range = and(range, below.union(&above));\n                }\n\n                Some(Gt) => {\n                    self.pop()?;\n                    range = and(\n                        range,\n                        PubgrubRange::higher_than(self.version()?.bump_patch()),\n                    );\n                }\n\n                Some(GtEq) => {\n                    self.pop()?;\n                    range = and(range, PubgrubRange::higher_than(self.version()?));\n                }\n\n                Some(Lt) => {\n                    self.pop()?;\n                    range = and(range, PubgrubRange::strictly_lower_than(self.version()?));\n                }\n\n                Some(LtEq) => {\n                    self.pop()?;\n                    range = and(\n                        range,\n                        PubgrubRange::strictly_lower_than(self.version()?.bump_patch()),\n                    );\n                }\n\n                Some(Pessimistic) => {\n                    self.pop()?;\n                    self.skip_whitespace()?;\n                    range = and(range, self.pessimistic_version_constraint()?);\n                }\n\n                Some(_) => return Err(UnexpectedToken(self.pop()?.to_string())),\n            };\n\n            self.skip_whitespace()?;\n            if self.peek() == Some(&Token::And) {\n                self.pop()?;\n                self.expect_whitespace()?;\n            } else {\n                break;\n            }\n        }\n        self.skip_whitespace()?;\n        range.ok_or(UnexpectedEnd)\n    }\n\n    /// Check if we have reached the end of input.\n    pub fn is_eof(&mut self) -> bool {\n        self.c1.is_none()\n    }\n\n    /// Get the rest of the tokens in the parser.\n    ///\n    /// Useful for debugging.\n    pub fn tail(&mut self) -> Result<Vec<Token<'input>>, Error> {\n        let mut out = Vec::new();\n\n        if let Some(t) = self.c1.take() {\n            out.push(t);\n        }\n\n        for t in self.lexer.by_ref() {\n            out.push(t?);\n        }\n\n        Ok(out)\n    }\n}\n"
  },
  {
    "path": "hexpm/src/version/tests.rs",
    "content": "use std::cmp::Ordering::{Equal, Greater, Less};\nuse std::collections::HashMap;\n\nuse parser::Error;\n\nuse super::{\n    Identifier::{AlphaNumeric, Numeric},\n    *,\n};\n\n// Tests adapted from the tests for Elixir's version module\n\nmacro_rules! version_parse_test {\n    ($name:ident, $input:expr, $major:expr, $minor:expr, $patch:expr,$pre:expr, $build:expr) => {\n        #[test]\n        fn $name() {\n            assert_eq!(\n                Version::parse($input).unwrap(),\n                Version {\n                    major: $major,\n                    minor: $minor,\n                    patch: $patch,\n                    pre: $pre,\n                    build: $build\n                }\n            );\n        }\n    };\n\n    ($name:ident, $input:expr, $major:expr, $minor:expr, $patch:expr, $pre:expr) => {\n        #[test]\n        fn $name() {\n            assert_eq!(\n                Version::parse($input).unwrap(),\n                Version {\n                    major: $major,\n                    minor: $minor,\n                    patch: $patch,\n                    pre: $pre,\n                    build: None\n                }\n            );\n        }\n    };\n\n    ($name:ident, $input:expr, $major:expr, $minor:expr, $patch:expr) => {\n        #[test]\n        fn $name() {\n            assert_eq!(\n                Version::parse($input).unwrap(),\n                Version {\n                    major: $major,\n                    minor: $minor,\n                    patch: $patch,\n                    pre: vec![],\n                    build: None\n                }\n            );\n        }\n    };\n}\n\nmacro_rules! version_parse_fail_test {\n    ($name:ident, $input:expr) => {\n        #[test]\n        fn $name() {\n            println!(\"{}\", $input);\n            Version::parse($input).unwrap_err();\n        }\n    };\n}\n\nmacro_rules! version_parse_print {\n    ($name:ident, $input:expr) => {\n        #[test]\n        fn $name() {\n            assert_eq!($input, Version::parse($input).unwrap().to_string().as_str());\n        }\n    };\n}\n\nversion_parse_test!(triplet, \"1.2.3\", 1, 2, 3);\n\nversion_parse_test!(\n    build,\n    \"1.4.5+ignore\",\n    1,\n    4,\n    5,\n    vec![],\n    Some(\"ignore\".to_string())\n);\n\nversion_parse_test!(\n    two_part_build,\n    \"0.0.1+sha.0702245\",\n    0,\n    0,\n    1,\n    vec![],\n    Some(\"sha.0702245\".to_string())\n);\n\nversion_parse_test!(\n    pre,\n    \"1.4.5-6-g3318bd5\",\n    1,\n    4,\n    5,\n    vec![AlphaNumeric(\"6-g3318bd5\".to_string())]\n);\n\nversion_parse_test!(\n    multi_part_pre,\n    \"1.4.5-6.7.eight\",\n    1,\n    4,\n    5,\n    vec![Numeric(6), Numeric(7), AlphaNumeric(\"eight\".to_string())]\n);\n\nversion_parse_test!(\n    pre_and_build,\n    \"1.4.5-6-g3318bd5+ignore\",\n    1,\n    4,\n    5,\n    vec![AlphaNumeric(\"6-g3318bd5\".to_string())],\n    Some(\"ignore\".to_string())\n);\n\nversion_parse_fail_test!(just_a_word, \"foobar\");\n\nversion_parse_fail_test!(just_major, \"2\");\n\nversion_parse_fail_test!(major_dor, \"2.\");\n\nversion_parse_fail_test!(major_minor, \"2.3\");\n\nversion_parse_fail_test!(major_minor_dot, \"2.3.\");\n\nversion_parse_fail_test!(triplet_dash, \"2.3.0-\");\n\nversion_parse_fail_test!(triplet_plus, \"2.3.0+\");\n\nversion_parse_fail_test!(triplet_dot, \"2.3.0.\");\n\nversion_parse_fail_test!(quad, \"2.3.0.4\");\n\nversion_parse_fail_test!(missing_minor, \"2.3.-rc.1\");\n\nversion_parse_fail_test!(missing_minor_with_dot, \"2.3.+rc.1\");\n\nversion_parse_fail_test!(zero_pre, \"2.3.0-01\");\n\nversion_parse_fail_test!(double_zero_pre, \"2.3.00-1\");\n\nversion_parse_fail_test!(double_zero, \"2.3.00\");\n\nversion_parse_fail_test!(leading_zero_minor, \"2.03.0\");\n\nversion_parse_fail_test!(leading_zero_major, \"02.3.0\");\n\nversion_parse_fail_test!(extra_whitespace, \"0. 0.0\");\n\nversion_parse_fail_test!(and_in_version, \"0.1.0-andpre\");\n\nversion_parse_print!(print_triplet, \"1.100.1000\");\n\nversion_parse_print!(print_pre, \"1.100.4-dev\");\n\nversion_parse_print!(print_pre_dot, \"1.100.4-dev.1.r.t\");\n\nversion_parse_print!(print_build, \"1.100.4+dev.1.r.t\");\n\nversion_parse_print!(print_pre_build, \"1.100.4-ewfjhwefj.wefw.w.1.ff+dev.1.r.t\");\n\nmacro_rules! parse_range_test {\n    ($name:ident, $input:expr, $expected:expr) => {\n        #[test]\n        fn $name() {\n            assert_eq!(Version::parse_range($input).unwrap(), $expected);\n        }\n    };\n}\n\nmacro_rules! parse_range_fail_test {\n    ($name:ident, $input:expr) => {\n        #[test]\n        fn $name() {\n            Version::parse_range($input).unwrap_err();\n        }\n    };\n}\n\nfn v(a: u32, b: u32, c: u32) -> Version {\n    Version::new(a, b, c)\n}\n\nfn v_(major: u32, minor: u32, patch: u32, pre: Vec<Identifier>, build: Option<String>) -> Version {\n    Version {\n        major,\n        minor,\n        patch,\n        pre,\n        build,\n    }\n}\n\ntype PubgrubRange = pubgrub::Range<Version>;\n\nparse_range_test!(leading_space, \" 1.2.3\", PubgrubRange::singleton(v(1, 2, 3)));\nparse_range_test!(\n    trailing_space,\n    \"1.2.3 \",\n    PubgrubRange::singleton(v(1, 2, 3))\n);\n\nparse_range_test!(eq_triplet, \"== 1.2.3 \", PubgrubRange::singleton(v(1, 2, 3)));\n\nparse_range_test!(\n    eq_triplet_nospace,\n    \"==1.2.3 \",\n    PubgrubRange::singleton(v(1, 2, 3))\n);\n\nparse_range_test!(\n    neq_triplet,\n    \"!= 1.2.3\",\n    PubgrubRange::strictly_lower_than(v(1, 2, 3)).union(&PubgrubRange::higher_than(v(1, 2, 4)))\n);\n\nparse_range_test!(implicit_eq, \"2.2.3\", PubgrubRange::singleton(v(2, 2, 3)));\n\nparse_range_test!(\n    range_pre_build,\n    \"1.2.3-thing+oop\",\n    PubgrubRange::singleton(v_(\n        1,\n        2,\n        3,\n        vec![Identifier::AlphaNumeric(\"thing\".to_string())],\n        Some(\"oop\".to_string())\n    ))\n);\n\nparse_range_test!(\n    and,\n    \"< 1.2.3 and > 1.0.1\",\n    PubgrubRange::strictly_lower_than(v(1, 2, 3))\n        .intersection(&PubgrubRange::higher_than(v(1, 0, 2)))\n);\n\nparse_range_test!(\n    or,\n    \"< 1.2.3 or > 1.0.1\",\n    PubgrubRange::strictly_lower_than(v(1, 2, 3)).union(&PubgrubRange::higher_than(v(1, 0, 2)))\n);\n\nparse_range_test!(gt, \"> 1.0.0\", PubgrubRange::higher_than(v(1, 0, 1)));\nparse_range_test!(gt_eq, \">= 1.0.0\", PubgrubRange::higher_than(v(1, 0, 0)));\nparse_range_test!(lt, \"< 1.0.0\", PubgrubRange::strictly_lower_than(v(1, 0, 0)));\nparse_range_test!(\n    lt_eq,\n    \"<= 1.0.0\",\n    PubgrubRange::strictly_lower_than(v(1, 0, 1))\n);\n\nparse_range_test!(\n    pessimistic_pair,\n    \"~> 2.2\",\n    PubgrubRange::higher_than(v(2, 2, 0))\n        .intersection(&PubgrubRange::strictly_lower_than(v(3, 0, 0)))\n);\n\nparse_range_test!(\n    pessimistic_triplet,\n    \"~> 4.6.5\",\n    PubgrubRange::higher_than(v(4, 6, 5))\n        .intersection(&PubgrubRange::strictly_lower_than(v(4, 7, 0)))\n);\n\nparse_range_test!(\n    pessimistic_triplet_pre,\n    \"~> 4.6.5-eee\",\n    PubgrubRange::higher_than(v_(\n        4,\n        6,\n        5,\n        vec![Identifier::AlphaNumeric(\"eee\".to_string())],\n        None,\n    ))\n    .intersection(&PubgrubRange::strictly_lower_than(v(4, 7, 0)))\n);\n\nparse_range_test!(\n    pessimistic_triplet_build,\n    \"~> 4.6.5+eee\",\n    PubgrubRange::higher_than(v_(4, 6, 5, vec![], Some(\"eee\".to_string())))\n        .intersection(&PubgrubRange::strictly_lower_than(v(4, 7, 0)))\n);\n\nparse_range_test!(\n    greater_or_pessimistic,\n    \"> 10.0.0 or ~> 3.0.0\",\n    PubgrubRange::higher_than(v(10, 0, 1)).union(\n        &PubgrubRange::higher_than(v(3, 0, 0))\n            .intersection(&PubgrubRange::strictly_lower_than(v(3, 1, 0)))\n    )\n);\n\nparse_range_test!(\n    pessimistic_or_pessimistic,\n    \"~> 1.0.0 or ~> 3.0.0\",\n    PubgrubRange::higher_than(v(1, 0, 0))\n        .intersection(&PubgrubRange::strictly_lower_than(v(1, 1, 0)))\n        .union(\n            &PubgrubRange::higher_than(v(3, 0, 0))\n                .intersection(&PubgrubRange::strictly_lower_than(v(3, 1, 0)))\n        )\n);\n\nparse_range_test!(\n    pessimistic_and_gt,\n    \"~> 0.6 and >= 0.6.16\",\n    PubgrubRange::higher_than(v(0, 6, 0))\n        .intersection(&PubgrubRange::strictly_lower_than(v(1, 0, 0)))\n        .intersection(&PubgrubRange::higher_than(v(0, 6, 16)))\n);\n\nparse_range_test!(\n    pessimistic_and_gt_pre,\n    \"~> 1.0-pre and >= 1.0.0-pre.5\",\n    PubgrubRange::higher_than(v_(\n        1,\n        0,\n        0,\n        vec![Identifier::AlphaNumeric(\"pre\".to_string())],\n        None\n    ))\n    .intersection(&PubgrubRange::strictly_lower_than(v(2, 0, 0)))\n    .intersection(&PubgrubRange::higher_than(v_(\n        1,\n        0,\n        0,\n        vec![\n            Identifier::AlphaNumeric(\"pre\".to_string()),\n            Identifier::Numeric(5)\n        ],\n        None\n    )))\n);\n\nparse_range_fail_test!(range_quad, \"1.1.1.1\");\nparse_range_fail_test!(range_just_major, \"1\");\nparse_range_fail_test!(range_just_major_minor, \"1.1\");\nparse_range_fail_test!(alpha_component, \"1.1.a\");\n\nparse_range_fail_test!(range_word, \"foobar\");\nparse_range_fail_test!(range_major_dot, \"2.\");\nparse_range_fail_test!(range_major_minor_dot, \"2.3.\");\nparse_range_fail_test!(range_triplet_dash, \"2.3.0-\");\nparse_range_fail_test!(range_triplet_plus, \"2.3.0+\");\nparse_range_fail_test!(range_triplet_dot, \"2.3.0.\");\nparse_range_fail_test!(range_dot_dash, \"2.3.-rc.1\");\nparse_range_fail_test!(range_dot_plus, \"2.3.+rc.1\");\nparse_range_fail_test!(range_zero_pre, \"2.3.0-01\");\nparse_range_fail_test!(patch_zerozero_dash, \"2.3.00-1\");\nparse_range_fail_test!(patch_zerozero, \"2.3.00\");\nparse_range_fail_test!(minor_leading_zero, \"2.03.0\");\nparse_range_fail_test!(major_leading_zero, \"02.3.0\");\nparse_range_fail_test!(triplet_containing_whitespace, \"0. 0.0\");\nparse_range_fail_test!(dash_amp, \"0.1.0-&&pre\");\n\nparse_range_fail_test!(or_whitespace_before, \"!= 1.2.3or == 1.0.1\");\nparse_range_fail_test!(or_whitespace_after, \"!= 1.2.3 or== 1.0.1\");\nparse_range_fail_test!(and_whitespace_before, \"!= 1.2.3and == 1.0.1\");\nparse_range_fail_test!(and_whitespace_after, \"!= 1.2.3 and== 1.0.1\");\n\nparse_range_fail_test!(trailing_and, \"1.1.1 and\");\nparse_range_fail_test!(trailing_or, \"1.1.1 or\");\nparse_range_fail_test!(leading_and, \"and 1.1.1\");\nparse_range_fail_test!(leading_or, \"and 1.1.1\");\nparse_range_fail_test!(just_and, \"and\");\nparse_range_fail_test!(just_or, \"and\");\n\nparse_range_fail_test!(duplicate_eq, \"== ==\");\nparse_range_fail_test!(just_eq, \"==\");\nparse_range_fail_test!(empty, \"\");\n\nparse_range_fail_test!(pessimistic_major, \"~> 1\");\n\nmacro_rules! assert_order {\n    ($name:ident, $left:expr, $ord:expr, $right:expr) => {\n        #[test]\n        fn $name() {\n            let left = Version::parse($left);\n            let right = Version::parse($right);\n            assert_eq!(left.cmp(&right), $ord)\n        }\n    };\n}\n\nassert_order!(ord_same, \"1.0.0\", Equal, \"1.0.0\");\nassert_order!(ord_same_build_right, \"1.0.0\", Equal, \"1.0.0+1\");\nassert_order!(ord_same_build_left, \"1.0.0+1\", Equal, \"1.0.0\");\nassert_order!(ord_same_diff_build, \"1.0.0+1\", Equal, \"1.0.0+2\");\n\nassert_order!(ord_diff_build, \"1.0.0+2\", Equal, \"1.0.0+1\");\n\nassert_order!(ord_major_greater, \"3.0.0\", Greater, \"2.0.0\");\nassert_order!(ord_major_lesser, \"1.0.0\", Less, \"2.0.0\");\n\nassert_order!(ord_minor_greater, \"1.1.0\", Greater, \"1.0.0\");\nassert_order!(ord_minor_lesser, \"1.0.0\", Less, \"1.1.0\");\n\nassert_order!(ord_patch_greater, \"1.0.1\", Greater, \"1.0.0\");\nassert_order!(ord_patch_lesser, \"1.0.0\", Less, \"1.0.1\");\n\nassert_order!(ord_pre_smaller_than_zero, \"1.0.0\", Greater, \"1.0.0-rc1\");\nassert_order!(ord_pre_smaller_than_zero_flip, \"1.0.0-rc1\", Less, \"1.0.0\");\n\nassert_order!(ord_pre_rc1_2, \"1.0.0-rc1\", Less, \"1.0.0-rc2\");\n\n#[test]\nfn manifest_toml() {\n    let manifest = toml::to_string(\n        &vec![\n            (\n                \"gleam_stdlib\".to_string(),\n                Version {\n                    major: 0,\n                    minor: 17,\n                    patch: 1,\n                    pre: vec![],\n                    build: None,\n                },\n            ),\n            (\n                \"thingy\".to_string(),\n                Version {\n                    major: 0,\n                    minor: 1,\n                    patch: 0,\n                    pre: vec![],\n                    build: None,\n                },\n            ),\n        ]\n        .into_iter()\n        .collect::<HashMap<String, Version>>(),\n    )\n    .unwrap();\n    let expected1 = r#\"thingy = \"0.1.0\"\ngleam_stdlib = \"0.17.1\"\n\"#;\n    let expected2 = r#\"gleam_stdlib = \"0.17.1\"\nthingy = \"0.1.0\"\n\"#;\n    assert!(manifest == expected1 || manifest == expected2);\n}\n\n#[test]\nfn missing_minor_has_correct_error_type() {\n    assert_eq!(Version::parse(\"1\"), Err(Error::MinorVersionMissing(1)))\n}\n\n#[test]\nfn missing_patch_has_correct_error_type() {\n    assert_eq!(Version::parse(\"1.2\"), Err(Error::PatchVersionMissing(1, 2)))\n}\n"
  },
  {
    "path": "hexpm/src/version.rs",
    "content": "//! Functions for parsing and matching versions against requirements, based off\n//! and compatible with the Elixir Version module, which is used by Hex\n//! internally as well as be the Elixir build tool Hex client.\n\nuse std::{cmp::Ordering, convert::TryFrom, fmt};\n\nuse self::parser::Parser;\nuse serde::{\n    Deserialize, Serialize,\n    de::{self, Deserializer, Visitor},\n};\n\nmod lexer;\nmod parser;\n#[cfg(test)]\nmod tests;\n\n/// In a nutshell, a version is represented by three numbers:\n///\n/// MAJOR.MINOR.PATCH\n///\n/// Pre-releases are supported by optionally appending a hyphen and a series of\n/// period-separated identifiers immediately following the patch version.\n/// Identifiers consist of only ASCII alphanumeric characters and hyphens (`[0-9A-Za-z-]`):\n///\n/// \"1.0.0-alpha.3\"\n///\n/// Build information can be added by appending a plus sign and a series of\n/// dot-separated identifiers immediately following the patch or pre-release version.\n/// Identifiers consist of only ASCII alphanumeric characters and hyphens (`[0-9A-Za-z-]`):\n///\n/// \"1.0.0-alpha.3+20130417140000.amd64\"\n///\n#[derive(Clone, Debug, PartialEq, Eq, Hash)]\npub struct Version {\n    pub major: u32,\n    pub minor: u32,\n    pub patch: u32,\n    pub pre: Vec<Identifier>,\n    pub build: Option<String>,\n}\n\nimpl Version {\n    pub fn new(major: u32, minor: u32, patch: u32) -> Self {\n        Self {\n            major,\n            minor,\n            patch,\n            pre: vec![],\n            build: None,\n        }\n    }\n\n    fn bump_major(&self) -> Self {\n        Self {\n            major: self.major + 1,\n            minor: 0,\n            patch: 0,\n            pre: vec![],\n            build: None,\n        }\n    }\n\n    fn bump_minor(&self) -> Self {\n        Self {\n            major: self.major,\n            minor: self.minor + 1,\n            patch: 0,\n            pre: vec![],\n            build: None,\n        }\n    }\n\n    fn bump_patch(&self) -> Self {\n        Self {\n            major: self.major,\n            minor: self.minor,\n            patch: self.patch + 1,\n            pre: vec![],\n            build: None,\n        }\n    }\n\n    /// Parse a version.\n    pub fn parse(input: &str) -> Result<Self, parser::Error> {\n        let mut parser = Parser::new(input)?;\n        let version = parser.version()?;\n        if !parser.is_eof() {\n            return Err(parser::Error::MoreInput(\n                parser\n                    .tail()?\n                    .into_iter()\n                    .map(|t| t.to_string())\n                    .collect::<Vec<_>>()\n                    .join(\"\"),\n            ));\n        }\n        Ok(version)\n    }\n\n    /// Parse a Hex compatible version range. i.e. `> 1 and < 2 or == 4.5.2`.\n    fn parse_range(input: &str) -> Result<pubgrub::Range<Version>, parser::Error> {\n        let mut parser = Parser::new(input)?;\n        let version = parser.range()?;\n        if !parser.is_eof() {\n            return Err(parser::Error::MoreInput(\n                parser\n                    .tail()?\n                    .into_iter()\n                    .map(|t| t.to_string())\n                    .collect::<Vec<_>>()\n                    .join(\"\"),\n            ));\n        }\n        Ok(version)\n    }\n\n    pub fn lowest() -> Self {\n        Self::new(0, 0, 0)\n    }\n\n    fn tuple(&self) -> (u32, u32, u32, PreOrder<'_>) {\n        (\n            self.major,\n            self.minor,\n            self.patch,\n            PreOrder(self.pre.as_slice()),\n        )\n    }\n\n    pub fn is_pre(&self) -> bool {\n        !self.pre.is_empty()\n    }\n}\n\npub trait LowestVersion {\n    fn lowest_version(&self) -> Option<Version>;\n}\nimpl LowestVersion for pubgrub::Range<Version> {\n    fn lowest_version(&self) -> Option<Version> {\n        self.iter()\n            .flat_map(|(lower, _higher)| match lower {\n                std::ops::Bound::Included(v) => Some(v.clone()),\n                std::ops::Bound::Excluded(_) => None,\n                std::ops::Bound::Unbounded => Some(Version::lowest()),\n            })\n            .min()\n    }\n}\n\nimpl<'de> Deserialize<'de> for Version {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        deserializer.deserialize_str(VersionVisitor)\n    }\n}\n\nstruct VersionVisitor;\n\nimpl<'de> Visitor<'de> for VersionVisitor {\n    type Value = Version;\n\n    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n        formatter.write_str(\"a Hex version string\")\n    }\n\n    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n    where\n        E: de::Error,\n    {\n        Version::try_from(value).map_err(de::Error::custom)\n    }\n}\n\nimpl Serialize for Version {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_str(&self.to_string())\n    }\n}\n\nimpl std::cmp::PartialOrd for Version {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl std::cmp::Ord for Version {\n    fn cmp(&self, other: &Self) -> Ordering {\n        self.tuple().cmp(&other.tuple())\n    }\n}\n\nimpl<'a> TryFrom<&'a str> for Version {\n    type Error = parser::Error;\n\n    fn try_from(value: &'a str) -> Result<Self, Self::Error> {\n        Self::parse(value)\n    }\n}\n\nimpl fmt::Display for Version {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}.{}.{}\", self.major, self.minor, self.patch)?;\n        if !self.pre.is_empty() {\n            write!(f, \"-\")?;\n            for (i, identifier) in self.pre.iter().enumerate() {\n                if i != 0 {\n                    write!(f, \".\")?;\n                }\n                identifier.fmt(f)?;\n            }\n        }\n        if let Some(build) = self.build.as_ref() {\n            write!(f, \"+{build}\")?;\n        }\n        Ok(())\n    }\n}\n\n#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\npub enum Identifier {\n    Numeric(u32),\n    AlphaNumeric(String),\n}\n\nimpl fmt::Display for Identifier {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match *self {\n            Identifier::Numeric(ref id) => id.fmt(f),\n            Identifier::AlphaNumeric(ref id) => id.fmt(f),\n        }\n    }\n}\n\nimpl Identifier {\n    pub fn concat(self, add_str: &str) -> Identifier {\n        match self {\n            Identifier::Numeric(n) => Identifier::AlphaNumeric(format!(\"{n}{add_str}\")),\n            Identifier::AlphaNumeric(mut s) => {\n                s.push_str(add_str);\n                Identifier::AlphaNumeric(s)\n            }\n        }\n    }\n}\n\n#[derive(Clone, PartialEq, Eq)]\npub struct Range {\n    spec: String,\n    range: pubgrub::Range<Version>,\n}\n\nimpl Range {\n    pub fn new(spec: String) -> Result<Self, parser::Error> {\n        let range = Version::parse_range(&spec)?;\n        Ok(Self { spec, range })\n    }\n}\n\nimpl Range {\n    pub fn to_pubgrub(&self) -> &pubgrub::Range<Version> {\n        &self.range\n    }\n\n    pub fn as_str(&self) -> &str {\n        &self.spec\n    }\n}\n\nimpl From<pubgrub::Range<Version>> for Range {\n    fn from(range: pubgrub::Range<Version>) -> Self {\n        let spec = range.to_string();\n        Self { spec, range }\n    }\n}\n\nimpl From<Version> for Range {\n    fn from(version: Version) -> Self {\n        pubgrub::Range::singleton(version).into()\n    }\n}\n\nimpl From<Range> for pubgrub::Range<Version> {\n    fn from(range: Range) -> Self {\n        range.range\n    }\n}\n\nimpl fmt::Debug for Range {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"Range\").field(&self.spec).finish()\n    }\n}\n\nimpl<'de> Deserialize<'de> for Range {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s: &str = Deserialize::deserialize(deserializer)?;\n        Range::new(s.to_string()).map_err(serde::de::Error::custom)\n    }\n}\n\nimpl Serialize for Range {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_str(&self.to_string())\n    }\n}\n\nimpl fmt::Display for Range {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(&self.spec)\n    }\n}\n\n// A wrapper around Vec where an empty vector is greater than a non-empty one.\n// This is desires as if there is a pre-segment in a version (1.0.0-rc1) it is\n// lower than the same version with no pre-segments (1.0.0).\n#[derive(PartialEq, Eq)]\npub struct PreOrder<'a>(&'a [Identifier]);\n\nimpl PreOrder<'_> {\n    fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n}\n\nimpl std::cmp::PartialOrd for PreOrder<'_> {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl std::cmp::Ord for PreOrder<'_> {\n    fn cmp(&self, other: &Self) -> Ordering {\n        if self.is_empty() && other.is_empty() {\n            Ordering::Equal\n        } else if self.is_empty() {\n            Ordering::Greater\n        } else if other.is_empty() {\n            Ordering::Less\n        } else {\n            self.0.cmp(other.0)\n        }\n    }\n}\n"
  },
  {
    "path": "hexpm/test/public_key",
    "content": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB\nEdvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+\nIqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM\n3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW\nXgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ\nJ1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4\n0wIDAQAB\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "language-server/Cargo.toml",
    "content": "[package]\nname = \"gleam-language-server\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\ngleam-core = { path = \"../compiler-core\" }\n\ncamino.workspace = true\ndebug-ignore.workspace = true\necow.workspace = true\nhexpm = { path = \"../hexpm\" }\nim.workspace = true\nitertools.workspace = true\nlsp-server.workspace = true\nlsp-types.workspace = true\nserde_json.workspace = true\nstrum.workspace = true\nvec1.workspace = true\nserde.workspace = true\ntracing.workspace = true\ntoml.workspace = true\n\n[dev-dependencies]\ninsta.workspace = true\n"
  },
  {
    "path": "language-server/src/code_action.rs",
    "content": "use std::{collections::HashSet, iter, sync::Arc};\n\nuse ecow::{EcoString, eco_format};\nuse gleam_core::{\n    Error, STDLIB_PACKAGE_NAME,\n    analyse::Inferred,\n    ast::{\n        self, ArgNames, AssignName, AssignmentKind, BitArraySegmentTruncation, BoundVariable,\n        BoundVariableName, CallArg, CustomType, FunctionLiteralKind, ImplicitCallArgOrigin, Import,\n        InvalidExpression, PIPE_PRECEDENCE, Pattern, PatternUnusedArguments,\n        PipelineAssignmentKind, Publicity, RecordConstructor, SrcSpan, TodoKind, TypedArg,\n        TypedAssignment, TypedClauseGuard, TypedDefinitions, TypedExpr, TypedFunction,\n        TypedModuleConstant, TypedPattern, TypedPipelineAssignment, TypedRecordConstructor,\n        TypedStatement, TypedTailPattern, TypedUse, visit::Visit as _,\n    },\n    build::{Located, Module},\n    config::PackageConfig,\n    exhaustiveness::CompiledCase,\n    line_numbers::LineNumbers,\n    parse::{extra::ModuleExtra, lexer::str_to_keyword},\n    strings::to_snake_case,\n    type_::{\n        self, FieldMap, ModuleValueConstructor, Opaque, Type, TypeVar, TypedCallArg,\n        ValueConstructor,\n        error::{ModuleSuggestion, VariableDeclaration, VariableOrigin},\n        printer::Printer,\n    },\n};\nuse im::HashMap;\nuse itertools::Itertools;\nuse lsp_types::{CodeAction, CodeActionKind, CodeActionParams, Position, Range, TextEdit, Url};\nuse vec1::{Vec1, vec1};\n\nuse super::{\n    TextEdits,\n    compiler::LspProjectCompiler,\n    edits,\n    edits::{add_newlines_after_import, get_import_edit, position_of_first_definition_if_import},\n    engine::{overlaps, within},\n    files::FileSystemProxy,\n    reference::{FindVariableReferences, VariableReferenceKind},\n    src_span_to_lsp_range, url_from_path,\n};\n\n#[derive(Debug)]\npub struct CodeActionBuilder {\n    action: CodeAction,\n}\n\nimpl CodeActionBuilder {\n    pub fn new(title: &str) -> Self {\n        Self {\n            action: CodeAction {\n                title: title.to_string(),\n                kind: None,\n                diagnostics: None,\n                edit: None,\n                command: None,\n                is_preferred: None,\n                disabled: None,\n                data: None,\n            },\n        }\n    }\n\n    pub fn kind(mut self, kind: CodeActionKind) -> Self {\n        self.action.kind = Some(kind);\n        self\n    }\n\n    pub fn changes(mut self, uri: Url, edits: Vec<TextEdit>) -> Self {\n        let mut edit = self.action.edit.take().unwrap_or_default();\n        let mut changes = edit.changes.take().unwrap_or_default();\n        _ = changes.insert(uri, edits);\n\n        edit.changes = Some(changes);\n        self.action.edit = Some(edit);\n        self\n    }\n\n    pub fn preferred(mut self, is_preferred: bool) -> Self {\n        self.action.is_preferred = Some(is_preferred);\n        self\n    }\n\n    pub fn push_to(self, actions: &mut Vec<CodeAction>) {\n        actions.push(self.action);\n    }\n}\n\n/// A small helper function to get the indentation at a given position.\nfn count_indentation(code: &str, line_numbers: &LineNumbers, line: u32) -> usize {\n    let mut indent_size = 0;\n    let line_start = *line_numbers\n        .line_starts\n        .get(line as usize)\n        .expect(\"Line number should be valid\");\n\n    let mut chars = code[line_start as usize..].chars();\n    while chars.next() == Some(' ') {\n        indent_size += 1;\n    }\n\n    indent_size\n}\n\n/// Code action to remove literal tuples in case subjects, essentially making\n/// the elements of the tuples into the case's subjects.\n///\n/// The code action is only available for the i'th subject if:\n/// - it is a non-empty tuple, and\n/// - the i'th pattern (including alternative patterns) is a literal tuple for all clauses.\n///\n/// # Basic example:\n///\n/// The following case expression:\n///\n/// ```gleam\n/// case #(1, 2) {\n///     #(a, b) -> 0\n/// }\n/// ```\n///\n/// Becomes:\n///\n/// ```gleam\n/// case 1, 2 {\n///     a, b -> 0\n/// }\n/// ```\n///\n/// # Another example:\n///\n/// The following case expression does not produce any code action\n///\n/// ```gleam\n/// case #(1, 2) {\n///     a -> 0 // <- the pattern is not a tuple\n/// }\n/// ```\npub struct RedundantTupleInCaseSubject<'a> {\n    edits: TextEdits<'a>,\n    code: &'a EcoString,\n    extra: &'a ModuleExtra,\n    params: &'a CodeActionParams,\n    module: &'a ast::TypedModule,\n    hovered: bool,\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for RedundantTupleInCaseSubject<'_> {\n    fn visit_typed_expr_case(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        subjects: &'ast [TypedExpr],\n        clauses: &'ast [ast::TypedClause],\n        compiled_case: &'ast CompiledCase,\n    ) {\n        for (subject_idx, subject) in subjects.iter().enumerate() {\n            let TypedExpr::Tuple {\n                location, elements, ..\n            } = subject\n            else {\n                continue;\n            };\n\n            // Ignore empty tuple\n            if elements.is_empty() {\n                continue;\n            }\n\n            // We cannot rewrite clauses whose i-th pattern is not a discard or\n            // tuples.\n            let all_ith_patterns_are_tuples_or_discards = clauses\n                .iter()\n                .map(|clause| clause.pattern.get(subject_idx))\n                .all(|pattern| {\n                    matches!(\n                        pattern,\n                        Some(Pattern::Tuple { .. } | Pattern::Discard { .. })\n                    )\n                });\n\n            if !all_ith_patterns_are_tuples_or_discards {\n                continue;\n            }\n\n            self.delete_tuple_tokens(*location, elements.last().map(|element| element.location()));\n\n            for clause in clauses {\n                match clause.pattern.get(subject_idx) {\n                    Some(Pattern::Tuple { location, elements }) => self.delete_tuple_tokens(\n                        *location,\n                        elements.last().map(|element| element.location()),\n                    ),\n                    Some(Pattern::Discard { location, .. }) => {\n                        self.discard_tuple_items(*location, elements.len())\n                    }\n                    _ => panic!(\"safe: we've just checked all patterns must be discards/tuples\"),\n                }\n            }\n            let range = self.edits.src_span_to_lsp_range(*location);\n            self.hovered = self.hovered || overlaps(self.params.range, range);\n        }\n\n        ast::visit::visit_typed_expr_case(self, location, type_, subjects, clauses, compiled_case)\n    }\n}\n\nimpl<'a> RedundantTupleInCaseSubject<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            edits: TextEdits::new(line_numbers),\n            code: &module.code,\n            extra: &module.extra,\n            params,\n            module: &module.ast,\n            hovered: false,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(self.module);\n        if !self.hovered {\n            return vec![];\n        }\n\n        self.edits.edits.sort_by_key(|edit| edit.range.start);\n\n        let mut actions = vec![];\n        CodeActionBuilder::new(\"Remove redundant tuples\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut actions);\n\n        actions\n    }\n\n    fn delete_tuple_tokens(&mut self, location: SrcSpan, last_elem_location: Option<SrcSpan>) {\n        let tuple_code = self\n            .code\n            .get(location.start as usize..location.end as usize)\n            .expect(\"valid span\");\n\n        // Delete `#`\n        self.edits\n            .delete(SrcSpan::new(location.start, location.start + 1));\n\n        // Delete `(`\n        let (lparen_offset, _) = tuple_code\n            .match_indices('(')\n            // Ignore in comments\n            .find(|(i, _)| !self.extra.is_within_comment(location.start + *i as u32))\n            .expect(\"`(` not found in tuple\");\n\n        self.edits.delete(SrcSpan::new(\n            location.start + lparen_offset as u32,\n            location.start + lparen_offset as u32 + 1,\n        ));\n\n        // Delete trailing `,` (if applicable)\n        if let Some(last_elem_location) = last_elem_location {\n            // Get the code after the last element until the tuple's `)`\n            let code_after_last_elem = self\n                .code\n                .get(last_elem_location.end as usize..location.end as usize)\n                .expect(\"valid span\");\n\n            if let Some((trailing_comma_offset, _)) = code_after_last_elem\n                .rmatch_indices(',')\n                // Ignore in comments\n                .find(|(i, _)| {\n                    !self\n                        .extra\n                        .is_within_comment(last_elem_location.end + *i as u32)\n                })\n            {\n                self.edits.delete(SrcSpan::new(\n                    last_elem_location.end + trailing_comma_offset as u32,\n                    last_elem_location.end + trailing_comma_offset as u32 + 1,\n                ));\n            }\n        }\n\n        // Delete )\n        self.edits\n            .delete(SrcSpan::new(location.end - 1, location.end));\n    }\n\n    fn discard_tuple_items(&mut self, discard_location: SrcSpan, tuple_items: usize) {\n        // Replace the old discard with multiple discard, one for each of the\n        // tuple items.\n        self.edits.replace(\n            discard_location,\n            itertools::intersperse(iter::repeat_n(\"_\", tuple_items), \", \").collect(),\n        )\n    }\n}\n\n/// Builder for code action to convert `let assert` into a case expression.\n///\npub struct LetAssertToCase<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    actions: Vec<CodeAction>,\n    edits: TextEdits<'a>,\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for LetAssertToCase<'_> {\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        let assignment_range = self.edits.src_span_to_lsp_range(assignment.location);\n        let assignment_start_range = self.edits.src_span_to_lsp_range(SrcSpan {\n            start: assignment.location.start,\n            end: assignment.value.location().start,\n        });\n        self.visit_typed_expr(&assignment.value);\n\n        // Only offer the code action if the cursor is over the statement and\n        // to prevent weird behaviour when `let assert` statements are nested,\n        // we only check for the code action between the `let` and `=`.\n        if !(within(self.params.range, assignment_range)\n            && overlaps(self.params.range, assignment_start_range))\n        {\n            return;\n        }\n\n        // This pattern only applies to `let assert`\n        let AssignmentKind::Assert { message, .. } = &assignment.kind else {\n            return;\n        };\n\n        // Get the source code for the tested expression\n        let location = assignment.value.location();\n        let expr = self\n            .module\n            .code\n            .get(location.start as usize..location.end as usize)\n            .expect(\"Location must be valid\");\n\n        // Get the source code for the pattern\n        let pattern_location = assignment.pattern.location();\n        let pattern = self\n            .module\n            .code\n            .get(pattern_location.start as usize..pattern_location.end as usize)\n            .expect(\"Location must be valid\");\n\n        let message = message.as_ref().map(|message| {\n            let location = message.location();\n            self.module\n                .code\n                .get(location.start as usize..location.end as usize)\n                .expect(\"Location must be valid\")\n        });\n\n        let range = self.edits.src_span_to_lsp_range(assignment.location);\n\n        // Figure out which variables are assigned in the pattern\n        let variables = PatternVariableFinder::find_variables_in_pattern(&assignment.pattern);\n\n        let assigned = match variables.len() {\n            0 => \"_\",\n            1 => variables.first().expect(\"Variables is length one\"),\n            _ => &format!(\"#({})\", variables.join(\", \")),\n        };\n\n        let mut new_text = format!(\"let {assigned} = \");\n        let panic_message = if let Some(message) = message {\n            &format!(\"panic as {message}\")\n        } else {\n            \"panic\"\n        };\n        let clauses = vec![\n            // The existing pattern\n            CaseClause {\n                pattern,\n                // `_` is not a valid expression, so if we are not\n                // binding any variables in the pattern, we simply return Nil.\n                expression: if assigned == \"_\" { \"Nil\" } else { assigned },\n            },\n            CaseClause {\n                pattern: \"_\",\n                expression: panic_message,\n            },\n        ];\n        print_case_expression(range.start.character as usize, expr, clauses, &mut new_text);\n\n        let uri = &self.params.text_document.uri;\n\n        CodeActionBuilder::new(\"Convert to case\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(uri.clone(), vec![TextEdit { range, new_text }])\n            .preferred(false)\n            .push_to(&mut self.actions);\n    }\n}\n\nimpl<'a> LetAssertToCase<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            actions: Vec::new(),\n            edits: TextEdits::new(line_numbers),\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n        self.actions\n    }\n}\n\nstruct PatternVariableFinder {\n    pattern_variables: Vec<EcoString>,\n}\n\nimpl PatternVariableFinder {\n    fn new() -> Self {\n        Self {\n            pattern_variables: Vec::new(),\n        }\n    }\n\n    fn find_variables_in_pattern(pattern: &TypedPattern) -> Vec<EcoString> {\n        let mut finder = Self::new();\n        finder.visit_typed_pattern(pattern);\n        finder.pattern_variables\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for PatternVariableFinder {\n    fn visit_typed_pattern_variable(\n        &mut self,\n        _location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        _type: &'ast Arc<Type>,\n        _origin: &'ast VariableOrigin,\n    ) {\n        self.pattern_variables.push(name.clone());\n    }\n\n    fn visit_typed_pattern_assign(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        pattern: &'ast TypedPattern,\n    ) {\n        self.pattern_variables.push(name.clone());\n        ast::visit::visit_typed_pattern_assign(self, location, name, pattern);\n    }\n\n    fn visit_typed_pattern_string_prefix(\n        &mut self,\n        _location: &'ast SrcSpan,\n        _left_location: &'ast SrcSpan,\n        left_side_assignment: &'ast Option<(EcoString, SrcSpan)>,\n        _right_location: &'ast SrcSpan,\n        _left_side_string: &'ast EcoString,\n        right_side_assignment: &'ast AssignName,\n    ) {\n        if let Some((name, _)) = left_side_assignment {\n            self.pattern_variables.push(name.clone());\n        }\n        if let AssignName::Variable(name) = right_side_assignment {\n            self.pattern_variables.push(name.clone());\n        }\n    }\n}\n\npub fn code_action_inexhaustive_let_to_case(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &CodeActionParams,\n    error: &Option<Error>,\n    actions: &mut Vec<CodeAction>,\n) {\n    let Some(Error::Type { errors, .. }) = error else {\n        return;\n    };\n    let inexhaustive_assignments = errors\n        .iter()\n        .filter_map(|error| {\n            if let type_::Error::InexhaustiveLetAssignment { location, missing } = error {\n                Some((*location, missing))\n            } else {\n                None\n            }\n        })\n        .collect_vec();\n\n    if inexhaustive_assignments.is_empty() {\n        return;\n    }\n\n    for (location, missing) in inexhaustive_assignments {\n        let mut text_edits = TextEdits::new(line_numbers);\n\n        let range = text_edits.src_span_to_lsp_range(location);\n        if !overlaps(params.range, range) {\n            return;\n        }\n\n        let Some(Located::Statement(TypedStatement::Assignment(assignment))) =\n            module.find_node(location.start)\n        else {\n            continue;\n        };\n\n        let TypedAssignment {\n            value,\n            pattern,\n            kind: AssignmentKind::Let,\n            location,\n            compiled_case: _,\n            annotation: _,\n        } = assignment.as_ref()\n        else {\n            continue;\n        };\n\n        // Get the source code for the tested expression\n        let value_location = value.location();\n        let expr = module\n            .code\n            .get(value_location.start as usize..value_location.end as usize)\n            .expect(\"Location must be valid\");\n\n        // Get the source code for the pattern\n        let pattern_location = pattern.location();\n        let pattern_code = module\n            .code\n            .get(pattern_location.start as usize..pattern_location.end as usize)\n            .expect(\"Location must be valid\");\n\n        let range = text_edits.src_span_to_lsp_range(*location);\n\n        // Figure out which variables are assigned in the pattern\n        let variables = PatternVariableFinder::find_variables_in_pattern(pattern);\n\n        let assigned = match variables.len() {\n            0 => \"_\",\n            1 => variables.first().expect(\"Variables is length one\"),\n            _ => &format!(\"#({})\", variables.join(\", \")),\n        };\n\n        let mut new_text = format!(\"let {assigned} = \");\n        print_case_expression(\n            range.start.character as usize,\n            expr,\n            iter::once(CaseClause {\n                pattern: pattern_code,\n                expression: if assigned == \"_\" { \"Nil\" } else { assigned },\n            })\n            .chain(missing.iter().map(|pattern| CaseClause {\n                pattern,\n                expression: \"todo\",\n            }))\n            .collect(),\n            &mut new_text,\n        );\n\n        let uri = &params.text_document.uri;\n\n        text_edits.replace(*location, new_text);\n\n        CodeActionBuilder::new(\"Convert to case\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(uri.clone(), text_edits.edits)\n            .preferred(true)\n            .push_to(actions);\n    }\n}\n\nstruct CaseClause<'a> {\n    pattern: &'a str,\n    expression: &'a str,\n}\n\nfn print_case_expression(\n    indent_size: usize,\n    subject: &str,\n    clauses: Vec<CaseClause<'_>>,\n    buffer: &mut String,\n) {\n    let indent = \" \".repeat(indent_size);\n\n    // Print the beginning of the expression\n    buffer.push_str(\"case \");\n    buffer.push_str(subject);\n    buffer.push_str(\" {\");\n\n    for clause in clauses.iter() {\n        // Print the newline and indentation for this clause\n        buffer.push('\\n');\n        buffer.push_str(&indent);\n        // Indent this clause one level deeper than the case expression\n        buffer.push_str(\"  \");\n\n        // Print the clause\n        buffer.push_str(clause.pattern);\n        buffer.push_str(\" -> \");\n        buffer.push_str(clause.expression);\n    }\n\n    // If there are no clauses to print, the closing brace should be\n    // on the same line as the opening one, with no space between.\n    if !clauses.is_empty() {\n        buffer.push('\\n');\n        buffer.push_str(&indent);\n    }\n    buffer.push('}');\n}\n\n/// Builder for code action to apply the label shorthand syntax on arguments\n/// where the label has the same name as the variable.\n///\npub struct UseLabelShorthandSyntax<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n}\n\nimpl<'a> UseLabelShorthandSyntax<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n        if self.edits.edits.is_empty() {\n            return vec![];\n        }\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Use label shorthand syntax\")\n            .kind(CodeActionKind::REFACTOR)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for UseLabelShorthandSyntax<'_> {\n    fn visit_typed_call_arg(&mut self, arg: &'ast TypedCallArg) {\n        let arg_range = self.edits.src_span_to_lsp_range(arg.location);\n        let is_selected = overlaps(arg_range, self.params.range);\n\n        match arg {\n            CallArg {\n                label: Some(label),\n                value: TypedExpr::Var { name, location, .. },\n                ..\n            } if is_selected && !arg.uses_label_shorthand() && label == name => {\n                self.edits.delete(*location)\n            }\n            _ => (),\n        }\n\n        ast::visit::visit_typed_call_arg(self, arg)\n    }\n\n    fn visit_typed_pattern_call_arg(&mut self, arg: &'ast CallArg<TypedPattern>) {\n        let arg_range = self.edits.src_span_to_lsp_range(arg.location);\n        let is_selected = overlaps(arg_range, self.params.range);\n\n        match arg {\n            CallArg {\n                label: Some(label),\n                value: TypedPattern::Variable { name, location, .. },\n                ..\n            } if is_selected && !arg.uses_label_shorthand() && label == name => {\n                self.edits.delete(*location)\n            }\n            _ => (),\n        }\n\n        ast::visit::visit_typed_pattern_call_arg(self, arg)\n    }\n}\n\n/// Builder for code action to apply the fill in the missing labelled arguments\n/// of the selected function call.\n///\npub struct FillInMissingLabelledArgs<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    use_right_hand_side_location: Option<SrcSpan>,\n    selected_call: Option<SelectedCall<'a>>,\n    current_function: Option<&'a TypedFunction>,\n}\n\nstruct SelectedCall<'a> {\n    location: SrcSpan,\n    field_map: &'a FieldMap,\n    arguments: Vec<CallArg<()>>,\n    kind: SelectedCallKind,\n    fun_type: Option<Arc<Type>>,\n    enclosing_function: Option<&'a TypedFunction>,\n}\n\nenum SelectedCallKind {\n    Value,\n    Pattern,\n}\n\nimpl<'a> FillInMissingLabelledArgs<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            use_right_hand_side_location: None,\n            selected_call: None,\n            current_function: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        if let Some(SelectedCall {\n            location: call_location,\n            field_map,\n            arguments,\n            kind,\n            fun_type,\n            enclosing_function,\n        }) = self.selected_call\n        {\n            let is_use_call = arguments.iter().any(|arg| arg.is_use_implicit_callback());\n            let missing_labels = field_map.missing_labels(&arguments);\n\n            // If we're applying the code action to a use call, then we know\n            // that the last missing argument is going to be implicitly inserted\n            // by the compiler, so in that case we don't want to also add that\n            // last label to the completions.\n            let missing_labels = missing_labels.iter().peekable();\n            let mut missing_labels = if is_use_call {\n                missing_labels.dropping_back(1)\n            } else {\n                missing_labels\n            };\n\n            // If we couldn't find any missing label to insert we just return.\n            if missing_labels.peek().is_none() {\n                return vec![];\n            }\n\n            // A pattern could have been written with no parentheses at all!\n            // So we need to check for the last character to see if parentheses\n            // are there or not before filling the arguments in\n            let has_parentheses = \")\"\n                == code_at(\n                    self.module,\n                    SrcSpan::new(call_location.end - 1, call_location.end),\n                );\n            let label_insertion_start = if has_parentheses {\n                // If it ends with a parentheses we'll need to start inserting\n                // right before the closing one...\n                call_location.end - 1\n            } else {\n                // ...otherwise we just append the result\n                call_location.end\n            };\n\n            // Now we need to figure out if there's a comma at the end of the\n            // arguments list:\n            //\n            //   call(one, |)\n            //             ^ Cursor here, with a comma behind\n            //\n            //   call(one|)\n            //           ^ Cursor here, no comma behind, we'll have to add one!\n            //\n            let has_comma_after_last_argument =\n                if let Some(last_arg) = arguments.iter().rfind(|arg| !arg.is_implicit()) {\n                    self.module\n                        .code\n                        .get(last_arg.location.end as usize..=label_insertion_start as usize)\n                        .is_some_and(|text| text.contains(','))\n                } else {\n                    false\n                };\n\n            let variables_in_scope = enclosing_function\n                .map(|fun| {\n                    ScopeVariableCollector::new(call_location.start).collect_from_function(fun)\n                })\n                .unwrap_or_default();\n\n            let labels_list = missing_labels\n                .map(|label| {\n                    Self::format_label(label, &kind, &fun_type, field_map, &variables_in_scope)\n                })\n                .join(\", \");\n\n            let has_no_explicit_arguments = arguments\n                .iter()\n                .filter(|arg| !arg.is_implicit())\n                .peekable()\n                .peek()\n                .is_none();\n\n            let labels_list = if has_no_explicit_arguments || has_comma_after_last_argument {\n                labels_list\n            } else {\n                format!(\", {labels_list}\")\n            };\n\n            let edit = if has_parentheses {\n                labels_list\n            } else {\n                // If the variant whose arguments we're filling in was written\n                // with no parentheses we need to add those as well to make it a\n                // valid constructor.\n                format!(\"({labels_list})\")\n            };\n\n            self.edits.insert(label_insertion_start, edit);\n\n            let mut action = Vec::with_capacity(1);\n            CodeActionBuilder::new(\"Fill labels\")\n                .kind(CodeActionKind::QUICKFIX)\n                .changes(self.params.text_document.uri.clone(), self.edits.edits)\n                .preferred(true)\n                .push_to(&mut action);\n            return action;\n        }\n\n        vec![]\n    }\n\n    /// Formats a label for insertion. Uses `label:` syntax if there's a variable\n    /// in scope with matching name and type, otherwise uses `label: todo`.\n    fn format_label(\n        label: &EcoString,\n        kind: &SelectedCallKind,\n        fun_type: &Option<Arc<Type>>,\n        field_map: &FieldMap,\n        variables_in_scope: &HashMap<EcoString, Arc<Type>>,\n    ) -> String {\n        if matches!(kind, SelectedCallKind::Pattern) {\n            return format!(\"{label}:\");\n        }\n\n        if let Some(var_type) = variables_in_scope.get(label) {\n            let expected_type = fun_type.as_ref().and_then(|ft| {\n                let (arg_types, _) = ft.fn_types()?;\n                let &index = field_map.fields.get(label)?;\n                arg_types.get(index as usize).cloned()\n            });\n\n            if let Some(expected) = expected_type\n                && expected.same_as(var_type)\n            {\n                return format!(\"{label}:\");\n            }\n        }\n\n        format!(\"{label}: todo\")\n    }\n\n    fn empty_argument<A>(argument: &CallArg<A>) -> CallArg<()> {\n        CallArg {\n            label: argument.label.clone(),\n            location: argument.location,\n            value: (),\n            implicit: argument.implicit,\n        }\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for FillInMissingLabelledArgs<'ast> {\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        // We store the current function as the containing function while we traverse\n        // it, allowing handling nested functions correctly.\n        let previous_function = self.current_function;\n        self.current_function = Some(fun);\n        ast::visit::visit_typed_function(self, fun);\n        self.current_function = previous_function;\n    }\n\n    fn visit_typed_use(&mut self, use_: &'ast TypedUse) {\n        // If we're adding labels to a use call the correct location of the\n        // function we need to add labels to is `use_right_hand_side_location`.\n        // So we store it for when we're typing the use call.\n        let previous = self.use_right_hand_side_location;\n        self.use_right_hand_side_location = Some(use_.right_hand_side_location);\n        ast::visit::visit_typed_use(self, use_);\n        self.use_right_hand_side_location = previous;\n    }\n\n    fn visit_typed_expr_call(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        fun: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        let call_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, call_range) {\n            return;\n        }\n\n        if let Some(field_map) = fun.field_map() {\n            let location = self.use_right_hand_side_location.unwrap_or(*location);\n            self.selected_call = Some(SelectedCall {\n                location,\n                field_map,\n                arguments: arguments.iter().map(Self::empty_argument).collect(),\n                kind: SelectedCallKind::Value,\n                fun_type: Some(fun.type_()),\n                enclosing_function: self.current_function,\n            })\n        }\n\n        // We only want to take into account the innermost function call\n        // containing the current selection so we can't stop at the first call\n        // we find (the outermost one) and have to keep traversing it in case\n        // we're inside a nested call.\n        let previous = self.use_right_hand_side_location;\n        self.use_right_hand_side_location = None;\n        ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);\n        self.use_right_hand_side_location = previous;\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        let call_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, call_range) {\n            return;\n        }\n\n        if let Some(field_map) = constructor.field_map() {\n            self.selected_call = Some(SelectedCall {\n                location: *location,\n                field_map,\n                arguments: arguments.iter().map(Self::empty_argument).collect(),\n                kind: SelectedCallKind::Pattern,\n                fun_type: None,\n                enclosing_function: self.current_function,\n            })\n        }\n\n        ast::visit::visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n}\n\n/// Collects variables that are in scope at a given cursor position.\nstruct ScopeVariableCollector {\n    cursor: u32,\n    variables: HashMap<EcoString, Arc<Type>>,\n}\n\nimpl ScopeVariableCollector {\n    fn new(cursor: u32) -> Self {\n        Self {\n            cursor,\n            variables: HashMap::new(),\n        }\n    }\n\n    fn collect_from_function(mut self, fun: &TypedFunction) -> HashMap<EcoString, Arc<Type>> {\n        for arg in &fun.arguments {\n            if let Some(name) = arg.get_variable_name() {\n                _ = self.variables.insert(name.clone(), arg.type_.clone());\n            }\n        }\n\n        for statement in &fun.body {\n            self.visit_typed_statement(statement);\n        }\n\n        self.variables\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ScopeVariableCollector {\n    fn visit_typed_statement(&mut self, statement: &'ast TypedStatement) {\n        // We need to consider variables defined only before the cursor\n        if statement.location().start >= self.cursor {\n            return;\n        }\n\n        ast::visit::visit_typed_statement(self, statement);\n    }\n\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        // if cursor is inside the assignment, we only visit the value expression,\n        // because the variable being defined isn't in scope yet.\n        if assignment.location.contains(self.cursor) {\n            self.visit_typed_expr(&assignment.value);\n        } else {\n            self.visit_typed_pattern(&assignment.pattern);\n        }\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        _location: &'ast SrcSpan,\n        _type_: &'ast Arc<Type>,\n        _kind: &'ast FunctionLiteralKind,\n        _arguments: &'ast [TypedArg],\n        _body: &'ast Vec1<TypedStatement>,\n        _return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        // We don't descend into nested functions, as their variables aren't in\n        // our scope\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast SrcSpan,\n        statements: &'ast [TypedStatement],\n    ) {\n        if self.cursor >= location.end {\n            return;\n        }\n        ast::visit::visit_typed_expr_block(self, location, statements);\n    }\n\n    fn visit_typed_pattern_variable(\n        &mut self,\n        _location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        _origin: &'ast VariableOrigin,\n    ) {\n        if !name.starts_with('_') {\n            _ = self.variables.insert(name.clone(), type_.clone());\n        }\n    }\n\n    fn visit_typed_pattern_assign(\n        &mut self,\n        _location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        pattern: &'ast Pattern<Arc<Type>>,\n    ) {\n        self.visit_typed_pattern(pattern);\n        if !name.starts_with('_') {\n            _ = self.variables.insert(name.clone(), pattern.type_().clone());\n        }\n    }\n}\n\nstruct MissingImport {\n    location: SrcSpan,\n    suggestions: Vec<ImportSuggestion>,\n}\n\nstruct ImportSuggestion {\n    // The name to replace with, if the user made a typo\n    name: EcoString,\n    // The optional module to import, if suggesting an importable module\n    import: Option<EcoString>,\n}\n\npub fn code_action_import_module(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &CodeActionParams,\n    error: &Option<Error>,\n    actions: &mut Vec<CodeAction>,\n) {\n    let uri = &params.text_document.uri;\n    let Some(Error::Type { errors, .. }) = error else {\n        return;\n    };\n\n    let missing_imports = errors\n        .into_iter()\n        .filter_map(|e| {\n            if let type_::Error::UnknownModule {\n                location,\n                suggestions,\n                ..\n            } = e\n            {\n                suggest_imports(*location, suggestions)\n            } else {\n                None\n            }\n        })\n        .collect_vec();\n\n    if missing_imports.is_empty() {\n        return;\n    }\n\n    let first_import_pos = position_of_first_definition_if_import(module, line_numbers);\n    let first_is_import = first_import_pos.is_some();\n    let import_location = first_import_pos.unwrap_or_default();\n\n    let after_import_newlines =\n        add_newlines_after_import(import_location, first_is_import, line_numbers, &module.code);\n\n    for missing_import in missing_imports {\n        let range = src_span_to_lsp_range(missing_import.location, line_numbers);\n        if !overlaps(params.range, range) {\n            continue;\n        }\n\n        for suggestion in missing_import.suggestions {\n            let mut edits = vec![TextEdit {\n                range,\n                new_text: suggestion.name.to_string(),\n            }];\n            if let Some(import) = &suggestion.import {\n                edits.push(get_import_edit(\n                    import_location,\n                    import,\n                    &after_import_newlines,\n                ))\n            };\n\n            let title = match &suggestion.import {\n                Some(import) => &format!(\"Import `{import}`\"),\n                _ => &format!(\"Did you mean `{}`\", suggestion.name),\n            };\n\n            CodeActionBuilder::new(title)\n                .kind(CodeActionKind::QUICKFIX)\n                .changes(uri.clone(), edits)\n                .preferred(true)\n                .push_to(actions);\n        }\n    }\n}\n\nfn suggest_imports(\n    location: SrcSpan,\n    importable_modules: &[ModuleSuggestion],\n) -> Option<MissingImport> {\n    let suggestions = importable_modules\n        .iter()\n        .map(|suggestion| {\n            let imported_name = suggestion.last_name_component();\n            match suggestion {\n                ModuleSuggestion::Importable(name) => ImportSuggestion {\n                    name: imported_name.into(),\n                    import: Some(name.clone()),\n                },\n                ModuleSuggestion::Imported(_) => ImportSuggestion {\n                    name: imported_name.into(),\n                    import: None,\n                },\n            }\n        })\n        .collect_vec();\n\n    if suggestions.is_empty() {\n        None\n    } else {\n        Some(MissingImport {\n            location,\n            suggestions,\n        })\n    }\n}\n\npub fn code_action_add_missing_patterns(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &CodeActionParams,\n    error: &Option<Error>,\n    actions: &mut Vec<CodeAction>,\n) {\n    let uri = &params.text_document.uri;\n    let Some(Error::Type { errors, .. }) = error else {\n        return;\n    };\n    let missing_patterns = errors\n        .iter()\n        .filter_map(|error| {\n            if let type_::Error::InexhaustiveCaseExpression { location, missing } = error {\n                Some((*location, missing))\n            } else {\n                None\n            }\n        })\n        .collect_vec();\n\n    if missing_patterns.is_empty() {\n        return;\n    }\n\n    for (location, missing) in missing_patterns {\n        let mut edits = TextEdits::new(line_numbers);\n        let range = edits.src_span_to_lsp_range(location);\n        if !overlaps(params.range, range) {\n            return;\n        }\n\n        let Some(Located::Expression {\n            expression: TypedExpr::Case {\n                clauses, subjects, ..\n            },\n            ..\n        }) = module.find_node(location.start)\n        else {\n            continue;\n        };\n\n        let indent_size = count_indentation(&module.code, edits.line_numbers, range.start.line);\n\n        let indent = \" \".repeat(indent_size);\n\n        // Insert the missing patterns just after the final clause, or just before\n        // the closing brace if there are no clauses\n\n        let insert_at = clauses\n            .last()\n            .map(|clause| clause.location.end)\n            .unwrap_or(location.end - 1);\n\n        for pattern in missing {\n            let new_text = format!(\"\\n{indent}  {pattern} -> todo\");\n            edits.insert(insert_at, new_text);\n        }\n\n        // Add a newline + indent after the last pattern if there are no clauses\n        //\n        // This improves the generated code for this case:\n        // ```gleam\n        // case True {}\n        // ```\n        // This produces:\n        // ```gleam\n        // case True {\n        //   True -> todo\n        //   False -> todo\n        // }\n        // ```\n        // Instead of:\n        // ```gleam\n        // case True {\n        //   True -> todo\n        //   False -> todo}\n        // ```\n        //\n        if clauses.is_empty() {\n            let last_subject_location = subjects\n                .last()\n                .expect(\"Case expressions have at least one subject\")\n                .location()\n                .end;\n\n            // Find the opening brace of the case expression\n            let chars = module.code[last_subject_location as usize..].chars();\n            let mut start_brace_location = last_subject_location;\n            for char in chars {\n                start_brace_location += 1;\n                if char == '{' {\n                    break;\n                }\n            }\n\n            // Remove any blank spaces/lines between the start brace and end brace\n            edits.delete(SrcSpan::new(start_brace_location, insert_at));\n            edits.insert(insert_at, format!(\"\\n{indent}\"));\n        }\n\n        CodeActionBuilder::new(\"Add missing patterns\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(uri.clone(), edits.edits)\n            .preferred(true)\n            .push_to(actions);\n    }\n}\n\n/// Builder for code action to add annotations to an assignment or function\n///\npub struct AddAnnotations<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    printer: Printer<'a>,\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for AddAnnotations<'_> {\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        self.visit_typed_expr(&assignment.value);\n\n        // We only offer this code action between `let` and `=`, because\n        // otherwise it could lead to confusing behaviour if inside a block\n        // which is part of a let binding.\n        let pattern_location = assignment.pattern.location();\n        let location = SrcSpan::new(assignment.location.start, pattern_location.end);\n        let code_action_range = self.edits.src_span_to_lsp_range(location);\n\n        // Only offer the code action if the cursor is over the statement\n        if !overlaps(code_action_range, self.params.range) {\n            return;\n        }\n\n        // We don't need to add an annotation if there already is one\n        if assignment.annotation.is_some() {\n            return;\n        }\n\n        // Various expressions such as pipelines and `use` expressions generate assignments\n        // internally. However, these cannot be annotated and so we don't offer a code action here.\n        if matches!(assignment.kind, AssignmentKind::Generated) {\n            return;\n        }\n\n        self.edits.insert(\n            pattern_location.end,\n            format!(\": {}\", self.printer.print_type(&assignment.type_())),\n        );\n    }\n\n    fn visit_typed_module_constant(&mut self, constant: &'ast TypedModuleConstant) {\n        // Since type variable names are local to definitions, any type variables\n        // in other parts of the module shouldn't affect what we print for the\n        // annotations of this constant.\n        self.printer.clear_type_variables();\n\n        let code_action_range = self.edits.src_span_to_lsp_range(constant.location);\n\n        // Only offer the code action if the cursor is over the statement\n        if !overlaps(code_action_range, self.params.range) {\n            return;\n        }\n\n        // We don't need to add an annotation if there already is one\n        if constant.annotation.is_some() {\n            return;\n        }\n\n        self.edits.insert(\n            constant.name_location.end,\n            format!(\": {}\", self.printer.print_type(&constant.type_)),\n        );\n    }\n\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        // Since type variable names are local to definitions, any type variables\n        // in other parts of the module shouldn't affect what we print for the\n        // annotations of this functions. The only variables which cannot clash\n        // are ones defined in the signature of this function, which we register\n        // when we visit the parameters of this function inside `collect_type_variables`.\n        self.printer.clear_type_variables();\n        collect_type_variables(&mut self.printer, fun);\n\n        ast::visit::visit_typed_function(self, fun);\n\n        let code_action_range = self.edits.src_span_to_lsp_range(\n            fun.body_start\n                .map(|body_start| SrcSpan {\n                    start: fun.location.start,\n                    end: body_start,\n                })\n                .unwrap_or(fun.location),\n        );\n\n        // Only offer the code action if the cursor is over the statement\n        if !overlaps(code_action_range, self.params.range) {\n            return;\n        }\n\n        // Annotate each argument separately\n        for argument in fun.arguments.iter() {\n            // Don't annotate the argument if it's already annotated\n            if argument.annotation.is_some() {\n                continue;\n            }\n\n            self.edits.insert(\n                argument.location.end,\n                format!(\": {}\", self.printer.print_type(&argument.type_)),\n            );\n        }\n\n        // Annotate the return type if it isn't already annotated\n        if fun.return_annotation.is_none() {\n            self.edits.insert(\n                fun.location.end,\n                format!(\" -> {}\", self.printer.print_type(&fun.return_type)),\n            );\n        }\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        ast::visit::visit_typed_expr_fn(\n            self,\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n        );\n\n        // If the function doesn't have a head, we can't annotate it\n        let location = match kind {\n            // Function captures don't need any type annotations\n            FunctionLiteralKind::Capture { .. } => return,\n            FunctionLiteralKind::Anonymous { head } => head,\n            FunctionLiteralKind::Use { location } => location,\n        };\n\n        let code_action_range = self.edits.src_span_to_lsp_range(*location);\n\n        // Only offer the code action if the cursor is over the expression\n        if !overlaps(code_action_range, self.params.range) {\n            return;\n        }\n\n        // Annotate each argument separately\n        for argument in arguments.iter() {\n            // Don't annotate the argument if it's already annotated\n            if argument.annotation.is_some() {\n                continue;\n            }\n\n            self.edits.insert(\n                argument.location.end,\n                format!(\": {}\", self.printer.print_type(&argument.type_)),\n            );\n        }\n\n        // Annotate the return type if it isn't already annotated, and this is\n        // an anonymous function.\n        if return_annotation.is_none() && matches!(kind, FunctionLiteralKind::Anonymous { .. }) {\n            let return_type = &type_.return_type().expect(\"Type must be a function\");\n            let pretty_type = self.printer.print_type(return_type);\n            self.edits\n                .insert(location.end, format!(\" -> {pretty_type}\"));\n        }\n    }\n}\n\nimpl<'a> AddAnnotations<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            // We need to use the same printer for all the edits because otherwise\n            // we could get duplicate type variable names.\n            printer: Printer::new_without_type_variables(&module.ast.names),\n        }\n    }\n\n    pub fn code_action(mut self, actions: &mut Vec<CodeAction>) {\n        self.visit_typed_module(&self.module.ast);\n\n        let uri = &self.params.text_document.uri;\n\n        let title = match self.edits.edits.len() {\n            // We don't offer a code action if there is no action to perform\n            0 => return,\n            1 => \"Add type annotation\",\n            _ => \"Add type annotations\",\n        };\n\n        CodeActionBuilder::new(title)\n            .kind(CodeActionKind::REFACTOR)\n            .changes(uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(actions);\n    }\n}\n\n/// Code action to add type annotations to all top level definitions\n///\npub struct AnnotateTopLevelDefinitions<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    is_hovering_definition_requiring_annotations: bool,\n}\n\nimpl<'a> AnnotateTopLevelDefinitions<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            is_hovering_definition_requiring_annotations: false,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        // We only want to trigger the action if we're over one of the definition\n        // which is lacking some annotations in the module\n        if !self.is_hovering_definition_requiring_annotations {\n            return vec![];\n        };\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Annotate all top level definitions\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for AnnotateTopLevelDefinitions<'_> {\n    fn visit_typed_module_constant(&mut self, constant: &'ast TypedModuleConstant) {\n        let code_action_range = self.edits.src_span_to_lsp_range(constant.location);\n\n        // We don't need to add an annotation if there already is one\n        if constant.annotation.is_some() {\n            return;\n        }\n\n        // We're hovering definition which needs some annotations\n        if overlaps(code_action_range, self.params.range) {\n            self.is_hovering_definition_requiring_annotations = true;\n        }\n\n        self.edits.insert(\n            constant.name_location.end,\n            format!(\n                \": {}\",\n                // Create new printer to ignore type variables from other definitions\n                Printer::new_without_type_variables(&self.module.ast.names)\n                    .print_type(&constant.type_)\n            ),\n        );\n    }\n\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        // Don't annotate already annotated arguments\n        let arguments_to_annotate = fun\n            .arguments\n            .iter()\n            .filter(|argument| argument.annotation.is_none())\n            .collect::<Vec<_>>();\n        let needs_return_annotation = fun.return_annotation.is_none();\n\n        if arguments_to_annotate.is_empty() && !needs_return_annotation {\n            return;\n        }\n\n        let code_action_range = self.edits.src_span_to_lsp_range(fun.location);\n        if overlaps(code_action_range, self.params.range) {\n            self.is_hovering_definition_requiring_annotations = true;\n        }\n\n        // Create new printer to ignore type variables from other definitions\n        let mut printer = Printer::new_without_type_variables(&self.module.ast.names);\n        collect_type_variables(&mut printer, fun);\n\n        // Annotate each argument separately\n        for argument in arguments_to_annotate {\n            self.edits.insert(\n                argument.location.end,\n                format!(\": {}\", printer.print_type(&argument.type_)),\n            );\n        }\n\n        // Annotate the return type if it isn't already annotated\n        if needs_return_annotation {\n            self.edits.insert(\n                fun.location.end,\n                format!(\" -> {}\", printer.print_type(&fun.return_type)),\n            );\n        }\n    }\n}\n\nstruct TypeVariableCollector<'a, 'b> {\n    printer: &'a mut Printer<'b>,\n}\n\n/// Collect type variables defined within a function and register them for a\n/// `Printer`\nfn collect_type_variables(printer: &mut Printer<'_>, function: &TypedFunction) {\n    TypeVariableCollector { printer }.visit_typed_function(function);\n}\n\nimpl<'ast, 'a, 'b> ast::visit::Visit<'ast> for TypeVariableCollector<'a, 'b> {\n    fn visit_type_ast_var(&mut self, _location: &'ast SrcSpan, name: &'ast EcoString) {\n        // Register this type variable so that we don't duplicate names when\n        // adding annotations.\n        self.printer.register_type_variable(name.clone());\n    }\n}\n\npub struct QualifiedConstructor<'a> {\n    import: &'a Import<EcoString>,\n    used_name: EcoString,\n    constructor: EcoString,\n    layer: ast::Layer,\n}\n\nimpl QualifiedConstructor<'_> {\n    fn constructor_import(&self) -> String {\n        if self.layer.is_value() {\n            self.constructor.to_string()\n        } else {\n            format!(\"type {}\", self.constructor)\n        }\n    }\n}\n\npub struct QualifiedToUnqualifiedImportFirstPass<'a, IO> {\n    module: &'a Module,\n    compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n    params: &'a CodeActionParams,\n    line_numbers: &'a LineNumbers,\n    qualified_constructor: Option<QualifiedConstructor<'a>>,\n}\n\nimpl<'a, IO> QualifiedToUnqualifiedImportFirstPass<'a, IO> {\n    fn new(\n        module: &'a Module,\n        compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n        params: &'a CodeActionParams,\n        line_numbers: &'a LineNumbers,\n    ) -> Self {\n        Self {\n            module,\n            compiler,\n            params,\n            line_numbers,\n            qualified_constructor: None,\n        }\n    }\n\n    fn get_module_import(\n        &self,\n        module_name: &EcoString,\n        constructor: &EcoString,\n        layer: ast::Layer,\n    ) -> Option<&'a Import<EcoString>> {\n        let mut matching_import = None;\n\n        for import in &self.module.ast.definitions.imports {\n            if import.used_name().as_deref() == Some(module_name)\n                && let Some(module) = self.compiler.get_module_interface(&import.module)\n            {\n                // If the import is the one we're referring to, we see if the\n                // referred module exports the type/value we are trying to\n                // unqualify: we don't want to offer the action indiscriminately if\n                // it would generate invalid code!\n                let module_exports_constructor = match layer {\n                    ast::Layer::Value => module.get_public_value(constructor).is_some(),\n                    ast::Layer::Type => module.get_public_type(constructor).is_some(),\n                };\n                if module_exports_constructor {\n                    matching_import = Some(import);\n                }\n            } else {\n                // If the import refers to another module we still want to check\n                // if in its unqualified import list there is a name that's equal\n                // to the one we're trying to unqualify. In this case we can't\n                // offer the action as it would generate invalid code.\n                //\n                // For example:\n                // ```gleam\n                // import wibble.{Some}\n                // import option\n                //\n                // pub fn something() {\n                //   option.Some(1)\n                //          ^^^^ We can't unqualify this because `Some` is already\n                //               imported unqualified from the `wibble` module\n                // }\n                // ```\n                //\n                let imported = match layer {\n                    ast::Layer::Value => &import.unqualified_values,\n                    ast::Layer::Type => &import.unqualified_types,\n                };\n                let constructor_already_imported_by_other_module = imported\n                    .iter()\n                    .any(|value| value.used_name() == constructor);\n\n                if constructor_already_imported_by_other_module {\n                    return None;\n                }\n            }\n        }\n\n        matching_import\n    }\n}\n\nimpl<'ast, IO> ast::visit::Visit<'ast> for QualifiedToUnqualifiedImportFirstPass<'ast, IO> {\n    fn visit_type_ast_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast [ast::TypeAst],\n        arguments_types: Option<Vec<Arc<Type>>>,\n    ) {\n        let range = src_span_to_lsp_range(*location, self.line_numbers);\n        if overlaps(self.params.range, range)\n            && let Some((module_alias, _)) = module\n            && let Some(import) = self.get_module_import(module_alias, name, ast::Layer::Type)\n        {\n            self.qualified_constructor = Some(QualifiedConstructor {\n                import,\n                used_name: module_alias.clone(),\n                constructor: name.clone(),\n                layer: ast::Layer::Type,\n            });\n        }\n        ast::visit::visit_type_ast_constructor(\n            self,\n            location,\n            name_location,\n            module,\n            name,\n            arguments,\n            arguments_types,\n        );\n    }\n\n    fn visit_typed_expr_module_select(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        type_: &'ast Arc<Type>,\n        label: &'ast EcoString,\n        module_name: &'ast EcoString,\n        module_alias: &'ast EcoString,\n        constructor: &'ast ModuleValueConstructor,\n    ) {\n        // When hovering over a Record Value Constructor, we want to expand the source span to\n        // include the module name:\n        // option.Some\n        //  ↑\n        // This allows us to offer a code action when hovering over the module name.\n        let range = src_span_to_lsp_range(*location, self.line_numbers);\n        if overlaps(self.params.range, range)\n            && let ModuleValueConstructor::Record {\n                name: constructor_name,\n                ..\n            } = constructor\n            && let Some(import) =\n                self.get_module_import(module_alias, constructor_name, ast::Layer::Value)\n        {\n            self.qualified_constructor = Some(QualifiedConstructor {\n                import,\n                used_name: module_alias.clone(),\n                constructor: constructor_name.clone(),\n                layer: ast::Layer::Value,\n            });\n        }\n        ast::visit::visit_typed_expr_module_select(\n            self,\n            location,\n            field_start,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            constructor,\n        )\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        let range = src_span_to_lsp_range(*location, self.line_numbers);\n        if overlaps(self.params.range, range)\n            && let Some((module_alias, _)) = module\n            && let Inferred::Known(_) = constructor\n            && let Some(import) = self.get_module_import(module_alias, name, ast::Layer::Value)\n        {\n            self.qualified_constructor = Some(QualifiedConstructor {\n                import,\n                used_name: module_alias.clone(),\n                constructor: name.clone(),\n                layer: ast::Layer::Value,\n            });\n        }\n        ast::visit::visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n\n    fn visit_typed_constant_record(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<ast::TypedConstant>>,\n        tag: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        field_map: &'ast Inferred<FieldMap>,\n        record_constructor: &'ast Option<Box<ValueConstructor>>,\n    ) {\n        let range = src_span_to_lsp_range(*location, self.line_numbers);\n        if overlaps(self.params.range, range)\n            && let Some((module_alias, _)) = module\n            && let Some(import) = self.get_module_import(module_alias, name, ast::Layer::Value)\n        {\n            self.qualified_constructor = Some(QualifiedConstructor {\n                import,\n                used_name: module_alias.clone(),\n                constructor: name.clone(),\n                layer: ast::Layer::Value,\n            });\n        }\n        ast::visit::visit_typed_constant_record(\n            self,\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        );\n    }\n\n    fn visit_typed_constant_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        let range = src_span_to_lsp_range(*location, self.line_numbers);\n        if overlaps(self.params.range, range)\n            && let Some((module_alias, _)) = module\n            && let Some(constructor) = constructor\n            && let type_::ValueConstructorVariant::Record { .. } = &constructor.variant\n            && let Some(import) = self.get_module_import(module_alias, name, ast::Layer::Value)\n        {\n            self.qualified_constructor = Some(QualifiedConstructor {\n                import,\n                used_name: module_alias.clone(),\n                constructor: name.clone(),\n                layer: ast::Layer::Value,\n            });\n        }\n        ast::visit::visit_typed_constant_var(self, location, module, name, constructor, type_);\n    }\n}\n\npub struct QualifiedToUnqualifiedImportSecondPass<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    qualified_constructor: QualifiedConstructor<'a>,\n}\n\nimpl<'a> QualifiedToUnqualifiedImportSecondPass<'a> {\n    pub fn new(\n        module: &'a Module,\n        params: &'a CodeActionParams,\n        line_numbers: &'a LineNumbers,\n        qualified_constructor: QualifiedConstructor<'a>,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            qualified_constructor,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n        if self.edits.edits.is_empty() {\n            return vec![];\n        }\n        self.edit_import();\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(&format!(\n            \"Unqualify {}.{}\",\n            self.qualified_constructor.used_name, self.qualified_constructor.constructor\n        ))\n        .kind(CodeActionKind::REFACTOR)\n        .changes(self.params.text_document.uri.clone(), self.edits.edits)\n        .preferred(false)\n        .push_to(&mut action);\n        action\n    }\n\n    fn remove_module_qualifier(&mut self, location: SrcSpan) {\n        self.edits.delete(SrcSpan {\n            start: location.start,\n            end: location.start + self.qualified_constructor.used_name.len() as u32 + 1, // plus .\n        })\n    }\n\n    fn edit_import(&mut self) {\n        let QualifiedConstructor {\n            constructor,\n            layer,\n            import,\n            ..\n        } = &self.qualified_constructor;\n        let is_imported = if layer.is_value() {\n            import\n                .unqualified_values\n                .iter()\n                .any(|value| value.used_name() == constructor)\n        } else {\n            import\n                .unqualified_types\n                .iter()\n                .any(|type_| type_.used_name() == constructor)\n        };\n        if is_imported {\n            return;\n        }\n        let (insert_pos, new_text) = edits::insert_unqualified_import(\n            import,\n            &self.module.code,\n            self.qualified_constructor.constructor_import(),\n        );\n        let span = SrcSpan::new(insert_pos, insert_pos);\n        self.edits.replace(span, new_text);\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for QualifiedToUnqualifiedImportSecondPass<'ast> {\n    fn visit_type_ast_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast [ast::TypeAst],\n        arguments_types: Option<Vec<Arc<Type>>>,\n    ) {\n        if let Some((module_name, _)) = module {\n            let QualifiedConstructor {\n                used_name,\n                constructor,\n                layer,\n                ..\n            } = &self.qualified_constructor;\n\n            if !layer.is_value() && used_name == module_name && name == constructor {\n                self.remove_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_type_ast_constructor(\n            self,\n            location,\n            name_location,\n            module,\n            name,\n            arguments,\n            arguments_types,\n        );\n    }\n\n    fn visit_typed_expr_module_select(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        type_: &'ast Arc<Type>,\n        label: &'ast EcoString,\n        module_name: &'ast EcoString,\n        module_alias: &'ast EcoString,\n        constructor: &'ast ModuleValueConstructor,\n    ) {\n        if let ModuleValueConstructor::Record { name, .. } = constructor {\n            let QualifiedConstructor {\n                used_name,\n                constructor,\n                layer,\n                ..\n            } = &self.qualified_constructor;\n\n            if layer.is_value() && used_name == module_alias && name == constructor {\n                self.remove_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_expr_module_select(\n            self,\n            location,\n            field_start,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            constructor,\n        )\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        if let Some((module_alias, _)) = module\n            && let Inferred::Known(_) = constructor\n        {\n            let QualifiedConstructor {\n                used_name,\n                constructor,\n                layer,\n                ..\n            } = &self.qualified_constructor;\n\n            if layer.is_value() && used_name == module_alias && name == constructor {\n                self.remove_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n\n    fn visit_typed_constant_record(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<ast::TypedConstant>>,\n        tag: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        field_map: &'ast Inferred<FieldMap>,\n        record_constructor: &'ast Option<Box<ValueConstructor>>,\n    ) {\n        if let Some((module_alias, _)) = module {\n            let QualifiedConstructor {\n                used_name,\n                constructor,\n                layer,\n                ..\n            } = &self.qualified_constructor;\n\n            if layer.is_value() && used_name == module_alias && name == constructor {\n                self.remove_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_constant_record(\n            self,\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        );\n    }\n\n    fn visit_typed_constant_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        if let Some((module_alias, _)) = module {\n            let QualifiedConstructor {\n                used_name,\n                constructor: wanted_constructor,\n                layer,\n                ..\n            } = &self.qualified_constructor;\n\n            if layer.is_value() && used_name == module_alias && name == wanted_constructor {\n                self.remove_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_constant_var(self, location, module, name, constructor, type_);\n    }\n}\n\npub fn code_action_convert_qualified_constructor_to_unqualified<IO>(\n    module: &Module,\n    compiler: &LspProjectCompiler<FileSystemProxy<IO>>,\n    line_numbers: &LineNumbers,\n    params: &CodeActionParams,\n    actions: &mut Vec<CodeAction>,\n) {\n    let mut first_pass =\n        QualifiedToUnqualifiedImportFirstPass::new(module, compiler, params, line_numbers);\n    first_pass.visit_typed_module(&module.ast);\n    let Some(qualified_constructor) = first_pass.qualified_constructor else {\n        return;\n    };\n    let second_pass = QualifiedToUnqualifiedImportSecondPass::new(\n        module,\n        params,\n        line_numbers,\n        qualified_constructor,\n    );\n    let new_actions = second_pass.code_actions();\n    actions.extend(new_actions);\n}\n\nstruct UnqualifiedConstructor<'a> {\n    module_name: EcoString,\n    constructor: &'a ast::UnqualifiedImport,\n    layer: ast::Layer,\n}\n\nstruct UnqualifiedToQualifiedImportFirstPass<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    line_numbers: &'a LineNumbers,\n    unqualified_constructor: Option<UnqualifiedConstructor<'a>>,\n}\n\nimpl<'a> UnqualifiedToQualifiedImportFirstPass<'a> {\n    fn new(\n        module: &'a Module,\n        params: &'a CodeActionParams,\n        line_numbers: &'a LineNumbers,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            line_numbers,\n            unqualified_constructor: None,\n        }\n    }\n\n    fn get_module_import_from_value_constructor(\n        &mut self,\n        module_name: &EcoString,\n        constructor_name: &EcoString,\n    ) {\n        self.unqualified_constructor = self\n            .module\n            .ast\n            .definitions\n            .imports\n            .iter()\n            .filter(|import| import.module == *module_name)\n            .find_map(|import| {\n                import\n                    .unqualified_values\n                    .iter()\n                    .find(|value| value.used_name() == constructor_name)\n                    .and_then(|value| {\n                        Some(UnqualifiedConstructor {\n                            constructor: value,\n                            module_name: import.used_name()?,\n                            layer: ast::Layer::Value,\n                        })\n                    })\n            })\n    }\n\n    fn get_module_import_from_type_constructor(&mut self, constructor_name: &EcoString) {\n        self.unqualified_constructor =\n            self.module\n                .ast\n                .definitions\n                .imports\n                .iter()\n                .find_map(|import| {\n                    if let Some(ty) = import\n                        .unqualified_types\n                        .iter()\n                        .find(|ty| ty.used_name() == constructor_name)\n                    {\n                        return Some(UnqualifiedConstructor {\n                            constructor: ty,\n                            module_name: import.used_name()?,\n                            layer: ast::Layer::Type,\n                        });\n                    }\n                    None\n                })\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for UnqualifiedToQualifiedImportFirstPass<'ast> {\n    fn visit_type_ast_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast [ast::TypeAst],\n        arguments_types: Option<Vec<Arc<Type>>>,\n    ) {\n        if module.is_none()\n            && overlaps(\n                self.params.range,\n                src_span_to_lsp_range(*location, self.line_numbers),\n            )\n        {\n            self.get_module_import_from_type_constructor(name);\n        }\n\n        ast::visit::visit_type_ast_constructor(\n            self,\n            location,\n            name_location,\n            module,\n            name,\n            arguments,\n            arguments_types,\n        );\n    }\n\n    fn visit_typed_expr_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        let range = src_span_to_lsp_range(*location, self.line_numbers);\n        if overlaps(self.params.range, range)\n            && let Some(module_name) = match &constructor.variant {\n                type_::ValueConstructorVariant::ModuleConstant { module, .. }\n                | type_::ValueConstructorVariant::ModuleFn { module, .. }\n                | type_::ValueConstructorVariant::Record { module, .. } => Some(module),\n\n                type_::ValueConstructorVariant::LocalVariable { .. } => None,\n            }\n        {\n            self.get_module_import_from_value_constructor(module_name, name);\n        }\n        ast::visit::visit_typed_expr_var(self, location, constructor, name);\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        if module.is_none()\n            && overlaps(\n                self.params.range,\n                src_span_to_lsp_range(*location, self.line_numbers),\n            )\n            && let Inferred::Known(constructor) = constructor\n        {\n            self.get_module_import_from_value_constructor(&constructor.module, name);\n        }\n\n        ast::visit::visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n\n    fn visit_typed_constant_record(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<ast::TypedConstant>>,\n        _tag: &'ast EcoString,\n        _type_: &'ast Arc<Type>,\n        _field_map: &'ast Inferred<FieldMap>,\n        record_constructor: &'ast Option<Box<ValueConstructor>>,\n    ) {\n        if module.is_none()\n            && overlaps(\n                self.params.range,\n                src_span_to_lsp_range(*location, self.line_numbers),\n            )\n            && let Some(record_constructor) = record_constructor\n            && let Some(module_name) = match &record_constructor.variant {\n                type_::ValueConstructorVariant::ModuleConstant { module, .. }\n                | type_::ValueConstructorVariant::ModuleFn { module, .. }\n                | type_::ValueConstructorVariant::Record { module, .. } => Some(module),\n\n                type_::ValueConstructorVariant::LocalVariable { .. } => None,\n            }\n        {\n            self.get_module_import_from_value_constructor(module_name, name);\n        }\n        ast::visit::visit_typed_constant_record(\n            self,\n            location,\n            module,\n            name,\n            arguments,\n            _tag,\n            _type_,\n            _field_map,\n            record_constructor,\n        );\n    }\n\n    fn visit_typed_constant_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        if module.is_none()\n            && overlaps(\n                self.params.range,\n                src_span_to_lsp_range(*location, self.line_numbers),\n            )\n            && let Some(constructor) = constructor\n            && let Some(module_name) = match &constructor.variant {\n                type_::ValueConstructorVariant::ModuleConstant { module, .. }\n                | type_::ValueConstructorVariant::ModuleFn { module, .. }\n                | type_::ValueConstructorVariant::Record { module, .. } => Some(module),\n\n                type_::ValueConstructorVariant::LocalVariable { .. } => None,\n            }\n        {\n            self.get_module_import_from_value_constructor(module_name, name);\n        }\n        ast::visit::visit_typed_constant_var(self, location, module, name, constructor, type_);\n    }\n}\n\nstruct UnqualifiedToQualifiedImportSecondPass<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    unqualified_constructor: UnqualifiedConstructor<'a>,\n}\n\nimpl<'a> UnqualifiedToQualifiedImportSecondPass<'a> {\n    pub fn new(\n        module: &'a Module,\n        params: &'a CodeActionParams,\n        line_numbers: &'a LineNumbers,\n        unqualified_constructor: UnqualifiedConstructor<'a>,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            unqualified_constructor,\n        }\n    }\n\n    fn add_module_qualifier(&mut self, location: SrcSpan) {\n        let src_span = SrcSpan::new(\n            location.start,\n            location.start + self.unqualified_constructor.constructor.used_name().len() as u32,\n        );\n\n        self.edits.replace(\n            src_span,\n            format!(\n                \"{}.{}\",\n                self.unqualified_constructor.module_name,\n                self.unqualified_constructor.constructor.name\n            ),\n        );\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n        if self.edits.edits.is_empty() {\n            return vec![];\n        }\n        self.edit_import();\n        let mut action = Vec::with_capacity(1);\n        let UnqualifiedConstructor {\n            module_name,\n            constructor,\n            ..\n        } = self.unqualified_constructor;\n        CodeActionBuilder::new(&format!(\n            \"Qualify {} as {}.{}\",\n            constructor.used_name(),\n            module_name,\n            constructor.name,\n        ))\n        .kind(CodeActionKind::REFACTOR)\n        .changes(self.params.text_document.uri.clone(), self.edits.edits)\n        .preferred(false)\n        .push_to(&mut action);\n        action\n    }\n\n    fn edit_import(&mut self) {\n        let UnqualifiedConstructor {\n            constructor:\n                ast::UnqualifiedImport {\n                    location: constructor_import_span,\n                    ..\n                },\n            ..\n        } = self.unqualified_constructor;\n\n        let mut last_char_pos = constructor_import_span.end as usize;\n        while self.module.code.get(last_char_pos..last_char_pos + 1) == Some(\" \") {\n            last_char_pos += 1;\n        }\n        if self.module.code.get(last_char_pos..last_char_pos + 1) == Some(\",\") {\n            last_char_pos += 1;\n        }\n        if self.module.code.get(last_char_pos..last_char_pos + 1) == Some(\" \") {\n            last_char_pos += 1;\n        }\n\n        self.edits.delete(SrcSpan::new(\n            constructor_import_span.start,\n            last_char_pos as u32,\n        ));\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for UnqualifiedToQualifiedImportSecondPass<'ast> {\n    fn visit_type_ast_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast [ast::TypeAst],\n        arguments_types: Option<Vec<Arc<Type>>>,\n    ) {\n        if module.is_none() {\n            let UnqualifiedConstructor {\n                constructor, layer, ..\n            } = &self.unqualified_constructor;\n            if !layer.is_value() && constructor.used_name() == name {\n                self.add_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_type_ast_constructor(\n            self,\n            location,\n            name_location,\n            module,\n            name,\n            arguments,\n            arguments_types,\n        );\n    }\n\n    fn visit_typed_expr_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        let UnqualifiedConstructor {\n            constructor: wanted_constructor,\n            layer,\n            ..\n        } = &self.unqualified_constructor;\n\n        if layer.is_value()\n            && wanted_constructor.used_name() == name\n            && !constructor.is_local_variable()\n        {\n            self.add_module_qualifier(*location);\n        }\n        ast::visit::visit_typed_expr_var(self, location, constructor, name);\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        if module.is_none() {\n            let UnqualifiedConstructor {\n                constructor: wanted_constructor,\n                layer,\n                ..\n            } = &self.unqualified_constructor;\n            if layer.is_value() && wanted_constructor.used_name() == name {\n                self.add_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n\n    fn visit_typed_constant_record(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<ast::TypedConstant>>,\n        tag: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        field_map: &'ast Inferred<FieldMap>,\n        record_constructor: &'ast Option<Box<ValueConstructor>>,\n    ) {\n        if module.is_none() {\n            let UnqualifiedConstructor {\n                constructor: wanted_constructor,\n                layer,\n                ..\n            } = &self.unqualified_constructor;\n            if layer.is_value() && wanted_constructor.used_name() == name {\n                self.add_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_constant_record(\n            self,\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        );\n    }\n\n    fn visit_typed_constant_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        if module.is_none() {\n            let UnqualifiedConstructor {\n                constructor: wanted_constructor,\n                layer,\n                ..\n            } = &self.unqualified_constructor;\n            if layer.is_value() && wanted_constructor.used_name() == name {\n                self.add_module_qualifier(*location);\n            }\n        }\n        ast::visit::visit_typed_constant_var(self, location, module, name, constructor, type_);\n    }\n}\n\npub fn code_action_convert_unqualified_constructor_to_qualified(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &CodeActionParams,\n    actions: &mut Vec<CodeAction>,\n) {\n    let mut first_pass = UnqualifiedToQualifiedImportFirstPass::new(module, params, line_numbers);\n    first_pass.visit_typed_module(&module.ast);\n    let Some(unqualified_constructor) = first_pass.unqualified_constructor else {\n        return;\n    };\n    let second_pass = UnqualifiedToQualifiedImportSecondPass::new(\n        module,\n        params,\n        line_numbers,\n        unqualified_constructor,\n    );\n    let new_actions = second_pass.code_actions();\n    actions.extend(new_actions);\n}\n\n/// Builder for code action to apply the convert from use action, turning a use\n/// expression into a regular function call.\n///\npub struct ConvertFromUse<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    selected_use: Option<&'a TypedUse>,\n}\n\nimpl<'a> ConvertFromUse<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            selected_use: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(use_) = self.selected_use else {\n            return vec![];\n        };\n\n        let TypedExpr::Call { arguments, fun, .. } = use_.call.as_ref() else {\n            return vec![];\n        };\n\n        // If the use callback we're desugaring is using labels, that means we\n        // have to add the last argument's label when writing the callback;\n        // otherwise, it would result in invalid code.\n        //\n        //     use acc, item <- list.fold(over: list, from: 1)\n        //     todo\n        //\n        // Needs to be rewritten as:\n        //\n        //     list.fold(over: list, from: 1, with: fn(acc, item) { ... })\n        //                                    ^^^^^ We cannot forget to add this label back!\n        //\n        let callback_label = if arguments.iter().any(|arg| arg.label.is_some()) {\n            fun.field_map()\n                .and_then(|field_map| field_map.missing_labels(arguments).last().cloned())\n                .map(|label| eco_format!(\"{label}: \"))\n                .unwrap_or(EcoString::from(\"\"))\n        } else {\n            EcoString::from(\"\")\n        };\n\n        // The use callback is not necessarily the last argument. If you have\n        // the following function: `wibble(a a, b b) { todo }`\n        // And use it like this: `use <- wibble(b: 1)`, the first argument `a`\n        // is going to be the use callback, not the last one!\n        let use_callback = arguments.iter().find(|arg| arg.is_use_implicit_callback());\n        let Some(CallArg {\n            implicit: Some(ImplicitCallArgOrigin::Use),\n            value: TypedExpr::Fn { body, type_, .. },\n            ..\n        }) = use_callback\n        else {\n            return vec![];\n        };\n\n        // If there's arguments on the left hand side of the function we extract\n        // those so we can paste them back as the anonymous function arguments.\n        let assignments = if type_.fn_arity().is_some_and(|arity| arity >= 1) {\n            let assignments_range =\n                use_.assignments_location.start as usize..use_.assignments_location.end as usize;\n            self.module\n                .code\n                .get(assignments_range)\n                .expect(\"use assignments\")\n        } else {\n            \"\"\n        };\n\n        // We first delete everything on the left hand side of use and the use\n        // arrow.\n        self.edits.delete(SrcSpan {\n            start: use_.location.start,\n            end: use_.right_hand_side_location.start,\n        });\n\n        let use_line_end = use_.right_hand_side_location.end;\n        let use_rhs_function_has_some_explicit_arguments = arguments\n            .iter()\n            .filter(|argument| !argument.is_use_implicit_callback())\n            .peekable()\n            .peek()\n            .is_some();\n\n        let use_rhs_function_ends_with_closed_parentheses = self\n            .module\n            .code\n            .get(use_line_end as usize - 1..use_line_end as usize)\n            == Some(\")\");\n\n        let last_explicit_arg = arguments.iter().rfind(|argument| !argument.is_implicit());\n        let last_arg_end = last_explicit_arg.map_or(use_line_end - 1, |arg| arg.location.end);\n\n        // This is the piece of code between the end of the last argument and\n        // the end of the use_expression:\n        //\n        //   use <- wibble(a, b,    )\n        //                     ^^^^^ This piece right here, from `,` included\n        //                           up to `)` excluded.\n        //\n        let text_after_last_argument = self\n            .module\n            .code\n            .get(last_arg_end as usize..use_line_end as usize - 1);\n        let use_rhs_has_comma_after_last_argument =\n            text_after_last_argument.is_some_and(|code| code.contains(','));\n        let needs_space_before_callback =\n            text_after_last_argument.is_some_and(|code| !code.is_empty() && !code.ends_with(' '));\n\n        if use_rhs_function_ends_with_closed_parentheses {\n            // If the function on the right hand side of use ends with a closed\n            // parentheses then we have to remove it and add it later at the end\n            // of the anonymous function we're inserting.\n            //\n            //     use <- wibble()\n            //                   ^ To add the fn() we need to first remove this\n            //\n            // So here we write over the last closed parentheses to remove it.\n            let callback_start = format!(\"{callback_label}fn({assignments}) {{\");\n            self.edits.replace(\n                SrcSpan {\n                    start: use_line_end - 1,\n                    end: use_line_end,\n                },\n                // If the function on the rhs of use has other orguments besides\n                // the implicit fn expression then we need to put a comma after\n                // the last argument.\n                if use_rhs_function_has_some_explicit_arguments\n                    && !use_rhs_has_comma_after_last_argument\n                {\n                    format!(\", {callback_start}\")\n                } else if needs_space_before_callback {\n                    format!(\" {callback_start}\")\n                } else {\n                    callback_start.to_string()\n                },\n            )\n        } else {\n            // On the other hand, if the function on the right hand side doesn't\n            // end with a closed parenthese then we have to manually add it.\n            //\n            //     use <- wibble\n            //                  ^ No parentheses\n            //\n            self.edits\n                .insert(use_line_end, format!(\"(fn({assignments}) {{\"))\n        };\n\n        // Then we have to increase indentation for all the lines of the use\n        // body.\n        let first_fn_expression_range = self.edits.src_span_to_lsp_range(body.first().location());\n        let use_body_range = self.edits.src_span_to_lsp_range(use_.call.location());\n\n        for line in first_fn_expression_range.start.line..=use_body_range.end.line {\n            self.edits.edits.push(TextEdit {\n                range: Range {\n                    start: Position { line, character: 0 },\n                    end: Position { line, character: 0 },\n                },\n                new_text: \"  \".to_string(),\n            })\n        }\n\n        let final_line_indentation = \" \".repeat(use_body_range.start.character as usize);\n        self.edits.insert(\n            use_.call.location().end,\n            format!(\"\\n{final_line_indentation}}})\"),\n        );\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Convert from `use`\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ConvertFromUse<'ast> {\n    fn visit_typed_use(&mut self, use_: &'ast TypedUse) {\n        let use_range = self.edits.src_span_to_lsp_range(use_.location);\n\n        // If the use expression is using patterns that are not just variable\n        // assignments then we can't automatically rewrite it as it would result\n        // in a syntax error as we can't pattern match in an anonymous function\n        // head.\n        // At the same time we can't safely add bindings inside the anonymous\n        // function body by picking placeholder names as we'd risk shadowing\n        // variables coming from the outer scope.\n        // So we just skip those use expressions we can't safely rewrite!\n        if within(self.params.range, use_range)\n            && use_\n                .assignments\n                .iter()\n                .all(|assignment| assignment.pattern.is_variable())\n        {\n            self.selected_use = Some(use_);\n        }\n\n        // We still want to visit the use expression so that we always end up\n        // picking the innermost, most relevant use under the cursor.\n        self.visit_typed_expr(&use_.call);\n    }\n}\n\n/// Builder for code action to apply the convert to use action.\n///\npub struct ConvertToUse<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    selected_call: Option<CallLocations>,\n}\n\n/// All the locations we'll need to transform a function call into a use\n/// expression.\n///\nstruct CallLocations {\n    call_span: SrcSpan,\n    called_function_span: SrcSpan,\n    callback_arguments_span: Option<SrcSpan>,\n    arg_before_callback_span: Option<SrcSpan>,\n    callback_body_span: SrcSpan,\n}\n\nimpl<'a> ConvertToUse<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            selected_call: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(CallLocations {\n            call_span,\n            called_function_span,\n            callback_arguments_span,\n            arg_before_callback_span,\n            callback_body_span,\n        }) = self.selected_call\n        else {\n            return vec![];\n        };\n\n        // This is the nesting level of the `use` keyword we've inserted, we\n        // want to move the entire body of the anonymous function to this level.\n        let use_nesting_level = self.edits.src_span_to_lsp_range(call_span).start.character;\n        let indentation = \" \".repeat(use_nesting_level as usize);\n\n        // First we move the callback arguments to the left hand side of the\n        // call and add the `use` keyword.\n        let left_hand_side_text = if let Some(arguments_location) = callback_arguments_span {\n            let arguments_start = arguments_location.start as usize;\n            let arguments_end = arguments_location.end as usize;\n            let arguments_text = self\n                .module\n                .code\n                .get(arguments_start..arguments_end)\n                .expect(\"fn args\");\n            format!(\"use {arguments_text} <- \")\n        } else {\n            \"use <- \".into()\n        };\n\n        self.edits.insert(call_span.start, left_hand_side_text);\n\n        match arg_before_callback_span {\n            // If the function call has no other arguments besides the callback then\n            // we just have to remove the `fn(...) {` part.\n            //\n            //     wibble(fn(...) { ... })\n            //           ^^^^^^^^^^ This goes from the end of the called function\n            //                      To the start of the first thing in the anonymous\n            //                      function's body.\n            //\n            None => self.edits.replace(\n                SrcSpan::new(called_function_span.end, callback_body_span.start),\n                format!(\"\\n{indentation}\"),\n            ),\n            // If it has other arguments we'll have to remove those and add a closed\n            // parentheses too:\n            //\n            //     wibble(1, 2, fn(...) { ... })\n            //                ^^^^^^^^^^^ We have to replace this with a `)`, it\n            //                            goes from the end of the second-to-last\n            //                            argument to the start of the first thing\n            //                            in the anonymous function's body.\n            //\n            Some(arg_before_callback) => self.edits.replace(\n                SrcSpan::new(arg_before_callback.end, callback_body_span.start),\n                format!(\")\\n{indentation}\"),\n            ),\n        };\n\n        // Then we have to remove two spaces of indentation from each line of\n        // the callback function's body.\n        let body_range = self.edits.src_span_to_lsp_range(callback_body_span);\n        for line in body_range.start.line + 1..=body_range.end.line {\n            self.edits.delete_range(Range::new(\n                Position { line, character: 0 },\n                Position { line, character: 2 },\n            ))\n        }\n\n        // Then we have to remove the anonymous fn closing `}` and the call's\n        // closing `)`.\n        self.edits\n            .delete(SrcSpan::new(callback_body_span.end, call_span.end));\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Convert to `use`\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ConvertToUse<'ast> {\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        // The cursor has to be inside the last statement of the function to\n        // offer the code action.\n        if let Some(last) = &fun.body.last()\n            && within(\n                self.params.range,\n                self.edits.src_span_to_lsp_range(last.location()),\n            )\n            && let Some(call_data) = turn_statement_into_use(last)\n        {\n            self.selected_call = Some(call_data);\n        }\n\n        ast::visit::visit_typed_function(self, fun)\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        // The cursor has to be inside the last statement of the body to\n        // offer the code action.\n        let last_statement_range = self.edits.src_span_to_lsp_range(body.last().location());\n        if within(self.params.range, last_statement_range)\n            && let Some(call_data) = turn_statement_into_use(body.last())\n        {\n            self.selected_call = Some(call_data);\n        }\n\n        ast::visit::visit_typed_expr_fn(\n            self,\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n        );\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast SrcSpan,\n        statements: &'ast [TypedStatement],\n    ) {\n        let Some(last_statement) = statements.last() else {\n            return;\n        };\n\n        // The cursor has to be inside the last statement of the block to offer\n        // the code action.\n        let statement_range = self.edits.src_span_to_lsp_range(last_statement.location());\n        if within(self.params.range, statement_range) {\n            // Only the last statement of a block can be turned into a use!\n            if let Some(selected_call) = turn_statement_into_use(last_statement) {\n                self.selected_call = Some(selected_call)\n            }\n        }\n\n        ast::visit::visit_typed_expr_block(self, location, statements);\n    }\n}\n\nfn turn_statement_into_use(statement: &TypedStatement) -> Option<CallLocations> {\n    match statement {\n        ast::Statement::Use(_) | ast::Statement::Assignment(_) | ast::Statement::Assert(_) => None,\n        ast::Statement::Expression(expression) => turn_expression_into_use(expression),\n    }\n}\n\nfn turn_expression_into_use(expr: &TypedExpr) -> Option<CallLocations> {\n    let TypedExpr::Call {\n        arguments,\n        location: call_span,\n        fun: called_function,\n        ..\n    } = expr\n    else {\n        return None;\n    };\n\n    // The function arguments in the ast are reordered using function's field map.\n    // This means that in the `args` array they might not appear in the same order\n    // in which they are written by the user. Since the rest of the code relies\n    // on their order in the written code we first have to sort them by their\n    // source position.\n    let arguments = arguments\n        .iter()\n        .sorted_by_key(|argument| argument.location.start)\n        .collect_vec();\n\n    let CallArg {\n        value: last_arg,\n        implicit: None,\n        ..\n    } = arguments.last()?\n    else {\n        return None;\n    };\n\n    let TypedExpr::Fn {\n        arguments: callback_arguments,\n        body,\n        ..\n    } = last_arg\n    else {\n        return None;\n    };\n\n    let callback_arguments_span = match (callback_arguments.first(), callback_arguments.last()) {\n        (Some(first), Some(last)) => Some(first.location.merge(&last.location)),\n        _ => None,\n    };\n\n    let arg_before_callback_span = if arguments.len() >= 2 {\n        arguments\n            .get(arguments.len() - 2)\n            .map(|call_arg| call_arg.location)\n    } else {\n        None\n    };\n\n    let callback_body_span = body.first().location().merge(&body.last().last_location());\n\n    Some(CallLocations {\n        call_span: *call_span,\n        called_function_span: called_function.location(),\n        callback_arguments_span,\n        arg_before_callback_span,\n        callback_body_span,\n    })\n}\n\n/// Builder for code action to extract expression into a variable.\n/// The action will wrap the expression in a block if needed in the appropriate scope.\n///\n/// For using the code action on the following selection:\n///\n/// ```gleam\n/// fn void() {\n///   case result {\n///     Ok(value) -> 2 * value + 1\n/// //               ^^^^^^^^^\n///     Error(_) -> panic\n///   }\n/// }\n/// ```\n///\n/// Will result:\n///\n/// ```gleam\n/// fn void() {\n///   case result {\n///     Ok(value) -> {\n///       let int = 2 * value\n///       int + 1\n///     }\n///     Error(_) -> panic\n///   }\n/// }\n/// ```\npub struct ExtractVariable<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    position: Option<ExtractVariablePosition>,\n    selected_expression: Option<ExtractedToVariable>,\n    statement_before_selected_expression: Option<SrcSpan>,\n    latest_statement: Option<SrcSpan>,\n    to_be_wrapped: bool,\n    name_generator: NameGenerator,\n}\n\npub enum ExtractedToVariable {\n    Expression { location: SrcSpan, name: EcoString },\n    StartOfPipeline { location: SrcSpan, name: EcoString },\n}\n\n/// The Position of the selected code\n#[derive(PartialEq, Eq, Copy, Clone, Debug)]\nenum ExtractVariablePosition {\n    InsideCaptureBody,\n    /// Full statements (i.e. assignments, `use`s, and simple expressions).\n    TopLevelStatement,\n    /// The call on the right hand side of a pipe `|>`.\n    PipelineCall,\n    /// The right hand side of the `->` in a case expression.\n    InsideCaseClause,\n    /// A call argument. This can also be a `use` callback.\n    CallArg,\n}\n\nimpl<'a> ExtractVariable<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            position: None,\n            selected_expression: None,\n            statement_before_selected_expression: None,\n            latest_statement: None,\n            to_be_wrapped: false,\n            name_generator: NameGenerator::new(),\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let (Some(extracted_value), Some(insert_location)) = (\n            self.selected_expression,\n            self.statement_before_selected_expression,\n        ) else {\n            return vec![];\n        };\n\n        let variable_name = match &extracted_value {\n            ExtractedToVariable::Expression { name, .. }\n            | ExtractedToVariable::StartOfPipeline { name, .. } => name,\n        };\n        let expression_span = match &extracted_value {\n            ExtractedToVariable::Expression { location, .. }\n            | ExtractedToVariable::StartOfPipeline { location, .. } => location,\n        };\n\n        let content = self\n            .module\n            .code\n            .get(expression_span.start as usize..expression_span.end as usize)\n            .expect(\"selected expression\");\n\n        let range = self.edits.src_span_to_lsp_range(insert_location);\n\n        let indent_size =\n            count_indentation(&self.module.code, self.edits.line_numbers, range.start.line);\n\n        let mut indent = \" \".repeat(indent_size);\n\n        // We insert the variable declaration\n        // Wrap in a block if needed\n        let mut insertion = match extracted_value {\n            ExtractedToVariable::Expression { .. } => format!(\"let {variable_name} = {content}\"),\n            ExtractedToVariable::StartOfPipeline { .. } => {\n                format!(\"let {variable_name} =\\n{indent}  {content}\\n\")\n            }\n        };\n\n        if self.to_be_wrapped {\n            let line_end = self\n                .edits\n                .line_numbers\n                .line_starts\n                .get((range.end.line + 1) as usize)\n                .expect(\"Line number should be valid\");\n\n            self.edits.insert(*line_end, format!(\"{indent}}}\\n\"));\n            indent += \"  \";\n            insertion = format!(\"{{\\n{indent}{insertion}\");\n        };\n\n        self.edits\n            .insert(insert_location.start, format!(\"{insertion}\\n{indent}\"));\n\n        self.edits\n            .replace(*expression_span, String::from(variable_name));\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Extract variable\")\n            .kind(CodeActionKind::REFACTOR_EXTRACT)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    fn inside_new_scope<F>(&mut self, fun: F)\n    where\n        F: Fn(&mut Self),\n    {\n        let names = self.name_generator.clone();\n        fun(self);\n        self.name_generator = names;\n    }\n\n    fn generate_candidate_name(&mut self, type_: Arc<Type>) -> EcoString {\n        let name = self.name_generator.generate_name_from_type(&type_);\n        // When the generator generates a name, it rightfully inserts it in the\n        // current scope so that it cannot be used again.\n        // However, in our case it's not what we want: the name we're generating\n        // is a candidate for what we might use for a single variable, at the\n        // end of the whole process we're gonna pick just a single name.\n        // If we were to insert this name into scope, that means that all the\n        // other candidates would have a suffix `int_2`, `int_3`, ...\n        // When we finally pick one it would be strange if the picked name had\n        // a suffix but no `int`, `int_1`, ... were in scope!\n        let _ = self.name_generator.used_names.remove(&name);\n        name\n    }\n\n    fn at_position<F>(&mut self, position: ExtractVariablePosition, fun: F)\n    where\n        F: Fn(&mut Self),\n    {\n        self.at_optional_position(Some(position), fun);\n    }\n\n    fn at_optional_position<F>(&mut self, position: Option<ExtractVariablePosition>, fun: F)\n    where\n        F: Fn(&mut Self),\n    {\n        let previous_statement = self.latest_statement;\n        let previous_position = self.position;\n        self.position = position;\n        fun(self);\n        self.position = previous_position;\n        self.latest_statement = previous_statement;\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ExtractVariable<'ast> {\n    fn visit_typed_statement(&mut self, statement: &'ast TypedStatement) {\n        let range = self.edits.src_span_to_lsp_range(statement.location());\n        if !within(self.params.range, range) {\n            self.latest_statement = Some(statement.location());\n            ast::visit::visit_typed_statement(self, statement);\n            return;\n        }\n\n        match self.position {\n            // A capture body is comprised of just a single expression statement\n            // that is inserted by the compiler, we don't really want to put\n            // anything before that; so in this case we avoid tracking it.\n            Some(ExtractVariablePosition::InsideCaptureBody) => {}\n            Some(ExtractVariablePosition::PipelineCall) => {\n                // Insert above the pipeline start\n                self.latest_statement = Some(statement.location());\n            }\n            _ => {\n                // Insert below the previous statement\n                self.latest_statement = Some(statement.location());\n                self.statement_before_selected_expression = self.latest_statement;\n            }\n        }\n\n        self.at_position(ExtractVariablePosition::TopLevelStatement, |this| {\n            ast::visit::visit_typed_statement(this, statement);\n        });\n    }\n\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        let fun_range = self.edits.src_span_to_lsp_range(SrcSpan {\n            start: fun.location.start,\n            end: fun.end_position,\n        });\n\n        if !within(self.params.range, fun_range) {\n            return;\n        }\n\n        // We reset the name generator to purge the variable names from other\n        // scopes.\n        // We then reserve the names already used by top level definitions.\n        self.name_generator = NameGenerator::new();\n        self.name_generator\n            .reserve_module_value_names(&self.module.ast.definitions);\n\n        ast::visit::visit_typed_function(self, fun);\n    }\n\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        if let Pattern::Variable { name, .. } = &assignment.pattern {\n            self.name_generator.add_used_name(name.clone())\n        };\n        ast::visit::visit_typed_assignment(self, assignment);\n    }\n\n    fn visit_typed_expr_pipeline(\n        &mut self,\n        location: &'ast SrcSpan,\n        first_value: &'ast TypedPipelineAssignment,\n        assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)],\n        finally: &'ast TypedExpr,\n        finally_kind: &'ast PipelineAssignmentKind,\n    ) {\n        let expr_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, expr_range) {\n            ast::visit::visit_typed_expr_pipeline(\n                self,\n                location,\n                first_value,\n                assignments,\n                finally,\n                finally_kind,\n            );\n            return;\n        };\n\n        // Visiting a pipeline requires a bit of care, we don't want to extract\n        // intermediate steps as variables (those are function calls)!\n        // So we start by checking if the selected section contains multiple\n        // steps including the first one: in that case we can extract all those\n        // steps as a single variable.\n        let selection = self.edits.lsp_range_to_src_span(self.params.range);\n        let is_inside_first_step = first_value.location.contains(selection.start);\n        let last_included_step = assignments.iter().find_map(|(assignment, _kind)| {\n            if assignment.location.contains(selection.end) {\n                Some(assignment)\n            } else {\n                None\n            }\n        });\n\n        if let Some(last) = last_included_step\n            && is_inside_first_step\n        {\n            let location = first_value.location.merge(&last.value.location());\n            self.selected_expression = Some(ExtractedToVariable::StartOfPipeline {\n                location,\n                name: self.generate_candidate_name(last.type_()),\n            });\n            return;\n        }\n\n        // Otherwise we visit all the steps individually to see  if there's\n        // something _inside_ a step that might be extracted.\n        let all_assignments =\n            iter::once(first_value).chain(assignments.iter().map(|(assignment, _kind)| assignment));\n        for assignment in all_assignments {\n            // With the position as \"PipelineCall\" we know we can't extract the\n            // pipeline step itself!\n            self.at_position(ExtractVariablePosition::PipelineCall, |this| {\n                this.visit_typed_pipeline_assignment(assignment);\n            });\n        }\n\n        self.at_position(ExtractVariablePosition::PipelineCall, |this| {\n            this.visit_typed_expr(finally)\n        });\n    }\n\n    fn visit_typed_expr(&mut self, expr: &'ast TypedExpr) {\n        let expr_location = expr.location();\n        let expr_range = self.edits.src_span_to_lsp_range(expr_location);\n        if !within(self.params.range, expr_range) {\n            ast::visit::visit_typed_expr(self, expr);\n            return;\n        }\n\n        // If the expression is a top level statement we don't want to extract\n        // it into a variable. It would mean we would turn this:\n        //\n        // ```gleam\n        // pub fn main() {\n        //   let wibble = 1\n        //   //           ^ cursor here\n        // }\n        //\n        // // into:\n        //\n        // pub fn main() {\n        //   let int = 1\n        //   let wibble = int\n        // }\n        // ```\n        //\n        // Not all that useful!\n        //\n        match self.position {\n            Some(\n                ExtractVariablePosition::TopLevelStatement | ExtractVariablePosition::PipelineCall,\n            ) => {\n                self.at_optional_position(None, |this| {\n                    ast::visit::visit_typed_expr(this, expr);\n                });\n                return;\n            }\n            Some(\n                ExtractVariablePosition::InsideCaptureBody\n                | ExtractVariablePosition::InsideCaseClause\n                | ExtractVariablePosition::CallArg,\n            )\n            | None => {}\n        }\n\n        match expr {\n            TypedExpr::Fn {\n                kind: FunctionLiteralKind::Anonymous { .. },\n                ..\n            } => {\n                self.at_position(ExtractVariablePosition::TopLevelStatement, |this| {\n                    ast::visit::visit_typed_expr(this, expr);\n                });\n                return;\n            }\n\n            // Expressions that don't make sense to extract\n            TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Invalid { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Var { .. } => (),\n\n            TypedExpr::Int { location, .. }\n            | TypedExpr::Float { location, .. }\n            | TypedExpr::String { location, .. }\n            | TypedExpr::Pipeline { location, .. }\n            | TypedExpr::Fn { location, .. }\n            | TypedExpr::Todo { location, .. }\n            | TypedExpr::List { location, .. }\n            | TypedExpr::Call { location, .. }\n            | TypedExpr::BinOp { location, .. }\n            | TypedExpr::Case { location, .. }\n            | TypedExpr::RecordAccess { location, .. }\n            | TypedExpr::Tuple { location, .. }\n            | TypedExpr::TupleIndex { location, .. }\n            | TypedExpr::BitArray { location, .. }\n            | TypedExpr::RecordUpdate { location, .. }\n            | TypedExpr::NegateBool { location, .. }\n            | TypedExpr::NegateInt { location, .. } => {\n                if let Some(ExtractVariablePosition::CallArg) = self.position {\n                    // Don't update latest statement, we don't want to insert the extracted\n                    // variable inside the parenthesis where the call argument is located.\n                } else {\n                    self.statement_before_selected_expression = self.latest_statement;\n                };\n                self.selected_expression = Some(ExtractedToVariable::Expression {\n                    location: *location,\n                    name: self.generate_candidate_name(expr.type_()),\n                });\n            }\n        }\n\n        ast::visit::visit_typed_expr(self, expr);\n    }\n\n    fn visit_typed_use(&mut self, use_: &'ast TypedUse) {\n        let range = self.edits.src_span_to_lsp_range(use_.call.location());\n        if !within(self.params.range, range) {\n            ast::visit::visit_typed_use(self, use_);\n            return;\n        }\n\n        // Insert code under the `use`\n        self.statement_before_selected_expression = Some(use_.call.location());\n        self.at_position(ExtractVariablePosition::TopLevelStatement, |this| {\n            ast::visit::visit_typed_use(this, use_);\n        });\n    }\n\n    fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {\n        let range = self.edits.src_span_to_lsp_range(clause.location());\n        if !within(self.params.range, range) {\n            self.inside_new_scope(|this| {\n                ast::visit::visit_typed_clause(this, clause);\n            });\n            return;\n        }\n\n        // Insert code after the `->`\n        self.latest_statement = Some(clause.then.location());\n        self.to_be_wrapped = true;\n        self.at_position(ExtractVariablePosition::InsideCaseClause, |this| {\n            this.inside_new_scope(|this| {\n                ast::visit::visit_typed_clause(this, clause);\n            });\n        });\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast SrcSpan,\n        statements: &'ast [TypedStatement],\n    ) {\n        let range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, range) {\n            self.inside_new_scope(|this| {\n                ast::visit::visit_typed_expr_block(this, location, statements);\n            });\n            return;\n        }\n\n        // Don't extract block as variable\n        let mut position = self.position;\n        if let Some(ExtractVariablePosition::InsideCaseClause) = position {\n            position = None;\n            self.to_be_wrapped = false;\n        }\n\n        self.at_optional_position(position, |this| {\n            this.inside_new_scope(|this| {\n                ast::visit::visit_typed_expr_block(this, location, statements);\n            });\n        });\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        let range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, range) {\n            self.inside_new_scope(|this| {\n                ast::visit::visit_typed_expr_fn(\n                    this,\n                    location,\n                    type_,\n                    kind,\n                    arguments,\n                    body,\n                    return_annotation,\n                );\n            });\n            return;\n        }\n\n        let position = match kind {\n            // If a fn is a capture `int.wibble(1, _)` its body will consist of\n            // just a single expression statement. When visiting we must record\n            // we're inside a capture body.\n            FunctionLiteralKind::Capture { .. } => Some(ExtractVariablePosition::InsideCaptureBody),\n            FunctionLiteralKind::Use { .. } => Some(ExtractVariablePosition::TopLevelStatement),\n            FunctionLiteralKind::Anonymous { .. } => self.position,\n        };\n\n        self.at_optional_position(position, |this| {\n            this.inside_new_scope(|this| {\n                ast::visit::visit_typed_expr_fn(\n                    this,\n                    location,\n                    type_,\n                    kind,\n                    arguments,\n                    body,\n                    return_annotation,\n                );\n            });\n        });\n    }\n\n    fn visit_typed_call_arg(&mut self, arg: &'ast TypedCallArg) {\n        let range = self.edits.src_span_to_lsp_range(arg.location);\n        if !within(self.params.range, range) {\n            ast::visit::visit_typed_call_arg(self, arg);\n            return;\n        }\n\n        // An implicit record update arg in inserted by the compiler, we don't\n        // want folks to interact with this since it doesn't translate to\n        // anything in the source code despite having a default position.\n        if let Some(ImplicitCallArgOrigin::RecordUpdate) = arg.implicit {\n            return;\n        }\n\n        let position = if arg.is_use_implicit_callback() {\n            Some(ExtractVariablePosition::TopLevelStatement)\n        } else {\n            Some(ExtractVariablePosition::CallArg)\n        };\n\n        self.at_optional_position(position, |this| {\n            ast::visit::visit_typed_call_arg(this, arg);\n        });\n    }\n\n    // We don't want to offer the action if the cursor is over some invalid\n    // piece of code.\n    fn visit_typed_expr_invalid(\n        &mut self,\n        location: &'ast SrcSpan,\n        _type_: &'ast Arc<Type>,\n        _extra_information: &'ast Option<InvalidExpression>,\n    ) {\n        let invalid_range = self.edits.src_span_to_lsp_range(*location);\n        if within(self.params.range, invalid_range) {\n            self.selected_expression = None;\n        }\n    }\n}\n\n/// Builder for code action to convert a literal use into a const.\n///\n/// For using the code action on each of the following lines:\n///\n/// ```gleam\n/// fn void() {\n///   let var = [1, 2, 3]\n///   let res = function(\"Statement\", var)\n/// }\n/// ```\n///\n/// Both value literals will become:\n///\n/// ```gleam\n/// const var = [1, 2, 3]\n/// const string = \"Statement\"\n///\n/// fn void() {\n///   let res = function(string, var)\n/// }\n/// ```\npub struct ExtractConstant<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    /// The whole selected expression\n    selected_expression: Option<SrcSpan>,\n    /// The location of the start of the function containing the expression.\n    /// It includes function's documentation as well\n    container_function_start: Option<u32>,\n    /// The variant of the extractable expression being extracted (if any)\n    variant_of_extractable: Option<ExtractableToConstant>,\n    /// The name of the newly created constant\n    name_to_use: Option<EcoString>,\n    /// The right hand side expression of the newly created constant\n    value_to_use: Option<EcoString>,\n}\n\n/// Used when an expression can be extracted to a constant\nenum ExtractableToConstant {\n    /// Used for collections and operator uses. This means that elements\n    /// inside, are also extractable as constants.\n    ComposedValue,\n    /// Used for single values. Literals in Gleam can be Ints, Floats, Strings\n    /// and type variants (not records).\n    SingleValue,\n    /// Used for whole variable assignments. If the right hand side of the\n    /// expression can be extracted, the whole expression extracted and use the\n    /// local variable as a constant.\n    Assignment,\n}\n\nfn can_be_constant(\n    module: &Module,\n    expr: &TypedExpr,\n    module_constants: Option<&HashSet<&EcoString>>,\n) -> bool {\n    // We pass the `module_constants` on recursion to not compute them each time\n    let module_constants = match module_constants {\n        Some(module_constants) => module_constants,\n        None => &module\n            .ast\n            .definitions\n            .constants\n            .iter()\n            .map(|constant| &constant.name)\n            .collect(),\n    };\n\n    match expr {\n        // Attempt to extract whole list as long as it's comprised of only literals\n        TypedExpr::List { elements, tail, .. } => {\n            elements\n                .iter()\n                .all(|element| can_be_constant(module, element, Some(module_constants)))\n                && tail.is_none()\n        }\n\n        // Attempt to extract whole bit array as long as it's made up of literals\n        TypedExpr::BitArray { segments, .. } => {\n            segments\n                .iter()\n                .all(|segment| can_be_constant(module, &segment.value, Some(module_constants)))\n                && segments.iter().all(|segment| {\n                    segment.options.iter().all(|option| match option {\n                        ast::BitArrayOption::Size { value, .. } => {\n                            can_be_constant(module, value, Some(module_constants))\n                        }\n\n                        ast::BitArrayOption::Bytes { .. }\n                        | ast::BitArrayOption::Int { .. }\n                        | ast::BitArrayOption::Float { .. }\n                        | ast::BitArrayOption::Bits { .. }\n                        | ast::BitArrayOption::Utf8 { .. }\n                        | ast::BitArrayOption::Utf16 { .. }\n                        | ast::BitArrayOption::Utf32 { .. }\n                        | ast::BitArrayOption::Utf8Codepoint { .. }\n                        | ast::BitArrayOption::Utf16Codepoint { .. }\n                        | ast::BitArrayOption::Utf32Codepoint { .. }\n                        | ast::BitArrayOption::Signed { .. }\n                        | ast::BitArrayOption::Unsigned { .. }\n                        | ast::BitArrayOption::Big { .. }\n                        | ast::BitArrayOption::Little { .. }\n                        | ast::BitArrayOption::Native { .. }\n                        | ast::BitArrayOption::Unit { .. } => true,\n                    })\n                })\n        }\n\n        // Attempt to extract whole tuple as long as it's comprised of only literals\n        TypedExpr::Tuple { elements, .. } => elements\n            .iter()\n            .all(|element| can_be_constant(module, element, Some(module_constants))),\n\n        // Extract literals directly\n        TypedExpr::Int { .. } | TypedExpr::Float { .. } | TypedExpr::String { .. } => true,\n\n        // Extract non-record types directly\n        TypedExpr::Var {\n            constructor, name, ..\n        } => {\n            matches!(\n                constructor.variant,\n                type_::ValueConstructorVariant::Record { arity: 0, .. }\n            ) || module_constants.contains(name)\n        }\n\n        // Extract record types as long as arguments can be constant\n        TypedExpr::Call { arguments, fun, .. } => {\n            fun.is_record_literal()\n                && arguments\n                    .iter()\n                    .all(|arg| can_be_constant(module, &arg.value, Some(module_constants)))\n        }\n\n        // Extract concat binary operation if both sides can be constants\n        TypedExpr::BinOp {\n            name, left, right, ..\n        } => {\n            matches!(name, ast::BinOp::Concatenate)\n                && can_be_constant(module, left, Some(module_constants))\n                && can_be_constant(module, right, Some(module_constants))\n        }\n\n        TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => false,\n    }\n}\n\n/// Takes the list of already existing constants and functions and creates a\n/// name that doesn't conflict with them\n///\nfn generate_new_name_for_constant(module: &Module, expr: &TypedExpr) -> EcoString {\n    let mut name_generator = NameGenerator::new();\n    name_generator.reserve_module_value_names(&module.ast.definitions);\n    name_generator.generate_name_from_type(&expr.type_())\n}\n\n/// Converts the source start position of a documentation comment's contents into\n/// the position of the leading slash in its marker ('///').\nfn get_doc_marker_position(content_pos: u32) -> u32 {\n    content_pos.saturating_sub(3)\n}\n\nimpl<'a> ExtractConstant<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            selected_expression: None,\n            container_function_start: None,\n            variant_of_extractable: None,\n            name_to_use: None,\n            value_to_use: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let (\n            Some(expr_span),\n            Some(function_start),\n            Some(type_of_extractable),\n            Some(new_const_name),\n            Some(const_value),\n        ) = (\n            self.selected_expression,\n            self.container_function_start,\n            self.variant_of_extractable,\n            self.name_to_use,\n            self.value_to_use,\n        )\n        else {\n            return vec![];\n        };\n\n        // We insert the constant declaration\n        self.edits.insert(\n            function_start,\n            format!(\"const {new_const_name} = {const_value}\\n\\n\"),\n        );\n\n        // We remove or replace the selected expression\n        match type_of_extractable {\n            // The whole expression is deleted for assignments\n            ExtractableToConstant::Assignment => {\n                let range = self\n                    .edits\n                    .src_span_to_lsp_range(self.selected_expression.expect(\"Real range value\"));\n\n                let indent_size =\n                    count_indentation(&self.module.code, self.edits.line_numbers, range.start.line);\n\n                let expr_span_with_new_line = SrcSpan {\n                    // We remove leading indentation + 1 to remove the newline with it\n                    start: expr_span.start - (indent_size as u32 + 1),\n                    end: expr_span.end,\n                };\n                self.edits.delete(expr_span_with_new_line);\n            }\n\n            // Only  right hand side is replaced for collection or values\n            ExtractableToConstant::ComposedValue | ExtractableToConstant::SingleValue => {\n                self.edits.replace(expr_span, String::from(new_const_name));\n            }\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Extract constant\")\n            .kind(CodeActionKind::REFACTOR_EXTRACT)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ExtractConstant<'ast> {\n    /// To get the position of the function containing the value or assignment\n    /// to extract\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        let fun_location = fun.location;\n        let fun_range = self.edits.src_span_to_lsp_range(SrcSpan {\n            start: fun_location.start,\n            end: fun.end_position,\n        });\n\n        if !within(self.params.range, fun_range) {\n            return;\n        }\n\n        // Here we need to get position of the function, starting from the leading slash in the\n        // documentation comment's marker ('///'), not from comment's content (of which\n        // we have the position), so we must convert the content start position\n        // to the leading slash's position.\n        self.container_function_start = Some(\n            fun.documentation\n                .as_ref()\n                .map(|(doc_start, _)| get_doc_marker_position(*doc_start))\n                .unwrap_or(fun_location.start),\n        );\n\n        ast::visit::visit_typed_function(self, fun);\n    }\n\n    /// To extract the whole assignment\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        let expr_location = assignment.location;\n\n        // We only offer this code action for extracting the whole assignment\n        // between `let` and `=`.\n        let pattern_location = assignment.pattern.location();\n        let location = SrcSpan::new(assignment.location.start, pattern_location.end);\n        let code_action_range = self.edits.src_span_to_lsp_range(location);\n\n        if !within(self.params.range, code_action_range) {\n            ast::visit::visit_typed_assignment(self, assignment);\n            return;\n        }\n\n        // Has to be variable because patterns can't be constants.\n        if assignment.pattern.is_variable() && can_be_constant(self.module, &assignment.value, None)\n        {\n            self.variant_of_extractable = Some(ExtractableToConstant::Assignment);\n            self.selected_expression = Some(expr_location);\n            self.name_to_use = if let Pattern::Variable { name, .. } = &assignment.pattern {\n                Some(name.clone())\n            } else {\n                None\n            };\n            self.value_to_use = Some(EcoString::from(\n                self.module\n                    .code\n                    .get(\n                        (assignment.value.location().start as usize)\n                            ..(assignment.location.end as usize),\n                    )\n                    .expect(\"selected expression\"),\n            ));\n        }\n    }\n\n    /// To extract only the literal\n    fn visit_typed_expr(&mut self, expr: &'ast TypedExpr) {\n        let expr_location = expr.location();\n        let expr_range = self.edits.src_span_to_lsp_range(expr_location);\n\n        if !within(self.params.range, expr_range) {\n            ast::visit::visit_typed_expr(self, expr);\n            return;\n        }\n\n        // Keep going down recursively if:\n        // - It's no extractable has been found yet (`None`).\n        // - It's a collection, which may or may not contain a value that can\n        //   be extracted.\n        // - It's a binary operator, which may or may not operate on\n        //   extractable values.\n        if matches!(\n            self.variant_of_extractable,\n            None | Some(ExtractableToConstant::ComposedValue)\n        ) && can_be_constant(self.module, expr, None)\n        {\n            self.variant_of_extractable = match expr {\n                TypedExpr::Var { .. }\n                | TypedExpr::Int { .. }\n                | TypedExpr::Float { .. }\n                | TypedExpr::String { .. } => Some(ExtractableToConstant::SingleValue),\n\n                TypedExpr::List { .. }\n                | TypedExpr::Tuple { .. }\n                | TypedExpr::BitArray { .. }\n                | TypedExpr::BinOp { .. }\n                | TypedExpr::Call { .. } => Some(ExtractableToConstant::ComposedValue),\n\n                TypedExpr::Block { .. }\n                | TypedExpr::Pipeline { .. }\n                | TypedExpr::Fn { .. }\n                | TypedExpr::Case { .. }\n                | TypedExpr::RecordAccess { .. }\n                | TypedExpr::PositionalAccess { .. }\n                | TypedExpr::ModuleSelect { .. }\n                | TypedExpr::TupleIndex { .. }\n                | TypedExpr::Todo { .. }\n                | TypedExpr::Panic { .. }\n                | TypedExpr::Echo { .. }\n                | TypedExpr::RecordUpdate { .. }\n                | TypedExpr::NegateBool { .. }\n                | TypedExpr::NegateInt { .. }\n                | TypedExpr::Invalid { .. } => None,\n            };\n\n            self.selected_expression = Some(expr_location);\n            self.name_to_use = Some(generate_new_name_for_constant(self.module, expr));\n            self.value_to_use = Some(EcoString::from(\n                self.module\n                    .code\n                    .get((expr_location.start as usize)..(expr_location.end as usize))\n                    .expect(\"selected expression\"),\n            ));\n        }\n\n        ast::visit::visit_typed_expr(self, expr);\n    }\n}\n\n/// Builder for code action to apply the \"expand function capture\" action.\n///\npub struct ExpandFunctionCapture<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    function_capture_data: Option<FunctionCaptureData>,\n}\n\npub struct FunctionCaptureData {\n    function_span: SrcSpan,\n    hole_span: SrcSpan,\n    hole_type: Arc<Type>,\n    reserved_names: VariablesNames,\n}\n\nimpl<'a> ExpandFunctionCapture<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            function_capture_data: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(FunctionCaptureData {\n            function_span,\n            hole_span,\n            hole_type,\n            reserved_names,\n        }) = self.function_capture_data\n        else {\n            return vec![];\n        };\n\n        let mut name_generator = NameGenerator::new();\n        name_generator.reserve_variable_names(reserved_names);\n        let name = name_generator.generate_name_from_type(&hole_type);\n\n        self.edits.replace(hole_span, name.clone().into());\n        self.edits.insert(function_span.end, \" }\".into());\n        self.edits\n            .insert(function_span.start, format!(\"fn({name}) {{ \"));\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Expand function capture\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ExpandFunctionCapture<'ast> {\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        let fn_range = self.edits.src_span_to_lsp_range(*location);\n        if within(self.params.range, fn_range)\n            && kind.is_capture()\n            && let [argument] = arguments\n        {\n            self.function_capture_data = Some(FunctionCaptureData {\n                function_span: *location,\n                hole_span: argument.location,\n                hole_type: argument.type_.clone(),\n                reserved_names: VariablesNames::from_statements(body),\n            });\n        }\n\n        ast::visit::visit_typed_expr_fn(\n            self,\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n        )\n    }\n}\n\nstruct VariablesNames {\n    names: HashSet<EcoString>,\n}\n\nimpl VariablesNames {\n    fn from_statements(statements: &[TypedStatement]) -> Self {\n        let mut variables = Self {\n            names: HashSet::new(),\n        };\n\n        for statement in statements {\n            variables.visit_typed_statement(statement);\n        }\n        variables\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for VariablesNames {\n    fn visit_typed_expr_var(\n        &mut self,\n        _location: &'ast SrcSpan,\n        _constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        let _ = self.names.insert(name.clone());\n    }\n}\n\n/// Builder for code action to apply the \"generate dynamic decoder action.\n///\npub struct GenerateDynamicDecoder<'a, IO> {\n    compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    printer: Printer<'a>,\n    actions: &'a mut Vec<CodeAction>,\n}\n\nconst DECODE_MODULE: &str = \"gleam/dynamic/decode\";\n\nimpl<'a, IO> GenerateDynamicDecoder<'a, IO> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n        actions: &'a mut Vec<CodeAction>,\n        compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n    ) -> Self {\n        // Since we are generating a new function, type variables from other\n        // functions and constants are irrelevant to the types we print.\n        let printer = Printer::new_without_type_variables(&module.ast.names);\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            printer,\n            actions,\n            compiler,\n        }\n    }\n\n    pub fn code_actions(&mut self) {\n        self.visit_typed_module(&self.module.ast);\n    }\n\n    fn custom_type_decoder_body(\n        &mut self,\n        custom_type: &CustomType<Arc<Type>>,\n    ) -> Option<EcoString> {\n        // We cannot generate a decoder for an external type with no constructors!\n        let constructors_size = custom_type.constructors.len();\n        let (first, rest) = custom_type.constructors.split_first()?;\n        let mode = EncodingMode::for_custom_type(custom_type);\n\n        // We generate a decoder for a type with a single constructor: it does not\n        // require pattern matching on a tag as there's no variants to tell apart.\n        if rest.is_empty() && mode == EncodingMode::ObjectWithNoTypeTag {\n            return self.constructor_decoder(mode, custom_type, first, 0);\n        }\n\n        // Otherwise we need to generate a decoder that has to tell apart different\n        // variants, depending on the mode we might have to decode a type field or\n        // plain strings!\n        let module = self.printer.print_module(DECODE_MODULE);\n        let discriminant = if mode == EncodingMode::PlainString {\n            eco_format!(\"use variant <- {module}.then({module}.string)\")\n        } else {\n            eco_format!(\"use variant <- {module}.field(\\\"type\\\", {module}.string)\")\n        };\n\n        let mut clauses = Vec::with_capacity(constructors_size);\n        for constructor in iter::once(first).chain(rest) {\n            let body = self.constructor_decoder(mode, custom_type, constructor, 4)?;\n            let name = to_snake_case(&constructor.name);\n            clauses.push(eco_format!(r#\"    \"{name}\" -> {body}\"#));\n        }\n\n        let failure_clause = self.failure_clause(custom_type);\n\n        let cases = clauses.join(\"\\n\");\n        Some(eco_format!(\n            r#\"{{\n  {discriminant}\n  case variant {{\n{cases}\n{failure_clause}\n  }}\n}}\"#,\n        ))\n    }\n\n    fn constructor_decoder(\n        &mut self,\n        mode: EncodingMode,\n        custom_type: &ast::TypedCustomType,\n        constructor: &TypedRecordConstructor,\n        nesting: usize,\n    ) -> Option<EcoString> {\n        let decode_module = self.printer.print_module(DECODE_MODULE);\n        let constructor_name = &constructor.name;\n\n        // If the constructor was encoded as a plain string with no additional\n        // fields it means there's nothing else to decode and we can just\n        // succeed.\n        if mode == EncodingMode::PlainString {\n            return Some(eco_format!(\"{decode_module}.success({constructor_name})\"));\n        }\n\n        // Otherwise we have to decode all the constructor fields to build it.\n        let mut fields = Vec::with_capacity(constructor.arguments.len());\n        for argument in constructor.arguments.iter() {\n            let (_, name) = argument.label.as_ref()?;\n            let field = RecordField {\n                label: RecordLabel::Labeled(name),\n                type_: &argument.type_,\n            };\n            fields.push(field);\n        }\n\n        let mut decoder_printer = DecoderPrinter::new(\n            &mut self.printer,\n            custom_type.name.clone(),\n            self.module.name.clone(),\n            self.compiler,\n        );\n\n        let decoders = fields\n            .iter()\n            .map(|field| decoder_printer.decode_field(field, nesting + 2))\n            .join(\"\\n\");\n\n        let indent = \" \".repeat(nesting);\n\n        Some(if decoders.is_empty() {\n            eco_format!(\"{decode_module}.success({constructor_name})\")\n        } else {\n            let field_names = fields\n                .iter()\n                .map(|field| format!(\"{}:\", field.label.variable_name()))\n                .join(\", \");\n\n            eco_format!(\n                \"{{\n{decoders}\n{indent}  {decode_module}.success({constructor_name}({field_names}))\n{indent}}}\",\n            )\n        })\n    }\n\n    /// Generates the failure/catch-all clause in a decoder function for a\n    /// type with `EncodingMode::ObjectWithTypeTag` i.e. the `_ -> decode.failure()`\n    /// clause executed when the `type` field does not match any of the known variants.\n    ///\n    /// # Arguments\n    /// * `custom_type` -  The root type we are printing a decoder for\n    fn failure_clause(&mut self, custom_type: &CustomType<Arc<Type>>) -> EcoString {\n        let decode_module = self.printer.print_module(DECODE_MODULE);\n        let type_name = &custom_type.name;\n\n        let mut decoder_printer = DecoderPrinter::new(\n            &mut self.printer,\n            type_name.clone(),\n            self.module.name.clone(),\n            self.compiler,\n        );\n\n        // The construction of the zero value might necessitate importing\n        // modules that aren't currently in scope. We keep track of them here.\n        let mut modules_to_import = HashSet::new();\n        // We also need to keep track of the path we are tracing through the types\n        // to make sure we don't get stuck in an infinite loop building a recursive\n        // type.\n        let mut path = vec![];\n\n        if let Some(zero_value) = decoder_printer.zero_value_for_custom_type(\n            &self.module.name,\n            type_name,\n            &mut path,\n            &mut modules_to_import,\n        ) {\n            for module_name in modules_to_import {\n                maybe_import(&mut self.edits, self.module, &module_name);\n            }\n            eco_format!(r#\"    _ -> {decode_module}.failure({zero_value}, \"{type_name}\")\"#,)\n        } else {\n            eco_format!(\n                r#\"    _ -> {decode_module}.failure(todo as \"Zero value for {type_name}\", \"{type_name}\")\"#\n            )\n        }\n    }\n}\n\nimpl<'ast, IO> ast::visit::Visit<'ast> for GenerateDynamicDecoder<'ast, IO> {\n    fn visit_typed_custom_type(&mut self, custom_type: &'ast ast::TypedCustomType) {\n        let range = self.edits.src_span_to_lsp_range(custom_type.location);\n        if !overlaps(self.params.range, range) {\n            return;\n        }\n\n        let name = eco_format!(\"{}_decoder\", to_snake_case(&custom_type.name));\n        let Some(function_body) = self.custom_type_decoder_body(custom_type) else {\n            return;\n        };\n\n        let parameters = match custom_type.parameters.len() {\n            0 => EcoString::new(),\n            _ => eco_format!(\n                \"({})\",\n                custom_type\n                    .parameters\n                    .iter()\n                    .map(|(_, name)| name)\n                    .join(\", \")\n            ),\n        };\n\n        let decoder_type = self.printer.print_type(&Type::Named {\n            publicity: Publicity::Public,\n            package: STDLIB_PACKAGE_NAME.into(),\n            module: DECODE_MODULE.into(),\n            name: \"Decoder\".into(),\n            arguments: vec![],\n            inferred_variant: None,\n        });\n\n        let function = format!(\n            \"\\n\\nfn {name}() -> {decoder_type}({type_name}{parameters}) {function_body}\",\n            type_name = custom_type.name,\n        );\n\n        self.edits.insert(custom_type.end_position, function);\n        maybe_import(&mut self.edits, self.module, DECODE_MODULE);\n\n        CodeActionBuilder::new(\"Generate dynamic decoder\")\n            .kind(CodeActionKind::REFACTOR)\n            .preferred(false)\n            .changes(\n                self.params.text_document.uri.clone(),\n                std::mem::take(&mut self.edits.edits),\n            )\n            .push_to(self.actions);\n    }\n}\n\n/// If `module_name` is not already imported inside `module`, adds an edit to\n/// add that import.\n/// This function also makes sure not to import a module in itself.\n///\nfn maybe_import(edits: &mut TextEdits<'_>, module: &Module, module_name: &str) {\n    if module.ast.names.is_imported(module_name) || module.name == module_name {\n        return;\n    }\n\n    let first_import_pos = position_of_first_definition_if_import(module, edits.line_numbers);\n    let first_is_import = first_import_pos.is_some();\n    let import_location = first_import_pos.unwrap_or_default();\n    let after_import_newlines = add_newlines_after_import(\n        import_location,\n        first_is_import,\n        edits.line_numbers,\n        &module.code,\n    );\n\n    edits.edits.push(get_import_edit(\n        import_location,\n        module_name,\n        &after_import_newlines,\n    ));\n}\n\nstruct DecoderPrinter<'a, 'b, IO> {\n    printer: &'a mut Printer<'b>,\n    /// The name of the root type we are printing a decoder for\n    type_name: EcoString,\n    /// The module name of the root type we are printing a decoder for\n    type_module: EcoString,\n    compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n}\n\nconst DYNAMIC_MODULE: &str = \"gleam/dynamic\";\nconst DICT_MODULE: &str = \"gleam/dict\";\nconst OPTION_MODULE: &str = \"gleam/option\";\n\nstruct RecordField<'a> {\n    label: RecordLabel<'a>,\n    type_: &'a Type,\n}\n\nenum RecordLabel<'a> {\n    Labeled(&'a str),\n    Unlabeled(usize),\n}\n\nimpl RecordLabel<'_> {\n    fn field_key(&self) -> EcoString {\n        match self {\n            RecordLabel::Labeled(label) => eco_format!(\"\\\"{label}\\\"\"),\n            RecordLabel::Unlabeled(index) => {\n                eco_format!(\"{index}\")\n            }\n        }\n    }\n\n    fn variable_name(&self) -> EcoString {\n        match self {\n            RecordLabel::Labeled(label) => (*label).into(),\n            &RecordLabel::Unlabeled(mut index) => {\n                let mut characters = Vec::new();\n                let alphabet_length = 26;\n                let alphabet_offset = b'a';\n                loop {\n                    let alphabet_index = (index % alphabet_length) as u8;\n                    characters.push((alphabet_offset + alphabet_index) as char);\n                    index /= alphabet_length;\n\n                    if index == 0 {\n                        break;\n                    }\n                    index -= 1;\n                }\n                characters.into_iter().rev().collect()\n            }\n        }\n    }\n}\n\nimpl<'a, 'b, IO> DecoderPrinter<'a, 'b, IO> {\n    fn new(\n        printer: &'a mut Printer<'b>,\n        type_name: EcoString,\n        type_module: EcoString,\n        compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n    ) -> Self {\n        Self {\n            type_name,\n            type_module,\n            printer,\n            compiler,\n        }\n    }\n\n    fn decoder_for(&mut self, type_: &Type, indent: usize) -> EcoString {\n        let module_name = self.printer.print_module(DECODE_MODULE);\n        if type_.is_bit_array() {\n            eco_format!(\"{module_name}.bit_array\")\n        } else if type_.is_bool() {\n            eco_format!(\"{module_name}.bool\")\n        } else if type_.is_float() {\n            eco_format!(\"{module_name}.float\")\n        } else if type_.is_int() {\n            eco_format!(\"{module_name}.int\")\n        } else if type_.is_string() {\n            eco_format!(\"{module_name}.string\")\n        } else if type_.is_nil() {\n            eco_format!(\"{module_name}.success(Nil)\")\n        } else {\n            match type_.tuple_types() {\n                Some(types) => {\n                    let fields = types\n                        .iter()\n                        .enumerate()\n                        .map(|(index, type_)| RecordField {\n                            type_,\n                            label: RecordLabel::Unlabeled(index),\n                        })\n                        .collect_vec();\n                    let decoders = fields\n                        .iter()\n                        .map(|field| self.decode_field(field, indent + 2))\n                        .join(\"\\n\");\n                    let mut field_names = fields.iter().map(|field| field.label.variable_name());\n\n                    eco_format!(\n                        \"{{\n{decoders}\n\n{indent}  {module_name}.success(#({fields}))\n{indent}}}\",\n                        fields = field_names.join(\", \"),\n                        indent = \" \".repeat(indent)\n                    )\n                }\n                _ => {\n                    let type_information = type_.named_type_information();\n                    let type_information =\n                        type_information.as_ref().map(|(module, name, arguments)| {\n                            (module.as_str(), name.as_str(), arguments.as_slice())\n                        });\n\n                    match type_information {\n                        Some((\"gleam/dynamic\", \"Dynamic\", _)) => {\n                            eco_format!(\"{module_name}.dynamic\")\n                        }\n                        Some((\"gleam\", \"List\", [element])) => {\n                            eco_format!(\"{module_name}.list({})\", self.decoder_for(element, indent))\n                        }\n                        Some((\"gleam/option\", \"Option\", [some])) => {\n                            eco_format!(\n                                \"{module_name}.optional({})\",\n                                self.decoder_for(some, indent)\n                            )\n                        }\n                        Some((\"gleam/dict\", \"Dict\", [key, value])) => {\n                            eco_format!(\n                                \"{module_name}.dict({}, {})\",\n                                self.decoder_for(key, indent),\n                                self.decoder_for(value, indent)\n                            )\n                        }\n                        Some((module, name, _))\n                            if module == self.type_module && name == self.type_name =>\n                        {\n                            eco_format!(\"{}_decoder()\", to_snake_case(name))\n                        }\n                        _ => eco_format!(\n                            r#\"todo as \"Decoder for {}\"\"#,\n                            self.printer.print_type(type_)\n                        ),\n                    }\n                }\n            }\n        }\n    }\n\n    fn decode_field(&mut self, field: &RecordField<'_>, indent: usize) -> EcoString {\n        let decoder = self.decoder_for(field.type_, indent);\n\n        eco_format!(\n            r#\"{indent}use {variable} <- {module}.field({field}, {decoder})\"#,\n            indent = \" \".repeat(indent),\n            variable = field.label.variable_name(),\n            field = field.label.field_key(),\n            module = self.printer.print_module(DECODE_MODULE)\n        )\n    }\n\n    /// Performs best-effort generation of zero values for a given type.\n    /// Will succeed for all prelude types and most stdlib types.\n    /// For specifics on how custom user-defined types are handled, see\n    /// `zero_value_for_custom_type`.\n    fn zero_value_for_type(\n        &mut self,\n        type_: &Type,\n        // Keeps track of types visited already to ensure we don't end up in an infinite\n        // loop due to recursive types\n        path: &mut Vec<(EcoString, EcoString)>,\n        modules_to_import: &mut HashSet<EcoString>,\n    ) -> Option<EcoString> {\n        if type_.is_bit_array() {\n            return Some(\"<<>>\".into());\n        }\n        if type_.is_bool() {\n            return Some(\"False\".into());\n        }\n        if type_.is_float() {\n            return Some(\"0.0\".into());\n        }\n        if type_.is_int() {\n            return Some(\"0\".into());\n        }\n        if type_.is_string() {\n            return Some(\"\\\"\\\"\".into());\n        }\n        if type_.is_list() {\n            return Some(\"[]\".into());\n        }\n        if type_.is_nil() {\n            return Some(\"Nil\".into());\n        }\n\n        if let Some(types) = type_.tuple_types() {\n            // We try generating zero values for the tuple members and exit early if any of them fail.\n            let field_zeroes = types\n                .iter()\n                .map_while(|type_| self.zero_value_for_type(type_, path, modules_to_import))\n                .collect_vec();\n\n            if field_zeroes.len() < types.len() {\n                return None;\n            } else {\n                return Some(eco_format!(\"#({})\", field_zeroes.iter().join(\", \")));\n            }\n        };\n\n        let (module, name, _) = type_.named_type_information()?;\n        match (module.as_str(), name.as_str()) {\n            (OPTION_MODULE, \"Option\") => {\n                let _ = modules_to_import.insert(OPTION_MODULE.into());\n                Some(eco_format!(\n                    \"{}.None\",\n                    self.printer.print_module(OPTION_MODULE)\n                ))\n            }\n\n            (DYNAMIC_MODULE, \"Dynamic\") => {\n                let _ = modules_to_import.insert(DYNAMIC_MODULE.into());\n                Some(eco_format!(\n                    \"{}.nil()\",\n                    self.printer.print_module(DYNAMIC_MODULE)\n                ))\n            }\n\n            (DICT_MODULE, \"Dict\") => {\n                let _ = modules_to_import.insert(DICT_MODULE.into());\n                Some(eco_format!(\n                    \"{}.new()\",\n                    self.printer.print_module(DICT_MODULE)\n                ))\n            }\n\n            _ => self.zero_value_for_custom_type(&module, &name, path, modules_to_import),\n        }\n    }\n\n    /// Best-effort zero value generation for user-defined types in the\n    /// current package.\n    fn zero_value_for_custom_type(\n        &mut self,\n        custom_type_module: &EcoString,\n        custom_type_name: &EcoString,\n        path: &mut Vec<(EcoString, EcoString)>,\n        modules_to_import: &mut HashSet<EcoString>,\n    ) -> Option<EcoString> {\n        // First we check that we have not already visited this type before to\n        // avoid cycles.\n        let already_seen_type = path.iter().any(|(path_module, path_type_name)| {\n            path_module == custom_type_module && path_type_name == custom_type_name\n        });\n\n        if already_seen_type {\n            return None;\n        };\n\n        let type_is_inside_current_module = &self.type_module == custom_type_module;\n\n        let current_module_interface = self\n            .compiler\n            .modules\n            .get(&self.type_module)\n            .map(|module| &module.ast.type_info)?;\n\n        let type_module_interface = if !type_is_inside_current_module {\n            self.compiler.get_module_interface(custom_type_module)?\n        } else {\n            current_module_interface\n        };\n\n        // We only try and generate zero values for user-defined types in the current\n        // package. If you are expanding the scope of this functionality to\n        // remove this limitation, make sure to check for internal modules.\n        if current_module_interface.package != type_module_interface.package {\n            return None;\n        }\n\n        let constructors = type_module_interface\n            .types_value_constructors\n            .get(custom_type_name)?;\n\n        // Opaque types cannot be constructed outside the module they were defined in,\n        // so we will be unable to produce a zero value.\n        if !type_is_inside_current_module && constructors.opaque == Opaque::Opaque {\n            return None;\n        }\n\n        // Ideally, we want to use the \"smallest\" (i.e. fewest fields) constructor\n        // to construct our zero value to reduce visual noise, but this might not always\n        // be possible. So we check all constructors in increasing order of size to\n        // find the first one that succeeds, and then short circuit.\n        constructors\n            .variants\n            .iter()\n            .sorted_by_key(|v| v.parameters.len())\n            .find_map(|zero_constructor| {\n                self.zero_value_for_custom_type_constructor(\n                    custom_type_module,\n                    custom_type_name,\n                    zero_constructor,\n                    type_is_inside_current_module,\n                    path,\n                    modules_to_import,\n                )\n            })\n    }\n\n    /// Attempts to construct a zero value for one specific constructor\n    /// of a custom type. Use `zero_value_for_custom_type` instead as it performs\n    /// _important checks on type visibility that this method does NOT_.\n    /// This is a helper method extracted for readability.\n    fn zero_value_for_custom_type_constructor(\n        &mut self,\n        custom_type_module: &EcoString,\n        custom_type_name: &EcoString,\n        zero_constructor: &type_::TypeValueConstructor,\n        type_is_inside_current_module: bool,\n        path: &mut Vec<(EcoString, EcoString)>,\n        modules_to_import: &mut HashSet<EcoString>,\n    ) -> Option<EcoString> {\n        path.push((custom_type_module.clone(), custom_type_name.clone()));\n\n        // Try to generate zero values for all fields in the constructor\n        let zero_params = zero_constructor\n            .parameters\n            .iter()\n            .map_while(|parameter| {\n                let zero = self.zero_value_for_type(&parameter.type_, path, modules_to_import)?;\n\n                if let Some(label) = &parameter.label {\n                    Some(eco_format!(\"{label}: {zero}\"))\n                } else {\n                    Some(zero)\n                }\n            })\n            .collect_vec();\n\n        // We need to make sure to clean up the path once we've finished\n        // \"visiting\" this type.\n        let _ = path.pop();\n\n        // Only proceed if we were able to construct every field successfully\n        if zero_params.len() < zero_constructor.parameters.len() {\n            return None;\n        };\n\n        let zero_constructor = if !type_is_inside_current_module {\n            // Type constructors from other modules need to be qualified appropriately,\n            // and they might need to be brought into scope.\n            let _ = modules_to_import.insert(custom_type_module.clone());\n            eco_format!(\n                \"{}.{}\",\n                self.printer.print_module(custom_type_module),\n                zero_constructor.name\n            )\n        } else {\n            eco_format!(\"{}\", zero_constructor.name)\n        };\n\n        if zero_params.is_empty() {\n            Some(eco_format!(\"{zero_constructor}\"))\n        } else {\n            let zero_args = zero_params.iter().join(\", \");\n            Some(eco_format!(\"{zero_constructor}({zero_args})\"))\n        }\n    }\n}\n\n/// Builder for code action to apply the \"Generate to-JSON function\" action.\n///\npub struct GenerateJsonEncoder<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    printer: Printer<'a>,\n    actions: &'a mut Vec<CodeAction>,\n    config: &'a PackageConfig,\n}\n\nconst JSON_MODULE: &str = \"gleam/json\";\nconst JSON_PACKAGE_NAME: &str = \"gleam_json\";\n\n#[derive(Eq, PartialEq, Copy, Clone)]\nenum EncodingMode {\n    PlainString,\n    ObjectWithTypeTag,\n    ObjectWithNoTypeTag,\n}\n\nimpl EncodingMode {\n    pub fn for_custom_type(type_: &CustomType<Arc<Type>>) -> Self {\n        match type_.constructors.as_slice() {\n            [constructor] if constructor.arguments.is_empty() => EncodingMode::PlainString,\n            [_constructor] => EncodingMode::ObjectWithNoTypeTag,\n            constructors if constructors.iter().all(|c| c.arguments.is_empty()) => {\n                EncodingMode::PlainString\n            }\n            _constructors => EncodingMode::ObjectWithTypeTag,\n        }\n    }\n}\n\nimpl<'a> GenerateJsonEncoder<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n        actions: &'a mut Vec<CodeAction>,\n        config: &'a PackageConfig,\n    ) -> Self {\n        // Since we are generating a new function, type variables from other\n        // functions and constants are irrelevant to the types we print.\n        let printer = Printer::new_without_type_variables(&module.ast.names);\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            printer,\n            actions,\n            config,\n        }\n    }\n\n    pub fn code_actions(&mut self) {\n        if self.config.dependencies.contains_key(JSON_PACKAGE_NAME)\n            || self.config.dev_dependencies.contains_key(JSON_PACKAGE_NAME)\n        {\n            self.visit_typed_module(&self.module.ast);\n        }\n    }\n\n    fn custom_type_encoder_body(\n        &mut self,\n        record_name: EcoString,\n        custom_type: &CustomType<Arc<Type>>,\n    ) -> Option<EcoString> {\n        // We cannot generate a decoder for an external type with no constructors!\n        let constructors_size = custom_type.constructors.len();\n        let (first, rest) = custom_type.constructors.split_first()?;\n        let mode = EncodingMode::for_custom_type(custom_type);\n\n        // We generate an encoder for a type with a single constructor: it does not\n        // require pattern matching on the argument as we can access all its fields\n        // with the usual record access syntax.\n        if rest.is_empty() {\n            let encoder = self.constructor_encoder(mode, first, custom_type.name.clone(), 2)?;\n            let unpacking = if first.arguments.is_empty() {\n                \"\"\n            } else {\n                &eco_format!(\n                    \"let {name}({fields}:) = {record_name}\\n  \",\n                    name = first.name,\n                    fields = first\n                        .arguments\n                        .iter()\n                        .filter_map(|argument| {\n                            argument.label.as_ref().map(|(_location, label)| label)\n                        })\n                        .join(\":, \")\n                )\n            };\n            return Some(eco_format!(\"{unpacking}{encoder}\"));\n        }\n\n        // Otherwise we generate an encoder for a type with multiple constructors:\n        // it will need to pattern match on the various constructors and encode each\n        // one separately.\n        let mut clauses = Vec::with_capacity(constructors_size);\n        for constructor in iter::once(first).chain(rest) {\n            let RecordConstructor { name, .. } = constructor;\n            let encoder =\n                self.constructor_encoder(mode, constructor, custom_type.name.clone(), 4)?;\n            if constructor.arguments.is_empty() {\n                clauses.push(eco_format!(\"    {name} -> {encoder}\"));\n            } else {\n                let unpacking = constructor\n                    .arguments\n                    .iter()\n                    .filter_map(|argument| {\n                        argument.label.as_ref().map(|(_location, label)| {\n                            if is_nil_like(&argument.type_) {\n                                eco_format!(\"{}: _\", label)\n                            } else {\n                                eco_format!(\"{}:\", label)\n                            }\n                        })\n                    })\n                    .join(\", \");\n                clauses.push(eco_format!(\"    {name}({unpacking}) -> {encoder}\"));\n            }\n        }\n\n        let clauses = clauses.join(\"\\n\");\n        Some(eco_format!(\n            \"case {record_name} {{\n{clauses}\n  }}\",\n        ))\n    }\n\n    fn constructor_encoder(\n        &mut self,\n        mode: EncodingMode,\n        constructor: &TypedRecordConstructor,\n        type_name: EcoString,\n        nesting: usize,\n    ) -> Option<EcoString> {\n        let json_module = self.printer.print_module(JSON_MODULE);\n        let tag = to_snake_case(&constructor.name);\n        let indent = \" \".repeat(nesting);\n\n        // If the variant is encoded as a simple json string we just call the\n        // `json.string` with the variant tag as an argument.\n        if mode == EncodingMode::PlainString {\n            return Some(eco_format!(\"{json_module}.string(\\\"{tag}\\\")\"));\n        }\n\n        // Otherwise we turn it into an object with a `type` tag field.\n        let mut encoder_printer =\n            JsonEncoderPrinter::new(&mut self.printer, type_name, self.module.name.clone());\n\n        // These are the fields of the json object to encode.\n        let mut fields = Vec::with_capacity(constructor.arguments.len());\n        if mode == EncodingMode::ObjectWithTypeTag {\n            // Any needed type tag is always going to be the first field in the object\n            fields.push(eco_format!(\n                \"{indent}  #(\\\"type\\\", {json_module}.string(\\\"{tag}\\\"))\"\n            ));\n        }\n\n        for argument in constructor.arguments.iter() {\n            let (_, label) = argument.label.as_ref()?;\n            let field = RecordField {\n                label: RecordLabel::Labeled(label),\n                type_: &argument.type_,\n            };\n            let encoder = encoder_printer.encode_field(&field, nesting + 2);\n            fields.push(encoder);\n        }\n\n        let fields = fields.join(\",\\n\");\n        Some(eco_format!(\n            \"{json_module}.object([\n{fields},\n{indent}])\"\n        ))\n    }\n}\n\n/// When generating an encoder, we need to know when we can ignore the fields\n/// destructured from a constructor.\n/// If a field is of type `Nil` or is a tuple type composed entirely of `Nil`\n/// types, then we will never need to use the field in our encoder function.\nfn is_nil_like(type_: &Type) -> bool {\n    if type_.is_nil() {\n        return true;\n    }\n\n    match type_.tuple_types() {\n        Some(types) => types.iter().all(|type_| is_nil_like(type_)),\n        _ => false,\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for GenerateJsonEncoder<'ast> {\n    fn visit_typed_custom_type(&mut self, custom_type: &'ast ast::TypedCustomType) {\n        let range = self.edits.src_span_to_lsp_range(custom_type.location);\n        if !overlaps(self.params.range, range) {\n            return;\n        }\n\n        let record_name = to_snake_case(&custom_type.name);\n        let name = eco_format!(\"{record_name}_to_json\");\n        let Some(encoder) = self.custom_type_encoder_body(record_name.clone(), custom_type) else {\n            return;\n        };\n\n        let json_type = self.printer.print_type(&Type::Named {\n            publicity: Publicity::Public,\n            package: JSON_PACKAGE_NAME.into(),\n            module: JSON_MODULE.into(),\n            name: \"Json\".into(),\n            arguments: vec![],\n            inferred_variant: None,\n        });\n\n        let type_ = if custom_type.parameters.is_empty() {\n            custom_type.name.clone()\n        } else {\n            let parameters = custom_type\n                .parameters\n                .iter()\n                .map(|(_, name)| name)\n                .join(\", \");\n            eco_format!(\"{}({})\", custom_type.name, parameters)\n        };\n\n        let function = format!(\n            \"\n\nfn {name}({record_name}: {type_}) -> {json_type} {{\n  {encoder}\n}}\",\n        );\n\n        self.edits.insert(custom_type.end_position, function);\n        maybe_import(&mut self.edits, self.module, JSON_MODULE);\n\n        CodeActionBuilder::new(\"Generate to-JSON function\")\n            .kind(CodeActionKind::REFACTOR)\n            .preferred(false)\n            .changes(\n                self.params.text_document.uri.clone(),\n                std::mem::take(&mut self.edits.edits),\n            )\n            .push_to(self.actions);\n    }\n}\n\nstruct JsonEncoderPrinter<'a, 'b> {\n    printer: &'a mut Printer<'b>,\n    /// The name of the root type we are printing an encoder for\n    type_name: EcoString,\n    /// The module name of the root type we are printing an encoder for\n    type_module: EcoString,\n}\n\nimpl<'a, 'b> JsonEncoderPrinter<'a, 'b> {\n    fn new(printer: &'a mut Printer<'b>, type_name: EcoString, type_module: EcoString) -> Self {\n        Self {\n            type_name,\n            type_module,\n            printer,\n        }\n    }\n\n    fn encoder_for(&mut self, encoded_value: &str, type_: &Type, indent: usize) -> EcoString {\n        let module_name = self.printer.print_module(JSON_MODULE);\n        let is_capture = encoded_value == \"_\";\n        let maybe_capture = |mut function: EcoString| {\n            if is_capture {\n                function\n            } else {\n                function.push('(');\n                function.push_str(encoded_value);\n                function.push(')');\n                function\n            }\n        };\n\n        if type_.is_bool() {\n            maybe_capture(eco_format!(\"{module_name}.bool\"))\n        } else if type_.is_float() {\n            maybe_capture(eco_format!(\"{module_name}.float\"))\n        } else if type_.is_int() {\n            maybe_capture(eco_format!(\"{module_name}.int\"))\n        } else if type_.is_string() {\n            maybe_capture(eco_format!(\"{module_name}.string\"))\n        } else if type_.is_nil() {\n            if is_capture {\n                eco_format!(\"fn(_) {{ {module_name}.null() }}\")\n            } else {\n                eco_format!(\"{module_name}.null()\")\n            }\n        } else {\n            match type_.tuple_types() {\n                Some(types) => {\n                    let (tuple, new_indent) = if is_capture {\n                        (\"value\", indent + 4)\n                    } else {\n                        (encoded_value, indent + 2)\n                    };\n\n                    // We need to iterate over all of the tuple's fields\n                    // to obtain an encoder for each one, so we reuse the\n                    // iteration to check whether this tuple can be ignored\n                    // in the encoder without calling `is_nil_like`.\n                    let mut encoders = Vec::new();\n                    let all_values_are_nil = types.iter().enumerate().fold(\n                        true,\n                        |all_values_are_nil, (index, type_)| {\n                            encoders.push(self.encoder_for(\n                                &format!(\"{tuple}.{index}\"),\n                                type_,\n                                new_indent,\n                            ));\n                            all_values_are_nil && is_nil_like(type_)\n                        },\n                    );\n\n                    if is_capture {\n                        eco_format!(\n                            \"fn({value}) {{\n{indent}  {module_name}.preprocessed_array([\n{indent}    {encoders},\n{indent}  ])\n{indent}}}\",\n                            value = if all_values_are_nil { \"_\" } else { \"value\" },\n                            indent = \" \".repeat(indent),\n                            encoders = encoders.join(&format!(\",\\n{}\", \" \".repeat(new_indent))),\n                        )\n                    } else {\n                        eco_format!(\n                            \"{module_name}.preprocessed_array([\n{indent}  {encoders},\n{indent}])\",\n                            indent = \" \".repeat(indent),\n                            encoders = encoders.join(&format!(\",\\n{}\", \" \".repeat(new_indent))),\n                        )\n                    }\n                }\n                _ => {\n                    let type_information = type_.named_type_information();\n                    let type_information: Option<(&str, &str, &[Arc<Type>])> =\n                        type_information.as_ref().map(|(module, name, arguments)| {\n                            (module.as_str(), name.as_str(), arguments.as_slice())\n                        });\n\n                    match type_information {\n                        Some((\"gleam\", \"List\", [element])) => {\n                            eco_format!(\n                                \"{module_name}.array({encoded_value}, {map_function})\",\n                                map_function = self.encoder_for(\"_\", element, indent)\n                            )\n                        }\n                        Some((\"gleam/option\", \"Option\", [some])) => {\n                            eco_format!(\n                                \"case {encoded_value} {{\n{indent}  {none} -> {module_name}.null()\n{indent}  {some}({value}) -> {encoder}\n{indent}}}\",\n                                indent = \" \".repeat(indent),\n                                none = self\n                                    .printer\n                                    .print_constructor(&\"gleam/option\".into(), &\"None\".into()),\n                                some = self\n                                    .printer\n                                    .print_constructor(&\"gleam/option\".into(), &\"Some\".into()),\n                                value = if is_nil_like(some) { \"_\" } else { \"value\" },\n                                encoder = self.encoder_for(\"value\", some, indent + 2)\n                            )\n                        }\n                        Some((\"gleam/dict\", \"Dict\", [key, value])) => {\n                            let stringify_function = match key\n                                .named_type_information()\n                                .as_ref()\n                                .map(|(module, name, arguments)| {\n                                    (module.as_str(), name.as_str(), arguments.as_slice())\n                                }) {\n                                Some((\"gleam\", \"String\", [])) => \"fn(string) { string }\",\n                                _ => &format!(\n                                    r#\"todo as \"Function to stringify {}\"\"#,\n                                    self.printer.print_type(key)\n                                ),\n                            };\n                            eco_format!(\n                                \"{module_name}.dict({encoded_value}, {stringify_function}, {})\",\n                                self.encoder_for(\"_\", value, indent)\n                            )\n                        }\n                        Some((module, name, _))\n                            if module == self.type_module && name == self.type_name =>\n                        {\n                            maybe_capture(eco_format!(\"{}_to_json\", to_snake_case(name)))\n                        }\n                        _ => eco_format!(\n                            r#\"todo as \"Encoder for {}\"\"#,\n                            self.printer.print_type(type_)\n                        ),\n                    }\n                }\n            }\n        }\n    }\n\n    fn encode_field(&mut self, field: &RecordField<'_>, indent: usize) -> EcoString {\n        let field_name = field.label.variable_name();\n        let encoder = self.encoder_for(&field_name, field.type_, indent);\n\n        eco_format!(\n            r#\"{indent}#(\"{field_name}\", {encoder})\"#,\n            indent = \" \".repeat(indent),\n        )\n    }\n}\n\n/// Builder for code action to pattern match on things like (anonymous) function\n/// arguments or variables.\n/// For example:\n///\n/// ```gleam\n/// pub fn wibble(arg: #(key, value)) {\n/// //            ^ [pattern match on argument]\n/// }\n///\n/// // Generates\n///\n/// pub fn wibble(arg: #(key, value)) {\n///   let #(value_0, value_1) = arg\n/// }\n/// ```\n///\n/// Another example with variables:\n///\n/// ```gleam\n/// pub fn main() {\n///   let pair = #(1, 3)\n///   //   ^ [pattern match on value]\n/// }\n///\n/// // Generates\n///\n/// pub fn main() {\n///   let pair = #(1, 3)\n///   let #(value_0, value_1) = pair\n/// }\n/// ```\n///\npub struct PatternMatchOnValue<'a, A> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    compiler: &'a LspProjectCompiler<A>,\n    pattern_variable_under_cursor: Option<(&'a EcoString, PatternLocation, Arc<Type>)>,\n    selected_value: Option<PatternMatchedValue<'a>>,\n    edits: TextEdits<'a>,\n}\n\n/// A value we might want to pattern match on.\n/// Each variant will also contain all the info needed to know how to properly\n/// print and format the corresponding pattern matching code; that's why you'll\n/// see `Range`s and `SrcSpan` besides the type of the thing being matched.\n///\n#[derive(Clone)]\npub enum PatternMatchedValue<'a> {\n    FunctionArgument {\n        /// The argument being pattern matched on.\n        ///\n        arg: &'a TypedArg,\n        /// The first statement inside the function body. Used to correctly\n        /// position the inserted pattern matching.\n        ///\n        first_statement: &'a TypedStatement,\n        /// The range of the entire function holding the argument.\n        ///\n        function_range: Range,\n    },\n    LetVariable {\n        variable_name: &'a EcoString,\n        variable_type: Arc<Type>,\n        /// The location of the entire let assignment the variable is part of,\n        /// so that we can add the pattern matching _after_ it.\n        ///\n        assignment_location: SrcSpan,\n    },\n    /// A variable that is bound in a case branch's pattern. For example:\n    /// ```gleam\n    /// case wibble {\n    ///   wobble -> 1\n    /// // ^^^^^ This!\n    /// }\n    /// ```\n    ///\n    ClausePatternVariable {\n        variable_type: Arc<Type>,\n        variable_location: PatternLocation,\n        clause_location: SrcSpan,\n        /// All the names in the clause that are already taken by pattern variables.\n        /// We need this to avoid generating invalid code were two pattern variables\n        /// have the same name.\n        ///\n        /// For example:\n        ///\n        /// ```gleam\n        /// case wibble {\n        ///   [first, ..rest] -> todo\n        ///    ^^^^^ When expanding `first` we can't add any variable pattern\n        ///          called `rest` as it would clash with the `rest` tail that is\n        ///          already there.\n        /// }\n        /// ```\n        ///\n        bound_variables: Vec<BoundVariable>,\n    },\n    UseVariable {\n        variable_name: &'a EcoString,\n        variable_type: Arc<Type>,\n        /// The location of the entire use expression the variable is part of,\n        /// so that we can add the pattern matching _after_ it.\n        ///\n        use_location: SrcSpan,\n    },\n}\n\n#[derive(Clone)]\npub enum PatternLocation {\n    /// Any pattern that doesn't need any special handling.\n    ///\n    Regular { location: SrcSpan },\n    /// List tails need some care to not generate invalid syntax when pattern\n    /// matched on in case expressions.\n    ///\n    ListTail {\n        /// This location covers the entire list tail pattern, including the `..`\n        location: SrcSpan,\n    },\n}\n\nimpl PatternLocation {\n    fn regular(location: SrcSpan) -> Self {\n        Self::Regular { location }\n    }\n}\n\nimpl<'a, IO> PatternMatchOnValue<'a, IO> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n        compiler: &'a LspProjectCompiler<IO>,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            compiler,\n            selected_value: None,\n            pattern_variable_under_cursor: None,\n            edits: TextEdits::new(line_numbers),\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let action_title = match self.selected_value.clone() {\n            Some(PatternMatchedValue::FunctionArgument {\n                arg,\n                first_statement: function_body,\n                function_range,\n            }) => {\n                self.match_on_function_argument(arg, function_body, function_range);\n                \"Pattern match on argument\"\n            }\n            Some(\n                PatternMatchedValue::LetVariable {\n                    variable_name,\n                    variable_type,\n                    assignment_location: location,\n                }\n                | PatternMatchedValue::UseVariable {\n                    variable_name,\n                    variable_type,\n                    use_location: location,\n                },\n            ) => {\n                self.match_on_let_variable(variable_name, variable_type, location);\n                \"Pattern match on variable\"\n            }\n\n            Some(PatternMatchedValue::ClausePatternVariable {\n                variable_type,\n                variable_location,\n                clause_location,\n                bound_variables,\n            }) => {\n                self.match_on_clause_variable(\n                    variable_type,\n                    variable_location,\n                    clause_location,\n                    &bound_variables,\n                );\n                \"Pattern match on variable\"\n            }\n\n            None => return vec![],\n        };\n\n        if self.edits.edits.is_empty() {\n            return vec![];\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(action_title)\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    fn match_on_function_argument(\n        &mut self,\n        arg: &TypedArg,\n        first_statement: &TypedStatement,\n        function_range: Range,\n    ) {\n        let Some(arg_name) = arg.get_variable_name() else {\n            return;\n        };\n\n        let Some(patterns) =\n            self.type_to_destructure_patterns(arg.type_.as_ref(), &mut NameGenerator::new())\n        else {\n            return;\n        };\n\n        let first_statement_location = first_statement.location();\n        let first_statement_range = self.edits.src_span_to_lsp_range(first_statement_location);\n\n        // If we're trying to insert the pattern matching on the same\n        // line as the one where the function is defined we will want to\n        // put it on a new line instead. So in that case the nesting will\n        // be the default 2 spaces.\n        let needs_newline = function_range.start.line == first_statement_range.start.line;\n        let nesting = if needs_newline {\n            String::from(\"  \")\n        } else {\n            \" \".repeat(first_statement_range.start.character as usize)\n        };\n\n        let pattern_matching = if patterns.len() == 1 {\n            let pattern = patterns.first();\n            format!(\"let {pattern} = {arg_name}\")\n        } else {\n            let patterns = patterns\n                .iter()\n                .map(|p| format!(\"  {nesting}{p} -> todo\"))\n                .join(\"\\n\");\n            format!(\"case {arg_name} {{\\n{patterns}\\n{nesting}}}\")\n        };\n\n        let pattern_matching = if needs_newline {\n            format!(\"\\n{nesting}{pattern_matching}\")\n        } else {\n            pattern_matching\n        };\n\n        let has_empty_body = match first_statement {\n            ast::Statement::Expression(TypedExpr::Todo {\n                kind: TodoKind::EmptyFunction { .. },\n                ..\n            }) => true,\n            ast::Statement::Expression(_)\n            | ast::Statement::Assignment(_)\n            | ast::Statement::Use(_)\n            | ast::Statement::Assert(_) => false,\n        };\n\n        // If the pattern matching is added to a function with an empty\n        // body then we do not add any nesting after it, or we would be\n        // increasing the nesting of the closing `}`!\n        let pattern_matching = if has_empty_body {\n            format!(\"{pattern_matching}\\n\")\n        } else {\n            format!(\"{pattern_matching}\\n{nesting}\")\n        };\n\n        self.edits\n            .insert(first_statement_location.start, pattern_matching);\n    }\n\n    fn match_on_let_variable(\n        &mut self,\n        variable_name: &EcoString,\n        variable_type: Arc<Type>,\n        assignment_location: SrcSpan,\n    ) {\n        let Some(patterns) =\n            self.type_to_destructure_patterns(variable_type.as_ref(), &mut NameGenerator::new())\n        else {\n            return;\n        };\n\n        let assignment_range = self.edits.src_span_to_lsp_range(assignment_location);\n        let nesting = \" \".repeat(assignment_range.start.character as usize);\n\n        let pattern_matching = if patterns.len() == 1 {\n            let pattern = patterns.first();\n            format!(\"let {pattern} = {variable_name}\")\n        } else {\n            let patterns = patterns\n                .iter()\n                .map(|p| format!(\"  {nesting}{p} -> todo\"))\n                .join(\"\\n\");\n            format!(\"case {variable_name} {{\\n{patterns}\\n{nesting}}}\")\n        };\n\n        self.edits.insert(\n            assignment_location.end,\n            format!(\"\\n{nesting}{pattern_matching}\"),\n        );\n    }\n\n    fn match_on_clause_variable(\n        &mut self,\n        variable_type: Arc<Type>,\n        variable_location: PatternLocation,\n        clause_location: SrcSpan,\n        bound_variables: &[BoundVariable],\n    ) {\n        let mut names = NameGenerator::new();\n        names.reserve_bound_variables(bound_variables);\n\n        let patterns = if matches!(variable_location, PatternLocation::ListTail { .. }) {\n            // Here we're dealing with a special case: if someone wants to expand the tail\n            // of a list we can't just replace it with the usual list patterns `[]`, `[first, ..rest]`.\n            // That would result in invalid syntax. So we have to generate list patterns\n            // that have no square brackets.\n            let first = names.rename_to_avoid_shadowing(\"first\".into());\n            let rest = names.rename_to_avoid_shadowing(\"rest\".into());\n            vec1![\"\".into(), eco_format!(\"{first}, ..{rest}\")]\n        } else if let Some(patterns) =\n            self.type_to_destructure_patterns(variable_type.as_ref(), &mut names)\n        {\n            patterns\n        } else {\n            return;\n        };\n\n        let clause_range = self.edits.src_span_to_lsp_range(clause_location);\n        let nesting = \" \".repeat(clause_range.start.character as usize);\n\n        let variable_location = match variable_location {\n            PatternLocation::Regular { location } => location,\n            PatternLocation::ListTail { location } => location,\n        };\n\n        let variable_start = (variable_location.start - clause_location.start) as usize;\n        let variable_end = variable_start + variable_location.len();\n\n        let clause_code = code_at(self.module, clause_location);\n        let patterns = patterns\n            .iter()\n            .map(|pattern| {\n                let mut clause_code = clause_code.to_string();\n                // If we're replacing a variable that's using the shorthand\n                // syntax we want to add a space to separate it from the\n                // preceding `:`.\n                let pattern = if variable_start == variable_end {\n                    &eco_format!(\" {pattern}\")\n                } else {\n                    pattern\n                };\n\n                clause_code.replace_range(variable_start..variable_end, pattern);\n                clause_code\n            })\n            .join(&format!(\"\\n{nesting}\"));\n\n        self.edits.replace(clause_location, patterns);\n    }\n\n    /// Will produce a pattern that can be used on the left hand side of a let\n    /// assignment to destructure a value of the given type. For example given\n    /// this type:\n    ///\n    /// ```gleam\n    /// pub type Wibble {\n    ///   Wobble(Int, label: String)\n    /// }\n    /// ```\n    ///\n    /// The produced pattern will look like this: `Wobble(value_0, label:)`.\n    /// The pattern will use the correct qualified/unqualified name for the\n    /// constructor if it comes from another package.\n    ///\n    /// The function will only produce a list of patterns that can be used from\n    /// the current module. So if the type comes from another module it must be\n    /// public! Otherwise this function will return an empty vec.\n    ///\n    fn type_to_destructure_patterns(\n        &mut self,\n        type_: &Type,\n        names: &mut NameGenerator,\n    ) -> Option<Vec1<EcoString>> {\n        match type_ {\n            Type::Fn { .. } => None,\n            Type::Var { type_ } => self.type_var_to_destructure_patterns(&type_.borrow(), names),\n\n            // We special case lists, they don't have \"regular\" constructors\n            // like other types. Instead we always add the two clauses covering\n            // the empty and non empty list.\n            Type::Named { .. } if type_.is_list() => {\n                let first = names.rename_to_avoid_shadowing(\"first\".into());\n                let rest = names.rename_to_avoid_shadowing(\"rest\".into());\n                Some(vec1![\n                    EcoString::from(\"[]\"),\n                    eco_format!(\"[{first}, ..{rest}]\")\n                ])\n            }\n\n            Type::Named {\n                module: type_module,\n                name: type_name,\n                ..\n            } => {\n                let mut patterns = vec![];\n                let constructors =\n                    get_type_constructors(self.compiler, &self.module.name, type_module, type_name);\n                for constructor in constructors {\n                    let names_before = names.clone();\n                    if let Some(pattern) =\n                        self.record_constructor_to_destructure_pattern(constructor, names)\n                    {\n                        patterns.push(pattern);\n                    }\n                    *names = names_before;\n                }\n\n                Vec1::try_from_vec(patterns).ok()\n            }\n\n            // We don't want to suggest this action for empty tuple as it\n            // doesn't make a lot of sense to match on those.\n            Type::Tuple { elements } if elements.is_empty() => None,\n            Type::Tuple { elements } => {\n                let elements = elements\n                    .iter()\n                    .map(|element| names.generate_name_from_type(element))\n                    .join(\", \");\n                Some(vec1![eco_format!(\"#({elements})\")])\n            }\n        }\n    }\n\n    fn type_var_to_destructure_patterns(\n        &mut self,\n        type_var: &TypeVar,\n        names: &mut NameGenerator,\n    ) -> Option<Vec1<EcoString>> {\n        match type_var {\n            TypeVar::Unbound { .. } | TypeVar::Generic { .. } => None,\n            TypeVar::Link { type_ } => self.type_to_destructure_patterns(type_, names),\n        }\n    }\n\n    /// Given the value constructor of a record, returns a string with the\n    /// pattern used to match on that specific variant.\n    ///\n    /// Note how:\n    /// - If the constructor is internal to another module or comes from another\n    ///   module, then this returns `None` since one cannot pattern match on it.\n    /// - If the provided `ValueConstructor` is not a record constructor this\n    ///   will return `None`.\n    ///\n    fn record_constructor_to_destructure_pattern(\n        &self,\n        constructor: &ValueConstructor,\n        names: &mut NameGenerator,\n    ) -> Option<EcoString> {\n        let type_::ValueConstructorVariant::Record {\n            name: constructor_name,\n            arity: constructor_arity,\n            module: constructor_module,\n            field_map,\n            ..\n        } = &constructor.variant\n        else {\n            // The constructor should always be a record, in case it's not\n            // there's not much we can do and just fail.\n            return None;\n        };\n\n        // Since the constructor is a record constructor we know that its type\n        // is either `Named` or a `Fn` type, in either case we have to get the\n        // arguments types out of it.\n        let Some(arguments_types) = constructor\n            .type_\n            .fn_types()\n            .map(|(arguments_types, _return)| arguments_types)\n            .or_else(|| constructor.type_.constructor_types())\n        else {\n            // This should never happen but just in case we don't want to unwrap\n            // and panic.\n            return None;\n        };\n\n        let index_to_label = match field_map {\n            None => HashMap::new(),\n            Some(field_map) => {\n                names.reserve_all_labels(field_map);\n\n                field_map\n                    .fields\n                    .iter()\n                    .map(|(label, index)| (index, label))\n                    .collect::<HashMap<_, _>>()\n            }\n        };\n\n        let mut pattern =\n            pretty_constructor_name(self.module, constructor_module, constructor_name)?;\n\n        if *constructor_arity == 0 {\n            return Some(pattern);\n        }\n\n        pattern.push('(');\n        let arguments = (0..*constructor_arity as u32)\n            .map(|i| match index_to_label.get(&i) {\n                Some(label) => eco_format!(\"{label}:\"),\n                None => match arguments_types.get(i as usize) {\n                    None => names.rename_to_avoid_shadowing(EcoString::from(\"value\")),\n                    Some(type_) => names.generate_name_from_type(type_),\n                },\n            })\n            .join(\", \");\n\n        pattern.push_str(&arguments);\n        pattern.push(')');\n        Some(pattern)\n    }\n}\n\nfn code_at(module: &Module, span: SrcSpan) -> &str {\n    module\n        .code\n        .get(span.start as usize..span.end as usize)\n        .expect(\"code location must be valid\")\n}\n\nimpl<'ast, IO> ast::visit::Visit<'ast> for PatternMatchOnValue<'ast, IO> {\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        // If we're not inside the function there's no point in exploring its\n        // ast further.\n        let function_span = SrcSpan {\n            start: fun.location.start,\n            end: fun.end_position,\n        };\n        let function_range = self.edits.src_span_to_lsp_range(function_span);\n        if !within(self.params.range, function_range) {\n            return;\n        }\n\n        for arg in &fun.arguments {\n            // If the cursor is placed on one of the arguments, then we can try\n            // and generate code for that one.\n            let arg_range = self.edits.src_span_to_lsp_range(arg.location);\n            if within(self.params.range, arg_range)\n                && let Some(first_statement) = fun.body.first()\n            {\n                self.selected_value = Some(PatternMatchedValue::FunctionArgument {\n                    arg,\n                    first_statement,\n                    function_range,\n                });\n                return;\n            }\n        }\n\n        // If the cursor is not on any of the function arguments then we keep\n        // exploring the function body as we might want to destructure the\n        // argument of an expression function!\n        ast::visit::visit_typed_function(self, fun);\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        kind: &'ast FunctionLiteralKind,\n        arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        // If we're not inside the function there's no point in exploring its\n        // ast further.\n        let function_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, function_range) {\n            return;\n        }\n\n        for argument in arguments {\n            // If the cursor is placed on one of the arguments, then we can try\n            // and generate code for that one.\n            let arg_range = self.edits.src_span_to_lsp_range(argument.location);\n            if within(self.params.range, arg_range) {\n                self.selected_value = Some(PatternMatchedValue::FunctionArgument {\n                    arg: argument,\n                    first_statement: body.first(),\n                    function_range,\n                });\n                return;\n            }\n        }\n\n        // If the cursor is not on any of the function arguments then we keep\n        // exploring the function body as we might want to destructure the\n        // argument of an expression function!\n        ast::visit::visit_typed_expr_fn(\n            self,\n            location,\n            type_,\n            kind,\n            arguments,\n            body,\n            return_annotation,\n        );\n    }\n\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        // If we're not inside the assignment there's no point in exploring its\n        // ast further.\n        let assignment_range = self.edits.src_span_to_lsp_range(assignment.location);\n        if !within(self.params.range, assignment_range) {\n            return;\n        }\n\n        ast::visit::visit_typed_assignment(self, assignment);\n        if let Some((name, _, ref type_)) = self.pattern_variable_under_cursor {\n            self.selected_value = Some(PatternMatchedValue::LetVariable {\n                variable_name: name,\n                variable_type: type_.clone(),\n                assignment_location: assignment.location,\n            });\n        }\n    }\n\n    fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {\n        // If we're not inside the clause there's no point in exploring its\n        // ast further.\n        let clause_range = self.edits.src_span_to_lsp_range(clause.location);\n        if !within(self.params.range, clause_range) {\n            return;\n        }\n\n        for pattern in clause.pattern.iter() {\n            self.visit_typed_pattern(pattern);\n        }\n        for patterns in clause.alternative_patterns.iter() {\n            for pattern in patterns {\n                self.visit_typed_pattern(pattern);\n            }\n        }\n\n        if let Some((_, variable_location, type_)) = self.pattern_variable_under_cursor.take() {\n            self.selected_value = Some(PatternMatchedValue::ClausePatternVariable {\n                variable_type: type_,\n                variable_location,\n                clause_location: clause.location(),\n                bound_variables: clause.bound_variables().collect_vec(),\n            });\n        } else {\n            self.visit_typed_expr(&clause.then);\n        }\n    }\n\n    fn visit_typed_use(&mut self, use_: &'ast TypedUse) {\n        if let Some(assignments) = use_.callback_arguments() {\n            for variable in assignments {\n                let ast::Arg {\n                    names: ArgNames::Named { name, .. },\n                    location: variable_location,\n                    type_,\n                    ..\n                } = variable\n                else {\n                    continue;\n                };\n\n                // If we use a pattern in a use assignment, that will end up\n                // being called `_use` something. We don't want to offer the\n                // action when hovering a pattern so we ignore those.\n                if name.starts_with(\"_use\") {\n                    continue;\n                }\n\n                let variable_range = self.edits.src_span_to_lsp_range(*variable_location);\n                if within(self.params.range, variable_range) {\n                    self.selected_value = Some(PatternMatchedValue::UseVariable {\n                        variable_name: name,\n                        variable_type: type_.clone(),\n                        use_location: use_.location,\n                    });\n                    // If we've found the variable to pattern match on, there's no\n                    // point in keeping traversing the AST.\n                    return;\n                }\n            }\n        }\n\n        ast::visit::visit_typed_use(self, use_);\n    }\n\n    fn visit_typed_pattern_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        _origin: &'ast VariableOrigin,\n    ) {\n        if within(\n            self.params.range,\n            self.edits.src_span_to_lsp_range(*location),\n        ) {\n            let location = PatternLocation::regular(*location);\n            self.pattern_variable_under_cursor = Some((name, location, type_.clone()));\n        }\n    }\n\n    fn visit_typed_pattern_call_arg(&mut self, arg: &'ast CallArg<TypedPattern>) {\n        if let Some(name) = arg.label_shorthand_name()\n            && within(\n                self.params.range,\n                self.edits.src_span_to_lsp_range(arg.location),\n            )\n        {\n            let location = PatternLocation::regular(SrcSpan {\n                start: arg.location.end,\n                end: arg.location.end,\n            });\n            self.pattern_variable_under_cursor = Some((name, location, arg.value.type_()));\n            return;\n        }\n\n        ast::visit::visit_typed_pattern_call_arg(self, arg);\n    }\n\n    fn visit_typed_pattern_string_prefix(\n        &mut self,\n        _location: &'ast SrcSpan,\n        _left_location: &'ast SrcSpan,\n        left_side_assignment: &'ast Option<(EcoString, SrcSpan)>,\n        right_location: &'ast SrcSpan,\n        _left_side_string: &'ast EcoString,\n        right_side_assignment: &'ast AssignName,\n    ) {\n        if let Some((name, location)) = left_side_assignment\n            && within(\n                self.params.range,\n                self.edits.src_span_to_lsp_range(*location),\n            )\n        {\n            let location = PatternLocation::regular(*location);\n            self.pattern_variable_under_cursor = Some((name, location, type_::string()));\n        } else if let AssignName::Variable(name) = right_side_assignment\n            && within(\n                self.params.range,\n                self.edits.src_span_to_lsp_range(*right_location),\n            )\n        {\n            let location = PatternLocation::regular(*right_location);\n            self.pattern_variable_under_cursor = Some((name, location, type_::string()));\n        }\n    }\n\n    fn visit_typed_pattern_list(\n        &mut self,\n        location: &'ast SrcSpan,\n        elements: &'ast Vec<TypedPattern>,\n        tail: &'ast Option<Box<TypedTailPattern>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        let (name, tail_location, tail_type) = if let Some(tail) = tail\n            && let Pattern::Variable { name, type_, .. } = &tail.pattern\n        {\n            (name, tail.location, type_)\n        } else {\n            ast::visit::visit_typed_pattern_list(self, location, elements, tail, type_);\n            return;\n        };\n\n        let tail_range = self.edits.src_span_to_lsp_range(tail_location);\n        if !within(self.params.range, tail_range) {\n            ast::visit::visit_typed_pattern_list(self, location, elements, tail, type_);\n            return;\n        }\n\n        let location = PatternLocation::ListTail {\n            location: tail_location,\n        };\n        self.pattern_variable_under_cursor = Some((name, location, tail_type.clone()))\n    }\n}\n\n/// Given a type and its module, returns a list of its *importable*\n/// constructors.\n///\n/// Since this focuses just on importable constructors, if either the module or\n/// the type are internal the returned array will be empty!\n///\nfn get_type_constructors<'a, 'b, IO>(\n    compiler: &'a LspProjectCompiler<IO>,\n    current_module: &'b EcoString,\n    type_module: &'b EcoString,\n    type_name: &'b EcoString,\n) -> Vec<&'a ValueConstructor> {\n    let type_is_inside_current_module = current_module == type_module;\n    let module_interface = if !type_is_inside_current_module {\n        // If the type is outside of the module we're in, we can only pattern\n        // match on it if the module can be imported.\n        // The `get_module_interface` already takes care of making this check.\n        compiler.get_module_interface(type_module)\n    } else {\n        // However, if the type is defined in the module we're in, we can always\n        // pattern match on it. So we get the current module's interface.\n        compiler\n            .modules\n            .get(current_module)\n            .map(|module| &module.ast.type_info)\n    };\n\n    let Some(module_interface) = module_interface else {\n        return vec![];\n    };\n\n    // If the type is in an internal module that is not the current one, we\n    // cannot use its constructors!\n    if !type_is_inside_current_module && module_interface.is_internal {\n        return vec![];\n    }\n\n    let Some(constructors) = module_interface.types_value_constructors.get(type_name) else {\n        return vec![];\n    };\n\n    constructors\n        .variants\n        .iter()\n        .filter_map(|variant| {\n            let constructor = module_interface.values.get(&variant.name)?;\n            if type_is_inside_current_module || constructor.publicity.is_public() {\n                Some(constructor)\n            } else {\n                None\n            }\n        })\n        .collect_vec()\n}\n\n/// Returns a pretty printed record constructor name, the way it would be used\n/// inside the given `module` (with the correct name and qualification).\n///\n/// If the constructor cannot be used inside the module because it's not\n/// imported, then this function will return `None`.\n///\nfn pretty_constructor_name(\n    module: &Module,\n    constructor_module: &EcoString,\n    constructor_name: &EcoString,\n) -> Option<EcoString> {\n    match module\n        .ast\n        .names\n        .named_constructor(constructor_module, constructor_name)\n    {\n        type_::printer::NameContextInformation::Unimported(_, _) => None,\n        type_::printer::NameContextInformation::Unqualified(constructor_name) => {\n            Some(eco_format!(\"{constructor_name}\"))\n        }\n        type_::printer::NameContextInformation::Qualified(module_name, constructor_name) => {\n            Some(eco_format!(\"{module_name}.{constructor_name}\"))\n        }\n    }\n}\n\n/// Builder for the \"generate function\" code action.\n/// Whenever someone hovers an invalid expression that is inferred to have a\n/// function type the language server can generate a function definition for it.\n/// For example:\n///\n/// ```gleam\n/// pub fn main() {\n///   wibble(1, 2, \"hello\")\n///  //  ^ [generate function]\n/// }\n/// ```\n///\n/// Will generate the following definition:\n///\n/// ```gleam\n/// pub fn wibble(arg_0: Int, arg_1: Int, arg_2: String) -> a {\n///   todo\n/// }\n/// ```\n///\npub struct GenerateFunction<'a> {\n    module: &'a Module,\n    modules: &'a std::collections::HashMap<EcoString, Module>,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    last_visited_definition_end: Option<u32>,\n    function_to_generate: Option<FunctionToGenerate<'a>>,\n}\n\nstruct FunctionToGenerate<'a> {\n    module: Option<&'a str>,\n    name: &'a str,\n    arguments_types: Vec<Arc<Type>>,\n\n    /// The arguments actually supplied as input to the function, if any.\n    /// A function to generate might as well be just a name passed as an argument\n    /// `list.map([1, 2, 3], to_generate)` so it's not guaranteed to actually\n    /// have any actual arguments!\n    given_arguments: Option<&'a [TypedCallArg]>,\n    return_type: Arc<Type>,\n    previous_definition_end: Option<u32>,\n}\n\nimpl<'a> GenerateFunction<'a> {\n    pub fn new(\n        module: &'a Module,\n        modules: &'a std::collections::HashMap<EcoString, Module>,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            modules,\n            params,\n            edits: TextEdits::new(line_numbers),\n            last_visited_definition_end: None,\n            function_to_generate: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(\n            function_to_generate @ FunctionToGenerate {\n                module,\n                previous_definition_end: Some(insert_at),\n                ..\n            },\n        ) = self.function_to_generate.take()\n        else {\n            return vec![];\n        };\n\n        if let Some(module) = module {\n            if let Some(module) = self.modules.get(module) {\n                let insert_at = module.code.len() as u32;\n                self.code_action_for_module(\n                    module,\n                    Publicity::Public,\n                    function_to_generate,\n                    insert_at,\n                )\n            } else {\n                Vec::new()\n            }\n        } else {\n            let module = self.module;\n            self.code_action_for_module(module, Publicity::Private, function_to_generate, insert_at)\n        }\n    }\n\n    fn code_action_for_module(\n        mut self,\n        module: &'a Module,\n        publicity: Publicity,\n        function_to_generate: FunctionToGenerate<'a>,\n        insert_at: u32,\n    ) -> Vec<CodeAction> {\n        let FunctionToGenerate {\n            name,\n            arguments_types,\n            given_arguments,\n            return_type,\n            ..\n        } = function_to_generate;\n\n        // This might be triggered on variants as well, in that case we don't\n        // want to offer this action. The \"generate variant\" action will be\n        // offered instead.\n        if !is_valid_lowercase_name(name) {\n            return vec![];\n        }\n\n        // Labels do not share the same namespace as argument so we use two\n        // separate generators to avoid renaming a label in case it shares a\n        // name with an argument.\n        let mut label_names = NameGenerator::new();\n        let mut argument_names = NameGenerator::new();\n\n        // Since we are generating a new function, type variables from other\n        // functions and constants are irrelevant to the types we print.\n        let mut printer = Printer::new_without_type_variables(&module.ast.names);\n        let arguments = arguments_types\n            .iter()\n            .enumerate()\n            .map(|(index, argument_type)| {\n                let call_argument = given_arguments.and_then(|arguments| arguments.get(index));\n                let (label, name) =\n                    argument_names.generate_label_and_name(call_argument, argument_type);\n                let pretty_type = printer.print_type(argument_type);\n                if let Some(label) = label {\n                    let label = label_names.rename_to_avoid_shadowing(label.clone());\n                    format!(\"{label} {name}: {pretty_type}\")\n                } else {\n                    format!(\"{name}: {pretty_type}\")\n                }\n            })\n            .join(\", \");\n\n        let return_type = printer.print_type(&return_type);\n\n        let publicity = if publicity.is_public() { \"pub \" } else { \"\" };\n\n        // Make sure we use the line number information of the module we are\n        // editing, which might not be the module where the code action is\n        // triggered.\n        self.edits.line_numbers = &module.ast.type_info.line_numbers;\n        self.edits.insert(\n            insert_at,\n            format!(\"\\n\\n{publicity}fn {name}({arguments}) -> {return_type} {{\\n  todo\\n}}\"),\n        );\n\n        let Some(uri) = url_from_path(module.input_path.as_str()) else {\n            return Vec::new();\n        };\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Generate function\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(uri, self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n\n    fn try_save_function_to_generate(\n        &mut self,\n        name: &'a EcoString,\n        function_type: &Arc<Type>,\n        given_arguments: Option<&'a [TypedCallArg]>,\n    ) {\n        match function_type.fn_types() {\n            None => {}\n            Some((arguments_types, return_type)) => {\n                self.function_to_generate = Some(FunctionToGenerate {\n                    name,\n                    arguments_types,\n                    given_arguments,\n                    return_type,\n                    previous_definition_end: self.last_visited_definition_end,\n                    module: None,\n                })\n            }\n        }\n    }\n\n    fn try_save_function_from_other_module(\n        &mut self,\n        module: &'a str,\n        name: &'a str,\n        function_type: &Arc<Type>,\n        given_arguments: Option<&'a [TypedCallArg]>,\n    ) {\n        if let Some((arguments_types, return_type)) = function_type.fn_types()\n            && is_valid_lowercase_name(name)\n        {\n            self.function_to_generate = Some(FunctionToGenerate {\n                name,\n                arguments_types,\n                given_arguments,\n                return_type,\n                previous_definition_end: self.last_visited_definition_end,\n                module: Some(module),\n            })\n        }\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        self.last_visited_definition_end = Some(fun.end_position);\n        ast::visit::visit_typed_function(self, fun);\n    }\n\n    fn visit_typed_module_constant(&mut self, constant: &'ast TypedModuleConstant) {\n        self.last_visited_definition_end = Some(constant.value.location().end);\n        ast::visit::visit_typed_module_constant(self, constant);\n    }\n\n    fn visit_typed_expr_invalid(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        extra_information: &'ast Option<InvalidExpression>,\n    ) {\n        let invalid_range = self.edits.src_span_to_lsp_range(*location);\n        if within(self.params.range, invalid_range) {\n            match extra_information {\n                Some(InvalidExpression::ModuleSelect { module_name, label }) => {\n                    self.try_save_function_from_other_module(module_name, label, type_, None)\n                }\n                Some(InvalidExpression::UnknownVariable { name }) => {\n                    self.try_save_function_to_generate(name, type_, None)\n                }\n                None => {}\n            }\n        }\n\n        ast::visit::visit_typed_expr_invalid(self, location, type_, extra_information);\n    }\n\n    fn visit_typed_constant_invalid(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        extra_information: &'ast Option<InvalidExpression>,\n    ) {\n        let constant_range = self.edits.src_span_to_lsp_range(*location);\n        if let Some(extra_information) = extra_information\n            && within(self.params.range, constant_range)\n        {\n            match extra_information {\n                InvalidExpression::ModuleSelect { module_name, label } => {\n                    self.try_save_function_from_other_module(module_name, label, type_, None)\n                }\n                InvalidExpression::UnknownVariable { name } => {\n                    self.try_save_function_to_generate(name, type_, None)\n                }\n            }\n        }\n    }\n\n    fn visit_typed_expr_call(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        fun: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        // If the function being called is invalid we need to generate a\n        // function that has the proper labels.\n        let fun_range = self.edits.src_span_to_lsp_range(fun.location());\n\n        if within(self.params.range, fun_range) {\n            if !labels_are_correct(arguments) {\n                return;\n            }\n\n            match fun {\n                TypedExpr::Invalid {\n                    type_,\n                    extra_information: Some(InvalidExpression::ModuleSelect { module_name, label }),\n                    location: _,\n                } => {\n                    return self.try_save_function_from_other_module(\n                        module_name,\n                        label,\n                        type_,\n                        Some(arguments),\n                    );\n                }\n                TypedExpr::Invalid {\n                    type_,\n                    extra_information: Some(InvalidExpression::UnknownVariable { name }),\n                    location: _,\n                } => {\n                    return self.try_save_function_to_generate(name, type_, Some(arguments));\n                }\n                TypedExpr::Int { .. }\n                | TypedExpr::Float { .. }\n                | TypedExpr::String { .. }\n                | TypedExpr::Block { .. }\n                | TypedExpr::Pipeline { .. }\n                | TypedExpr::Var { .. }\n                | TypedExpr::Fn { .. }\n                | TypedExpr::List { .. }\n                | TypedExpr::Call { .. }\n                | TypedExpr::BinOp { .. }\n                | TypedExpr::Case { .. }\n                | TypedExpr::RecordAccess { .. }\n                | TypedExpr::PositionalAccess { .. }\n                | TypedExpr::ModuleSelect { .. }\n                | TypedExpr::Tuple { .. }\n                | TypedExpr::TupleIndex { .. }\n                | TypedExpr::Todo { .. }\n                | TypedExpr::Panic { .. }\n                | TypedExpr::Echo { .. }\n                | TypedExpr::BitArray { .. }\n                | TypedExpr::RecordUpdate { .. }\n                | TypedExpr::NegateBool { .. }\n                | TypedExpr::NegateInt { .. }\n                | TypedExpr::Invalid { .. } => {}\n            }\n        }\n\n        ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);\n    }\n}\n\n/// Builder for the \"generate variant\" code action. This will generate a variant\n/// for a type if it can tell the type it should come from. It will work with\n/// non-existing variants both used as expressions\n///\n/// ```gleam\n/// let a = IDoNotExist(1)\n/// //      ^^^^^^^^^^^ It would generate this variant here\n/// ```\n///\n/// And as patterns:\n///\n/// ```gleam\n/// let assert IDoNotExist(1) = todo\n///            ^^^^^^^^^^^ It would generate this variant here\n/// ```\n///\npub struct GenerateVariant<'a, IO> {\n    module: &'a Module,\n    compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n    params: &'a CodeActionParams,\n    line_numbers: &'a LineNumbers,\n    variant_to_generate: Option<VariantToGenerate<'a>>,\n}\n\nstruct VariantToGenerate<'a> {\n    name: &'a str,\n    end_position: u32,\n    arguments_types: Vec<Arc<Type>>,\n\n    /// Wether the type we're adding the variant to is written with braces or\n    /// not. We need this information to add braces when missing.\n    ///\n    type_braces: TypeBraces,\n\n    /// The module this variant will be added to.\n    ///\n    module_name: EcoString,\n\n    /// The arguments actually supplied as input to the variant, if any.\n    /// A variant to generate might as well be just a name passed as an argument\n    /// `list.map([1, 2, 3], ToGenerate)` so it's not guaranteed to actually\n    /// have any actual arguments!\n    ///\n    given_arguments: Option<Arguments<'a>>,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum TypeBraces {\n    /// If the type is written like this: `pub type Wibble`\n    HasBraces,\n    /// If the type is written like this: `pub type Wibble {}`\n    NoBraces,\n}\n\n/// The arguments to an invalid call or pattern we can use to generate a variant.\n///\nenum Arguments<'a> {\n    /// These are the arguments provided to the invalid variant constructor\n    /// when it's used as a function: `let a = Wibble(1, 2)`.\n    ///\n    Expressions(&'a [TypedCallArg]),\n    /// These are the arguments provided to the invalid variant constructor when\n    /// it's used in a pattern: `let assert Wibble(1, 2) = a`\n    ///\n    Patterns(&'a [CallArg<TypedPattern>]),\n}\n\n/// An invalid variant might be used both as a pattern in a case expression or\n/// as a regular value in an expression. We want to generate the variant in both\n/// cases, so we use this enum to tell apart the two cases and be able to reuse\n/// most of the code for both as they are very similar.\n///\nenum Argument<'a> {\n    Expression(&'a TypedCallArg),\n    Pattern(&'a CallArg<TypedPattern>),\n}\n\nimpl<'a> Arguments<'a> {\n    fn get(&self, index: usize) -> Option<Argument<'a>> {\n        match self {\n            Arguments::Patterns(call_arguments) => call_arguments.get(index).map(Argument::Pattern),\n            Arguments::Expressions(call_arguments) => {\n                call_arguments.get(index).map(Argument::Expression)\n            }\n        }\n    }\n\n    fn types(&self) -> Vec<Arc<Type>> {\n        match self {\n            Arguments::Expressions(call_arguments) => call_arguments\n                .iter()\n                .map(|argument| argument.value.type_())\n                .collect_vec(),\n\n            Arguments::Patterns(call_arguments) => call_arguments\n                .iter()\n                .map(|argument| argument.value.type_())\n                .collect_vec(),\n        }\n    }\n}\n\nimpl Argument<'_> {\n    fn label(&self) -> Option<EcoString> {\n        match self {\n            Argument::Expression(call_arg) => call_arg.label.clone(),\n            Argument::Pattern(call_arg) => call_arg.label.clone(),\n        }\n    }\n}\n\nimpl<'a, IO> GenerateVariant<'a, IO> {\n    pub fn new(\n        module: &'a Module,\n        compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            compiler,\n            line_numbers,\n            variant_to_generate: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(VariantToGenerate {\n            name,\n            arguments_types,\n            given_arguments,\n            module_name,\n            end_position,\n            type_braces,\n        }) = &self.variant_to_generate\n        else {\n            return vec![];\n        };\n\n        let Some((variant_module, variant_edits)) = self.edits_to_create_variant(\n            name,\n            arguments_types,\n            given_arguments,\n            module_name,\n            *end_position,\n            *type_braces,\n        ) else {\n            return vec![];\n        };\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Generate variant\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(variant_module, variant_edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n\n    /// Returns the edits needed to add this new variant to the given module.\n    /// It also returns the uri of the module the edits should be applied to.\n    ///\n    fn edits_to_create_variant(\n        &self,\n        variant_name: &str,\n        arguments_types: &[Arc<Type>],\n        given_arguments: &Option<Arguments<'_>>,\n        module_name: &EcoString,\n        end_position: u32,\n        type_braces: TypeBraces,\n    ) -> Option<(Url, Vec<TextEdit>)> {\n        let mut label_names = NameGenerator::new();\n        let mut printer = Printer::new(&self.module.ast.names);\n        let arguments = arguments_types\n            .iter()\n            .enumerate()\n            .map(|(index, argument_type)| {\n                let label = given_arguments\n                    .as_ref()\n                    .and_then(|arguments| arguments.get(index)?.label())\n                    .map(|label| label_names.rename_to_avoid_shadowing(label));\n\n                let pretty_type = printer.print_type(argument_type);\n                if let Some(arg_label) = label {\n                    format!(\"{arg_label}: {pretty_type}\")\n                } else {\n                    format!(\"{pretty_type}\")\n                }\n            })\n            .join(\", \");\n\n        let variant = if arguments.is_empty() {\n            variant_name.to_string()\n        } else {\n            format!(\"{variant_name}({arguments})\")\n        };\n\n        let (new_text, insert_at) = match type_braces {\n            TypeBraces::HasBraces => (format!(\"  {variant}\\n\"), end_position - 1),\n            TypeBraces::NoBraces => (format!(\" {{\\n  {variant}\\n}}\"), end_position),\n        };\n\n        if *module_name == self.module.name {\n            // If we're editing the current module we can use the line numbers that\n            // were already computed before-hand without wasting any time to add the\n            // new edit.\n            let mut edits = TextEdits::new(self.line_numbers);\n            edits.insert(insert_at, new_text);\n            Some((self.params.text_document.uri.clone(), edits.edits))\n        } else {\n            // Otherwise we're changing a different module and we need to get its\n            // code and line numbers to properly apply the new edit.\n            let module = self\n                .compiler\n                .modules\n                .get(module_name)\n                .expect(\"module to exist\");\n            let line_numbers = LineNumbers::new(&module.code);\n            let mut edits = TextEdits::new(&line_numbers);\n            edits.insert(insert_at, new_text);\n            Some((url_from_path(module.input_path.as_str())?, edits.edits))\n        }\n    }\n\n    fn try_save_variant_to_generate(\n        &mut self,\n        function_name_location: SrcSpan,\n        function_type: &Arc<Type>,\n        given_arguments: Option<Arguments<'a>>,\n    ) {\n        let variant_to_generate =\n            self.variant_to_generate(function_name_location, function_type, given_arguments);\n        if variant_to_generate.is_some() {\n            self.variant_to_generate = variant_to_generate;\n        }\n    }\n\n    fn variant_to_generate(\n        &mut self,\n        function_name_location: SrcSpan,\n        type_: &Arc<Type>,\n        given_arguments: Option<Arguments<'a>>,\n    ) -> Option<VariantToGenerate<'a>> {\n        let name = code_at(self.module, function_name_location);\n        if !is_valid_uppercase_name(name) {\n            return None;\n        }\n\n        let (arguments_types, custom_type) = match (type_.fn_types(), &given_arguments) {\n            (Some(result), _) => result,\n            (None, Some(arguments)) => (arguments.types(), type_.clone()),\n            (None, None) => (vec![], type_.clone()),\n        };\n\n        let (module_name, type_name, _) = custom_type.named_type_information()?;\n        let module = self.compiler.modules.get(&module_name)?;\n        let (end_position, type_braces) = (module.ast.definitions.custom_types.iter())\n            .filter(|custom_type| custom_type.name == type_name)\n            .find_map(|custom_type| {\n                // If there's already a variant with this name then we definitely\n                // don't want to generate a new variant with the same name!\n                let variant_with_this_name_already_exists = custom_type\n                    .constructors\n                    .iter()\n                    .map(|constructor| &constructor.name)\n                    .any(|existing_constructor_name| existing_constructor_name == name);\n                if variant_with_this_name_already_exists {\n                    return None;\n                }\n                let type_braces = if custom_type.end_position == custom_type.location.end {\n                    TypeBraces::NoBraces\n                } else {\n                    TypeBraces::HasBraces\n                };\n                Some((custom_type.end_position, type_braces))\n            })?;\n\n        Some(VariantToGenerate {\n            name,\n            arguments_types,\n            given_arguments,\n            module_name,\n            end_position,\n            type_braces,\n        })\n    }\n}\n\nimpl<'ast, IO> ast::visit::Visit<'ast> for GenerateVariant<'ast, IO> {\n    fn visit_typed_expr_invalid(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        extra_information: &'ast Option<InvalidExpression>,\n    ) {\n        let invalid_range = src_span_to_lsp_range(*location, self.line_numbers);\n        if within(self.params.range, invalid_range) {\n            self.try_save_variant_to_generate(*location, type_, None);\n        }\n        ast::visit::visit_typed_expr_invalid(self, location, type_, extra_information);\n    }\n\n    fn visit_typed_expr_call(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        fun: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        // If the function being called is invalid we need to generate a\n        // function that has the proper labels.\n        let fun_range = src_span_to_lsp_range(fun.location(), self.line_numbers);\n        if within(self.params.range, fun_range) && fun.is_invalid() {\n            if labels_are_correct(arguments) {\n                self.try_save_variant_to_generate(\n                    fun.location(),\n                    &fun.type_(),\n                    Some(Arguments::Expressions(arguments)),\n                );\n            }\n        } else {\n            ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);\n        }\n    }\n\n    fn visit_typed_pattern_invalid(&mut self, location: &'ast SrcSpan, type_: &'ast Arc<Type>) {\n        let invalid_range = src_span_to_lsp_range(*location, self.line_numbers);\n        if within(self.params.range, invalid_range) {\n            self.try_save_variant_to_generate(*location, type_, None);\n        }\n        ast::visit::visit_typed_pattern_invalid(self, location, type_);\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<CallArg<TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast Inferred<type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast Arc<Type>,\n    ) {\n        let pattern_range = src_span_to_lsp_range(*location, self.line_numbers);\n        if within(self.params.range, pattern_range) {\n            if labels_are_correct(arguments) {\n                self.try_save_variant_to_generate(\n                    *name_location,\n                    type_,\n                    Some(Arguments::Patterns(arguments)),\n                );\n            }\n        } else {\n            ast::visit::visit_typed_pattern_constructor(\n                self,\n                location,\n                name_location,\n                name,\n                arguments,\n                module,\n                constructor,\n                spread,\n                type_,\n            );\n        }\n    }\n}\n\n#[must_use]\n/// Checks the labels in the given arguments are correct: that is there's no\n/// duplicate labels and all labelled arguments come after the unlabelled ones.\nfn labels_are_correct<A>(arguments: &[CallArg<A>]) -> bool {\n    let mut labelled_arg_found = false;\n    let mut used_labels = HashSet::new();\n\n    for argument in arguments {\n        match &argument.label {\n            // Labels are invalid if there's duplicate ones or if an unlabelled\n            // argument comes after a labelled one.\n            Some(label) if used_labels.contains(label) => return false,\n            None if labelled_arg_found => return false,\n            // Otherwise we just add the label to the used ones.\n            Some(label) => {\n                labelled_arg_found = true;\n                let _ = used_labels.insert(label);\n            }\n            None => {}\n        }\n    }\n\n    true\n}\n\n#[derive(Clone)]\nstruct NameGenerator {\n    used_names: im::HashSet<EcoString>,\n}\n\nimpl NameGenerator {\n    pub fn new() -> Self {\n        NameGenerator {\n            used_names: im::HashSet::new(),\n        }\n    }\n\n    pub fn rename_to_avoid_shadowing(&mut self, base: EcoString) -> EcoString {\n        let mut i = 1;\n        let mut candidate_name = base.clone();\n\n        loop {\n            if self.used_names.contains(&candidate_name) {\n                i += 1;\n                candidate_name = eco_format!(\"{base}_{i}\");\n            } else {\n                let _ = self.used_names.insert(candidate_name.clone());\n                return candidate_name;\n            }\n        }\n    }\n\n    /// Given an argument type and the actual call argument (if any), comes up\n    /// with a label and a name to use for that argument when generating a\n    /// function.\n    ///\n    pub fn generate_label_and_name(\n        &mut self,\n        call_argument: Option<&CallArg<TypedExpr>>,\n        argument_type: &Arc<Type>,\n    ) -> (Option<EcoString>, EcoString) {\n        let label = call_argument.and_then(|argument| argument.label.clone());\n        let argument_name = call_argument\n            // We always favour a name derived from the expression (for example if\n            // the argument is a variable)\n            .and_then(|argument| self.generate_name_from_expression(&argument.value))\n            // If we don't have such a name and there's a label we use that name.\n            .or_else(|| Some(self.rename_to_avoid_shadowing(label.clone()?)))\n            // If all else fails we fallback to using a name derived from the\n            // argument's type.\n            .unwrap_or_else(|| self.generate_name_from_type(argument_type));\n\n        (label, argument_name)\n    }\n\n    pub fn generate_name_from_type(&mut self, type_: &Arc<Type>) -> EcoString {\n        let type_to_base_name = |type_: &Arc<Type>| {\n            type_\n                .named_type_name()\n                .map(|(_type_module, type_name)| to_snake_case(&type_name))\n                .filter(|name| is_valid_lowercase_name(name))\n                .unwrap_or(EcoString::from(\"value\"))\n        };\n\n        let base_name = match type_.list_type() {\n            None => type_to_base_name(type_),\n            // If we're coming up with a name for a list we want to use the\n            // plural form for the name of the inner type. For example:\n            // `List(Pokemon)` should generate `pokemons`.\n            Some(inner_type) => {\n                let base_name = type_to_base_name(&inner_type);\n                // If the inner type name already ends in \"s\" we leave it as it\n                // is, or it would look funny.\n                if base_name.ends_with('s') {\n                    base_name\n                } else {\n                    eco_format!(\"{base_name}s\")\n                }\n            }\n        };\n\n        self.rename_to_avoid_shadowing(base_name)\n    }\n\n    fn generate_name_from_expression(&mut self, expression: &TypedExpr) -> Option<EcoString> {\n        match expression {\n            // If the argument is a record, we can't use it as an argument name.\n            // Similarly, we don't want to base the variable name off a\n            // compiler-generated variable like `_pipe`.\n            TypedExpr::Var {\n                name, constructor, ..\n            } if !constructor.variant.is_record()\n                && !constructor.variant.is_generated_variable() =>\n            {\n                Some(self.rename_to_avoid_shadowing(name.clone()))\n            }\n\n            // If the argument is a record access, we generate a name from the\n            // label used.\n            // For example if we have `wibble.id` we would end up picking `id`.\n            TypedExpr::RecordAccess { label, .. } => {\n                Some(self.rename_to_avoid_shadowing(label.clone()))\n            }\n\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    /// Given some typed definitions this reserves all the value names defined\n    /// by all the top level definitions. That is: all function names, constant\n    /// names, and imported modules names.\n    pub fn reserve_module_value_names(&mut self, definitions: &TypedDefinitions) {\n        for constant in &definitions.constants {\n            self.add_used_name(constant.name.clone());\n        }\n\n        for function in &definitions.functions {\n            if let Some((_, name)) = &function.name {\n                self.add_used_name(name.clone());\n            }\n        }\n\n        for import in &definitions.imports {\n            let module_name = match &import.used_name() {\n                Some(used_name) => used_name.clone(),\n                None => import.module.clone(),\n            };\n            self.add_used_name(module_name);\n        }\n    }\n\n    pub fn add_used_name(&mut self, name: EcoString) {\n        let _ = self.used_names.insert(name);\n    }\n\n    pub fn reserve_all_labels(&mut self, field_map: &FieldMap) {\n        field_map\n            .fields\n            .iter()\n            .for_each(|(label, _)| self.add_used_name(label.clone()));\n    }\n\n    pub fn reserve_variable_names(&mut self, variable_names: VariablesNames) {\n        variable_names\n            .names\n            .iter()\n            .for_each(|name| self.add_used_name(name.clone()));\n    }\n\n    fn reserve_bound_variables(&mut self, bound_variables: &[BoundVariable]) {\n        for variable in bound_variables {\n            self.add_used_name(variable.name());\n        }\n    }\n}\n\n#[must_use]\nfn is_valid_lowercase_name(name: &str) -> bool {\n    if !name.starts_with(|char: char| char.is_ascii_lowercase()) {\n        return false;\n    }\n\n    for char in name.chars() {\n        let is_valid_char = char.is_ascii_digit() || char.is_ascii_lowercase() || char == '_';\n        if !is_valid_char {\n            return false;\n        }\n    }\n\n    str_to_keyword(name).is_none()\n}\n\n#[must_use]\nfn is_valid_uppercase_name(name: &str) -> bool {\n    if !name.starts_with(|char: char| char.is_ascii_uppercase()) {\n        return false;\n    }\n\n    for char in name.chars() {\n        if !char.is_ascii_alphanumeric() {\n            return false;\n        }\n    }\n\n    true\n}\n\n/// Code action to rewrite a single-step pipeline into a regular function call.\n/// For example: `a |> b(c, _)` would be rewritten as `b(c, a)`.\n///\npub struct ConvertToFunctionCall<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    locations: Option<ConvertToFunctionCallLocations>,\n}\n\n/// All the different locations the \"Convert to function call\" code action needs\n/// to properly rewrite a pipeline into a function call.\n///\nstruct ConvertToFunctionCallLocations {\n    /// This is the location of the value being piped into a call.\n    ///\n    /// ```gleam\n    ///    [1, 2, 3] |> list.length\n    /// // ^^^^^^^^^ This one here\n    /// ```\n    ///\n    first_value: SrcSpan,\n\n    /// This is the location of the call the value is being piped into.\n    ///\n    /// ```gleam\n    ///    [1, 2, 3] |> list.length\n    /// //              ^^^^^^^^^^^ This one here\n    /// ```\n    ///\n    call: SrcSpan,\n\n    /// This is the kind of desugaring that is taking place when piping\n    /// `first_value` into `call`.\n    ///\n    call_kind: PipelineAssignmentKind,\n}\n\nimpl<'a> ConvertToFunctionCall<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            locations: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        // If we couldn't find a pipeline to rewrite we don't return any action.\n        let Some(ConvertToFunctionCallLocations {\n            first_value,\n            call,\n            call_kind,\n        }) = self.locations\n        else {\n            return vec![];\n        };\n\n        // We first delete the first value of the pipeline as it's going to be\n        // inlined as a function call argument.\n        self.edits.delete(SrcSpan {\n            start: first_value.start,\n            end: call.start,\n        });\n\n        // Then we have to insert the piped value in the appropriate position.\n        // This will change based on how the pipeline is being desugared, we\n        // know this thanks to the `call_kind`\n        let first_value_text = self\n            .module\n            .code\n            .get(first_value.start as usize..first_value.end as usize)\n            .expect(\"invalid code span\")\n            .to_string();\n\n        match call_kind {\n            // When piping into a `_` we replace the hole with the piped value:\n            // `[1, 2] |> map(_, todo)` becomes `map([1, 2], todo)`.\n            PipelineAssignmentKind::Hole { hole } => self.edits.replace(hole, first_value_text),\n\n            // When piping is desguared as a function call we need to add the\n            // missing parentheses:\n            // `[1, 2] |> length` becomes `length([1, 2])`\n            PipelineAssignmentKind::FunctionCall => {\n                self.edits.insert(call.end, format!(\"({first_value_text})\"))\n            }\n\n            // When the piped value is inserted as the first argument there's two\n            // possible scenarios:\n            // - there's a second argument as well: in that case we insert it\n            //   before the second arg and add a comma\n            // - there's no other argument: `[1, 2] |> length()` becomes\n            //   `length([1, 2])`, we insert the value between the empty\n            //   parentheses\n            PipelineAssignmentKind::FirstArgument {\n                second_argument: Some(SrcSpan { start, .. }),\n            } => self.edits.insert(start, format!(\"{first_value_text}, \")),\n            PipelineAssignmentKind::FirstArgument {\n                second_argument: None,\n            } => self.edits.insert(call.end - 1, first_value_text),\n\n            // When the value is piped into an echo, to rewrite the pipeline we\n            // have to insert the value after the `echo` with no parentheses:\n            // `a |> echo` is rewritten as `echo a`.\n            PipelineAssignmentKind::Echo => {\n                self.edits.insert(call.end, format!(\" {first_value_text}\"))\n            }\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Convert to function call\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ConvertToFunctionCall<'ast> {\n    fn visit_typed_expr_pipeline(\n        &mut self,\n        location: &'ast SrcSpan,\n        first_value: &'ast TypedPipelineAssignment,\n        assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)],\n        finally: &'ast TypedExpr,\n        finally_kind: &'ast PipelineAssignmentKind,\n    ) {\n        let pipeline_range = self.edits.src_span_to_lsp_range(*location);\n        if within(self.params.range, pipeline_range) {\n            // We will always desugar the pipeline's first step. If there's no\n            // intermediate assignment it means we're dealing with a single step\n            // pipeline and the call is `finally`.\n            let (call, call_kind) = assignments\n                .first()\n                .map(|(call, kind)| (call.location, *kind))\n                .unwrap_or_else(|| (finally.location(), *finally_kind));\n\n            self.locations = Some(ConvertToFunctionCallLocations {\n                first_value: first_value.location,\n                call,\n                call_kind,\n            });\n\n            ast::visit::visit_typed_expr_pipeline(\n                self,\n                location,\n                first_value,\n                assignments,\n                finally,\n                finally_kind,\n            );\n        }\n    }\n}\n\n/// Builder for code action to inline a variable.\n///\npub struct InlineVariable<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    actions: Vec<CodeAction>,\n}\n\nimpl<'a> InlineVariable<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            actions: Vec::new(),\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        self.actions\n    }\n\n    fn maybe_inline(&mut self, location: SrcSpan, name: EcoString) {\n        let references =\n            FindVariableReferences::new(location, name).find_in_module(&self.module.ast);\n        let reference = if references.len() == 1 {\n            references\n                .into_iter()\n                .next()\n                .expect(\"References has length 1\")\n        } else {\n            return;\n        };\n\n        let Some(ast::Statement::Assignment(assignment)) =\n            self.module.ast.find_statement(location.start)\n        else {\n            return;\n        };\n\n        // If the assignment does not simple bind a variable, for example:\n        // ```gleam\n        // let #(first, second, third)\n        // io.println(first)\n        // //         ^ Inline here\n        // ```\n        // We can't inline it.\n        if !matches!(assignment.pattern, Pattern::Variable { .. }) {\n            return;\n        }\n\n        // If the assignment was generated by the compiler, it doesn't have a\n        // syntactical representation, so we can't inline it.\n        if matches!(assignment.kind, AssignmentKind::Generated) {\n            return;\n        }\n\n        let value_location = assignment.value.location();\n        let value = self\n            .module\n            .code\n            .get(value_location.start as usize..value_location.end as usize)\n            .expect(\"Span is valid\");\n\n        match reference.kind {\n            VariableReferenceKind::Variable => {\n                self.edits.replace(reference.location, value.into());\n            }\n            VariableReferenceKind::LabelShorthand => {\n                self.edits\n                    .insert(reference.location.end, format!(\" {value}\"));\n            }\n        }\n\n        let mut location = assignment.location;\n\n        let mut chars = self.module.code[location.end as usize..].chars();\n        // Delete any whitespace after the removed statement\n        while chars.next().is_some_and(char::is_whitespace) {\n            location.end += 1;\n        }\n\n        self.edits.delete(location);\n\n        CodeActionBuilder::new(\"Inline variable\")\n            .kind(CodeActionKind::REFACTOR_INLINE)\n            .changes(\n                self.params.text_document.uri.clone(),\n                std::mem::take(&mut self.edits.edits),\n            )\n            .preferred(false)\n            .push_to(&mut self.actions);\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for InlineVariable<'ast> {\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        let TypedPattern::Variable { location, name, .. } = &assignment.pattern else {\n            ast::visit::visit_typed_assignment(self, assignment);\n            return;\n        };\n\n        // We special case assignment variables because we want to trigger the\n        // code action also if we're over the let keyword:\n        //\n        // ```gleam\n        //    let wibble = 11\n        // // ^^^^^^^^^^ Here!\n        // ```\n        //\n        let assignment_range = self\n            .edits\n            .src_span_to_lsp_range(SrcSpan::new(assignment.location.start, location.end));\n        if !within(self.params.range, assignment_range) {\n            ast::visit::visit_typed_assignment(self, assignment);\n            return;\n        }\n\n        self.maybe_inline(*location, name.clone());\n    }\n\n    fn visit_typed_expr_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        let range = self.edits.src_span_to_lsp_range(*location);\n\n        if !within(self.params.range, range) {\n            return;\n        }\n\n        let type_::ValueConstructorVariant::LocalVariable { location, origin } =\n            &constructor.variant\n        else {\n            return;\n        };\n\n        // We can only inline variables assigned by `let` statements, as it\n        //doesn't make sense to do so with any other kind of variable.\n        match origin.declaration {\n            VariableDeclaration::LetPattern => {}\n            VariableDeclaration::UsePattern\n            | VariableDeclaration::ClausePattern\n            | VariableDeclaration::FunctionParameter { .. }\n            | VariableDeclaration::Generated => return,\n        }\n\n        self.maybe_inline(*location, name.clone());\n    }\n\n    fn visit_typed_pattern_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        _type: &'ast Arc<Type>,\n        origin: &'ast VariableOrigin,\n    ) {\n        // We can only inline variables assigned by `let` statements, as it\n        //doesn't make sense to do so with any other kind of variable.\n        match origin.declaration {\n            VariableDeclaration::LetPattern => {}\n            VariableDeclaration::UsePattern\n            | VariableDeclaration::ClausePattern\n            | VariableDeclaration::FunctionParameter { .. }\n            | VariableDeclaration::Generated => return,\n        }\n\n        let range = self.edits.src_span_to_lsp_range(*location);\n\n        if !within(self.params.range, range) {\n            return;\n        }\n\n        self.maybe_inline(*location, name.clone());\n    }\n}\n\n/// Builder for the \"convert to pipe\" code action.\n///\n/// ```gleam\n/// pub fn main() {\n///   wibble(wobble, woo)\n///  //  ^ [convert to pipe]\n/// }\n/// ```\n///\n/// Will turn the code into the following pipeline:\n///\n/// ```gleam\n/// pub fn main() {\n///   wobble |> wibble(woo)\n/// }\n/// ```\n///\npub struct ConvertToPipe<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    argument_to_pipe: Option<ConvertToPipeArg<'a>>,\n    visited_item: VisitedItem,\n}\n\npub enum VisitedItem {\n    RegularExpression,\n    UseRightHandSide,\n    PipelineFinalStep,\n}\n\n/// Holds all the data needed by the \"convert to pipe\" code action to properly\n/// rewrite a call into a pipe. Here's what each span means:\n///\n/// ```gleam\n///    wibble(wobb|le, woo)\n/// // ^^^^^^^^^^^^^^^^^^^^ call\n/// // ^^^^^^ called\n/// //        ^^^^^^^ arg\n/// //                 ^^^ next arg\n/// ```\n///\n/// In this example `position` is 0, since the cursor is over the first\n/// argument.\n///\npub struct ConvertToPipeArg<'a> {\n    /// The span of the called function.\n    called: SrcSpan,\n    /// The span of the entire function call.\n    call: SrcSpan,\n    /// The position (0-based) of the argument.\n    position: usize,\n    /// The argument we have to pipe.\n    arg: &'a TypedCallArg,\n    /// The span of the argument following the one we have to pipe, if there's\n    /// any.\n    next_arg: Option<SrcSpan>,\n}\n\nimpl<'a> ConvertToPipe<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            visited_item: VisitedItem::RegularExpression,\n            argument_to_pipe: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(ConvertToPipeArg {\n            called,\n            call,\n            position,\n            arg,\n            next_arg,\n        }) = self.argument_to_pipe\n        else {\n            return vec![];\n        };\n\n        let arg_location = if arg.uses_label_shorthand() {\n            SrcSpan {\n                start: arg.location.start,\n                end: arg.location.end - 1,\n            }\n        } else if arg.label.is_some() {\n            arg.value.location()\n        } else {\n            arg.location\n        };\n\n        let arg_text = code_at(self.module, arg_location);\n        // If the expression being piped is a binary operation with\n        // precedence lower than pipes then we have to wrap it in curly\n        // braces to not mess with the order of operations.\n        let arg_text = if let TypedExpr::BinOp { name, .. } = arg.value\n            && name.precedence() < PIPE_PRECEDENCE\n        {\n            &format!(\"{{ {arg_text} }}\")\n        } else {\n            arg_text\n        };\n\n        match next_arg {\n            // When extracting an argument we never want to remove any explicit\n            // label that was written down, so in case it is labelled (be it a\n            // shorthand or not) we'll always replace the value with a `_`\n            _ if arg.uses_label_shorthand() => self.edits.insert(arg.location.end, \" _\".into()),\n            _ if arg.label.is_some() => self.edits.replace(arg.value.location(), \"_\".into()),\n\n            // Now we can deal with unlabelled arguments:\n            // If we're removing the first argument and there's other arguments\n            // after it, we need to delete the comma that was separating the\n            // two.\n            Some(next_arg) if position == 0 => self.edits.delete(SrcSpan {\n                start: arg.location.start,\n                end: next_arg.start,\n            }),\n            // Otherwise, if we're deleting the first argument and there's\n            // no other arguments following it, we remove the call's\n            // parentheses.\n            None if position == 0 => self.edits.delete(SrcSpan {\n                start: called.end,\n                end: call.end,\n            }),\n            // In all other cases we're piping something that is not the first\n            // argument so we just replace it with an `_`.\n            _ => self.edits.replace(arg.location, \"_\".into()),\n        };\n\n        // Finally we can add the argument that was removed as the first step\n        // of the newly defined pipeline.\n        self.edits.insert(call.start, format!(\"{arg_text} |> \"));\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Convert to pipe\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ConvertToPipe<'ast> {\n    fn visit_typed_expr_call(\n        &mut self,\n        location: &'ast SrcSpan,\n        _type_: &'ast Arc<Type>,\n        fun: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        if arguments.iter().any(|arg| arg.is_capture_hole()) {\n            return;\n        }\n\n        // If we're visiting the typed function produced by typing a use, we\n        // skip the thing itself and only visit its arguments and called\n        // function, that is the body of the use.\n        match self.visited_item {\n            VisitedItem::RegularExpression => (),\n            VisitedItem::UseRightHandSide | VisitedItem::PipelineFinalStep => {\n                self.visited_item = VisitedItem::RegularExpression;\n                ast::visit::visit_typed_expr(self, fun);\n                arguments\n                    .iter()\n                    .for_each(|arg| ast::visit::visit_typed_call_arg(self, arg));\n                return;\n            }\n        }\n\n        // We only visit a call if the cursor is somewhere within its location,\n        // otherwise we skip it entirely.\n        let call_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, call_range) {\n            return;\n        }\n\n        // If the cursor is over any of the arguments then we'll use that as\n        // the one to extract.\n        // Otherwise the cursor must be over the called function, in that case\n        // we extract the first argument (if there's one):\n        //\n        // ```gleam\n        //    wibble(wobble, woo)\n        // // ^^^^^^^^^^^^^ pipe the first argument if I'm here\n        // //                ^^^ pipe the second argument if I'm here\n        // ```\n        let argument_to_pipe = arguments\n            .iter()\n            .enumerate()\n            .find_map(|(position, arg)| {\n                let arg_range = self.edits.src_span_to_lsp_range(arg.location);\n                if within(self.params.range, arg_range) {\n                    Some((position, arg))\n                } else {\n                    None\n                }\n            })\n            .or_else(|| arguments.first().map(|argument| (0, argument)));\n\n        // If we're not hovering over any of the arguments _or_ there's no\n        // argument to extract at all we just return, there's nothing we can do\n        // on this call or any of its arguments (since we've determined the\n        // cursor is not over any of those).\n        let Some((position, arg)) = argument_to_pipe else {\n            return;\n        };\n\n        self.argument_to_pipe = Some(ConvertToPipeArg {\n            called: fun.location(),\n            call: *location,\n            position,\n            arg,\n            next_arg: arguments\n                .get(position + 1)\n                .map(|argument| argument.location),\n        });\n\n        // We still want to visit the arguments so that if we're hovering a\n        // nested pipeline, that's going to be the one we transform:\n        //\n        // ```gleam\n        // wibble(Wobble(\n        //   field: call(other(last(1)))\n        //  //      ^^^^ We want to convert this one if we hover over it,\n        //  //           not the outer `wibble(Wobble(...))` call\n        // ))\n        // ```\n        //\n        for argument in arguments {\n            ast::visit::visit_typed_call_arg(self, argument);\n        }\n    }\n\n    fn visit_typed_expr_pipeline(\n        &mut self,\n        _location: &'ast SrcSpan,\n        first_value: &'ast TypedPipelineAssignment,\n        _assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)],\n        finally: &'ast TypedExpr,\n        _finally_kind: &'ast PipelineAssignmentKind,\n    ) {\n        // We can only apply the action on the first step of a pipeline, so we\n        // visit just that one and skip all the others.\n        ast::visit::visit_typed_pipeline_assignment(self, first_value);\n        self.visited_item = VisitedItem::PipelineFinalStep;\n        ast::visit::visit_typed_expr(self, finally);\n    }\n\n    fn visit_typed_use(&mut self, use_: &'ast TypedUse) {\n        self.visited_item = VisitedItem::UseRightHandSide;\n        ast::visit::visit_typed_use(self, use_);\n    }\n}\n\n/// Code action to interpolate a string. If the cursor is inside the string\n/// (not selecting anything) the language server will offer to split it:\n///\n/// ```gleam\n/// \"wibble | wobble\"\n/// //      ^ [Split string]\n/// // Will produce the following\n/// \"wibble \" <> todo <> \" wobble\"\n/// ```\n///\n/// If the cursor is selecting an entire valid gleam name, then the language\n/// server will offer to interpolate it as a variable:\n///\n/// ```gleam\n/// \"wibble wobble woo\"\n/// //      ^^^^^^ [Interpolate variable]\n/// // Will produce the following\n/// \"wibble \" <> wobble <> \" woo\"\n/// ```\n///\n/// > Note: the cursor won't end up right after the inserted variable/todo.\n/// > that's a bit annoying, but in a future LSP version we will be able to\n/// > isnert tab stops to allow one to jump to the newly added variable/todo.\n///\npub struct InterpolateString<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    string_interpolation: Option<(SrcSpan, StringInterpolation)>,\n    string_literal_position: StringLiteralPosition,\n}\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub enum StringLiteralPosition {\n    FirstPipelineStep,\n    Other,\n}\n\n#[derive(Clone, Copy)]\nenum StringInterpolation {\n    InterpolateValue { value_location: SrcSpan },\n    SplitString { split_at: u32 },\n}\n\nimpl<'a> InterpolateString<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            string_interpolation: None,\n            string_literal_position: StringLiteralPosition::Other,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some((string_location, interpolation)) = self.string_interpolation else {\n            return vec![];\n        };\n\n        if self.string_literal_position == StringLiteralPosition::FirstPipelineStep {\n            self.edits.insert(string_location.start, \"{ \".into());\n        }\n\n        match interpolation {\n            StringInterpolation::InterpolateValue { value_location } => {\n                let name = self\n                    .module\n                    .code\n                    .get(value_location.start as usize..value_location.end as usize)\n                    .expect(\"invalid value range\");\n\n                // We trust that the programmer has correctly selected the part\n                // of the string they want to interpolate and simply \"cut it out\"\n                // for them. In future, we could try and parse their selection to\n                // see if it is a valid expression in Gleam.\n                if value_location.start == string_location.start + 1 {\n                    self.edits\n                        .insert(string_location.start, format!(\"{name} <> \"));\n                } else if value_location.end == string_location.end - 1 {\n                    self.edits\n                        .insert(string_location.end, format!(\" <> {name}\"));\n                } else {\n                    self.edits\n                        .insert(value_location.start, format!(\"\\\" <> {name} <> \\\"\"));\n                }\n                self.edits.delete(value_location);\n            }\n\n            StringInterpolation::SplitString { split_at } if self.can_split_string_at(split_at) => {\n                self.edits.insert(split_at, \"\\\" <> todo <> \\\"\".into());\n            }\n\n            StringInterpolation::SplitString { .. } => return vec![],\n        };\n\n        if self.string_literal_position == StringLiteralPosition::FirstPipelineStep {\n            self.edits.insert(string_location.end, \" }\".into());\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Interpolate string\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    fn can_split_string_at(&self, at: u32) -> bool {\n        self.string_interpolation\n            .is_some_and(|(string_location, _)| {\n                !(at <= string_location.start + 1 || at >= string_location.end - 1)\n            })\n    }\n\n    fn visit_literal_string(\n        &mut self,\n        string_location: SrcSpan,\n        string_position: StringLiteralPosition,\n    ) {\n        // We can only interpolate/split a string if the cursor is somewhere\n        // within its location, otherwise we skip it.\n        let string_range = self.edits.src_span_to_lsp_range(string_location);\n        if !within(self.params.range, string_range) {\n            return;\n        }\n\n        let selection @ SrcSpan { start, end } =\n            self.edits.lsp_range_to_src_span(self.params.range);\n\n        // We can't interpolate/split if the double quotes delimiting the\n        // string have been selected.\n        if start == string_location.start || end == string_location.end {\n            return;\n        }\n\n        let name = self\n            .module\n            .code\n            .get(start as usize..end as usize)\n            .expect(\"invalid value range\");\n\n        // TUI editors like Helix and Kakoune that use the selection-action edit\n        // model are always in the equivalent of Vim's VISUAL mode, i.e. they always\n        // have something selected. For programmers using these editors, the\n        // smallest selection possible is a 1-character selection. The best we can do\n        // to provide parity with other editors is to consider a single-character SPACE\n        // selection as an empty selection, as they most likely want to split the\n        // string instead of interpolating a variable.\n        let interpolation = if start == end || (end - start == 1 && name == \" \") {\n            StringInterpolation::SplitString { split_at: start }\n        } else {\n            StringInterpolation::InterpolateValue {\n                value_location: selection,\n            }\n        };\n        self.string_interpolation = Some((string_location, interpolation));\n        self.string_literal_position = string_position;\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for InterpolateString<'ast> {\n    fn visit_typed_expr_string(\n        &mut self,\n        location: &'ast SrcSpan,\n        _type_: &'ast Arc<Type>,\n        _value: &'ast EcoString,\n    ) {\n        self.visit_literal_string(*location, StringLiteralPosition::Other);\n    }\n\n    fn visit_typed_expr_pipeline(\n        &mut self,\n        _location: &'ast SrcSpan,\n        first_value: &'ast TypedPipelineAssignment,\n        assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)],\n        finally: &'ast TypedExpr,\n        _finally_kind: &'ast PipelineAssignmentKind,\n    ) {\n        if first_value.value.is_literal_string() {\n            self.visit_literal_string(\n                first_value.location,\n                StringLiteralPosition::FirstPipelineStep,\n            );\n        } else {\n            ast::visit::visit_typed_pipeline_assignment(self, first_value);\n        }\n\n        assignments\n            .iter()\n            .for_each(|(a, _)| ast::visit::visit_typed_pipeline_assignment(self, a));\n        self.visit_typed_expr(finally);\n    }\n}\n\n/// Code action to replace a `..` in a pattern with all the missing fields that\n/// have not been explicitly provided; labelled ones are introduced with the\n/// shorthand syntax.\n///\n/// ```gleam\n/// pub type Pokemon {\n///   Pokemon(Int, name: String, moves: List(String))\n/// }\n///\n/// pub fn main() {\n///   let Pokemon(..) = todo\n/// //            ^^ Cursor over the spread\n/// }\n/// ```\n/// Would become\n/// ```gleam\n/// pub fn main() {\n///   let Pokemon(int, name:, moves:) = todo\n/// }\n///\npub struct FillUnusedFields<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    data: Option<FillUnusedFieldsData>,\n}\n\npub struct FillUnusedFieldsData {\n    /// All the missing positional and labelled fields.\n    positional: Vec<Arc<Type>>,\n    labelled: Vec<(EcoString, Arc<Type>)>,\n    /// We need this in order to tell where the missing positional arguments\n    /// should be inserted.\n    first_labelled_argument_start: Option<u32>,\n    /// The end of the final argument before the spread, if there's any.\n    /// We'll use this to delete everything that comes after the final argument,\n    /// after adding all the ignored fields.\n    last_argument_end: Option<u32>,\n    spread_location: SrcSpan,\n}\n\nimpl<'a> FillUnusedFields<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            data: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(FillUnusedFieldsData {\n            positional,\n            labelled,\n            first_labelled_argument_start,\n            last_argument_end,\n            spread_location,\n        }) = self.data\n        else {\n            return vec![];\n        };\n\n        // Do not suggest this code action if there's no ignored fields at all.\n        if positional.is_empty() && labelled.is_empty() {\n            return vec![];\n        };\n\n        // We add all the missing positional arguments before the first\n        // labelled one (and so after all the already existing positional ones).\n        if !positional.is_empty() {\n            // We want to make sure that all positional args will have a name\n            // that's different from any label. So we add those as already used\n            // names.\n            let mut names = NameGenerator::new();\n            for (label, _) in labelled.iter() {\n                names.add_used_name(label.clone());\n            }\n\n            let positional_arguments = positional\n                .iter()\n                .map(|type_| names.generate_name_from_type(type_))\n                .join(\", \");\n            let insert_at = first_labelled_argument_start.unwrap_or(spread_location.start);\n\n            // The positional arguments are going to be followed by some other\n            // arguments if there's some already existing labelled args\n            // (`last_argument_end.is_some`), of if we're adding those labelled args\n            // ourselves (`!labelled.is_empty()`). So we need to put a comma after the\n            // final positional argument we're adding to separate it from the ones that\n            // are going to come after.\n            let has_arguments_after = last_argument_end.is_some() || !labelled.is_empty();\n            let positional_arguments = if has_arguments_after {\n                format!(\"{positional_arguments}, \")\n            } else {\n                positional_arguments\n            };\n\n            self.edits.insert(insert_at, positional_arguments);\n        }\n\n        if !labelled.is_empty() {\n            // If there's labelled arguments to add, we replace the existing spread\n            // with the arguments to be added. This way commas and all should already\n            // be correct.\n            let labelled_arguments = labelled\n                .iter()\n                .map(|(label, _)| format!(\"{label}:\"))\n                .join(\", \");\n            self.edits.replace(spread_location, labelled_arguments);\n        } else if let Some(delete_start) = last_argument_end {\n            // However, if there's no labelled arguments to insert we still need\n            // to delete the entire spread: we start deleting from the end of the\n            // final argument, if there's one.\n            // This way we also get rid of any comma separating the last argument\n            // and the spread to be removed.\n            self.edits\n                .delete(SrcSpan::new(delete_start, spread_location.end))\n        } else {\n            // Otherwise we just delete the spread.\n            self.edits.delete(spread_location)\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Fill unused fields\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for FillUnusedFields<'ast> {\n    fn visit_typed_pattern(&mut self, pattern: &'ast TypedPattern) {\n        // We can only interpolate/split a string if the cursor is somewhere\n        // within its location, otherwise we skip it.\n        let pattern_range = self.edits.src_span_to_lsp_range(pattern.location());\n        if !within(self.params.range, pattern_range) {\n            return;\n        }\n\n        if let TypedPattern::Constructor {\n            arguments,\n            spread: Some(spread_location),\n            ..\n        } = pattern\n            && let Some(PatternUnusedArguments {\n                positional,\n                labelled,\n            }) = pattern.unused_arguments()\n        {\n            // If there's any unused argument that's being ignored we want to\n            // suggest the code action.\n            let first_labelled_argument_start = arguments\n                .iter()\n                .find(|arg| !arg.is_implicit() && arg.label.is_some())\n                .map(|arg| arg.location.start);\n\n            let last_argument_end = arguments\n                .iter()\n                .rfind(|arg| !arg.is_implicit())\n                .map(|arg| arg.location.end);\n\n            self.data = Some(FillUnusedFieldsData {\n                positional,\n                labelled,\n                first_labelled_argument_start,\n                last_argument_end,\n                spread_location: *spread_location,\n            });\n        };\n\n        ast::visit::visit_typed_pattern(self, pattern);\n    }\n}\n\n/// Code action to remove an echo.\n///\npub struct RemoveEchos<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    is_hovering_echo: bool,\n    echo_spans_to_delete: Vec<SrcSpan>,\n    // We need to keep a reference to the two latest pipeline assignments we\n    // run into to properly delete an echo that's inside a pipeline.\n    latest_pipe_step: Option<SrcSpan>,\n    second_to_latest_pipe_step: Option<SrcSpan>,\n}\n\nimpl<'a> RemoveEchos<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            is_hovering_echo: false,\n            echo_spans_to_delete: vec![],\n            latest_pipe_step: None,\n            second_to_latest_pipe_step: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        // We only want to trigger the action if we're over one of the echos in\n        // the module\n        if !self.is_hovering_echo {\n            return vec![];\n        };\n\n        for span in self.echo_spans_to_delete {\n            self.edits.delete(span);\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Remove all `echo`s from this module\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    fn visit_function_statements(&mut self, statements: &'a [TypedStatement]) {\n        for i in 0..statements.len() {\n            let statement = statements\n                .get(i)\n                .expect(\"Statement must exist in iteration\");\n            let next_statement = statements.get(i + 1);\n            let is_last = i == statements.len() - 1;\n\n            match statement {\n                // We remove any echo that is used as a standalone statement used\n                // to print a literal value.\n                //\n                // ```gleam\n                // pub fn main() {\n                //   echo \"I'm here\"\n                //   do_something()\n                //   echo \"Safe!\"\n                //   do_something_else()\n                // }\n                // ```\n                //\n                // Here we want to remove not just the echo but also the literal\n                // strings they're printing.\n                //\n                // It's safe to do this only if echo is not the last expression\n                // in a function's block (otherwise we might change the function's\n                // return type by removing the entire line) and the value being\n                // printed is a literal expression.\n                //\n                ast::Statement::Expression(TypedExpr::Echo {\n                    location,\n                    expression,\n                    ..\n                }) if !is_last\n                    && expression.as_ref().is_some_and(|expression| {\n                        expression.is_literal() || expression.is_var()\n                    }) =>\n                {\n                    let echo_range = self.edits.src_span_to_lsp_range(*location);\n                    if within(self.params.range, echo_range) {\n                        self.is_hovering_echo = true;\n                    }\n\n                    let end = next_statement\n                        .map(|next| {\n                            let echo_end = location.end;\n                            let next_start = next.location().start;\n                            // We want to remove everything until the start of the\n                            // following statement. However, we have to be careful not to\n                            // delete any comments. So if there's any comment between the\n                            // echo to remove and the next statement, we just delete until\n                            // the comment's start.\n                            self.module\n                                .extra\n                                .first_comment_between(echo_end, next_start)\n                                // For comments we record the start of their content, not of the `//`\n                                // so we're subtracting 2 here to not delete the `//` as well\n                                .map(|comment| comment.start - 2)\n                                .unwrap_or(next_start)\n                        })\n                        .unwrap_or(location.end);\n\n                    self.echo_spans_to_delete.push(SrcSpan {\n                        start: location.start,\n                        end,\n                    });\n                }\n\n                // Otherwise we visit the statement as usual.\n                ast::Statement::Expression(_)\n                | ast::Statement::Assignment(_)\n                | ast::Statement::Use(_)\n                | ast::Statement::Assert(_) => ast::visit::visit_typed_statement(self, statement),\n            }\n        }\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for RemoveEchos<'ast> {\n    fn visit_typed_function(&mut self, fun: &'ast TypedFunction) {\n        self.visit_function_statements(&fun.body);\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        _location: &'ast SrcSpan,\n        _type_: &'ast Arc<Type>,\n        _kind: &'ast FunctionLiteralKind,\n        _arguments: &'ast [TypedArg],\n        body: &'ast Vec1<TypedStatement>,\n        _return_annotation: &'ast Option<ast::TypeAst>,\n    ) {\n        self.visit_function_statements(body);\n    }\n\n    fn visit_typed_expr_echo(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        expression: &'ast Option<Box<TypedExpr>>,\n        message: &'ast Option<Box<TypedExpr>>,\n    ) {\n        // We also want to trigger the action if we're hovering over the expression\n        // being printed. So we create a unique span starting from the start of echo\n        // end ending at the end of the expression.\n        //\n        // ```\n        // echo 1 + 2\n        // ^^^^^^^^^^ This is `location`, we want to trigger the action if we're\n        //            inside it, not just the keyword\n        // ```\n        //\n        let echo_range = self.edits.src_span_to_lsp_range(*location);\n        if within(self.params.range, echo_range) {\n            self.is_hovering_echo = true;\n        }\n\n        // We also want to remove the echo message!\n        if message.is_some() {\n            let start = expression\n                .as_ref()\n                .map(|expression| expression.location().end)\n                .unwrap_or(location.start + 4);\n\n            self.echo_spans_to_delete\n                .push(SrcSpan::new(start, location.end));\n        }\n\n        if let Some(expression) = expression {\n            // If there's an expression we delete everything we find until its\n            // start (excluded).\n            let span_to_delete = SrcSpan::new(location.start, expression.location().start);\n            self.echo_spans_to_delete.push(span_to_delete);\n        } else {\n            // Othwerise we know we're inside a pipeline, we take the closest step\n            // that is not echo itself and delete everything from its end until the\n            // end of the echo keyword:\n            //\n            // ```txt\n            // wibble |> echo |> wobble\n            //       ^^^^^^^^ This span right here\n            // ```\n            let step_preceding_echo = self\n                .latest_pipe_step\n                .filter(|l| l != location)\n                .or(self.second_to_latest_pipe_step);\n            if let Some(step_preceding_echo) = step_preceding_echo {\n                let span_to_delete = SrcSpan::new(step_preceding_echo.end, location.start + 4);\n                self.echo_spans_to_delete.push(span_to_delete);\n            }\n        }\n\n        ast::visit::visit_typed_expr_echo(self, location, type_, expression, message);\n    }\n\n    fn visit_typed_pipeline_assignment(&mut self, assignment: &'ast TypedPipelineAssignment) {\n        if self.latest_pipe_step.is_some() {\n            self.second_to_latest_pipe_step = self.latest_pipe_step;\n        }\n        self.latest_pipe_step = Some(assignment.location);\n        ast::visit::visit_typed_pipeline_assignment(self, assignment);\n    }\n}\n\n/// Code action to wrap assignment and case clause values in a block.\n///\n/// ```gleam\n/// pub type PokemonType {\n///   Fire\n///   Water\n/// }\n///\n/// pub fn main() {\n///   let pokemon_type: PokemonType = todo\n///   case pokemon_type {\n///     Water -> soak()\n///              ^^^^^^ Cursor over the spread\n///     Fire -> burn()\n///   }\n/// }\n/// ```\n/// Becomes\n/// ```gleam\n/// pub type PokemonType {\n///   Fire\n///   Water\n/// }\n///\n/// pub fn main() {\n///   let pokemon_type: PokemonType = todo\n///   case pokemon_type {\n///     Water -> {\n///       soak()\n///     }\n///     Fire -> burn()\n///   }\n/// }\n/// ```\n///\npub struct WrapInBlock<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    selected_expression: Option<SrcSpan>,\n}\n\nimpl<'a> WrapInBlock<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            selected_expression: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(expr_span) = self.selected_expression else {\n            return vec![];\n        };\n\n        let Some(expr_string) = self\n            .module\n            .code\n            .get(expr_span.start as usize..(expr_span.end as usize + 1))\n        else {\n            return vec![];\n        };\n\n        let range = self\n            .edits\n            .src_span_to_lsp_range(self.selected_expression.expect(\"Real range value\"));\n\n        let indent_size =\n            count_indentation(&self.module.code, self.edits.line_numbers, range.start.line);\n\n        let expr_indent_size = indent_size + 2;\n\n        let indent = \" \".repeat(indent_size);\n        let inner_indent = \" \".repeat(expr_indent_size);\n\n        self.edits.replace(\n            expr_span,\n            format!(\"{{\\n{inner_indent}{expr_string}{indent}}}\"),\n        );\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Wrap in block\")\n            .kind(CodeActionKind::REFACTOR_EXTRACT)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for WrapInBlock<'ast> {\n    fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {\n        ast::visit::visit_typed_expr(self, &assignment.value);\n        if !within(\n            self.params.range,\n            self.edits\n                .src_span_to_lsp_range(assignment.value.location()),\n        ) {\n            return;\n        }\n        match &assignment.value {\n            // To avoid wrapping the same expression in multiple, nested blocks.\n            TypedExpr::Block { .. } => {}\n            TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Var { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::ModuleSelect { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => {\n                self.selected_expression = Some(assignment.value.location());\n            }\n        };\n        ast::visit::visit_typed_assignment(self, assignment);\n    }\n\n    fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {\n        ast::visit::visit_typed_clause(self, clause);\n\n        if !within(\n            self.params.range,\n            self.edits.src_span_to_lsp_range(clause.then.location()),\n        ) {\n            return;\n        }\n\n        // To avoid wrapping the same expression in multiple, nested blocks.\n        if !matches!(clause.then, TypedExpr::Block { .. }) {\n            self.selected_expression = Some(clause.then.location());\n        };\n\n        ast::visit::visit_typed_clause(self, clause);\n    }\n}\n\n/// Code action to fix wrong binary operators when the compiler can easily tell\n/// what the correct alternative is.\n///\n/// ```gleam\n/// 1 +. 2 // becomes 1 + 2\n/// 1.0 + 2.3 // becomes 1.0 +. 2.3\n/// ```\n///\npub struct FixBinaryOperation<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    fix: Option<(SrcSpan, ast::BinOp)>,\n}\n\nimpl<'a> FixBinaryOperation<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            fix: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some((location, replacement)) = self.fix else {\n            return vec![];\n        };\n\n        self.edits.replace(location, replacement.name().into());\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(&format!(\"Use `{}`\", replacement.name()))\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for FixBinaryOperation<'ast> {\n    fn visit_typed_expr_bin_op(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        name: &'ast ast::BinOp,\n        name_location: &'ast SrcSpan,\n        left: &'ast TypedExpr,\n        right: &'ast TypedExpr,\n    ) {\n        let binop_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, binop_range) {\n            return;\n        }\n\n        if name.is_int_operator() && left.type_().is_float() && right.type_().is_float() {\n            self.fix = name.float_equivalent().map(|fix| (*name_location, fix));\n        } else if name.is_float_operator() && left.type_().is_int() && right.type_().is_int() {\n            self.fix = name.int_equivalent().map(|fix| (*name_location, fix))\n        } else if *name == ast::BinOp::AddInt\n            && left.type_().is_string()\n            && right.type_().is_string()\n        {\n            self.fix = Some((*name_location, ast::BinOp::Concatenate))\n        }\n\n        ast::visit::visit_typed_expr_bin_op(\n            self,\n            location,\n            type_,\n            name,\n            name_location,\n            left,\n            right,\n        );\n    }\n}\n\n/// Code action builder to automatically fix segments that have a value that's\n/// guaranteed to overflow.\n///\npub struct FixTruncatedBitArraySegment<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    truncation: Option<BitArraySegmentTruncation>,\n}\n\nimpl<'a> FixTruncatedBitArraySegment<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            truncation: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(truncation) = self.truncation else {\n            return vec![];\n        };\n\n        let replacement = truncation.truncated_into.to_string();\n        self.edits\n            .replace(truncation.value_location, replacement.clone());\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(&format!(\"Replace with `{replacement}`\"))\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for FixTruncatedBitArraySegment<'ast> {\n    fn visit_typed_expr_bit_array_segment(&mut self, segment: &'ast ast::TypedExprBitArraySegment) {\n        let segment_range = self.edits.src_span_to_lsp_range(segment.location);\n        if !within(self.params.range, segment_range) {\n            return;\n        }\n\n        if let Some(truncation) = segment.check_for_truncated_value() {\n            self.truncation = Some(truncation);\n        }\n\n        ast::visit::visit_typed_expr_bit_array_segment(self, segment);\n    }\n}\n\n/// Code action builder to remove unused imports and values.\n///\npub struct RemoveUnusedImports<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n}\n\n#[derive(Debug)]\nenum UnusedImport {\n    ValueOrType(SrcSpan),\n    Module(SrcSpan),\n    ModuleAlias(SrcSpan),\n}\n\nimpl UnusedImport {\n    fn location(&self) -> SrcSpan {\n        match self {\n            UnusedImport::ValueOrType(location)\n            | UnusedImport::Module(location)\n            | UnusedImport::ModuleAlias(location) => *location,\n        }\n    }\n}\n\nimpl<'a> RemoveUnusedImports<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n        }\n    }\n\n    /// Given an import location, returns a list of the spans of all the\n    /// unqualified values it's importing. Sorted by SrcSpan location.\n    ///\n    fn imported_values(&self, import_location: SrcSpan) -> Vec<SrcSpan> {\n        self.module\n            .ast\n            .definitions\n            .imports\n            .iter()\n            .find(|import| import.location.contains(import_location.start))\n            .map(|import| {\n                let types = import.unqualified_types.iter().map(|type_| type_.location);\n                let values = import.unqualified_values.iter().map(|value| value.location);\n                types\n                    .chain(values)\n                    .sorted_by_key(|location| location.start)\n                    .collect_vec()\n            })\n            .unwrap_or_default()\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        // If there's no import in the module then there can't be any unused\n        // import to remove.\n        if self.module.ast.definitions.imports.is_empty() {\n            return vec![];\n        }\n\n        let unused_imports = self\n            .module\n            .ast\n            .type_info\n            .warnings\n            .iter()\n            .filter_map(|warning| match warning {\n                type_::Warning::UnusedImportedValue { location, .. } => {\n                    Some(UnusedImport::ValueOrType(*location))\n                }\n                type_::Warning::UnusedType {\n                    location,\n                    imported: true,\n                    ..\n                } => Some(UnusedImport::ValueOrType(*location)),\n                type_::Warning::UnusedImportedModule { location, .. } => {\n                    Some(UnusedImport::Module(*location))\n                }\n                type_::Warning::UnusedImportedModuleAlias { location, .. } => {\n                    Some(UnusedImport::ModuleAlias(*location))\n                }\n                type_::Warning::Todo { .. }\n                | type_::Warning::ImplicitlyDiscardedResult { .. }\n                | type_::Warning::UnusedLiteral { .. }\n                | type_::Warning::UnusedValue { .. }\n                | type_::Warning::NoFieldsRecordUpdate { .. }\n                | type_::Warning::AllFieldsRecordUpdate { .. }\n                | type_::Warning::UnusedType { .. }\n                | type_::Warning::UnusedConstructor { .. }\n                | type_::Warning::UnusedPrivateModuleConstant { .. }\n                | type_::Warning::UnusedPrivateFunction { .. }\n                | type_::Warning::UnusedVariable { .. }\n                | type_::Warning::UnnecessaryDoubleIntNegation { .. }\n                | type_::Warning::UnnecessaryDoubleBoolNegation { .. }\n                | type_::Warning::InefficientEmptyListCheck { .. }\n                | type_::Warning::TransitiveDependencyImported { .. }\n                | type_::Warning::DeprecatedItem { .. }\n                | type_::Warning::UnreachableCasePattern { .. }\n                | type_::Warning::UnusedDiscardPattern { .. }\n                | type_::Warning::CaseMatchOnLiteralCollection { .. }\n                | type_::Warning::CaseMatchOnLiteralValue { .. }\n                | type_::Warning::OpaqueExternalType { .. }\n                | type_::Warning::InternalTypeLeak { .. }\n                | type_::Warning::RedundantAssertAssignment { .. }\n                | type_::Warning::AssertAssignmentOnImpossiblePattern { .. }\n                | type_::Warning::TodoOrPanicUsedAsFunction { .. }\n                | type_::Warning::UnreachableCodeAfterPanic { .. }\n                | type_::Warning::RedundantPipeFunctionCapture { .. }\n                | type_::Warning::FeatureRequiresHigherGleamVersion { .. }\n                | type_::Warning::JavaScriptIntUnsafe { .. }\n                | type_::Warning::AssertLiteralBool { .. }\n                | type_::Warning::BitArraySegmentTruncatedValue { .. }\n                | type_::Warning::ModuleImportedTwice { .. }\n                | type_::Warning::TopLevelDefinitionShadowsImport { .. }\n                | type_::Warning::RedundantComparison { .. }\n                | type_::Warning::UnusedRecursiveArgument { .. } => None,\n            })\n            .sorted_by_key(|import| import.location())\n            .collect_vec();\n\n        // If the cursor is not over any of the unused imports then we don't offer\n        // the code action.\n        let hovering_unused_import = unused_imports.iter().any(|import| {\n            let unused_range = self.edits.src_span_to_lsp_range(import.location());\n            overlaps(self.params.range, unused_range)\n        });\n        if !hovering_unused_import {\n            return vec![];\n        }\n\n        // Otherwise we start removing all unused imports:\n        for import in &unused_imports {\n            match import {\n                // When an entire module is unused we can delete its entire location\n                // in the source code.\n                UnusedImport::Module(location) | UnusedImport::ModuleAlias(location) => {\n                    if self.edits.line_numbers.spans_entire_line(location) {\n                        // If the unused module spans over the entire line then\n                        // we also take care of removing the following newline\n                        // characther!\n                        self.edits.delete(SrcSpan {\n                            start: location.start,\n                            end: location.end + 1,\n                        })\n                    } else {\n                        self.edits.delete(*location)\n                    }\n                }\n\n                // When removing unused imported values we have to be a bit more\n                // careful: an unused value might be followed or preceded by a\n                // comma that we also need to remove!\n                UnusedImport::ValueOrType(location) => {\n                    let imported = self.imported_values(*location);\n                    let unused_index = imported.binary_search(location);\n                    let is_last = unused_index.is_ok_and(|index| index == imported.len() - 1);\n                    let next_value = unused_index\n                        .ok()\n                        .and_then(|value_index| imported.get(value_index + 1));\n                    let previous_value = unused_index.ok().and_then(|value_index| {\n                        value_index\n                            .checked_sub(1)\n                            .and_then(|previous_index| imported.get(previous_index))\n                    });\n                    let previous_is_unused = previous_value.is_some_and(|previous| {\n                        unused_imports\n                            .as_slice()\n                            .binary_search_by_key(previous, |import| import.location())\n                            .is_ok()\n                    });\n\n                    match (previous_value, next_value) {\n                        // If there's a value following the unused import we need\n                        // to remove all characters until its start!\n                        //\n                        // ```gleam\n                        // import wibble.{unused,    used}\n                        // //             ^^^^^^^^^^^ We need to remove all of this!\n                        // ```\n                        //\n                        (_, Some(next_value)) => self.edits.delete(SrcSpan {\n                            start: location.start,\n                            end: next_value.start,\n                        }),\n\n                        // If this unused import is the last of the unuqualified\n                        // list and is preceded by another used value then we\n                        // need to do some additional cleanup and remove all\n                        // characters starting from its end.\n                        // (If the previous one is unused as well it will take\n                        // care of removing all the extra space)\n                        //\n                        // ```gleam\n                        // import wibble.{used,     unused}\n                        // //                 ^^^^^^^^^^^^ We need to remove all of this!\n                        // ```\n                        //\n                        (Some(previous_value), _) if is_last && !previous_is_unused => {\n                            self.edits.delete(SrcSpan {\n                                start: previous_value.end,\n                                end: location.end,\n                            })\n                        }\n\n                        // In all other cases it means that this is the only\n                        // item in the import list. We can just remove it.\n                        //\n                        // ```gleam\n                        // import wibble.{unused}\n                        // //             ^^^^^^ We remove this import, the formatter will already\n                        // //                    take care of removing the empty curly braces\n                        // ```\n                        //\n                        (_, _) => self.edits.delete(*location),\n                    }\n                }\n            }\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Remove unused imports\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\n/// Code action to remove a block wrapping a single expression.\n///\npub struct RemoveBlock<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    block_span: Option<SrcSpan>,\n    position: RemoveBlockPosition,\n}\n\n#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]\nenum RemoveBlockPosition {\n    InsideBinOp,\n    OutsideBinOp,\n}\n\nimpl<'a> RemoveBlock<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            block_span: None,\n            position: RemoveBlockPosition::OutsideBinOp,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(SrcSpan { start, end }) = self.block_span else {\n            return vec![];\n        };\n\n        self.edits.delete(SrcSpan::new(start, start + 1));\n        self.edits.delete(SrcSpan::new(end - 1, end));\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Remove block\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for RemoveBlock<'ast> {\n    fn visit_typed_expr_bin_op(\n        &mut self,\n        _location: &'ast SrcSpan,\n        _type_: &'ast Arc<Type>,\n        _name: &'ast ast::BinOp,\n        _name_location: &'ast SrcSpan,\n        left: &'ast TypedExpr,\n        right: &'ast TypedExpr,\n    ) {\n        let old_position = self.position;\n        self.position = RemoveBlockPosition::InsideBinOp;\n        ast::visit::visit_typed_expr(self, left);\n        self.position = RemoveBlockPosition::InsideBinOp;\n        ast::visit::visit_typed_expr(self, right);\n        self.position = old_position;\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast SrcSpan,\n        statements: &'ast [TypedStatement],\n    ) {\n        let block_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, block_range) {\n            return;\n        }\n\n        match statements {\n            [] | [_, _, ..] => (),\n            [value] => match value {\n                ast::Statement::Use(_)\n                | ast::Statement::Assert(_)\n                | ast::Statement::Assignment(_) => {\n                    ast::visit::visit_typed_expr_block(self, location, statements)\n                }\n\n                ast::Statement::Expression(expr) => match expr {\n                    TypedExpr::Int { .. }\n                    | TypedExpr::Float { .. }\n                    | TypedExpr::String { .. }\n                    | TypedExpr::Block { .. }\n                    | TypedExpr::Var { .. }\n                    | TypedExpr::Fn { .. }\n                    | TypedExpr::List { .. }\n                    | TypedExpr::Call { .. }\n                    | TypedExpr::Case { .. }\n                    | TypedExpr::RecordAccess { .. }\n                    | TypedExpr::PositionalAccess { .. }\n                    | TypedExpr::ModuleSelect { .. }\n                    | TypedExpr::Tuple { .. }\n                    | TypedExpr::TupleIndex { .. }\n                    | TypedExpr::Todo { .. }\n                    | TypedExpr::Panic { .. }\n                    | TypedExpr::Echo { .. }\n                    | TypedExpr::BitArray { .. }\n                    | TypedExpr::RecordUpdate { .. }\n                    | TypedExpr::NegateBool { .. }\n                    | TypedExpr::NegateInt { .. }\n                    | TypedExpr::Invalid { .. } => {\n                        self.block_span = Some(*location);\n                    }\n                    TypedExpr::BinOp { .. } | TypedExpr::Pipeline { .. } => {\n                        if self.position == RemoveBlockPosition::OutsideBinOp {\n                            self.block_span = Some(*location);\n                        }\n                    }\n                },\n            },\n        }\n\n        ast::visit::visit_typed_expr_block(self, location, statements);\n    }\n}\n\n/// Code action to remove `opaque` from a private type.\n///\npub struct RemovePrivateOpaque<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    opaque_span: Option<SrcSpan>,\n}\n\nimpl<'a> RemovePrivateOpaque<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            opaque_span: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(opaque_span) = self.opaque_span else {\n            return vec![];\n        };\n\n        self.edits.delete(opaque_span);\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Remove opaque from private type\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for RemovePrivateOpaque<'ast> {\n    fn visit_typed_custom_type(&mut self, custom_type: &'ast ast::TypedCustomType) {\n        let custom_type_range = self.edits.src_span_to_lsp_range(custom_type.location);\n        if !within(self.params.range, custom_type_range) {\n            return;\n        }\n\n        if custom_type.opaque && custom_type.publicity.is_private() {\n            self.opaque_span = Some(SrcSpan {\n                start: custom_type.location.start,\n                end: custom_type.location.start + 7,\n            })\n        }\n    }\n}\n\n/// Code action to rewrite a case expression as part of an outer case expression\n/// branch. For example:\n///\n/// ```gleam\n/// case wibble {\n///   Ok(a) -> case a {\n///     1 -> todo\n///     _ -> todo\n///   }\n///   Error(_) -> todo\n/// }\n/// ```\n///\n/// Would become:\n///\n/// ```gleam\n/// case wibble {\n///   Ok(1) -> todo\n///   Ok(_) -> todo\n///   Error(_) -> todo\n/// }\n/// ```\n///\npub struct CollapseNestedCase<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    collapsed: Option<Collapsed<'a>>,\n}\n\n/// This holds all the needed data about the pattern to collapse.\n/// We'll use this piece of code as an example:\n/// ```gleam\n/// case something {\n///   User(username: _, NotAdmin) -> \"Stranger!!\"\n///   User(username:, Admin) if wibble ->\n///     case username {                // <- We're collapsing this nested case\n///       \"Joe\" -> \"Hello, Joe!\"\n///       _ -> \"I don't know you, \" <> username\n///     }\n/// }\n/// ```\n///\nstruct Collapsed<'a> {\n    /// This is the span covering the entire clause being collapsed:\n    ///\n    /// ```gleam\n    /// case something {\n    ///   User(username: _, NotAdmin) -> \"Stranger!!\"\n    ///   User(username:, Admin) if wibble ->\n    ///   ┬ It goes all the way from here...\n    /// ╭─╯\n    /// │   case username {\n    /// │     \"Joe\" -> \"Hello, Joe!\"\n    /// │     _ -> \"I don't know you, \" <> username\n    /// │   }\n    /// │   ┬ ...to here!\n    /// ╰───╯\n    /// }\n    /// ```\n    ///\n    outer_clause_span: SrcSpan,\n\n    /// The (optional) guard of the outer branch. In this exmaple it's this one:\n    ///\n    /// ```gleam\n    /// case something {\n    ///   User(username: _, NotAdmin) -> \"Stranger!!\"\n    ///   User(username:, Admin) if wibble ->\n    ///                          ┬────────\n    ///                          ╰─ `outer_guard`\n    ///     case username {\n    ///       \"Joe\" -> \"Hello, Joe!\"\n    ///       _ -> \"I don't know you, \" <> username\n    ///     }\n    /// }\n    /// ```\n    ///\n    outer_guard: &'a Option<TypedClauseGuard>,\n\n    /// The pattern variable being matched on:\n    ///\n    /// ```gleam\n    /// case something {\n    ///   User(username: _, NotAdmin) -> \"Stranger!!\"\n    ///   User(username:, Admin) if wibble ->\n    ///        ┬───────\n    ///        ╰─ `matched_variable`\n    ///     case username {\n    ///       \"Joe\" -> \"Hello, Joe!\"\n    ///       _ -> \"I don't know you, \" <> username\n    ///     }\n    /// }\n    /// ```\n    ///\n    matched_variable: BoundVariable,\n\n    /// The span covering the entire pattern that is bringing the matched\n    /// variable in scope:\n    ///\n    /// ```gleam\n    /// case something {\n    ///   User(username: _, NotAdmin) -> \"Stranger!!\"\n    ///   User(username:, Admin) if wibble ->\n    ///   ┬─────────────────────\n    ///   ╰─ `matched_pattern_span`\n    ///     case username {\n    ///       \"Joe\" -> \"Hello, Joe!\"\n    ///       _ -> \"I don't know you, \" <> username\n    ///     }\n    /// }\n    /// ```\n    ///\n    matched_pattern_span: SrcSpan,\n\n    /// The clauses matching on the `username` variable. In this case they are:\n    /// ```gleam\n    /// \"Joe\" -> \"Hello, Joe!\"\n    /// _ -> \"I don't know you, \" <> username\n    /// ```\n    ///\n    inner_clauses: &'a Vec<ast::TypedClause>,\n}\n\nimpl<'a> CollapseNestedCase<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            collapsed: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(Collapsed {\n            outer_clause_span,\n            outer_guard,\n            ref matched_variable,\n            matched_pattern_span,\n            inner_clauses,\n        }) = self.collapsed\n        else {\n            return vec![];\n        };\n\n        // Now comes the tricky part: we need to replace the current pattern\n        // that is bringing the variable into scope with many new patterns, one\n        // for each of the inner clauses.\n        //\n        // Each time we will have to replace the matched variable with the\n        // pattern used in the inner clause. Let's look at an example:\n        //\n        // ```gleam\n        // Ok(a) -> case a {\n        //   1 -> wibble\n        //   2 | 3 -> wobble\n        //   _ -> woo\n        // }\n        // ```\n        //\n        // Here we will replace `a` in the `Ok(a)` outer pattern with `1`, then\n        // with `2` and `3`, and finally with `_`. Obtaining something like\n        // this:\n        //\n        // ```gleam\n        // Ok(1) -> wibble\n        // Ok(2) | Ok(3) -> wobble\n        // Ok(_) -> woo\n        // ```\n        //\n        // Notice one key detail: since alternative patterns can't be nested we\n        // can't simply write `Ok(2 | 3)` but we have to write `Ok(2) | Ok(3)`!\n\n        let pattern_text: String = code_at(self.module, matched_pattern_span).into();\n        let matched_variable_span = matched_variable.location;\n\n        let pattern_with_variable = |mut new_content: String| {\n            let mut new_pattern = pattern_text.clone();\n\n            match matched_variable {\n                BoundVariable {\n                    name: BoundVariableName::Regular { .. } | BoundVariableName::ListTail { .. },\n                    ..\n                } => {\n                    let trimmed_contents = new_content.trim();\n\n                    let pattern_is_literal_list =\n                        trimmed_contents.starts_with(\"[\") && trimmed_contents.ends_with(\"]\");\n                    let pattern_is_discard = trimmed_contents == \"_\";\n\n                    let span_to_replace = match (\n                        &matched_variable.name,\n                        // We verify whether the pattern is compatible with the list prefix `..`.\n                        // For example, `..var` is valid syntax, but `..[]` and `.._` are not.\n                        pattern_is_literal_list || pattern_is_discard,\n                    ) {\n                        // We normally replace the selected variable with the pattern.\n                        (BoundVariableName::Regular { .. }, _) => matched_variable_span,\n\n                        // If the selected pattern is not a list, we also replace it normally.\n                        (BoundVariableName::ListTail { .. }, false) => matched_variable_span,\n                        // If the pattern is a list to also remove the list tail prefix.\n                        (BoundVariableName::ListTail { tail_location, .. }, true) => {\n                            // When it's a list literal, we remove the surrounding brackets.\n                            let len = trimmed_contents.len();\n                            if let Some(slice) = new_content.trim().get(1..(len - 1)) {\n                                new_content = slice.to_string()\n                            };\n\n                            *tail_location\n                        }\n\n                        (BoundVariableName::ShorthandLabel { .. }, _) => unreachable!(),\n                    };\n\n                    let start_of_pattern =\n                        (span_to_replace.start - matched_pattern_span.start) as usize;\n                    let pattern_length = span_to_replace.len();\n\n                    let end_of_pattern = start_of_pattern + pattern_length;\n                    let replaced_range = start_of_pattern..end_of_pattern;\n\n                    new_pattern.replace_range(replaced_range, &new_content);\n                }\n\n                BoundVariable {\n                    name: BoundVariableName::ShorthandLabel { .. },\n                    ..\n                } => {\n                    // But if it's introduced using the shorthand syntax we can't\n                    // just replace it's location with the new pattern: we would be\n                    // removing the label!!\n                    // So we instead insert the pattern right after the label.\n                    new_pattern.insert_str(\n                        (matched_variable_span.end - matched_pattern_span.start) as usize,\n                        &format!(\" {new_content}\"),\n                    );\n                }\n            }\n\n            new_pattern\n        };\n\n        let mut new_clauses = vec![];\n        for clause in inner_clauses {\n            // Here we take care of unrolling any alterantive patterns: for each\n            // of the alternatives we build a new pattern and then join\n            // everything together with ` | `.\n\n            let references_to_matched_variable =\n                FindVariableReferences::new(matched_variable_span, matched_variable.name())\n                    .find(&clause.then);\n\n            let new_patterns = iter::once(&clause.pattern)\n                .chain(&clause.alternative_patterns)\n                .map(|patterns| {\n                    // If we've reached this point we've already made in the\n                    // traversal that the inner clause is matching on a single\n                    // subject. So this should be safe to expect!\n                    let pattern_location =\n                        patterns.first().expect(\"must have a pattern\").location();\n\n                    let mut pattern_code = code_at(self.module, pattern_location).to_string();\n                    if !references_to_matched_variable.is_empty() {\n                        pattern_code = format!(\"{pattern_code} as {}\", matched_variable.name());\n                    };\n                    pattern_with_variable(pattern_code)\n                })\n                .join(\" | \");\n\n            let clause_code = code_at(self.module, clause.then.location());\n            let guard_code = match (outer_guard, &clause.guard) {\n                (Some(outer), Some(inner)) => {\n                    let mut outer_code = code_at(self.module, outer.location()).to_string();\n                    let mut inner_code = code_at(self.module, inner.location()).to_string();\n                    if ast::BinOp::And.precedence() > outer.precedence() {\n                        outer_code = format!(\"{{ {outer_code} }}\")\n                    }\n                    if ast::BinOp::And.precedence() > inner.precedence() {\n                        inner_code = format!(\"{{ {inner_code} }}\")\n                    }\n                    format!(\" if {outer_code} && {inner_code}\")\n                }\n                (None, Some(guard)) | (Some(guard), None) => {\n                    format!(\" if {}\", code_at(self.module, guard.location()))\n                }\n                (None, None) => \"\".into(),\n            };\n\n            new_clauses.push(format!(\"{new_patterns}{guard_code} -> {clause_code}\"));\n        }\n\n        let pattern_nesting = self\n            .edits\n            .src_span_to_lsp_range(outer_clause_span)\n            .start\n            .character;\n        let indentation = \" \".repeat(pattern_nesting as usize);\n\n        self.edits.replace(\n            outer_clause_span,\n            new_clauses.join(&format!(\"\\n{indentation}\")),\n        );\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Collapse nested case\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    /// If the clause can be flattened because it's matching on a single variable\n    /// defined in it, this function will return the info needed by the language\n    /// server to flatten that case.\n    ///\n    /// We can only flatten a case expression in a very specific case:\n    /// - This pattern may be introducing multiple variables,\n    /// - The expression following this branch must be a case, and\n    /// - It must be matching on one of those variables\n    ///\n    /// For example:\n    ///\n    /// ```gleam\n    /// Wibble(a, b, 1) -> case a { ... }\n    /// Wibble(a, b, 1) -> case b { ... }\n    /// ```\n    ///\n    fn flatten_clause(&self, clause: &'a ast::TypedClause) -> Option<Collapsed<'a>> {\n        let ast::TypedClause {\n            pattern,\n            alternative_patterns,\n            then,\n            location,\n            guard,\n        } = clause;\n\n        if !alternative_patterns.is_empty() {\n            return None;\n        }\n\n        // The `then` clause must be a single case expression matching on a\n        // single variable.\n        let Some(TypedExpr::Case {\n            subjects, clauses, ..\n        }) = single_expression(then)\n        else {\n            return None;\n        };\n\n        let [TypedExpr::Var { name, .. }] = subjects.as_slice() else {\n            return None;\n        };\n\n        // That variable must be one the variables we brought into scope in this\n        // branch.\n        let variable = pattern\n            .iter()\n            .flat_map(|pattern| pattern.bound_variables())\n            .find(|variable| variable.name() == *name)?;\n\n        // There's one last condition to trigger the code action: we must\n        // actually be with the cursor over the pattern or the nested case\n        // expression!\n        //\n        // ```gleam\n        // case wibble {\n        //   Ok(a) -> case a {\n        // //^^^^^^^^^^^^^^^ Anywhere over here!\n        //   }\n        // }\n        // ```\n        //\n        let first_pattern = pattern.first().expect(\"at least one pattern\");\n        let last_pattern = pattern.last().expect(\"at least one pattern\");\n        let pattern_location = first_pattern.location().merge(&last_pattern.location());\n\n        let last_inner_subject = subjects.last().expect(\"at least one subject\");\n        let trigger_location = pattern_location.merge(&last_inner_subject.location());\n        let trigger_range = self.edits.src_span_to_lsp_range(trigger_location);\n\n        if within(self.params.range, trigger_range) {\n            Some(Collapsed {\n                outer_clause_span: *location,\n                outer_guard: guard,\n                matched_variable: variable,\n                matched_pattern_span: pattern_location,\n                inner_clauses: clauses,\n            })\n        } else {\n            None\n        }\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for CollapseNestedCase<'ast> {\n    fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {\n        if let Some(collapsed) = self.flatten_clause(clause) {\n            self.collapsed = Some(collapsed);\n\n            // We're done, there's no need to keep exploring as we know the\n            // cursor is over this pattern and it can't be over any other one!\n            return;\n        };\n\n        ast::visit::visit_typed_clause(self, clause);\n    }\n}\n\n/// If the expression is a single expression, or a block containing a single\n/// expression, this function will return it.\n/// But if the expression is a block with multiple statements, an assignment\n/// of a use, this will return None.\n///\nfn single_expression(expression: &TypedExpr) -> Option<&TypedExpr> {\n    match expression {\n        // If a block has a single statement, we can flatten it into a\n        // single expression if that one statement is an expression.\n        TypedExpr::Block { statements, .. } if statements.len() == 1 => match statements.first() {\n            ast::Statement::Expression(expression) => single_expression(expression),\n            ast::Statement::Assignment(_) | ast::Statement::Use(_) | ast::Statement::Assert(_) => {\n                None\n            }\n        },\n\n        // If a block has multiple statements then it can't be flattened\n        // into a single expression.\n        TypedExpr::Block { .. } => None,\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::ModuleSelect { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => Some(expression),\n    }\n}\n\n/// Code action to remove unreachable clauses from a case expression.\n///\npub struct RemoveUnreachableCaseClauses<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    /// The source location of the patterns of all the unreachable clauses in\n    /// the current module.\n    ///\n    unreachable_clauses: HashSet<SrcSpan>,\n    clauses_to_delete: Vec<SrcSpan>,\n}\n\nimpl<'a> RemoveUnreachableCaseClauses<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        let unreachable_clauses = module\n            .ast\n            .type_info\n            .warnings\n            .iter()\n            .filter_map(|warning| {\n                if let type_::Warning::UnreachableCasePattern { location, .. } = warning {\n                    Some(*location)\n                } else {\n                    None\n                }\n            })\n            .collect();\n\n        Self {\n            unreachable_clauses,\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            clauses_to_delete: vec![],\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n        if self.clauses_to_delete.is_empty() {\n            return vec![];\n        }\n\n        for branch in self.clauses_to_delete {\n            self.edits.delete(branch);\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Remove unreachable clauses\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for RemoveUnreachableCaseClauses<'ast> {\n    fn visit_typed_expr_case(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        subjects: &'ast [TypedExpr],\n        clauses: &'ast [ast::TypedClause],\n        compiled_case: &'ast CompiledCase,\n    ) {\n        // We're showing the code action only if we're within one of the\n        // unreachable patterns. And the code action is going to remove all the\n        // unreachable patterns for this case.\n        let is_hovering_clause = clauses.iter().any(|clause| {\n            let pattern_range = self.edits.src_span_to_lsp_range(clause.pattern_location());\n            within(self.params.range, pattern_range)\n        });\n        if is_hovering_clause {\n            self.clauses_to_delete = clauses\n                .iter()\n                .filter(|clause| {\n                    self.unreachable_clauses\n                        .contains(&clause.pattern_location())\n                })\n                .map(|clause| clause.location())\n                .collect_vec();\n            return;\n        }\n\n        // If we're not hovering any of the clauses then we want to\n        // keep visiting the case expression as the unreachable branch might be\n        // in one of the nested cases.\n        ast::visit::visit_typed_expr_case(self, location, type_, subjects, clauses, compiled_case);\n    }\n}\n\n/// Code action to add labels to a constructor/call where all the labels where\n/// omitted.\n///\npub struct AddOmittedLabels<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    arguments_and_omitted_labels: Option<Vec<CallArgumentWithOmittedLabel>>,\n}\n\nstruct CallArgumentWithOmittedLabel {\n    location: SrcSpan,\n\n    /// If the argument has a label this will be the label we can use for it.\n    ///\n    omitted_label: Option<EcoString>,\n\n    /// If the argument is a variable that has the same name as the omitted label\n    /// and could use the shorthand syntax.\n    ///\n    can_use_shorthand_syntax: bool,\n}\n\nimpl<'a> AddOmittedLabels<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            arguments_and_omitted_labels: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(call_arguments) = self.arguments_and_omitted_labels else {\n            return vec![];\n        };\n\n        for call_argument in call_arguments {\n            let Some(label) = call_argument.omitted_label else {\n                continue;\n            };\n            if call_argument.can_use_shorthand_syntax {\n                self.edits.insert(call_argument.location.end, \":\".into());\n            } else {\n                self.edits\n                    .insert(call_argument.location.start, format!(\"{label}: \"))\n            }\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Add omitted labels\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for AddOmittedLabels<'ast> {\n    fn visit_typed_expr_call(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        fun: &'ast TypedExpr,\n        arguments: &'ast [TypedCallArg],\n    ) {\n        let called_function_range = self.edits.src_span_to_lsp_range(fun.location());\n        if !within(self.params.range, called_function_range) {\n            ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);\n            return;\n        }\n\n        let Some(field_map) = fun.field_map() else {\n            ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);\n            return;\n        };\n        let argument_index_to_label = field_map.indices_to_labels();\n\n        let mut omitted_labels = Vec::with_capacity(arguments.len());\n        for (index, argument) in arguments.iter().enumerate() {\n            // If the argument already has a label we don't want to add a label\n            // for it, so we skip it.\n            if let Some(label) = &argument.label {\n                // Though, before skipping, we want to make sure that the label\n                // is actually right for the function call. If it's not then we\n                // give up on adding labels because there wouldn't be no way of\n                // knowing which label to add.\n                if !field_map.fields.contains_key(label) {\n                    return;\n                } else {\n                    continue;\n                }\n            }\n            // No labels for pipes, uses, etc!\n            if argument.is_implicit() {\n                continue;\n            }\n\n            let label = argument_index_to_label\n                .get(&(index as u32))\n                .cloned()\n                .cloned();\n\n            let can_use_shorthand_syntax = match (&label, &argument.value) {\n                (Some(label), TypedExpr::Var { name, .. }) => name == label,\n                (Some(_) | None, _) => false,\n            };\n\n            omitted_labels.push(CallArgumentWithOmittedLabel {\n                location: argument.location,\n                omitted_label: label,\n                can_use_shorthand_syntax,\n            })\n        }\n        self.arguments_and_omitted_labels = Some(omitted_labels);\n    }\n}\n\n/// Code action to extract selected code into a separate function.\n/// If a user selected a portion of code in a function, we offer a code action\n/// to extract it into a new one. This can either be a single expression, such\n/// as in the following example:\n///\n/// ```gleam\n/// pub fn main() {\n///   let value = {\n///   //          ^ User selects from here\n///     ...\n///   }\n/// //^ Until here\n/// }\n/// ```\n///\n/// Here, we would extract the selected block expression. It could also be a\n/// series of statements. For example:\n///\n/// ```gleam\n/// pub fn main() {\n///   let a = 1\n/// //^ User selects from here\n///   let b = 2\n///   let c = a + b\n///   //          ^ Until here\n///\n///   do_more_things(c)\n/// }\n/// ```\n///\n/// Here, we want to extract the statements inside the user's selection.\n///\npub struct ExtractFunction<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    function: Option<ExtractedFunction<'a>>,\n    function_end_position: Option<u32>,\n    /// Since the `visit_typed_statement` visitor function doesn't tell us when\n    /// a statement is the last in a block or function, we need to track that\n    /// manually.\n    last_statement_location: Option<SrcSpan>,\n}\n\n/// Information about a section of code we are extracting as a function.\nstruct ExtractedFunction<'a> {\n    /// A list of parameters which need to be passed to the extracted function.\n    /// These are any variables used in the extracted code, which are defined\n    /// outside of the extracted code.\n    parameters: Vec<(EcoString, Arc<Type>)>,\n    /// A list of values which need to be returned from the extracted function.\n    /// These are the variables defined in the extracted code which are used\n    /// outside of the extracted section.\n    returned_variables: Vec<(EcoString, Arc<Type>)>,\n    /// The piece of code to be extracted. This is either a single expression or\n    /// a list of statements, as explained in the documentation of `ExtractFunction`\n    value: ExtractedValue<'a>,\n}\n\nimpl<'a> ExtractedFunction<'a> {\n    fn new(value: ExtractedValue<'a>) -> Self {\n        Self {\n            value,\n            parameters: Vec::new(),\n            returned_variables: Vec::new(),\n        }\n    }\n\n    fn location(&self) -> SrcSpan {\n        match &self.value {\n            ExtractedValue::Expression(expression) => expression.location(),\n            ExtractedValue::Statements { location, .. } => *location,\n        }\n    }\n}\n\n#[derive(Debug)]\nenum ExtractedValue<'a> {\n    Expression(&'a TypedExpr),\n    Statements {\n        location: SrcSpan,\n        position: StatementPosition,\n    },\n}\n\n/// When we are extracting multiple statements, there are two possible cases:\n/// The first is if we are extracting statements in the middle of a function.\n/// In this case, we will need to return some number of arguments, or `Nil`.\n/// For example:\n///\n/// ```gleam\n/// pub fn main() {\n///   let message = \"Hello!\"\n///   let log_message = \"[INFO] \" <> message\n/// //^ Select from here\n///   io.println(log_message)\n///   //                    ^ Until here\n///\n///   do_some_more_things()\n/// }\n/// ```\n///\n/// Here, the extracted function doesn't bind any variables which we need\n/// afterwards, it purely performs side effects. In this case we can just return\n/// `Nil` from the new function.\n///\n/// However, consider the following:\n///\n/// ```gleam\n/// pub fn main() {\n///   let a = 1\n///   let b = 2\n/// //^ Select from here\n///   a + b\n///   //  ^ Until here\n/// }\n/// ```\n///\n/// Here, despite us not needing any variables from the extracted code, there\n/// is one key difference: the `a + b` expression is at the end of the function,\n/// and so its value is returned from the entire function. This is known as the\n/// \"tail\" position. In that case, we can't return `Nil` as that would make the\n/// `main` function return `Nil` instead of the result of the addition. If we\n/// extract the tail-position statement, we need to return that last value rather\n/// than `Nil`.\n///\n#[derive(Debug)]\nenum StatementPosition {\n    Tail { type_: Arc<Type> },\n    NotTail,\n}\n\nimpl<'a> ExtractFunction<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            function: None,\n            function_end_position: None,\n            last_statement_location: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        // If no code is selected, then there is no function to extract and we\n        // can return no code actions.\n        if self.params.range.start == self.params.range.end {\n            return Vec::new();\n        }\n\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(end) = self.function_end_position else {\n            return Vec::new();\n        };\n\n        // If nothing was found in the selected range, there is no code action.\n        let Some(extracted) = self.function.take() else {\n            return Vec::new();\n        };\n\n        match extracted.value {\n            // If we extract a block, it isn't very helpful to have the body of the\n            // extracted function just be a single block expression, so instead we\n            // extract the statements inside the block. For example, the following\n            // code:\n            //\n            // ```gleam\n            // pub fn main() {\n            //   let x = {\n            //   //      ^ Select from here\n            //     let a = 1\n            //     let b = 2\n            //     a + b\n            //   }\n            // //^ Until here\n            //   x\n            // }\n            // ```\n            //\n            // Would produce the following extracted function:\n            //\n            // ```gleam\n            // fn function() {\n            //   let a = 1\n            //   let b = 2\n            //   a + b\n            // }\n            // ```\n            //\n            // Rather than:\n            //\n            // ```gleam\n            // fn function() {\n            //   {\n            //     let a = 1\n            //     let b = 2\n            //     a + b\n            //   }\n            // }\n            // ```\n            //\n            ExtractedValue::Expression(TypedExpr::Block {\n                statements,\n                location: full_location,\n            }) => {\n                let location = statements\n                    .first()\n                    .location()\n                    .merge(&statements.last().location());\n\n                self.extract_code_in_tail_position(\n                    *full_location,\n                    location,\n                    statements.last().type_(),\n                    extracted.parameters,\n                    end,\n                )\n            }\n            ExtractedValue::Expression(TypedExpr::Fn {\n                type_,\n                location: full_location,\n                kind: FunctionLiteralKind::Anonymous { .. },\n                arguments,\n                body,\n                ..\n            }) => {\n                let location = body.first().location().merge(&body.last().location());\n                let return_type = type_.return_type().expect(\"Fn should have a return type\");\n\n                if extracted.parameters.is_empty() {\n                    self.extract_anonymous_function(\n                        *full_location,\n                        location,\n                        arguments,\n                        return_type,\n                        end,\n                    )\n                } else if arguments.len() == 1 {\n                    self.extract_anonymous_function_with_capture_hole(\n                        *full_location,\n                        location,\n                        arguments.first().expect(\"There is exactly one argument\"),\n                        extracted.parameters,\n                        return_type,\n                        end,\n                    )\n                } else {\n                    self.extract_anonymous_function_body(\n                        location,\n                        arguments,\n                        extracted.parameters,\n                        return_type,\n                        end,\n                    )\n                }\n            }\n            ExtractedValue::Expression(expression) => {\n                let expression_type = if let TypedExpr::Fn {\n                    type_,\n                    kind: FunctionLiteralKind::Use { .. },\n                    ..\n                } = expression\n                {\n                    type_.fn_types().expect(\"use callback to be a function\").1\n                } else {\n                    expression.type_()\n                };\n                self.extract_code_in_tail_position(\n                    expression.location(),\n                    expression.location(),\n                    expression_type,\n                    extracted.parameters,\n                    end,\n                )\n            }\n            ExtractedValue::Statements {\n                location,\n                position: StatementPosition::NotTail,\n            } => self.extract_statements(\n                location,\n                extracted.parameters,\n                extracted.returned_variables,\n                end,\n            ),\n            ExtractedValue::Statements {\n                location,\n                position: StatementPosition::Tail { type_ },\n            } => self.extract_code_in_tail_position(\n                location,\n                location,\n                type_,\n                extracted.parameters,\n                end,\n            ),\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Extract function\")\n            .kind(CodeActionKind::REFACTOR_EXTRACT)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    /// Choose a suitable name for an extracted function to make sure it doesn't\n    /// clash with existing functions defined in the module and cause an error.\n    fn function_name(&self) -> EcoString {\n        if !self.module.ast.type_info.values.contains_key(\"function\") {\n            return \"function\".into();\n        }\n\n        let mut number = 2;\n        loop {\n            let name = eco_format!(\"function_{number}\");\n            if !self.module.ast.type_info.values.contains_key(&name) {\n                return name;\n            }\n            number += 1;\n        }\n    }\n\n    /// For anonymous functions that do not capture any variables from an outer scope.\n    /// Moves the function so it is defined at the module top-level instead,\n    /// replacing the original literal with a reference to the new function.\n    fn extract_anonymous_function(\n        &mut self,\n        location: SrcSpan,\n        code_location: SrcSpan,\n        arguments: &[TypedArg],\n        return_type: Arc<Type>,\n        function_end: u32,\n    ) {\n        // --- BEFORE\n        // ```gleam\n        // pub fn main() {\n        //   list.each([1, 2, 3], fn(x) { io.println(int.to_string(x)) })\n        //                        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑\n        // }\n        // ```\n        //\n        // --- AFTER\n        // ```gleam\n        // pub fn main() {\n        //   list.each([1, 2, 3], function)\n        // }\n        //\n        // fn function(x: Int) -> Nil {\n        //   io.println(int.to_string(x))\n        // }\n        // ```\n\n        let name = self.function_name();\n        self.edits.replace(location, name.to_string());\n\n        let mut printer = Printer::new(&self.module.ast.names);\n\n        let return_type = printer.print_type(&return_type);\n        let function_body = code_at(self.module, code_location);\n        let mut name_generator = NameGenerator::new();\n        let arguments = arguments\n            .iter()\n            .map(|arg| {\n                if let Some(name) = arg.get_variable_name() {\n                    eco_format!(\"{name}: {}\", printer.print_type(&arg.type_))\n                } else {\n                    let name = name_generator.generate_name_from_type(&arg.type_);\n                    eco_format!(\"_{name}: {}\", printer.print_type(&arg.type_))\n                }\n            })\n            .join(\", \");\n\n        let function = format!(\n            \"\\n\\nfn {name}({arguments}) -> {return_type} {{\n  {function_body}\n}}\"\n        );\n        self.edits.insert(function_end, function);\n    }\n\n    /// For anonymous functions that capture variables from an external scope\n    /// but only expect a single argument.\n    /// Uses function caputre syntax to provide a more concise refactoring than\n    /// `extract_anonymous_function_body`.\n    fn extract_anonymous_function_with_capture_hole(\n        &mut self,\n        location: SrcSpan,\n        code_location: SrcSpan,\n        argument: &TypedArg,\n        extra_parameters: Vec<(EcoString, Arc<Type>)>,\n        return_type: Arc<Type>,\n        function_end: u32,\n    ) {\n        let name = self.function_name();\n\n        // --- BEFORE\n        // ```gleam\n        // pub fn main() {\n        //   let needle = 42\n        //   let haystack = [25, 81, 74, 42, 33]\n        //   list.filter(haystack, fn(x) { x == needle })\n        //                         ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑\n        // }\n        // ```\n        //\n        // --- AFTER\n        // ```gleam\n        // pub fn main() {\n        //   let needle = 42\n        //   let haystack = [25, 81, 74, 42, 33]\n        //   list.filter(haystack, function(_, needle))\n        // }\n        //\n        // fn function(x: Int, needle: Int) -> Bool {\n        //   x == needle\n        // }\n        // ```\n\n        let call = format!(\n            \"{name}(_, {})\",\n            extra_parameters.iter().map(|(name, _)| name).join(\", \")\n        );\n        self.edits.replace(location, call);\n\n        let mut printer = Printer::new(&self.module.ast.names);\n\n        // build up the code for the newly generated function\n        let return_type = printer.print_type(&return_type);\n        let function_body = code_at(self.module, code_location);\n        let argument = if let Some(name) = argument.get_variable_name() {\n            eco_format!(\"{name}: {}\", printer.print_type(&argument.type_))\n        } else {\n            let name = NameGenerator::new().generate_name_from_type(&argument.type_);\n            eco_format!(\"_{name}: {}\", printer.print_type(&argument.type_))\n        };\n        let extra_parameters = extra_parameters\n            .iter()\n            .map(|(name, type_)| eco_format!(\"{name}: {}\", printer.print_type(type_)))\n            .join(\", \");\n\n        let function = format!(\n            \"\\n\\nfn {name}({argument}, {extra_parameters}) -> {return_type} {{\n  {function_body}\n}}\"\n        );\n        self.edits.insert(function_end, function);\n    }\n\n    /// For non-unary anonymous functions that capture variables from an external scope.\n    /// Replaces just the _function body_ with a call to the newly generated function.\n    fn extract_anonymous_function_body(\n        &mut self,\n        location: SrcSpan,\n        arguments: &[TypedArg],\n        extra_parameters: Vec<(EcoString, Arc<Type>)>,\n        return_type: Arc<Type>,\n        function_end: u32,\n    ) {\n        let name = self.function_name();\n        // --- BEFORE\n        // ```gleam\n        // pub fn main() {\n        //   let factor = 2\n        //   list.fold([], 0, fn(acc, value) { acc + value * factor })\n        //                    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑\n        // }\n        // ```\n        //\n        // --- AFTER\n        // ```gleam\n        // pub fn main() {\n        //   let factor = 2\n        //   list.fold([], 0, fn(acc, value) { function(acc, value, factor) })\n        // }\n        //\n        // fn function(acc: Int, value: Int, factor: Int) -> Int {\n        //   acc + value * factor\n        // }\n        // ```\n\n        // if the programmer has ignored an argument, the generated function\n        // cannot take it as an parameter\n        let arguments = arguments\n            .iter()\n            .filter_map(|arg| arg.get_variable_name().map(|name| (name, &arg.type_)))\n            .chain(extra_parameters.iter().map(|(name, type_)| (name, type_)))\n            .collect::<Vec<(&EcoString, &Arc<Type>)>>();\n\n        let call = format!(\n            \"{name}({})\",\n            arguments.iter().map(|(name, _)| name).join(\", \")\n        );\n        self.edits.replace(location, call);\n\n        let mut printer = Printer::new(&self.module.ast.names);\n\n        let return_type = printer.print_type(&return_type);\n        let function_body = code_at(self.module, location);\n        let arguments = arguments\n            .iter()\n            .map(|(name, type_)| eco_format!(\"{name}: {}\", printer.print_type(type_)))\n            .join(\", \");\n\n        let function = format!(\n            \"\\n\\nfn {name}({arguments}) -> {return_type} {{\n  {function_body}\n}}\"\n        );\n        self.edits.insert(function_end, function);\n    }\n\n    /// Extracts code from the end of a function or block. This could either be\n    /// a single expression, or multiple statements followed by a final expression.\n    fn extract_code_in_tail_position(\n        &mut self,\n        location: SrcSpan,\n        code_location: SrcSpan,\n        type_: Arc<Type>,\n        parameters: Vec<(EcoString, Arc<Type>)>,\n        function_end: u32,\n    ) {\n        let expression_code = code_at(self.module, code_location);\n\n        let name = self.function_name();\n        let arguments = parameters.iter().map(|(name, _)| name).join(\", \");\n        let call = format!(\"{name}({arguments})\");\n\n        // Since we are only extracting a single expression, we can just replace\n        // it with the call and preserve all other semantics; only one value can\n        // be returned from the expression, unlike when extracting multiple\n        // statements.\n        self.edits.replace(location, call);\n\n        let mut printer = Printer::new(&self.module.ast.names);\n\n        let parameters = parameters\n            .iter()\n            .map(|(name, type_)| eco_format!(\"{name}: {}\", printer.print_type(type_)))\n            .join(\", \");\n        let return_type = printer.print_type(&type_);\n\n        let function = format!(\n            \"\\n\\nfn {name}({parameters}) -> {return_type} {{\n  {expression_code}\n}}\"\n        );\n\n        self.edits.insert(function_end, function);\n    }\n\n    fn extract_statements(\n        &mut self,\n        location: SrcSpan,\n        parameters: Vec<(EcoString, Arc<Type>)>,\n        returned_variables: Vec<(EcoString, Arc<Type>)>,\n        function_end: u32,\n    ) {\n        let code = code_at(self.module, location);\n\n        let returns_anything = !returned_variables.is_empty();\n\n        // Here, we decide what value to return from the function. There are\n        // three cases:\n        // The first is when the extracted code is purely for side-effects, and\n        // does not produce any values which are needed outside of the extracted\n        // code. For example:\n        //\n        // ```gleam\n        // pub fn main() {\n        //   let message = \"Something important\"\n        // //^ Select from here\n        //   io.println(\"Something important\")\n        //   io.println(\"Something else which is repeated\")\n        //   //                                           ^ Until here\n        //\n        //   do_final_thing()\n        // }\n        // ```\n        //\n        // It doesn't make sense to return any values from this function, since\n        // no values from the extract code are used afterwards, so we simply\n        // return `Nil`.\n        //\n        // The next is when we need just a single value defined in the extracted\n        // function, such as in this piece of code:\n        //\n        // ```gleam\n        // pub fn main() {\n        //   let a = 10\n        // //^ Select from here\n        //   let b = 20\n        //   let c = a + b\n        //   //          ^ Until here\n        //\n        //   echo c\n        // }\n        // ```\n        //\n        // Here, we can just return the single value, `c`.\n        //\n        // The last situation is when we need multiple defined values, such as\n        // in the following code:\n        //\n        // ```gleam\n        // pub fn main() {\n        //   let a = 10\n        // //^ Select from here\n        //   let b = 20\n        //   let c = a + b\n        //   //          ^ Until here\n        //\n        //   echo a\n        //   echo b\n        //   echo c\n        // }\n        // ```\n        //\n        // In this case, we must return a tuple containing `a`, `b` and `c` in\n        // order for the calling function to have access to the correct values.\n        let (return_type, return_value) = match returned_variables.as_slice() {\n            [] => (type_::nil(), \"Nil\".into()),\n            [(name, type_)] => (type_.clone(), name.clone()),\n            _ => {\n                let values = returned_variables.iter().map(|(name, _)| name).join(\", \");\n                let type_ = type_::tuple(\n                    returned_variables\n                        .into_iter()\n                        .map(|(_, type_)| type_)\n                        .collect(),\n                );\n\n                (type_, eco_format!(\"#({values})\"))\n            }\n        };\n\n        let name = self.function_name();\n        let arguments = parameters.iter().map(|(name, _)| name).join(\", \");\n\n        // If any values are returned from the extracted function, we need to\n        // bind them so that they are accessible in the current scope.\n        let call = if returns_anything {\n            format!(\"let {return_value} = {name}({arguments})\")\n        } else {\n            format!(\"{name}({arguments})\")\n        };\n        self.edits.replace(location, call);\n\n        let mut printer = Printer::new(&self.module.ast.names);\n\n        let parameters = parameters\n            .iter()\n            .map(|(name, type_)| eco_format!(\"{name}: {}\", printer.print_type(type_)))\n            .join(\", \");\n\n        let return_type = printer.print_type(&return_type);\n\n        let function = format!(\n            \"\\n\\nfn {name}({parameters}) -> {return_type} {{\n  {code}\n  {return_value}\n}}\"\n        );\n\n        self.edits.insert(function_end, function);\n    }\n\n    /// When a variable is referenced, we need to decide if we need to do anything\n    /// to ensure that the reference is still valid after extracting a function.\n    /// If the variable is defined outside the extracted function, but used inside\n    /// it, then we need to add it as a parameter of the function. Similarly, if\n    /// a variable is defined inside the extracted code, but used outside of it,\n    /// we need to ensure that value is returned from the function so that it is\n    /// accessible.\n    fn register_referenced_variable(\n        &mut self,\n        name: &EcoString,\n        type_: &Arc<Type>,\n        location: SrcSpan,\n        definition_location: SrcSpan,\n    ) {\n        let Some(extracted) = &mut self.function else {\n            return;\n        };\n\n        let extracted_location = extracted.location();\n\n        // If a variable defined outside the extracted code is referenced inside\n        // it, we need to add it to the list of parameters.\n        let variables = if extracted_location.contains_span(location)\n            && !extracted_location.contains_span(definition_location)\n        {\n            &mut extracted.parameters\n        // If a variable defined inside the extracted code is referenced outside\n        // it, then we need to ensure that it is returned from the function.\n        } else if extracted_location.contains_span(definition_location)\n            && !extracted_location.contains_span(location)\n        {\n            &mut extracted.returned_variables\n        } else {\n            return;\n        };\n\n        // If the variable has already been tracked, no need to register it again.\n        // We use a `Vec` here rather than a `HashMap` because we want to ensure\n        // the order of arguments is consistent; in this case it will be determined\n        // by the order the variables are used. This isn't always desired, but it's\n        // better than random order, and makes it easier to write tests too.\n        // The cost of iterating the list here is minimal; it is unlikely that\n        // a given function will ever have more than 10 or so parameters.\n        if variables.iter().any(|(variable, _)| variable == name) {\n            return;\n        }\n\n        variables.push((name.clone(), type_.clone()));\n    }\n\n    fn can_extract(&self, location: SrcSpan) -> bool {\n        let expression_range = self.edits.src_span_to_lsp_range(location);\n        let selected_range = self.params.range;\n\n        // If the selected range doesn't touch the expression at all, then there\n        // is no reason to extract it.\n        if !overlaps(expression_range, selected_range) {\n            return false;\n        }\n\n        // Determine whether the selected range falls completely within the\n        // expression. For example:\n        // ```gleam\n        // pub fn main() {\n        //   let something = {\n        //     let a = 1\n        //     let b = 2\n        //     let c = a + b\n        //   //^ The user has selected from here\n        //     let d = a * b\n        //     c / d\n        //     //  ^ Until here\n        //   }\n        // }\n        // ```\n        //\n        // Here, the selected range does overlap with the `let something`\n        // statement; but we don't want to extract that whole statement! The\n        // user only wanted to extract the statements inside the block. So if\n        // the selected range falls completely within the expression, we ignore\n        // it and traverse the tree further until we find exactly what the user\n        // selected.\n        //\n        let selected_within_expression = selected_range.start > expression_range.start\n            && selected_range.start < expression_range.end\n            && selected_range.end > expression_range.start\n            && selected_range.end < expression_range.end;\n\n        // If the selected range is completely within the expression, we don't\n        // want to extract it.\n        !selected_within_expression\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ExtractFunction<'ast> {\n    fn visit_typed_function(&mut self, function: &'ast TypedFunction) {\n        let range = self.edits.src_span_to_lsp_range(function.full_location());\n\n        if within(self.params.range, range) {\n            self.function_end_position = Some(function.end_position);\n            self.last_statement_location = function.body.last().map(|last| last.location());\n\n            ast::visit::visit_typed_function(self, function);\n        }\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast SrcSpan,\n        statements: &'ast [TypedStatement],\n    ) {\n        let last_statement_location = self.last_statement_location;\n        self.last_statement_location = statements.last().map(|last| last.location());\n\n        ast::visit::visit_typed_expr_block(self, location, statements);\n\n        self.last_statement_location = last_statement_location;\n    }\n\n    fn visit_typed_expr(&mut self, expression: &'ast TypedExpr) {\n        // If we have already determined what code we want to extract, we don't\n        // want to extract this instead. This expression would be inside the\n        // piece of code we already are going to extract, leading to us\n        // extracting just a single literal in any selection, which is of course\n        // not desired.\n        if self.function.is_none() {\n            // If this expression is fully selected, we mark it as being extracted.\n            if self.can_extract(expression.location()) {\n                self.function = Some(ExtractedFunction::new(ExtractedValue::Expression(\n                    expression,\n                )));\n            }\n        }\n        ast::visit::visit_typed_expr(self, expression);\n    }\n\n    fn visit_typed_statement(&mut self, statement: &'ast TypedStatement) {\n        let statement_location = statement.location();\n\n        if self.can_extract(statement_location) {\n            let is_in_tail_position =\n                self.last_statement_location\n                    .is_some_and(|last_statement_location| {\n                        last_statement_location == statement_location\n                    });\n\n            // A use is always eating up the entire block, if we're extracting it,\n            // it will be in tail position there and the extracted function should\n            // return its returned value.\n            let position = if statement.is_use() || is_in_tail_position {\n                StatementPosition::Tail {\n                    type_: statement.type_(),\n                }\n            } else {\n                StatementPosition::NotTail\n            };\n\n            match &mut self.function {\n                None => {\n                    self.function = Some(ExtractedFunction::new(ExtractedValue::Statements {\n                        location: statement_location,\n                        position,\n                    }));\n                }\n                // If we have already chosen an expression to extract, that means\n                // that this statement is within the already extracted expression,\n                // so we don't want to extract this instead.\n                Some(ExtractedFunction {\n                    value: ExtractedValue::Expression(_),\n                    ..\n                }) => {}\n                // If we are selecting multiple statements, this statement should\n                // be included within list, so we merge the spans to ensure it\n                // is included.\n                Some(ExtractedFunction {\n                    value:\n                        ExtractedValue::Statements {\n                            location,\n                            position: extracted_position,\n                        },\n                    ..\n                }) => {\n                    *location = location.merge(&statement_location);\n                    *extracted_position = position;\n                }\n            }\n        }\n        ast::visit::visit_typed_statement(self, statement);\n    }\n\n    fn visit_typed_expr_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        name: &'ast EcoString,\n    ) {\n        if let type_::ValueConstructorVariant::LocalVariable {\n            location: definition_location,\n            ..\n        } = &constructor.variant\n        {\n            self.register_referenced_variable(\n                name,\n                &constructor.type_,\n                *location,\n                *definition_location,\n            );\n        }\n    }\n\n    fn visit_typed_clause_guard_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        definition_location: &'ast SrcSpan,\n        _origin: &'ast VariableOrigin,\n    ) {\n        self.register_referenced_variable(name, type_, *location, *definition_location);\n    }\n\n    fn visit_typed_bit_array_size_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        type_: &'ast Arc<Type>,\n    ) {\n        let variant = match constructor {\n            Some(constructor) => &constructor.variant,\n            None => return,\n        };\n        if let type_::ValueConstructorVariant::LocalVariable {\n            location: definition_location,\n            ..\n        } = variant\n        {\n            self.register_referenced_variable(name, type_, *location, *definition_location);\n        }\n    }\n}\n\n/// Code action to merge two identical branches together.\n///\npub struct MergeCaseBranches<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    /// These are the positions of the patterns of all the consecutive branches\n    /// we've determined can be merged, for example if we're mergin the first\n    /// two branches here:\n    ///\n    /// ```gleam\n    ///   case wibble {\n    ///     1 -> todo\n    /// //  ^ this location here\n    ///     20 -> todo\n    /// //  ^^ and this location here\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    /// We need those to delete all the space between each consecutive pattern,\n    /// replacing it with the `|` for alternatives\n    ///\n    patterns_to_merge: Option<MergeableBranches>,\n}\n\nstruct MergeableBranches {\n    /// The span of the body to keep when merging multiple branches. For\n    /// example:\n    ///\n    /// ```gleam\n    /// case n {\n    ///   // Imagine we're merging the first three branches together...\n    ///   1 -> todo\n    ///   2 -> n * 2\n    /// //     ^^^^^ This would be the location of the one body to keep\n    ///   3 -> todo\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    body_to_keep: SrcSpan,\n\n    /// The location body of the last of the branches that are going to be\n    /// merged; that is where we're going to place the code of the body to keep\n    /// once the action is done. For example:\n    ///\n    /// ```gleam\n    /// case n {\n    ///   // Imagine we're merging the first three branches together...\n    ///   1 -> todo\n    ///   2 -> n * 2\n    ///   3 -> todo\n    /// //     ^^^^ This would be the location of the final body\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    final_body: SrcSpan,\n\n    /// The span of the patterns whose branches are going to be merged. For\n    /// example:\n    ///\n    /// ```gleam\n    /// case n {\n    ///   // Imagine we're merging the first three branches together...\n    ///    1 -> todo\n    /// // ^\n    ///    2 -> n * 2\n    /// // ^\n    ///    3 -> todo\n    /// // ^ These would be the locations of the patterns\n    ///   _ -> todo\n    /// }\n    /// ```\n    ///\n    patterns_to_merge: Vec<SrcSpan>,\n}\n\nimpl<'a> MergeCaseBranches<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            patterns_to_merge: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(mergeable_branches) = self.patterns_to_merge else {\n            return vec![];\n        };\n\n        for (one, next) in mergeable_branches.patterns_to_merge.iter().tuple_windows() {\n            self.edits\n                .replace(SrcSpan::new(one.end, next.start), \" | \".into());\n        }\n\n        self.edits.replace(\n            mergeable_branches.final_body,\n            code_at(self.module, mergeable_branches.body_to_keep).into(),\n        );\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Merge case branches\")\n            .kind(CodeActionKind::REFACTOR_REWRITE)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(false)\n            .push_to(&mut action);\n        action\n    }\n\n    fn select_mergeable_branches(\n        &self,\n        clauses: &'a [ast::TypedClause],\n    ) -> Option<MergeableBranches> {\n        let mut clauses = clauses\n            .iter()\n            // We want to skip all the branches at the beginning of the case\n            // expression that the cursor is not hovering over. For example:\n            //\n            // ```gleam\n            // case wibble {\n            //   a -> 1   <- we want to skip this one here that is not selected\n            //   b -> 2\n            //     ^^^^   this is the selection\n            //   _ -> 3\n            //   ^^\n            // }\n            // ```\n            .skip_while(|clause| {\n                let clause_range = self.edits.src_span_to_lsp_range(clause.location);\n                !overlaps(self.params.range, clause_range)\n            })\n            // Then we only want to take the clauses that we're hovering over\n            // with our selection (even partially!)\n            // In the provious example they would be `b -> 2` and `_ -> 3`.\n            .take_while(|clause| {\n                let clause_range = self.edits.src_span_to_lsp_range(clause.location);\n                overlaps(self.params.range, clause_range)\n            });\n\n        let first_hovered_clause = clauses.next()?;\n\n        // This is the clause we're comparing all the others with. We need to\n        // make sure that all the clauses we're going to join can be merged with\n        // this one.\n        let mut reference_clause = first_hovered_clause;\n        let mut clause_patterns_to_merge = vec![reference_clause.pattern_location()];\n        let mut final_body = first_hovered_clause.then.location();\n\n        for clause in clauses {\n            // As soon as we find a clause that can't be merged with the current\n            // reference we know we're done looking for consecutive clauses to\n            // merge.\n            if !clauses_can_be_merged(reference_clause, clause) {\n                break;\n            }\n\n            clause_patterns_to_merge.push(clause.pattern_location());\n            final_body = clause.then.location();\n\n            // If the current reference is a `todo` expression, we want to use\n            // the newly found mergeable clause as the next reference. The\n            // reference clause is the one whose body will be kept around, so if\n            // we can we avoid keeping `todo`s\n            if reference_clause.then.is_todo_with_no_message() {\n                reference_clause = clause;\n            }\n        }\n\n        // We only offer the code action if we have found two or more clauses\n        // to merge.\n        if clause_patterns_to_merge.len() >= 2 {\n            Some(MergeableBranches {\n                final_body,\n                body_to_keep: reference_clause.then.location(),\n                patterns_to_merge: clause_patterns_to_merge,\n            })\n        } else {\n            None\n        }\n    }\n}\n\nfn clauses_can_be_merged(one: &ast::TypedClause, other: &ast::TypedClause) -> bool {\n    // Two clauses cannot be merged if any of those has an if guard\n    if one.guard.is_some() || other.guard.is_some() {\n        return false;\n    }\n\n    // Two clauses can only be merged if they define the same variables,\n    // otherwise joining them would result in invalid code.\n    let variables_one = one\n        .bound_variables()\n        .map(|variable| (variable.name(), variable.type_))\n        .collect::<HashMap<_, _>>();\n\n    let variables_other = other\n        .bound_variables()\n        .map(|variable| (variable.name(), variable.type_))\n        .collect::<HashMap<_, _>>();\n\n    for (name, type_) in variables_one.iter() {\n        if let Some(type_other) = variables_other.get(name)\n            && type_other.same_as(type_)\n        {\n            continue;\n        }\n\n        // There's a variable that is not defined in the second branch but\n        // is defined in the first one, or it's defined in the second branch\n        // but it has an incompatible type.\n        return false;\n    }\n\n    for (name, _) in variables_other.iter() {\n        if !variables_one.contains_key(name) {\n            // There's some variables defined in the second branch that are not\n            // defined in the first one, so they can't be merged!\n            return false;\n        }\n    }\n\n    // Anything can be merged with a simple todo, or the two bodies must be\n    // syntactically equal.\n    one.then.is_todo_with_no_message()\n        || other.then.is_todo_with_no_message()\n        || one.then.syntactically_eq(&other.then)\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for MergeCaseBranches<'ast> {\n    fn visit_typed_expr_case(\n        &mut self,\n        location: &'ast SrcSpan,\n        type_: &'ast Arc<Type>,\n        subjects: &'ast [TypedExpr],\n        clauses: &'ast [ast::TypedClause],\n        compiled_case: &'ast CompiledCase,\n    ) {\n        // We only trigger the code action if we are within a case expression,\n        // otherwise there's no point in exploring the expression any further.\n        let case_range = self.edits.src_span_to_lsp_range(*location);\n        if !within(self.params.range, case_range) {\n            return;\n        }\n\n        if let result @ Some(_) = self.select_mergeable_branches(clauses) {\n            self.patterns_to_merge = result\n        }\n\n        // We still need to visit the case expression in case we want to apply\n        // the code action to some case expression that is nested in one of its\n        // branches!\n        ast::visit::visit_typed_expr_case(self, location, type_, subjects, clauses, compiled_case);\n    }\n}\n\n/// Code action to add a missing type parameter to custom types.\n/// If a custom type is missing a type parameter, as it is the case\n/// in the following example, this action will offer to add the\n/// type parameter to the type definition.\n///\n/// Before:\n/// ```gleam\n/// type Wibble {\n///   Wibble(field: t)\n/// }\n/// ```\n///\n/// After:\n/// ```gleam\n/// type Wibble(t) {\n///   Wibble(field: t)\n/// }\n/// ```\n///\npub struct AddMissingTypeParameter<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    /// The source location where the parameters should be defined.\n    /// This might be a zero-length span if there are no parameters yet,\n    /// or it might cover the already existing type parameter definitions.\n    parameters_location: Option<SrcSpan>,\n    /// If the type definition already had existing parameters before.\n    has_existing_parameters: bool,\n    /// The set of all type parameter names in the different variants of the type\n    /// that are not already part of the type parameter definition on the type.\n    missing_parameters: HashSet<EcoString>,\n}\n\nimpl<'a> AddMissingTypeParameter<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            parameters_location: None,\n            has_existing_parameters: false,\n            missing_parameters: HashSet::new(),\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let Some(type_parameters_location) = self.parameters_location else {\n            return vec![];\n        };\n\n        if self.missing_parameters.is_empty() {\n            return vec![];\n        }\n\n        let mut new_parameters = self.missing_parameters.iter().sorted().join(\", \");\n        if self.has_existing_parameters {\n            let has_trailing_comma = self\n                .module\n                .extra\n                .trailing_commas\n                .iter()\n                .any(|&trailing_comma| type_parameters_location.contains(trailing_comma));\n\n            if !has_trailing_comma {\n                new_parameters.insert_str(0, \", \");\n            }\n\n            self.edits\n                .insert(type_parameters_location.end - 1, new_parameters);\n        } else {\n            self.edits\n                .insert(type_parameters_location.end, format!(\"({new_parameters})\"));\n        }\n\n        let mut action = Vec::with_capacity(1);\n        CodeActionBuilder::new(\"Add missing type parameter\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for AddMissingTypeParameter<'ast> {\n    fn visit_typed_custom_type(&mut self, custom_type: &'ast ast::TypedCustomType) {\n        let custom_type_range = self\n            .edits\n            .src_span_to_lsp_range(custom_type.full_location());\n\n        // Only continue, if the action was selected anywhere within the custom type definition.\n        if !overlaps(self.params.range, custom_type_range) {\n            return;\n        }\n\n        self.parameters_location = Some(SrcSpan::new(\n            custom_type.name_location.end,\n            custom_type.location.end,\n        ));\n\n        self.has_existing_parameters = !custom_type.typed_parameters.is_empty();\n\n        let existing_names: HashSet<_> = custom_type\n            .parameters\n            .iter()\n            .map(|(_, name)| name)\n            .collect();\n\n        // Collect the remaining type parameters from the variant constructors.\n        for record in &custom_type.constructors {\n            for argument in &record.arguments {\n                if let ast::TypeAst::Var(ast::TypeAstVar { name, .. }) = &argument.ast\n                    && !existing_names.contains(name)\n                {\n                    let _ = self.missing_parameters.insert(name.clone());\n                }\n            }\n        }\n    }\n}\n\n/// Code action to replace a `_` with its actual type in an annotation.\n///\n/// Before:\n/// ```gleam\n/// fn wibble() -> Ok(_) { Ok(1) }\n/// //                ^ Trigger it here\n/// ```\n///\n/// After:\n/// ```gleam\n/// fn wibble() -> Ok(Int) { Ok(1) }\n/// ```\n///\npub struct ReplaceUnderscoreWithType<'a> {\n    module: &'a Module,\n    params: &'a CodeActionParams,\n    edits: TextEdits<'a>,\n    hovered_hole: Option<HoveredHole>,\n}\n\nstruct HoveredHole {\n    type_: Arc<Type>,\n    location: SrcSpan,\n}\n\nimpl<'a> ReplaceUnderscoreWithType<'a> {\n    pub fn new(\n        module: &'a Module,\n        line_numbers: &'a LineNumbers,\n        params: &'a CodeActionParams,\n    ) -> Self {\n        Self {\n            module,\n            params,\n            edits: TextEdits::new(line_numbers),\n            hovered_hole: None,\n        }\n    }\n\n    pub fn code_actions(mut self) -> Vec<CodeAction> {\n        self.visit_typed_module(&self.module.ast);\n\n        let mut action = Vec::with_capacity(1);\n\n        let Some(HoveredHole { type_, location }) = self.hovered_hole else {\n            return vec![];\n        };\n        let mut printer = Printer::new(&self.module.ast.names);\n        self.edits\n            .replace(location, format!(\"{}\", printer.print_type(&type_)));\n\n        CodeActionBuilder::new(\"Replace `_` with type\")\n            .kind(CodeActionKind::QUICKFIX)\n            .changes(self.params.text_document.uri.clone(), self.edits.edits)\n            .preferred(true)\n            .push_to(&mut action);\n        action\n    }\n}\n\nimpl<'ast> ast::visit::Visit<'ast> for ReplaceUnderscoreWithType<'ast> {\n    fn visit_type_ast(&mut self, node: &'ast ast::TypeAst, inferred_type: Option<Arc<Type>>) {\n        // We never traverse a type annotation we're not hovering\n        let node_location = self.edits.src_span_to_lsp_range(node.location());\n        if !within(self.params.range, node_location) {\n            return;\n        }\n        ast::visit::visit_type_ast(self, node, inferred_type);\n    }\n\n    fn visit_type_ast_hole(\n        &mut self,\n        location: &'ast SrcSpan,\n        _name: &'ast EcoString,\n        type_: Option<Arc<Type>>,\n    ) {\n        if let Some(type_) = type_ {\n            self.hovered_hole = Some(HoveredHole {\n                type_,\n                location: *location,\n            })\n        }\n    }\n}\n"
  },
  {
    "path": "language-server/src/compiler.rs",
    "content": "use debug_ignore::DebugIgnore;\nuse ecow::EcoString;\nuse itertools::Itertools;\n\nuse gleam_core::{\n    Error, Result, Warning,\n    analyse::TargetSupport,\n    build::{self, Mode, Module, NullTelemetry, Outcome, ProjectCompiler},\n    config::PackageConfig,\n    io::{BeamCompiler, CommandExecutor, FileSystemReader, FileSystemWriter, Stdio},\n    line_numbers::LineNumbers,\n    manifest::Manifest,\n    paths::ProjectPaths,\n    type_::ModuleInterface,\n    warning::VectorWarningEmitterIO,\n};\nuse std::{collections::HashMap, rc::Rc};\n\nuse camino::Utf8PathBuf;\n\nuse super::{LockGuard, Locker};\n\n/// A wrapper around the project compiler which makes it possible to repeatedly\n/// recompile the top level package, reusing the information about the already\n/// compiled dependency packages.\n///\n#[derive(Debug)]\npub struct LspProjectCompiler<IO> {\n    pub project_compiler: ProjectCompiler<IO>,\n\n    /// Information on compiled modules.\n    pub modules: HashMap<EcoString, Module>,\n    pub sources: HashMap<EcoString, ModuleSourceInformation>,\n\n    /// The storage for the warning emitter.\n    pub warnings: Rc<VectorWarningEmitterIO>,\n\n    /// A lock to ensure that multiple instances of the LSP don't try and use\n    /// build directory at the same time.\n    pub locker: DebugIgnore<Box<dyn Locker>>,\n}\n\nimpl<IO> LspProjectCompiler<IO>\nwhere\n    IO: CommandExecutor + FileSystemWriter + FileSystemReader + BeamCompiler + Clone,\n{\n    pub fn new(\n        manifest: Manifest,\n        config: PackageConfig,\n        paths: ProjectPaths,\n        io: IO,\n        locker: Box<dyn Locker>,\n    ) -> Result<Self> {\n        let target = config.target;\n        let name = config.name.clone();\n        let warnings = Rc::new(VectorWarningEmitterIO::default());\n\n        // The build caches do not contain all the information we need in the\n        // LSP (e.g. the typed AST) so delete the caches for the top level\n        // package before we run for the first time.\n        {\n            let _guard: LockGuard = locker.lock_for_build()?;\n            let path = paths.build_directory_for_package(Mode::Lsp, target, &name);\n            io.delete_directory(&path)?;\n        }\n\n        let options = build::Options {\n            warnings_as_errors: false,\n            mode: Mode::Lsp,\n            target: None,\n            codegen: build::Codegen::None,\n            compile: build::Compile::All,\n            root_target_support: TargetSupport::Enforced,\n            no_print_progress: false,\n        };\n        let mut project_compiler = ProjectCompiler::new(\n            config,\n            options,\n            manifest.packages,\n            &NullTelemetry,\n            warnings.clone(),\n            paths,\n            io,\n        );\n\n        // To avoid the Erlang compiler printing to stdout (and thus\n        // violating LSP which is currently using stdout) we silence it.\n        project_compiler.subprocess_stdio = Stdio::Null;\n\n        Ok(Self {\n            locker: locker.into(),\n            warnings,\n            project_compiler,\n            modules: HashMap::new(),\n            sources: HashMap::new(),\n        })\n    }\n\n    pub fn compile(&mut self) -> Outcome<Vec<Utf8PathBuf>, Error> {\n        // Lock the build directory to ensure to ensure we are the only one compiling\n        let _lock_guard: LockGuard = match self.locker.lock_for_build() {\n            Ok(it) => it,\n            Err(err) => return err.into(),\n        };\n\n        // Verify that the build directory was created using the same version of\n        // Gleam as we are running. If it is not then we discard the build\n        // directory as the cache files may be in a different format.\n        if let Err(e) = self.project_compiler.check_gleam_version() {\n            return e.into();\n        }\n\n        self.project_compiler.reset_state_for_new_compile_run();\n\n        let compiled_dependencies = match self.project_compiler.compile_dependencies() {\n            Ok(it) => it,\n            Err(err) => return err.into(),\n        };\n\n        // Store the compiled dependency module information\n        for module in &compiled_dependencies {\n            let path = module.input_path.as_os_str().to_string_lossy().to_string();\n            // strip canonicalised windows prefix\n            #[cfg(target_family = \"windows\")]\n            let path = path\n                .strip_prefix(r\"\\\\?\\\")\n                .map(|s| s.to_string())\n                .unwrap_or(path);\n            let line_numbers = LineNumbers::new(&module.code);\n            let source = ModuleSourceInformation { path, line_numbers };\n            _ = self.sources.insert(module.name.clone(), source);\n        }\n\n        // Since cached modules are not recompiled we need to manually add them\n        for (name, module) in self.project_compiler.get_importable_modules() {\n            // It we already have the source for an importable module it means\n            // that we already have all the information we are adding here, so\n            // we can skip past to to avoid doing extra work for no gain.\n            if self.sources.contains_key(name) || name == \"gleam\" {\n                continue;\n            }\n            // Create the source information\n            let path = module.src_path.to_string();\n            // strip canonicalised windows prefix\n            #[cfg(target_family = \"windows\")]\n            let path = path\n                .strip_prefix(r\"\\\\?\\\")\n                .map(|s| s.to_string())\n                .unwrap_or(path);\n            let line_numbers = module.line_numbers.clone();\n            let source = ModuleSourceInformation { path, line_numbers };\n            _ = self.sources.insert(name.clone(), source);\n        }\n\n        // Warnings from dependencies are not fixable by the programmer so\n        // we don't bother them with diagnostics for them.\n        let _ = self.take_warnings();\n\n        // Compile the root package, that is, the one that the programmer is\n        // working in.\n        let (modules, error) = match self.project_compiler.compile_root_package() {\n            Outcome::Ok(package) => (package.modules, None),\n            Outcome::PartialFailure(package, error) => (package.modules, Some(error)),\n            Outcome::TotalFailure(error) => (vec![], Some(error)),\n        };\n\n        // Record the compiled dependency modules\n        let mut compiled_modules = compiled_dependencies\n            .into_iter()\n            .map(|m| m.input_path)\n            .collect_vec();\n\n        // Store the compiled module information\n        for module in modules {\n            let path = module.input_path.as_os_str().to_string_lossy().to_string();\n            let line_numbers = LineNumbers::new(&module.code);\n            let source = ModuleSourceInformation { path, line_numbers };\n            // Record that this one has been compiled. This is returned by this\n            // function and is used to determine what diagnostics to reset.\n            compiled_modules.push(module.input_path.clone());\n            // Register information for the LS to use\n            _ = self.sources.insert(module.name.clone(), source);\n            _ = self.modules.insert(module.name.clone(), module);\n        }\n\n        match error {\n            None => Outcome::Ok(compiled_modules),\n            Some(error) => Outcome::PartialFailure(compiled_modules, error),\n        }\n    }\n}\n\nimpl<IO> LspProjectCompiler<IO> {\n    pub fn take_warnings(&mut self) -> Vec<Warning> {\n        self.warnings.take()\n    }\n\n    pub fn get_source(&self, module: &str) -> Option<&ModuleSourceInformation> {\n        self.sources.get(module)\n    }\n\n    pub fn get_module_interface(&self, name: &str) -> Option<&ModuleInterface> {\n        self.project_compiler.get_importable_modules().get(name)\n    }\n}\n\n#[derive(Debug)]\npub struct ModuleSourceInformation {\n    /// The path to the source file from within the project root\n    pub path: String,\n\n    /// Useful for converting from Gleam's byte index offsets to the LSP line\n    /// and column number positions.\n    pub line_numbers: LineNumbers,\n}\n"
  },
  {
    "path": "language-server/src/completer.rs",
    "content": "use std::{collections::HashMap, sync::Arc};\n\nuse ecow::{EcoString, eco_format};\nuse itertools::Itertools;\nuse lsp_types::{\n    CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionTextEdit,\n    Documentation, MarkupContent, MarkupKind, Position, Range, TextDocumentPositionParams,\n    TextEdit,\n};\nuse strum::IntoEnumIterator;\nuse vec1::Vec1;\n\nuse gleam_core::{\n    Result,\n    ast::{\n        self, Arg, CallArg, Function, FunctionLiteralKind, Pattern, Publicity, TypedExpr,\n        visit::Visit,\n    },\n    build::{Module, Origin},\n    line_numbers::LineNumbers,\n    parse::{LiteralFloatValue, parse_int_value},\n    type_::{\n        self, FieldMap, ModuleInterface, PRELUDE_MODULE_NAME, PreludeType, RecordAccessor, Type,\n        TypeConstructor, ValueConstructorVariant, collapse_links, error::VariableOrigin,\n        pretty::Printer,\n    },\n};\n\nuse super::{\n    compiler::LspProjectCompiler,\n    edits::{\n        Newlines, add_newlines_after_import, get_import_edit,\n        position_of_first_definition_if_import,\n    },\n    files::FileSystemProxy,\n};\n\n// Represents the kind/specificity of completion that is being requested.\n#[derive(Copy, Clone)]\nenum CompletionKind {\n    // A language keyword that we can offer completions for, like `todo`,\n    // `panic`, or `echo`\n    Keyword,\n    // A label for a function or type definition\n    Label,\n    // A field of a record\n    FieldAccessor,\n    // Values or types defined in the current module\n    LocallyDefined,\n    // Values or types defined in an already imported module\n    ImportedModule,\n    // Types or values defined in the prelude\n    Prelude,\n    // Types defined in a module that has not been imported\n    ImportableModule,\n}\n\n#[derive(Copy, Clone)]\nenum TypeMatch {\n    Matching,\n    Incompatible,\n    Unknown,\n}\n\n// Gives the sort text for a completion item based on the kind and label.\n// This ensures that more specific kinds of completions are placed before\n// less specific ones..\nfn sort_text(kind: CompletionKind, label: &str, type_match: TypeMatch) -> String {\n    let priority: u8 = match kind {\n        CompletionKind::Keyword => 0,\n        CompletionKind::Label => 1,\n        CompletionKind::FieldAccessor => 2,\n        CompletionKind::LocallyDefined => 3,\n        CompletionKind::ImportedModule => 4,\n        CompletionKind::Prelude => 5,\n        CompletionKind::ImportableModule => 6,\n    };\n    match type_match {\n        // We want to prioritise type which match what is expected in the completion\n        // as those are more likely to be what the user wants.\n        TypeMatch::Matching => format!(\"0{priority}_{label}\"),\n        TypeMatch::Incompatible | TypeMatch::Unknown => format!(\"{priority}_{label}\"),\n    }\n}\n\n/// The form in which a type completion is needed in context.\n#[derive(Debug)]\nenum TypeCompletionContext {\n    /// The type completion is for an unqualified import that doesn't have an\n    /// import list yet. So adding the type will also require adding braces:\n    ///\n    /// ```gleam\n    /// import wibble.Wib|\n    /// //           ^^^^^ We're typing this...\n    /// import wibble.{type Wibble}\n    /// //           ^^^^^^^^^^^^^^ ...so this will be the completion\n    /// ```\n    ///\n    UnqualifiedImport,\n\n    /// The type completion is for an unqualified import within already existing\n    /// braces.\n    ///\n    /// ```gleam\n    /// import wibble.{type AlreadyImported, Wibb|}\n    /// //                                   ^^^^^ We're typing this...\n    /// import wibble.{type AlreadyImported, type Wibble}\n    /// //                                   ^^^^^^^^^^^ ...so this will be the completion\n    /// ```\n    ///\n    UnqualifiedImportWithinBraces,\n\n    /// The type completion is for an unqualified type (for example something\n    /// coming from the prelude, or a type that was already imported in a\n    /// unqualified way).\n    ///\n    /// ```gleam\n    /// import wobble.{type Wobble}\n    ///\n    /// pub fn new_wobble() -> Wob|\n    /// //                     ^^^^ We're typing this...\n    /// pub fn new_wobble() -> Wobble\n    /// //                     ^^^^^^ ... so this will be the completion\n    /// ```\n    ///\n    UnqualifiedType,\n\n    /// The type completion is for a qualified type.\n    ///\n    /// ```gleam\n    /// import wobble\n    ///\n    /// pub fn new_wobble() -> wobble.W|\n    /// //                     ^^^^^^^^ We're typing this...\n    /// pub fn new_wobble() -> wobble.Wobble\n    /// //                     ^^^^^^^^^^^^^ ...so this will be the completion\n    /// ```\n    ///\n    QualifiedType,\n}\n\n/// Represents the surroundings of the cursor when trying to figure out a\n/// completion.\n///\n/// ```gleam\n/// wibble.w|ob\n/// //      ^ cursor here\n/// ```\nstruct CursorSurroundings {\n    /// The text surrounding the cursor. For example:\n    ///\n    /// ```gleam\n    /// wibble.w|ob\n    /// //      ^ cursor here\n    /// // The surrounding text is: \"wibble.wob\"\n    /// ```\n    ///\n    surrounding_text: EcoString,\n    surrounding_text_range: Range,\n\n    /// The text that comes immediately before the cursor.\n    /// For example:\n    ///\n    /// ```gleam\n    ///    wibble.w|ob\n    /// //         ^ cursor here\n    /// // The text before is: \"wibble.w\"\n    /// ```\n    ///\n    text_before_cursor: EcoString,\n\n    /// The range of the text that comes immediately before the cursor.\n    /// For example:\n    ///\n    /// ```gleam\n    ///    wibble.w|ob\n    /// //         ^ cursor here\n    /// // ^^^^^^^^ This is the range\n    /// ```\n    ///\n    /// This is what is usually replaced with a completion.\n    ///\n    text_before_cursor_range: Range,\n\n    /// The text that comes immediately after the cursor.\n    /// For example:\n    ///\n    /// ```gleam\n    ///    wibble.w|ob\n    /// //         ^ cursor here\n    /// // The text before is: \"ob\"\n    /// ```\n    ///\n    text_after_cursor: EcoString,\n}\n\nimpl CursorSurroundings {\n    fn selected_module(&self) -> Option<EcoString> {\n        self.surrounding_text\n            .split_once('.')\n            .map(|(selected_module, _)| EcoString::from(selected_module))\n    }\n\n    /// Given a proposed completion, this returns the text edit to obtain that\n    /// completion.\n    ///\n    /// > This could also return `None` as sometimes no further edit is actually\n    /// > needed!\n    ///\n    fn to_text_edit(&self, new_text: String) -> Option<CompletionTextEdit> {\n        // We need to check if the new text we're adding could actually be\n        // a simple addition in the middle of something that is already being\n        // typed.\n        // Say we're editing our code to actually make the `Json` type\n        // qualified:\n        //\n        // ```gleam\n        // jso|Json\n        //    ^ cursor here\n        // ```\n        //\n        // Halfway through writing the module name we might just want to accept\n        // the completion for: `json.Json`.\n        // What one would normally expect is for the final code to be:\n        //\n        // ```gleam\n        // json.Json|\n        // // after accepting completion\n        //\n        // // and not something like this!\n        // // json.JsonJson\n        // ```\n        //\n        // This only makes sense if the completion we're adding has a prefix and\n        // suffix in common with the surrounding text:\n        let remaining_label = new_text\n            .strip_prefix(self.text_before_cursor.as_str())\n            .and_then(|rest| rest.strip_suffix(self.text_after_cursor.as_str()));\n\n        match remaining_label {\n            // The entire existing text is already the same as the new text we\n            // might want to add.\n            // In that case there's no need to perform any edit at all!\n            Some(\"\") => None,\n\n            // This is one of the cases (like the one in the example above) were\n            // the label is a more complete version of the text surrounding the\n            // cursor. So we replace the entire range.\n            Some(_) => Some(CompletionTextEdit::Edit(TextEdit {\n                range: self.surrounding_text_range,\n                new_text,\n            })),\n            // In all other cases the completion is never meant to replace text\n            // that comes after the cursor.\n            // We only replace what comes before it with the new text.\n            None => Some(CompletionTextEdit::Edit(TextEdit {\n                range: self.text_before_cursor_range,\n                new_text,\n            })),\n        }\n    }\n}\n\npub struct Completer<'a, IO> {\n    /// The direct buffer source code\n    src: &'a EcoString,\n    /// The line number information of the buffer source code\n    pub src_line_numbers: LineNumbers,\n    /// The current cursor position within the buffer source code\n    cursor_position: &'a Position,\n    /// A reference to the lsp compiler for getting module information\n    compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n    /// A reference to the current module the completion is for\n    module: &'a Module,\n    /// The line number information of the latest compiled module.\n    /// This is not necessarily the same as src_line_numbers if the module\n    /// is in a non-compiling state\n    pub module_line_numbers: LineNumbers,\n\n    /// The expected type of the value we are completing. `None` if we are\n    /// completing a type annotation or label, where this information is not\n    /// applicable.\n    pub expected_type: Option<Arc<Type>>,\n}\n\nimpl<'a, IO> Completer<'a, IO> {\n    pub fn new(\n        src: &'a EcoString,\n        params: &'a TextDocumentPositionParams,\n        compiler: &'a LspProjectCompiler<FileSystemProxy<IO>>,\n        module: &'a Module,\n    ) -> Self {\n        Completer {\n            src,\n            src_line_numbers: LineNumbers::new(src.as_str()),\n            cursor_position: &params.position,\n            compiler,\n            module,\n            module_line_numbers: LineNumbers::new(&module.code),\n            expected_type: None,\n        }\n    }\n\n    // Gets the current range around the cursor to place a completion\n    // and the phrase surrounding the cursor to use for completion.\n    // This method takes in a helper to determine what qualifies as\n    // a phrase depending on context.\n    fn get_phrase_surrounding_for_completion(\n        &'a self,\n        valid_phrase_char: &impl Fn(char) -> bool,\n    ) -> CursorSurroundings {\n        let cursor = self.src_line_numbers.byte_index(*self.cursor_position);\n\n        // Get part of phrase prior to cursor\n        let before = self\n            .src\n            .get(..cursor as usize)\n            .and_then(|line| line.rsplit_once(valid_phrase_char).map(|r| r.1))\n            .unwrap_or(\"\");\n\n        // Get part of phrase following cursor\n        let after = self\n            .src\n            .get(cursor as usize..)\n            .and_then(|line| line.split_once(valid_phrase_char).map(|r| r.0))\n            .unwrap_or(\"\");\n\n        let text_before_cursor_range = Range {\n            start: Position {\n                line: self.cursor_position.line,\n                character: self.cursor_position.character - before.len() as u32,\n            },\n            end: Position {\n                line: self.cursor_position.line,\n                character: self.cursor_position.character,\n            },\n        };\n\n        let surrounding_text_range = Range {\n            start: text_before_cursor_range.start,\n            end: Position {\n                line: self.cursor_position.line,\n                character: self.cursor_position.character + after.len() as u32,\n            },\n        };\n\n        CursorSurroundings {\n            surrounding_text: eco_format!(\"{before}{after}\"),\n            surrounding_text_range,\n            text_before_cursor: EcoString::from(before),\n            text_before_cursor_range,\n            text_after_cursor: EcoString::from(after),\n        }\n    }\n\n    // Gets the current range around the cursor to place a completion\n    // and any part of the phrase preceeding a dot if a module is being selected from.\n    // A continuous phrase in this case is a name or typename that may have a dot in it.\n    // This is used to match the exact location to fill in the completion.\n    fn get_phrase_surrounding_completion(&'a self) -> CursorSurroundings {\n        self.get_phrase_surrounding_for_completion(&|c: char| {\n            // Checks if a character is not a valid name/upname character or a dot.\n            !c.is_ascii_alphanumeric() && c != '.' && c != '_'\n        })\n    }\n\n    // Gets the current range around the cursor to place a completion.\n    // For unqualified imports we special case the word being completed to allow for whitespace but not dots.\n    // This is to allow `type MyType` to be treated as 1 \"phrase\" for the sake of completion.\n    fn get_phrase_surrounding_completion_for_import(&'a self) -> CursorSurroundings {\n        self.get_phrase_surrounding_for_completion(&|c: char| {\n            // Checks if a character is not a valid name/upname character or whitespace.\n            // The newline character is not included as well.\n            !c.is_ascii_alphanumeric() && c != '_' && c != ' ' && c != '\\t'\n        })\n    }\n\n    /// Checks if the line being editted is an import line and provides completions if it is.\n    /// If the line includes a dot then it provides unqualified import completions.\n    /// Otherwise it provides direct module import completions.\n    pub fn import_completions(&'a self) -> Option<Result<Option<Vec<CompletionItem>>>> {\n        let start_of_line = self.src_line_numbers.byte_index(Position {\n            line: self.cursor_position.line,\n            character: 0,\n        });\n        let end_of_line = self.src_line_numbers.byte_index(Position {\n            line: self.cursor_position.line + 1,\n            character: 0,\n        });\n\n        // Drop all lines except the line the cursor is on\n        let src = self.src.get(start_of_line as usize..end_of_line as usize)?;\n\n        // If this isn't an import line then we don't offer import completions\n        if !src.trim_start().starts_with(\"import\") {\n            return None;\n        }\n\n        // Check if we are completing an unqualified import\n        if let Some(dot_index) = src.find('.') {\n            // Find the module that is being imported from\n            let importing_module_name = src.get(6..dot_index)?.trim();\n            let importing_module: &ModuleInterface =\n                self.compiler.get_module_interface(importing_module_name)?;\n            let within_braces = match src.get(dot_index + 1..) {\n                Some(x) => x.trim_start().starts_with('{'),\n                None => false,\n            };\n\n            Some(Ok(Some(self.unqualified_completions_from_module(\n                importing_module,\n                within_braces,\n            ))))\n        } else {\n            // Find where to start and end the import completion\n            let start = self.src_line_numbers.line_and_column_number(start_of_line);\n            let end = self\n                .src_line_numbers\n                .line_and_column_number(end_of_line - 1);\n            let start = Position::new(start.line - 1, start.column + 6);\n            let end = Position::new(end.line - 1, end.column - 1);\n            let completions = self.complete_modules_for_import(start, end);\n\n            Some(Ok(Some(completions)))\n        }\n    }\n\n    /// Gets the completes for unqualified imports from a module.\n    pub fn unqualified_completions_from_module(\n        &'a self,\n        module_being_imported_from: &'a ModuleInterface,\n        within_braces: bool,\n    ) -> Vec<CompletionItem> {\n        let cursor_surroundings = self.get_phrase_surrounding_completion_for_import();\n        let mut completions = vec![];\n\n        // Find values and type that have already previously been imported\n        let mut already_imported_types = std::collections::HashSet::new();\n        let mut already_imported_values = std::collections::HashSet::new();\n\n        // Search the ast for import statements\n        for import in &self.module.ast.definitions.imports {\n            // Find the import that matches the module being imported from\n            if import.module == module_being_imported_from.name {\n                // Add the values and types that have already been imported\n                for unqualified in &import.unqualified_types {\n                    let _ = already_imported_types.insert(&unqualified.name);\n                }\n\n                for unqualified in &import.unqualified_values {\n                    let _ = already_imported_values.insert(&unqualified.name);\n                }\n            }\n        }\n\n        // Get completable types\n        for (name, type_) in &module_being_imported_from.types {\n            // Skip types that should not be suggested\n            if !self.is_suggestable_import(\n                &type_.publicity,\n                module_being_imported_from.package.as_str(),\n            ) {\n                continue;\n            }\n\n            // Skip type that are already imported\n            if already_imported_types.contains(name) {\n                continue;\n            }\n\n            completions.push(type_completion(\n                None,\n                name,\n                type_,\n                &cursor_surroundings,\n                if within_braces {\n                    TypeCompletionContext::UnqualifiedImportWithinBraces\n                } else {\n                    TypeCompletionContext::UnqualifiedImport\n                },\n                CompletionKind::ImportedModule,\n            ));\n        }\n\n        // Get completable values\n        for (name, value) in &module_being_imported_from.values {\n            // Skip values that should not be suggested\n            if !self.is_suggestable_import(\n                &value.publicity,\n                module_being_imported_from.package.as_str(),\n            ) {\n                continue;\n            }\n\n            // Skip values that are already imported\n            if already_imported_values.contains(name) {\n                continue;\n            }\n            completions.push(self.value_completion(\n                None,\n                &module_being_imported_from.name,\n                name,\n                value,\n                &cursor_surroundings,\n                CompletionKind::ImportedModule,\n            ));\n        }\n\n        completions\n    }\n\n    // Get all the modules that can be imported that have not already been imported.\n    fn completable_modules_for_import(&self) -> Vec<(&EcoString, &ModuleInterface)> {\n        let mut direct_dep_packages: std::collections::HashSet<&EcoString> =\n            std::collections::HashSet::from_iter(\n                self.compiler.project_compiler.config.dependencies.keys(),\n            );\n        if !self.module.origin.is_src() {\n            // In tests we can import direct dev dependencies\n            direct_dep_packages.extend(\n                self.compiler\n                    .project_compiler\n                    .config\n                    .dev_dependencies\n                    .keys(),\n            )\n        }\n\n        let already_imported: std::collections::HashSet<EcoString> =\n            std::collections::HashSet::from_iter(\n                self.module.dependencies.iter().map(|d| d.0.clone()),\n            );\n        self.compiler\n            .project_compiler\n            .get_importable_modules()\n            .iter()\n            //\n            // You cannot import yourself\n            .filter(|(name, _)| *name != &self.module.name)\n            //\n            // Different origin directories will get different import completions\n            .filter(|(_, module)| match self.module.origin {\n                // src/ can import from src/\n                Origin::Src => module.origin.is_src(),\n                // dev/ can import from src/ or dev/\n                Origin::Dev => !module.origin.is_test(),\n                // Test can import from anywhere\n                Origin::Test => true,\n            })\n            //\n            // It is possible to import internal modules from other packages,\n            // but it's not recommended so we don't include them in completions\n            .filter(|(_, module)| module.package == self.root_package_name() || !module.is_internal)\n            //\n            // You cannot import a module twice\n            .filter(|(name, _)| !already_imported.contains(*name))\n            //\n            // It is possible to import modules from dependencies of dependencies\n            // but it's not recommended so we don't include them in completions\n            .filter(|(_, module)| {\n                let is_root_or_prelude =\n                    module.package == self.root_package_name() || module.package.is_empty();\n                is_root_or_prelude || direct_dep_packages.contains(&module.package)\n            })\n            .collect()\n    }\n\n    // Get all the completions for modules that can be imported\n    fn complete_modules_for_import(\n        &'a self,\n        start: Position,\n        end: Position,\n    ) -> Vec<CompletionItem> {\n        self.completable_modules_for_import()\n            .iter()\n            .map(|(name, _)| CompletionItem {\n                label: name.to_string(),\n                kind: Some(CompletionItemKind::MODULE),\n                text_edit: Some(CompletionTextEdit::Edit(TextEdit {\n                    range: Range { start, end },\n                    new_text: name.to_string(),\n                })),\n                ..Default::default()\n            })\n            .collect()\n    }\n\n    // NOTE: completion_types and completion_values are really similar\n    // but just different enough that an abstraction would\n    // be really hard to understand or use a lot of trait magic.\n    // For now I've left it as is but might be worth revisiting.\n\n    /// Provides completions for when the context being editted is a type.\n    pub fn completion_types(&'a self) -> Vec<CompletionItem> {\n        let cursor_surroundings = self.get_phrase_surrounding_completion();\n        let selected_module = cursor_surroundings.selected_module();\n        let mut completions = vec![];\n\n        // Module and prelude types\n        // Do not complete direct module types if the user has already started\n        // typing a module select. That is, when the user has already typed\n        // `mymodule.|` we know local module types and prelude types are no\n        // longer relevant and needed for completions.\n        if selected_module.is_none() {\n            for (name, type_) in &self.module.ast.type_info.types {\n                completions.push(type_completion(\n                    None,\n                    name,\n                    type_,\n                    &cursor_surroundings,\n                    TypeCompletionContext::UnqualifiedType,\n                    CompletionKind::LocallyDefined,\n                ));\n            }\n\n            for type_ in PreludeType::iter() {\n                let label: String = type_.name().into();\n                let sort_text = Some(sort_text(\n                    CompletionKind::Prelude,\n                    &label,\n                    TypeMatch::Unknown,\n                ));\n                completions.push(CompletionItem {\n                    label,\n                    detail: Some(\"Type\".into()),\n                    kind: Some(CompletionItemKind::CLASS),\n                    sort_text,\n                    ..Default::default()\n                });\n            }\n        }\n\n        // Qualified types\n        for import in &self.module.ast.definitions.imports {\n            // The module may not be known of yet if it has not previously\n            // compiled yet in this editor session.\n            let Some(module) = self.compiler.get_module_interface(&import.module) else {\n                continue;\n            };\n            let Some(module_name) = &import.used_name() else {\n                continue;\n            };\n\n            for (name, type_) in &module.types {\n                if !self.is_suggestable_import(&type_.publicity, module.package.as_str()) {\n                    continue;\n                }\n\n                // If the user has already started typing a module select\n                // then don't show irrelevant modules.\n                // For example: when the user has typed `mymodule.|` we\n                // should only show items from `mymodule`.\n                if let Some(typed_module) = &selected_module\n                    && module_name != typed_module\n                {\n                    continue;\n                }\n\n                completions.push(type_completion(\n                    Some(module_name),\n                    name,\n                    type_,\n                    &cursor_surroundings,\n                    TypeCompletionContext::QualifiedType,\n                    CompletionKind::ImportedModule,\n                ));\n            }\n\n            // Unqualified types\n            // Do not complete unqualified types if the user has already started\n            // typing a module select.\n            // For example, when the user has already typed `mymodule.|` we know\n            // unqualified module types are no longer relevant.\n            if selected_module.is_none() {\n                for unqualified in &import.unqualified_types {\n                    if let Some(type_) = module.get_public_type(&unqualified.name) {\n                        completions.push(type_completion(\n                            None,\n                            unqualified.used_name(),\n                            type_,\n                            &cursor_surroundings,\n                            TypeCompletionContext::UnqualifiedType,\n                            CompletionKind::ImportedModule,\n                        ))\n                    }\n                }\n            }\n        }\n\n        // Importable modules\n        let first_import_pos =\n            position_of_first_definition_if_import(self.module, &self.src_line_numbers);\n        let first_is_import = first_import_pos.is_some();\n        let import_location = first_import_pos.unwrap_or_default();\n\n        let after_import_newlines = add_newlines_after_import(\n            import_location,\n            first_is_import,\n            &self.src_line_numbers,\n            self.src,\n        );\n        for (module_full_name, module) in self.completable_modules_for_import() {\n            // Do not try to import the prelude.\n            if module_full_name == \"gleam\" {\n                continue;\n            }\n\n            let qualifier = module_full_name\n                .split('/')\n                .next_back()\n                .unwrap_or(module_full_name);\n\n            // If the user has already started a module select then don't show irrelevant modules.\n            // e.x. when the user has typed mymodule.| we should only show items from mymodule.\n            if let Some(selected_module) = &selected_module\n                && qualifier != selected_module\n            {\n                continue;\n            }\n\n            // Qualified types\n            for (name, type_) in &module.types {\n                if !self.is_suggestable_import(&type_.publicity, module.package.as_str()) {\n                    continue;\n                }\n\n                let mut completion = type_completion(\n                    Some(qualifier),\n                    name,\n                    type_,\n                    &cursor_surroundings,\n                    TypeCompletionContext::QualifiedType,\n                    CompletionKind::ImportableModule,\n                );\n                add_import_to_completion(\n                    &mut completion,\n                    import_location,\n                    module_full_name,\n                    &after_import_newlines,\n                );\n                completions.push(completion);\n            }\n        }\n\n        completions\n    }\n\n    /// Provides completions for when the context being editted is a value.\n    pub fn completion_values(&'a self) -> Vec<CompletionItem> {\n        let cursor_surroundings = self.get_phrase_surrounding_completion();\n        let selected_module = cursor_surroundings.selected_module();\n        let mut completions = vec![];\n        let mod_name = self.module.name.as_str();\n        let cursor = self.src_line_numbers.byte_index(*self.cursor_position);\n\n        // If the value for which we've been asked to give completions is a regular\n        // number it doesn't make sense to provide any completion!\n        //\n        // ```gleam\n        // // imagine you're typing a number...\n        //   2\n        // // ^ it would be quite annoying if suggestions popped up:\n        // //   [list.window_by_2]\n        // //   [int.to_base32]\n        // //   ...\n        // ```\n        //\n        // This usually happens in IDEs like Zed that still ask for completions\n        // even if the programmer is typing in a number. We can't control when\n        // an IDE asks for completions, but we can avoid replying nonsense in\n        // this context.\n        if parse_int_value(&cursor_surroundings.surrounding_text).is_some()\n            || LiteralFloatValue::parse(&cursor_surroundings.surrounding_text).is_some()\n        {\n            return vec![];\n        }\n\n        // Keyword completions\n        if !cursor_surroundings.surrounding_text.is_empty() {\n            for keyword in [\"panic\", \"todo\", \"echo\"] {\n                if keyword.starts_with(cursor_surroundings.surrounding_text.as_str()) {\n                    completions.push(self.keyword_completion(keyword, &cursor_surroundings))\n                }\n            }\n        }\n\n        // Module and prelude values\n        // Do not complete direct module values if the user has already started typing a module select.\n        // e.x. when the user has typed mymodule.| we know local module and prelude values are no longer\n        // relevant.\n        if selected_module.is_none() {\n            // Find the function that the cursor is in and push completions for\n            // its arguments and local variables.\n            if let Some(function) = self\n                .module\n                .ast\n                .definitions\n                .functions\n                .iter()\n                .filter(|function| function.full_location().contains(cursor))\n                .peekable()\n                .peek()\n            {\n                completions.extend(\n                    LocalCompletion::new(\n                        mod_name,\n                        cursor_surroundings.surrounding_text_range,\n                        cursor,\n                        self.expected_type.clone(),\n                    )\n                    .fn_completions(function),\n                );\n            }\n\n            for (name, value) in &self.module.ast.type_info.values {\n                // Here we do not check for the internal attribute: we always want\n                // to show autocompletions for values defined in the same module,\n                // even if those are internal.\n                completions.push(self.value_completion(\n                    None,\n                    mod_name,\n                    name,\n                    value,\n                    &cursor_surroundings,\n                    CompletionKind::LocallyDefined,\n                ));\n            }\n\n            let mut push_prelude_completion = |label: &str, kind, type_: Arc<Type>| {\n                let label = label.to_string();\n                let sort_text = Some(sort_text(\n                    CompletionKind::Prelude,\n                    &label,\n                    match_type(&self.expected_type, &type_),\n                ));\n                completions.push(CompletionItem {\n                    label,\n                    detail: Some(PRELUDE_MODULE_NAME.into()),\n                    kind: Some(kind),\n                    sort_text,\n                    ..Default::default()\n                });\n            };\n\n            for type_ in PreludeType::iter() {\n                match type_ {\n                    PreludeType::Bool => {\n                        push_prelude_completion(\n                            \"True\",\n                            CompletionItemKind::ENUM_MEMBER,\n                            type_::bool(),\n                        );\n                        push_prelude_completion(\n                            \"False\",\n                            CompletionItemKind::ENUM_MEMBER,\n                            type_::bool(),\n                        );\n                    }\n                    PreludeType::Nil => {\n                        push_prelude_completion(\n                            \"Nil\",\n                            CompletionItemKind::ENUM_MEMBER,\n                            type_::nil(),\n                        );\n                    }\n                    PreludeType::Result => {\n                        push_prelude_completion(\n                            \"Ok\",\n                            CompletionItemKind::CONSTRUCTOR,\n                            type_::result(type_::unbound_var(0), type_::unbound_var(0)),\n                        );\n                        push_prelude_completion(\n                            \"Error\",\n                            CompletionItemKind::CONSTRUCTOR,\n                            type_::result(type_::unbound_var(0), type_::unbound_var(0)),\n                        );\n                    }\n                    PreludeType::BitArray\n                    | PreludeType::Float\n                    | PreludeType::Int\n                    | PreludeType::List\n                    | PreludeType::String\n                    | PreludeType::UtfCodepoint => {}\n                }\n            }\n        }\n\n        // Imported modules\n        for import in &self.module.ast.definitions.imports {\n            // The module may not be known of yet if it has not previously\n            // compiled yet in this editor session.\n            let Some(module) = self.compiler.get_module_interface(&import.module) else {\n                continue;\n            };\n\n            // Qualified values\n            for (name, value) in &module.values {\n                if !self.is_suggestable_import(&value.publicity, module.package.as_str()) {\n                    continue;\n                }\n\n                if let Some(module) = import.used_name() {\n                    // If the user has already started a module select then don't show irrelevant modules.\n                    // e.x. when the user has typed mymodule.| we should only show items from mymodule.\n                    if let Some(input_mod_name) = &selected_module\n                        && &module != input_mod_name\n                    {\n                        continue;\n                    }\n                    completions.push(self.value_completion(\n                        Some(&module),\n                        mod_name,\n                        name,\n                        value,\n                        &cursor_surroundings,\n                        CompletionKind::ImportedModule,\n                    ));\n                }\n            }\n\n            // Unqualified values\n            // Do not complete unqualified values if the user has already started typing a module select.\n            // e.x. when the user has typed mymodule.| we know unqualified module values are no longer relevant.\n            if selected_module.is_none() {\n                for unqualified in &import.unqualified_values {\n                    if let Some(value) = module.get_public_value(&unqualified.name) {\n                        let name = unqualified.used_name();\n                        completions.push(self.value_completion(\n                            None,\n                            mod_name,\n                            name,\n                            value,\n                            &cursor_surroundings,\n                            CompletionKind::ImportedModule,\n                        ))\n                    }\n                }\n            }\n        }\n\n        // Importable modules\n        let first_import_pos =\n            position_of_first_definition_if_import(self.module, &self.src_line_numbers);\n        let first_is_import = first_import_pos.is_some();\n        let import_location = first_import_pos.unwrap_or_default();\n        let after_import_newlines = add_newlines_after_import(\n            import_location,\n            first_is_import,\n            &self.src_line_numbers,\n            self.src,\n        );\n        for (module_full_name, module) in self.completable_modules_for_import() {\n            // Do not try to import the prelude.\n            if module_full_name == \"gleam\" {\n                continue;\n            }\n            let qualifier = module_full_name\n                .split('/')\n                .next_back()\n                .unwrap_or(module_full_name);\n\n            // If the user has already started a module select then don't show irrelevant modules.\n            // e.x. when the user has typed mymodule.| we should only show items from mymodule.\n            if let Some(selected_module) = &selected_module\n                && qualifier != selected_module\n            {\n                continue;\n            }\n\n            // Qualified values\n            for (name, value) in &module.values {\n                if !self.is_suggestable_import(&value.publicity, module.package.as_str()) {\n                    continue;\n                }\n\n                let mut completion = self.value_completion(\n                    Some(qualifier),\n                    module_full_name,\n                    name,\n                    value,\n                    &cursor_surroundings,\n                    CompletionKind::ImportableModule,\n                );\n\n                add_import_to_completion(\n                    &mut completion,\n                    import_location,\n                    module_full_name,\n                    &after_import_newlines,\n                );\n                completions.push(completion);\n            }\n        }\n\n        completions\n    }\n\n    // Looks up the type accessors for the given type\n    fn type_accessors_from_modules(\n        &'a self,\n        importable_modules: &'a im::HashMap<EcoString, ModuleInterface>,\n        type_: Arc<Type>,\n    ) -> Option<&'a HashMap<EcoString, RecordAccessor>> {\n        let type_ = collapse_links(type_);\n        match type_.as_ref() {\n            Type::Named {\n                name,\n                module,\n                inferred_variant,\n                ..\n            } => importable_modules\n                .get(module)\n                .and_then(|i| i.accessors.get(name))\n                .filter(|a| a.publicity.is_importable() || module == &self.module.name)\n                .map(|a| a.accessors_for_variant(*inferred_variant)),\n\n            Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => None,\n        }\n    }\n\n    /// Provides completions for field accessors when the context being editted\n    /// is a custom type instance\n    pub fn completion_field_accessors(&'a self, type_: Arc<Type>) -> Vec<CompletionItem> {\n        if let Type::Named {\n            publicity,\n            module: type_module,\n            ..\n        } = type_.as_ref()\n            && publicity.is_internal()\n            && *type_module != self.module.name\n        {\n            // If we're asking for field completions for an internal type that\n            // is not defined in the current module we don't want to show\n            // anything. This makes it a lot harder to inadvertently rely on\n            // internal implementation details without noticing.\n            return vec![];\n        }\n\n        self.type_accessors_from_modules(\n            self.compiler.project_compiler.get_importable_modules(),\n            type_,\n        )\n        .map(|accessors| {\n            accessors\n                .values()\n                .map(|accessor| self.field_completion(&accessor.label, accessor.type_.clone()))\n                .collect_vec()\n        })\n        .unwrap_or_default()\n    }\n\n    fn callable_field_map(\n        &'a self,\n        expr: &'a TypedExpr,\n        importable_modules: &'a im::HashMap<EcoString, ModuleInterface>,\n    ) -> Option<&'a FieldMap> {\n        match expr {\n            TypedExpr::Var { constructor, .. } => constructor.field_map(),\n            TypedExpr::ModuleSelect {\n                module_name, label, ..\n            } => importable_modules\n                .get(module_name)\n                .and_then(|i| i.values.get(label))\n                .and_then(|a| a.field_map()),\n            TypedExpr::Int { .. }\n            | TypedExpr::Float { .. }\n            | TypedExpr::String { .. }\n            | TypedExpr::Block { .. }\n            | TypedExpr::Pipeline { .. }\n            | TypedExpr::Fn { .. }\n            | TypedExpr::List { .. }\n            | TypedExpr::Call { .. }\n            | TypedExpr::BinOp { .. }\n            | TypedExpr::Case { .. }\n            | TypedExpr::RecordAccess { .. }\n            | TypedExpr::PositionalAccess { .. }\n            | TypedExpr::Tuple { .. }\n            | TypedExpr::TupleIndex { .. }\n            | TypedExpr::Todo { .. }\n            | TypedExpr::Panic { .. }\n            | TypedExpr::Echo { .. }\n            | TypedExpr::BitArray { .. }\n            | TypedExpr::RecordUpdate { .. }\n            | TypedExpr::NegateBool { .. }\n            | TypedExpr::NegateInt { .. }\n            | TypedExpr::Invalid { .. } => None,\n        }\n    }\n\n    /// Provides completions for labels when the context being editted is a call\n    /// that has labelled arguments that can be passed\n    pub fn completion_labels(\n        &'a self,\n        fun: &TypedExpr,\n        existing_arguments: &[CallArg<TypedExpr>],\n    ) -> Vec<CompletionItem> {\n        let fun_type = fun.type_().fn_types().map(|(arguments, _)| arguments);\n        let already_included_labels = existing_arguments\n            .iter()\n            .filter_map(|argument| {\n                // Record updates can have implicit arguments added as placeholders\n                // by the compiler. Those are still arguments that could be typed\n                // by the developer and used, so we don't want to include those\n                // in the ones that have already been included and won't be recommended.\n                if argument.is_implicit() && !argument.is_use_implicit_callback() {\n                    None\n                } else {\n                    argument.label.clone()\n                }\n            })\n            .collect_vec();\n        let Some(field_map) =\n            self.callable_field_map(fun, self.compiler.project_compiler.get_importable_modules())\n        else {\n            return vec![];\n        };\n\n        field_map\n            .fields\n            .iter()\n            .filter(|field| !already_included_labels.contains(field.0))\n            .map(|(label, arg_index)| {\n                let detail = fun_type.as_ref().and_then(|arguments| {\n                    arguments\n                        .get(*arg_index as usize)\n                        .map(|argument| Printer::new().pretty_print(argument, 0))\n                });\n                let label = format!(\"{label}:\");\n                let sort_text = Some(sort_text(CompletionKind::Label, &label, TypeMatch::Unknown));\n                CompletionItem {\n                    label,\n                    detail,\n                    kind: Some(CompletionItemKind::FIELD),\n                    sort_text,\n                    ..Default::default()\n                }\n            })\n            .collect()\n    }\n\n    fn root_package_name(&self) -> &str {\n        self.compiler.project_compiler.config.name.as_str()\n    }\n\n    // checks based on the publicity if something should be suggested for import from root package\n    fn is_suggestable_import(&self, publicity: &Publicity, package: &str) -> bool {\n        match publicity {\n            // We skip private types as we never want those to appear in\n            // completions.\n            Publicity::Private => false,\n            // We only skip internal types if those are not defined in\n            // the root package.\n            Publicity::Internal { .. } if package != self.root_package_name() => false,\n            Publicity::Internal { .. } => true,\n            // We never skip public types.\n            Publicity::Public => true,\n        }\n    }\n\n    fn keyword_completion(\n        &self,\n        keyword: &str,\n        cursor_surrounding: &CursorSurroundings,\n    ) -> CompletionItem {\n        let label = keyword.to_string();\n\n        CompletionItem {\n            label: label.clone(),\n            kind: Some(CompletionItemKind::KEYWORD),\n            detail: None,\n            label_details: None,\n            documentation: None,\n            sort_text: Some(sort_text(\n                CompletionKind::Keyword,\n                &label,\n                TypeMatch::Matching,\n            )),\n            text_edit: cursor_surrounding.to_text_edit(label),\n            ..Default::default()\n        }\n    }\n\n    fn value_completion(\n        &self,\n        module_qualifier: Option<&str>,\n        module_name: &str,\n        name: &str,\n        value: &type_::ValueConstructor,\n        cursor_surrounding: &CursorSurroundings,\n        priority: CompletionKind,\n    ) -> CompletionItem {\n        let type_match = match_type(&self.expected_type, &value.type_);\n        let label = match module_qualifier {\n            Some(module) => format!(\"{module}.{name}\"),\n            None => name.to_string(),\n        };\n\n        let type_ = Printer::new().pretty_print(&value.type_, 0);\n\n        let kind = Some(match value.variant {\n            ValueConstructorVariant::LocalVariable { .. } => CompletionItemKind::VARIABLE,\n            ValueConstructorVariant::ModuleConstant { .. } => CompletionItemKind::CONSTANT,\n            ValueConstructorVariant::ModuleFn { .. } => CompletionItemKind::FUNCTION,\n            ValueConstructorVariant::Record { arity: 0, .. } => CompletionItemKind::ENUM_MEMBER,\n            ValueConstructorVariant::Record { .. } => CompletionItemKind::CONSTRUCTOR,\n        });\n\n        let documentation = value.get_documentation().map(|documentation| {\n            Documentation::MarkupContent(MarkupContent {\n                kind: MarkupKind::Markdown,\n                value: documentation.into(),\n            })\n        });\n\n        CompletionItem {\n            label: label.clone(),\n            kind,\n            detail: Some(type_),\n            label_details: Some(CompletionItemLabelDetails {\n                detail: None,\n                description: Some(module_name.into()),\n            }),\n            documentation,\n            sort_text: Some(sort_text(priority, &label, type_match)),\n            text_edit: cursor_surrounding.to_text_edit(label),\n            ..Default::default()\n        }\n    }\n\n    fn field_completion(&self, label: &str, type_: Arc<Type>) -> CompletionItem {\n        let type_match = match_type(&self.expected_type, &type_);\n        let type_ = Printer::new().pretty_print(&type_, 0);\n\n        CompletionItem {\n            label: label.into(),\n            kind: Some(CompletionItemKind::FIELD),\n            detail: Some(type_),\n            sort_text: Some(sort_text(CompletionKind::FieldAccessor, label, type_match)),\n            ..Default::default()\n        }\n    }\n}\n\nfn add_import_to_completion(\n    item: &mut CompletionItem,\n    import_location: Position,\n    module_full_name: &EcoString,\n    insert_newlines: &Newlines,\n) {\n    item.additional_text_edits = Some(vec![get_import_edit(\n        import_location,\n        module_full_name,\n        insert_newlines,\n    )]);\n}\n\nfn type_completion(\n    module: Option<&str>,\n    name: &str,\n    type_: &TypeConstructor,\n    cursor_surrounding: &CursorSurroundings,\n    type_completion_context: TypeCompletionContext,\n    priority: CompletionKind,\n) -> CompletionItem {\n    let label = match module {\n        Some(module) => format!(\"{module}.{name}\"),\n        None => name.to_string(),\n    };\n\n    let kind = Some(if type_.type_.is_variable() {\n        CompletionItemKind::VARIABLE\n    } else {\n        CompletionItemKind::CLASS\n    });\n\n    let completion_text = match type_completion_context {\n        TypeCompletionContext::UnqualifiedImport => format!(\"{{type {label}}}\"),\n        TypeCompletionContext::UnqualifiedImportWithinBraces => format!(\"type {label}\"),\n        TypeCompletionContext::QualifiedType | TypeCompletionContext::UnqualifiedType => {\n            label.clone()\n        }\n    };\n\n    CompletionItem {\n        label: label.clone(),\n        kind,\n        detail: Some(\"Type\".into()),\n        sort_text: Some(sort_text(priority, &label, TypeMatch::Unknown)),\n        text_edit: cursor_surrounding.to_text_edit(completion_text),\n        ..Default::default()\n    }\n}\n\nfn match_type(expected_type: &Option<Arc<Type>>, type_: &Type) -> TypeMatch {\n    if let Some(expected_type) = expected_type {\n        // If the type of the value we are completing is unbound, that\n        // technically means that all types match, which doesn't give us\n        // any useful information so we treat it as not knowing what the\n        // type is, which generally is the case.\n        if expected_type.is_unbound() {\n            TypeMatch::Unknown\n        }\n        // We also want to prioritise functions which return the desired type,\n        // as often the user's intention will be to write a function call.\n        else if let Some((_, return_)) = type_.fn_types()\n            && expected_type.same_as(&return_)\n        {\n            TypeMatch::Matching\n        } else if expected_type.same_as(type_) {\n            TypeMatch::Matching\n        } else {\n            TypeMatch::Incompatible\n        }\n    } else {\n        TypeMatch::Unknown\n    }\n}\n\npub struct LocalCompletion<'a> {\n    mod_name: &'a str,\n    insert_range: Range,\n    cursor: u32,\n    completions: HashMap<EcoString, CompletionItem>,\n    expected_type: Option<Arc<Type>>,\n}\n\nimpl<'a> LocalCompletion<'a> {\n    pub fn new(\n        mod_name: &'a str,\n        insert_range: Range,\n        cursor: u32,\n        expected_type: Option<Arc<Type>>,\n    ) -> Self {\n        Self {\n            mod_name,\n            insert_range,\n            cursor,\n            completions: HashMap::new(),\n            expected_type,\n        }\n    }\n\n    /// Generates completion items for a given function, including its arguments\n    /// and local variables.\n    pub fn fn_completions(\n        mut self,\n        fun: &'a Function<Arc<Type>, TypedExpr>,\n    ) -> Vec<CompletionItem> {\n        // Add function arguments to completions\n        self.visit_fn_arguments(&fun.arguments);\n\n        // Visit the function body statements\n        for statement in &fun.body {\n            // Visit the statement to find local variables\n            self.visit_typed_statement(statement);\n        }\n\n        self.completions.into_values().collect_vec()\n    }\n\n    fn visit_fn_arguments(&mut self, arguments: &[Arg<Arc<Type>>]) {\n        for argument in arguments {\n            if let Some(name) = argument.get_variable_name() {\n                self.push_completion(name, argument.type_.clone());\n            }\n        }\n    }\n\n    fn push_completion(&mut self, name: &EcoString, type_: Arc<Type>) {\n        if name.is_empty() || name.starts_with('_') {\n            return;\n        }\n\n        _ = self.completions.insert(\n            name.clone(),\n            self.local_value_completion(self.mod_name, name, type_, self.insert_range),\n        );\n    }\n\n    fn local_value_completion(\n        &self,\n        module_name: &str,\n        name: &str,\n        type_: Arc<Type>,\n        insert_range: Range,\n    ) -> CompletionItem {\n        let type_match = match_type(&self.expected_type, &type_);\n\n        let label = name.to_string();\n        let type_ = Printer::new().pretty_print(&type_, 0);\n\n        let documentation = Documentation::MarkupContent(MarkupContent {\n            kind: MarkupKind::Markdown,\n            value: String::from(\"A locally defined variable.\"),\n        });\n\n        CompletionItem {\n            label: label.clone(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(type_),\n            label_details: Some(CompletionItemLabelDetails {\n                detail: None,\n                description: Some(module_name.into()),\n            }),\n            documentation: Some(documentation),\n            sort_text: Some(sort_text(\n                CompletionKind::LocallyDefined,\n                &label,\n                type_match,\n            )),\n            text_edit: Some(CompletionTextEdit::Edit(TextEdit {\n                range: insert_range,\n                new_text: label.clone(),\n            })),\n            ..Default::default()\n        }\n    }\n}\n\nimpl<'ast> Visit<'ast> for LocalCompletion<'_> {\n    fn visit_typed_statement(&mut self, statement: &'ast ast::TypedStatement) {\n        // We only want to suggest local variables that are defined before\n        // the cursor\n        if statement.location().start >= self.cursor {\n            return;\n        }\n        ast::visit::visit_typed_statement(self, statement);\n    }\n\n    /// Visits a typed assignment, selectively processing either the value or the pattern\n    /// based on the cursor position.\n    /// - If the cursor is within the assignment It visits only the value expression.\n    ///   This avoids suggesting variables that are being defined in the assignment itself.\n    /// - If the cursor is outside the assignment It visits only the pattern.\n    ///   This prevents suggesting variables that might be out of scope.\n    fn visit_typed_assignment(&mut self, assignment: &'ast ast::TypedAssignment) {\n        if assignment.location.contains(self.cursor) {\n            self.visit_typed_expr(&assignment.value);\n        } else {\n            self.visit_typed_pattern(&assignment.pattern);\n        }\n    }\n\n    fn visit_typed_expr_fn(\n        &mut self,\n        location: &'ast ast::SrcSpan,\n        _: &'ast Arc<Type>,\n        _: &'ast FunctionLiteralKind,\n        arguments: &'ast [ast::TypedArg],\n        body: &'ast Vec1<ast::TypedStatement>,\n        _: &'ast Option<ast::TypeAst>,\n    ) {\n        // If we are completing after the function body, any locally defined\n        // variables are now out of scope so we don't register any.\n        if self.cursor >= location.end {\n            return;\n        }\n        self.visit_fn_arguments(arguments);\n        for statement in body {\n            self.visit_typed_statement(statement);\n        }\n    }\n\n    fn visit_typed_expr_block(\n        &mut self,\n        location: &'ast ast::SrcSpan,\n        statements: &'ast [ast::TypedStatement],\n    ) {\n        // If we are completing after the block, any locally defined variables\n        // are now out of scope so we don't register any.\n        if self.cursor >= location.end {\n            return;\n        }\n        ast::visit::visit_typed_expr_block(self, location, statements);\n    }\n\n    fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {\n        // Any code which comes before or after a case clause cannot access any\n        // of the variables defined within it, so we ignore this clause if so.\n        if self.cursor < clause.location.start || self.cursor > clause.location.end {\n            return;\n        }\n        ast::visit::visit_typed_clause(self, clause);\n    }\n\n    fn visit_typed_pattern_variable(\n        &mut self,\n        _: &'ast ast::SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n        _origin: &'ast VariableOrigin,\n    ) {\n        self.push_completion(name, type_.clone());\n    }\n\n    fn visit_typed_pattern_discard(\n        &mut self,\n        _: &'ast ast::SrcSpan,\n        name: &'ast EcoString,\n        type_: &'ast Arc<Type>,\n    ) {\n        self.push_completion(name, type_.clone());\n    }\n\n    fn visit_typed_pattern_string_prefix(\n        &mut self,\n        _: &'ast ast::SrcSpan,\n        _: &'ast ast::SrcSpan,\n        _: &'ast Option<(EcoString, ast::SrcSpan)>,\n        _: &'ast ast::SrcSpan,\n        _: &'ast EcoString,\n        right_side_assignment: &'ast ast::AssignName,\n    ) {\n        self.push_completion(right_side_assignment.name(), type_::string());\n    }\n\n    fn visit_typed_pattern_assign(\n        &mut self,\n        _: &'ast ast::SrcSpan,\n        name: &'ast EcoString,\n        pattern: &'ast Pattern<Arc<Type>>,\n    ) {\n        self.visit_typed_pattern(pattern);\n        self.push_completion(name, pattern.type_().clone());\n    }\n}\n"
  },
  {
    "path": "language-server/src/edits.rs",
    "content": "use ecow::EcoString;\nuse lsp_types::{Position, Range, TextEdit};\n\nuse gleam_core::{\n    ast::{Import, SrcSpan, TypedDefinitions},\n    build::Module,\n    line_numbers::LineNumbers,\n};\n\nuse super::src_span_to_lsp_range;\n\n// Gets the position of the import statement if it's the first definition in the module.\npub fn position_of_first_definition_if_import(\n    module: &Module,\n    line_numbers: &LineNumbers,\n) -> Option<Position> {\n    let TypedDefinitions {\n        imports,\n        constants,\n        custom_types,\n        type_aliases,\n        functions,\n    } = &module.ast.definitions;\n\n    // We first find the firts import by position\n    let first_import = imports.iter().min_by_key(|import| import.location)?;\n\n    // Then we need to make sure it actually comes before any other definition.\n    let import_is_first_definition = constants\n        .iter()\n        .map(|constant| constant.location)\n        .chain(custom_types.iter().map(|custom_type| custom_type.location))\n        .chain(type_aliases.iter().map(|type_alias| type_alias.location))\n        .chain(functions.iter().map(|function| function.location))\n        .all(|location| location >= first_import.location);\n\n    if import_is_first_definition {\n        Some(src_span_to_lsp_range(first_import.location, line_numbers).start)\n    } else {\n        None\n    }\n}\n\npub enum Newlines {\n    Single,\n    Double,\n}\n\n// Returns how many newlines should be added after an import statement. By default `Newlines::Single`,\n// but if there's not any import statement, it returns `Newlines::Double`.\n//\n// * ``import_location`` - The position of the first import statement in the source code.\npub fn add_newlines_after_import(\n    import_location: Position,\n    has_imports: bool,\n    line_numbers: &LineNumbers,\n    src: &str,\n) -> Newlines {\n    let import_start_cursor = line_numbers.byte_index(import_location);\n    let is_new_line = src\n        .chars()\n        .nth(import_start_cursor as usize)\n        .unwrap_or_default()\n        == '\\n';\n    match !has_imports && !is_new_line {\n        true => Newlines::Double,\n        false => Newlines::Single,\n    }\n}\n\npub fn get_import_edit(\n    import_location: Position,\n    module_full_name: &str,\n    insert_newlines: &Newlines,\n) -> TextEdit {\n    let new_lines = match insert_newlines {\n        Newlines::Single => \"\\n\",\n        Newlines::Double => \"\\n\\n\",\n    };\n    TextEdit {\n        range: Range {\n            start: import_location,\n            end: import_location,\n        },\n        new_text: [\"import \", module_full_name, new_lines].concat(),\n    }\n}\n\npub fn insert_unqualified_import(\n    import: &Import<EcoString>,\n    code: &str,\n    name: String,\n) -> (u32, String) {\n    let SrcSpan { start, end } = import.location;\n\n    let import_code = code\n        .get(start as usize..end as usize)\n        .expect(\"Import location is invalid\");\n    let has_brace = import_code.contains('}');\n\n    if has_brace {\n        insert_into_braced_import(name, import.location, import_code)\n    } else {\n        insert_into_unbraced_import(name, import, import_code)\n    }\n}\n\n// Handle inserting into an unbraced import\nfn insert_into_unbraced_import(\n    name: String,\n    import: &Import<EcoString>,\n    import_code: &str,\n) -> (u32, String) {\n    let location = import.location;\n    if import.as_name.is_none() {\n        // Case: import module\n        (location.end, format!(\".{{{name}}}\"))\n    } else {\n        // Case: import module as alias\n        let as_pos = import_code\n            .find(\" as \")\n            .expect(\"Expected ' as ' in import statement\");\n        let before_as_pos = import_code\n            .get(..as_pos)\n            .and_then(|s| s.rfind(|c: char| !c.is_whitespace()))\n            .map(|pos| location.start as usize + pos + 1)\n            .expect(\"Expected non-whitespace character before ' as '\");\n        (before_as_pos as u32, format!(\".{{{name}}}\"))\n    }\n}\n\n// Handle inserting into a braced import\nfn insert_into_braced_import(name: String, location: SrcSpan, import_code: &str) -> (u32, String) {\n    if let Some((pos, c)) = find_last_char_before_closing_brace(location, import_code) {\n        // Case: import module.{Existing, } (as alias)\n        if c == ',' {\n            (pos as u32 + 1, format!(\" {name}\"))\n        } else {\n            // Case: import module.{Existing} (as alias)\n            (pos as u32 + 1, format!(\", {name}\"))\n        }\n    } else {\n        // Case: import module.{} (as alias)\n        let left_brace_pos = import_code\n            .find('{')\n            .map(|pos| location.start as usize + pos)\n            .expect(\"Expected '{' in import statement\");\n        (left_brace_pos as u32 + 1, name)\n    }\n}\n\nfn find_last_char_before_closing_brace(\n    location: SrcSpan,\n    import_code: &str,\n) -> Option<(usize, char)> {\n    let closing_brace_pos = import_code.rfind('}')?;\n\n    let bytes = import_code.as_bytes();\n    let mut pos = closing_brace_pos;\n    while pos > 0 {\n        pos -= 1;\n        let c = (*bytes.get(pos)?) as char;\n        if c.is_whitespace() {\n            continue;\n        }\n        if c == '{' {\n            break;\n        }\n        return Some((location.start as usize + pos, c));\n    }\n    None\n}\n"
  },
  {
    "path": "language-server/src/engine.rs",
    "content": "use camino::Utf8PathBuf;\nuse ecow::{EcoString, eco_format};\nuse gleam_core::{\n    Error, Result, Warning,\n    analyse::name::correct_name_case,\n    ast::{\n        self, Constant, CustomType, DefinitionLocation, ModuleConstant, PatternUnusedArguments,\n        SrcSpan, TypedArg, TypedClauseGuard, TypedConstant, TypedExpr, TypedFunction, TypedModule,\n        TypedPattern, TypedRecordConstructor,\n    },\n    build::{\n        ExpressionPosition, Located, Module, UnqualifiedImport, type_constructor_from_modules,\n    },\n    config::PackageConfig,\n    io::{BeamCompiler, CommandExecutor, FileSystemReader, FileSystemWriter},\n    line_numbers::LineNumbers,\n    paths::ProjectPaths,\n    type_::{\n        self, Deprecation, ModuleInterface, Type, TypeConstructor, ValueConstructor,\n        ValueConstructorVariant,\n        error::{Named, VariableSyntax},\n        printer::Printer,\n    },\n};\nuse itertools::Itertools;\nuse lsp::CodeAction;\nuse lsp_server::ResponseError;\nuse lsp_types::{\n    self as lsp, DocumentSymbol, FoldingRange, FoldingRangeKind, Hover, HoverContents,\n    MarkedString, Position, PrepareRenameResponse, Range, SignatureHelp, SymbolKind, SymbolTag,\n    TextEdit, Url, WorkspaceEdit,\n};\nuse std::{collections::HashSet, sync::Arc};\n\nuse crate::{code_action::ReplaceUnderscoreWithType, rename::rename_module_alias};\n\nuse super::{\n    DownloadDependencies, MakeLocker,\n    code_action::{\n        AddAnnotations, AddMissingTypeParameter, AddOmittedLabels, AnnotateTopLevelDefinitions,\n        CodeActionBuilder, CollapseNestedCase, ConvertFromUse, ConvertToFunctionCall,\n        ConvertToPipe, ConvertToUse, ExpandFunctionCapture, ExtractConstant, ExtractFunction,\n        ExtractVariable, FillInMissingLabelledArgs, FillUnusedFields, FixBinaryOperation,\n        FixTruncatedBitArraySegment, GenerateDynamicDecoder, GenerateFunction, GenerateJsonEncoder,\n        GenerateVariant, InlineVariable, InterpolateString, LetAssertToCase, MergeCaseBranches,\n        PatternMatchOnValue, RedundantTupleInCaseSubject, RemoveBlock, RemoveEchos,\n        RemovePrivateOpaque, RemoveUnreachableCaseClauses, RemoveUnusedImports,\n        UseLabelShorthandSyntax, WrapInBlock, code_action_add_missing_patterns,\n        code_action_convert_qualified_constructor_to_unqualified,\n        code_action_convert_unqualified_constructor_to_qualified, code_action_import_module,\n        code_action_inexhaustive_let_to_case,\n    },\n    compiler::LspProjectCompiler,\n    completer::Completer,\n    files::FileSystemProxy,\n    progress::ProgressReporter,\n    reference::{\n        FindVariableReferences, Referenced, VariableReferenceKind, find_module_references,\n        reference_for_ast_node,\n    },\n    rename::{RenameOutcome, RenameTarget, Renamed, rename_local_variable, rename_module_entity},\n    signature_help, src_span_to_lsp_range,\n};\n\n#[derive(Debug, PartialEq, Eq)]\npub struct Response<T> {\n    pub result: Result<T, Error>,\n    pub warnings: Vec<Warning>,\n    pub compilation: Compilation,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub enum Compilation {\n    /// Compilation was attempted and succeeded for these modules.\n    Yes(Vec<Utf8PathBuf>),\n    /// Compilation was not attempted for this operation.\n    No,\n}\n\n#[derive(Debug)]\npub struct LanguageServerEngine<IO, Reporter> {\n    pub(crate) paths: ProjectPaths,\n\n    /// A compiler for the project that supports repeat compilation of the root\n    /// package.\n    /// In the event the project config changes this will need to be\n    /// discarded and reloaded to handle any changes to dependencies.\n    pub(crate) compiler: LspProjectCompiler<FileSystemProxy<IO>>,\n\n    modules_compiled_since_last_feedback: Vec<Utf8PathBuf>,\n    compiled_since_last_feedback: bool,\n    error: Option<Error>,\n\n    // Used to publish progress notifications to the client without waiting for\n    // the usual request-response loop.\n    progress_reporter: Reporter,\n\n    /// Used to know if to show the \"View on HexDocs\" link\n    /// when hovering on an imported value\n    hex_deps: HashSet<EcoString>,\n}\n\nimpl<'a, IO, Reporter> LanguageServerEngine<IO, Reporter>\nwhere\n    // IO to be supplied from outside of gleam-core\n    IO: FileSystemReader\n        + FileSystemWriter\n        + BeamCompiler\n        + CommandExecutor\n        + DownloadDependencies\n        + MakeLocker\n        + Clone,\n    // IO to be supplied from inside of gleam-core\n    Reporter: ProgressReporter + Clone + 'a,\n{\n    pub fn new(\n        config: PackageConfig,\n        progress_reporter: Reporter,\n        io: FileSystemProxy<IO>,\n        paths: ProjectPaths,\n    ) -> Result<Self> {\n        let locker = io.inner().make_locker(&paths, config.target)?;\n\n        // Download dependencies to ensure they are up-to-date for this new\n        // configuration and new instance of the compiler\n        progress_reporter.dependency_downloading_started();\n        let manifest = io.inner().download_dependencies(&paths);\n        progress_reporter.dependency_downloading_finished();\n\n        // NOTE: This must come after the progress reporter has finished!\n        let manifest = manifest?;\n\n        let compiler: LspProjectCompiler<FileSystemProxy<IO>> =\n            LspProjectCompiler::new(manifest, config, paths.clone(), io.clone(), locker)?;\n\n        let hex_deps = compiler\n            .project_compiler\n            .packages\n            .iter()\n            .flat_map(|(k, v)| match &v.source {\n                gleam_core::manifest::ManifestPackageSource::Hex { .. } => {\n                    Some(EcoString::from(k.as_str()))\n                }\n\n                gleam_core::manifest::ManifestPackageSource::Git { .. }\n                | gleam_core::manifest::ManifestPackageSource::Local { .. } => None,\n            })\n            .collect();\n\n        Ok(Self {\n            modules_compiled_since_last_feedback: vec![],\n            compiled_since_last_feedback: false,\n            progress_reporter,\n            compiler,\n            paths,\n            error: None,\n            hex_deps,\n        })\n    }\n\n    pub fn compile_please(&mut self) -> Response<()> {\n        self.respond(Self::compile)\n    }\n\n    /// Compile the project if we are in one. Otherwise do nothing.\n    fn compile(&mut self) -> Result<(), Error> {\n        self.compiled_since_last_feedback = true;\n\n        self.progress_reporter.compilation_started();\n        let outcome = self.compiler.compile();\n        self.progress_reporter.compilation_finished();\n\n        let result = outcome\n            // Register which modules have changed\n            .map(|modules| self.modules_compiled_since_last_feedback.extend(modules))\n            // Return the error, if present\n            .into_result();\n\n        self.error = match &result {\n            Ok(_) => None,\n            Err(error) => Some(error.clone()),\n        };\n\n        result\n    }\n\n    fn take_warnings(&mut self) -> Vec<Warning> {\n        self.compiler.take_warnings()\n    }\n\n    // TODO: implement unqualified imported module functions\n    //\n    pub fn goto_definition(\n        &mut self,\n        params: lsp::GotoDefinitionParams,\n    ) -> Response<Option<lsp::Location>> {\n        self.respond(|this| {\n            let params = params.text_document_position_params;\n            let (line_numbers, node) = match this.node_at_position(&params) {\n                Some(location) => location,\n                None => return Ok(None),\n            };\n\n            let Some(location) =\n                node.definition_location(this.compiler.project_compiler.get_importable_modules())\n            else {\n                return Ok(None);\n            };\n\n            Ok(this.definition_location_to_lsp_location(&line_numbers, &params, location))\n        })\n    }\n\n    pub(crate) fn goto_type_definition(\n        &mut self,\n        params: lsp_types::GotoDefinitionParams,\n    ) -> Response<Vec<lsp::Location>> {\n        self.respond(|this| {\n            let params = params.text_document_position_params;\n            let (line_numbers, node) = match this.node_at_position(&params) {\n                Some(location) => location,\n                None => return Ok(vec![]),\n            };\n\n            let Some(locations) = node\n                .type_definition_locations(this.compiler.project_compiler.get_importable_modules())\n            else {\n                return Ok(vec![]);\n            };\n\n            let locations = locations\n                .into_iter()\n                .filter_map(|location| {\n                    this.definition_location_to_lsp_location(&line_numbers, &params, location)\n                })\n                .collect_vec();\n\n            Ok(locations)\n        })\n    }\n\n    fn definition_location_to_lsp_location(\n        &self,\n        line_numbers: &LineNumbers,\n        params: &lsp_types::TextDocumentPositionParams,\n        location: DefinitionLocation,\n    ) -> Option<lsp::Location> {\n        let (uri, line_numbers) = match location.module {\n            None => (params.text_document.uri.clone(), line_numbers),\n            Some(name) => {\n                let module = self.compiler.get_source(&name)?;\n                let url = Url::parse(&format!(\"file:///{}\", &module.path))\n                    .expect(\"goto definition URL parse\");\n                (url, &module.line_numbers)\n            }\n        };\n        let range = src_span_to_lsp_range(location.span, line_numbers);\n\n        Some(lsp::Location { uri, range })\n    }\n\n    pub fn completion(\n        &mut self,\n        params: lsp::TextDocumentPositionParams,\n        src: EcoString,\n    ) -> Response<Option<Vec<lsp::CompletionItem>>> {\n        self.respond(|this| {\n            let module = match this.module_for_uri(&params.text_document.uri) {\n                Some(m) => m,\n                None => return Ok(None),\n            };\n\n            let mut completer = Completer::new(&src, &params, &this.compiler, module);\n            let byte_index = completer.module_line_numbers.byte_index(params.position);\n\n            // If in comment context, do not provide completions\n            if module.extra.is_within_comment(byte_index) {\n                return Ok(None);\n            }\n\n            // Check current file contents if the user is writing an import\n            // and handle separately from the rest of the completion flow\n            // Check if an import is being written\n            if let Some(value) = completer.import_completions() {\n                return value;\n            }\n\n            let Some(found) = module.find_node(byte_index) else {\n                return Ok(None);\n            };\n\n            let completions = match found {\n                Located::PatternSpread { .. } => None,\n                Located::Pattern(_pattern) => None,\n                Located::StringPrefixPatternVariable { .. } => None,\n\n                // Do not show completions when typing inside a string.\n                Located::Expression {\n                    expression: TypedExpr::String { .. },\n                    ..\n                }\n                | Located::Constant(Constant::String { .. }) => None,\n                Located::Expression {\n                    expression:\n                        TypedExpr::Call { fun, arguments, .. }\n                        | TypedExpr::RecordUpdate {\n                            constructor: fun,\n                            arguments,\n                            ..\n                        },\n                    ..\n                } => {\n                    let mut completions = vec![];\n                    completions.append(&mut completer.completion_values());\n                    completions.append(&mut completer.completion_labels(fun, arguments));\n                    Some(completions)\n                }\n                Located::Expression {\n                    expression: TypedExpr::RecordAccess { record, type_, .. },\n                    ..\n                } => {\n                    completer.expected_type = Some(type_.clone());\n                    let mut completions = vec![];\n                    completions.append(&mut completer.completion_values());\n                    completions.append(&mut completer.completion_field_accessors(record.type_()));\n                    Some(completions)\n                }\n                Located::Expression {\n                    position:\n                        ExpressionPosition::ArgumentOrLabel {\n                            called_function,\n                            function_arguments,\n                        },\n                    ..\n                } => {\n                    let mut completions = vec![];\n                    completions.append(&mut completer.completion_values());\n                    completions.append(\n                        &mut completer.completion_labels(called_function, function_arguments),\n                    );\n                    Some(completions)\n                }\n                Located::Expression { expression, .. } => {\n                    completer.expected_type = Some(expression.type_());\n                    Some(completer.completion_values())\n                }\n                Located::ModuleFunction(_) => Some(completer.completion_types()),\n\n                Located::Statement(_) => Some(completer.completion_values()),\n\n                Located::FunctionBody(_) => Some(completer.completion_values()),\n\n                Located::ModuleTypeAlias(_)\n                | Located::ModuleCustomType(_)\n                | Located::VariantConstructorDefinition(_) => Some(completer.completion_types()),\n\n                // If the import completions returned no results and we are in an import then\n                // we should try to provide completions for unqualified values\n                Located::ModuleImport(import) => this\n                    .compiler\n                    .get_module_interface(import.module.as_str())\n                    .map(|importing_module| {\n                        completer.unqualified_completions_from_module(importing_module, true)\n                    }),\n\n                Located::ModuleConstant(_) | Located::Constant(_) => {\n                    Some(completer.completion_values())\n                }\n\n                Located::UnqualifiedImport(_) => None,\n\n                Located::Arg(_) => None,\n\n                Located::Annotation { .. } => Some(completer.completion_types()),\n\n                Located::Label(_, _) => None,\n\n                Located::ModuleName {\n                    layer: ast::Layer::Type,\n                    ..\n                } => Some(completer.completion_types()),\n                Located::ModuleName {\n                    layer: ast::Layer::Value,\n                    ..\n                } => Some(completer.completion_values()),\n\n                Located::ClauseGuard(_) => Some(completer.completion_values()),\n            };\n\n            Ok(completions)\n        })\n    }\n\n    pub fn code_actions(\n        &mut self,\n        params: lsp::CodeActionParams,\n    ) -> Response<Option<Vec<CodeAction>>> {\n        self.respond(|this| {\n            let mut actions = vec![];\n            let Some(module) = this.module_for_uri(&params.text_document.uri) else {\n                return Ok(None);\n            };\n\n            let lines = LineNumbers::new(&module.code);\n\n            code_action_unused_values(module, &lines, &params, &mut actions);\n            actions.extend(RemoveUnusedImports::new(module, &lines, &params).code_actions());\n            code_action_convert_qualified_constructor_to_unqualified(\n                module,\n                &this.compiler,\n                &lines,\n                &params,\n                &mut actions,\n            );\n            code_action_convert_unqualified_constructor_to_qualified(\n                module,\n                &lines,\n                &params,\n                &mut actions,\n            );\n            code_action_fix_names(&lines, &params, &this.error, &mut actions);\n            code_action_import_module(module, &lines, &params, &this.error, &mut actions);\n            code_action_add_missing_patterns(module, &lines, &params, &this.error, &mut actions);\n            actions\n                .extend(RemoveUnreachableCaseClauses::new(module, &lines, &params).code_actions());\n            actions.extend(CollapseNestedCase::new(module, &lines, &params).code_actions());\n            code_action_inexhaustive_let_to_case(\n                module,\n                &lines,\n                &params,\n                &this.error,\n                &mut actions,\n            );\n            actions.extend(MergeCaseBranches::new(module, &lines, &params).code_actions());\n            actions.extend(FixBinaryOperation::new(module, &lines, &params).code_actions());\n            actions\n                .extend(FixTruncatedBitArraySegment::new(module, &lines, &params).code_actions());\n            actions.extend(LetAssertToCase::new(module, &lines, &params).code_actions());\n            actions\n                .extend(RedundantTupleInCaseSubject::new(module, &lines, &params).code_actions());\n            actions.extend(UseLabelShorthandSyntax::new(module, &lines, &params).code_actions());\n            actions.extend(FillInMissingLabelledArgs::new(module, &lines, &params).code_actions());\n            actions.extend(ConvertFromUse::new(module, &lines, &params).code_actions());\n            actions.extend(RemoveEchos::new(module, &lines, &params).code_actions());\n            actions.extend(ConvertToUse::new(module, &lines, &params).code_actions());\n            actions.extend(ExpandFunctionCapture::new(module, &lines, &params).code_actions());\n            actions.extend(FillUnusedFields::new(module, &lines, &params).code_actions());\n            actions.extend(InterpolateString::new(module, &lines, &params).code_actions());\n            actions.extend(ExtractVariable::new(module, &lines, &params).code_actions());\n            actions.extend(ExtractConstant::new(module, &lines, &params).code_actions());\n            actions.extend(\n                GenerateFunction::new(module, &this.compiler.modules, &lines, &params)\n                    .code_actions(),\n            );\n            actions.extend(\n                GenerateVariant::new(module, &this.compiler, &lines, &params).code_actions(),\n            );\n            actions.extend(ConvertToPipe::new(module, &lines, &params).code_actions());\n            actions.extend(ConvertToFunctionCall::new(module, &lines, &params).code_actions());\n            actions.extend(\n                PatternMatchOnValue::new(module, &lines, &params, &this.compiler).code_actions(),\n            );\n            actions.extend(AddOmittedLabels::new(module, &lines, &params).code_actions());\n            actions.extend(InlineVariable::new(module, &lines, &params).code_actions());\n            actions.extend(WrapInBlock::new(module, &lines, &params).code_actions());\n            actions.extend(RemoveBlock::new(module, &lines, &params).code_actions());\n            actions.extend(RemovePrivateOpaque::new(module, &lines, &params).code_actions());\n            actions.extend(ExtractFunction::new(module, &lines, &params).code_actions());\n            GenerateDynamicDecoder::new(module, &lines, &params, &mut actions, &this.compiler)\n                .code_actions();\n            GenerateJsonEncoder::new(\n                module,\n                &lines,\n                &params,\n                &mut actions,\n                &this.compiler.project_compiler.config,\n            )\n            .code_actions();\n            AddAnnotations::new(module, &lines, &params).code_action(&mut actions);\n            actions\n                .extend(AnnotateTopLevelDefinitions::new(module, &lines, &params).code_actions());\n            actions.extend(AddMissingTypeParameter::new(module, &lines, &params).code_actions());\n            actions.extend(ReplaceUnderscoreWithType::new(module, &lines, &params).code_actions());\n            Ok(if actions.is_empty() {\n                None\n            } else {\n                Some(actions)\n            })\n        })\n    }\n\n    pub fn document_symbol(\n        &mut self,\n        params: lsp::DocumentSymbolParams,\n    ) -> Response<Vec<DocumentSymbol>> {\n        self.respond(|this| {\n            let mut symbols = vec![];\n            let Some(module) = this.module_for_uri(&params.text_document.uri) else {\n                return Ok(symbols);\n            };\n            let line_numbers = LineNumbers::new(&module.code);\n\n            for function in &module.ast.definitions.functions {\n                // By default, the function's location ends right after the return type.\n                // For the full symbol range, have it end at the end of the body.\n                // Also include the documentation, if available.\n                //\n                // By convention, the symbol span starts from the leading slash in the\n                // documentation comment's marker ('///'), not from its content (of which\n                // we have the position), so we must convert the content start position\n                // to the leading slash's position.\n                let full_function_span = SrcSpan {\n                    start: function\n                        .documentation\n                        .as_ref()\n                        .map(|(doc_start, _)| get_doc_marker_position(*doc_start))\n                        .unwrap_or(function.location.start),\n\n                    end: function.end_position,\n                };\n\n                let (name_location, name) = function\n                    .name\n                    .as_ref()\n                    .expect(\"Function in a definition must be named\");\n\n                // The 'deprecated' field is deprecated, but we have to specify it anyway\n                // to be able to construct the 'DocumentSymbol' type, so\n                // we suppress the warning. We specify 'None' as specifying 'Some'\n                // is what is actually deprecated.\n                #[allow(deprecated)]\n                symbols.push(DocumentSymbol {\n                    name: name.to_string(),\n                    detail: Some(\n                        Printer::new(&module.ast.names)\n                            .print_type(&get_function_type(function))\n                            .to_string(),\n                    ),\n                    kind: SymbolKind::FUNCTION,\n                    tags: make_deprecated_symbol_tag(&function.deprecation),\n                    deprecated: None,\n                    range: src_span_to_lsp_range(full_function_span, &line_numbers),\n                    selection_range: src_span_to_lsp_range(*name_location, &line_numbers),\n                    children: None,\n                });\n            }\n\n            for alias in &module.ast.definitions.type_aliases {\n                let full_alias_span = match alias.documentation {\n                    Some((doc_position, _)) => {\n                        SrcSpan::new(get_doc_marker_position(doc_position), alias.location.end)\n                    }\n                    None => alias.location,\n                };\n\n                // The 'deprecated' field is deprecated, but we have to specify it anyway\n                // to be able to construct the 'DocumentSymbol' type, so\n                // we suppress the warning. We specify 'None' as specifying 'Some'\n                // is what is actually deprecated.\n                #[allow(deprecated)]\n                symbols.push(DocumentSymbol {\n                    name: alias.alias.to_string(),\n                    detail: Some(\n                        Printer::new(&module.ast.names)\n                            // If we print with aliases, we end up printing the alias which the user\n                            // is currently hovering, which is not helpful. Instead, we print the\n                            // raw type, so the user can see which type the alias represents\n                            .print_type_without_aliases(&alias.type_)\n                            .to_string(),\n                    ),\n                    kind: SymbolKind::CLASS,\n                    tags: make_deprecated_symbol_tag(&alias.deprecation),\n                    deprecated: None,\n                    range: src_span_to_lsp_range(full_alias_span, &line_numbers),\n                    selection_range: src_span_to_lsp_range(alias.name_location, &line_numbers),\n                    children: None,\n                });\n            }\n\n            for custom_type in &module.ast.definitions.custom_types {\n                symbols.push(custom_type_symbol(custom_type, &line_numbers, module));\n            }\n\n            for constant in &module.ast.definitions.constants {\n                // `ModuleConstant.location` ends at the constant's name or type.\n                // For the full symbol span, necessary for `range`, we need to\n                // include the constant value as well.\n                // Also include the documentation at the start, if available.\n                let full_constant_span = SrcSpan {\n                    start: constant\n                        .documentation\n                        .as_ref()\n                        .map(|(doc_start, _)| get_doc_marker_position(*doc_start))\n                        .unwrap_or(constant.location.start),\n\n                    end: constant.value.location().end,\n                };\n\n                // The 'deprecated' field is deprecated, but we have to specify it anyway\n                // to be able to construct the 'DocumentSymbol' type, so\n                // we suppress the warning. We specify 'None' as specifying 'Some'\n                // is what is actually deprecated.\n                #[allow(deprecated)]\n                symbols.push(DocumentSymbol {\n                    name: constant.name.to_string(),\n                    detail: Some(\n                        Printer::new(&module.ast.names)\n                            .print_type(&constant.type_)\n                            .to_string(),\n                    ),\n                    kind: SymbolKind::CONSTANT,\n                    tags: make_deprecated_symbol_tag(&constant.deprecation),\n                    deprecated: None,\n                    range: src_span_to_lsp_range(full_constant_span, &line_numbers),\n                    selection_range: src_span_to_lsp_range(constant.name_location, &line_numbers),\n                    children: None,\n                });\n            }\n\n            Ok(symbols)\n        })\n    }\n\n    pub fn folding_range(\n        &mut self,\n        params: lsp::FoldingRangeParams,\n    ) -> Response<Vec<FoldingRange>> {\n        self.respond(|this| {\n            let mut ranges: Vec<FoldingRange> = vec![];\n            let Some(module) = this.module_for_uri(&params.text_document.uri) else {\n                return Ok(vec![]);\n            };\n\n            let line_numbers = LineNumbers::new(&module.code);\n\n            for import in\n                import_folding_spans(&module.ast.definitions.imports, &module.code, &line_numbers)\n            {\n                let Some(range) =\n                    folding_range_for_span(import, &line_numbers, Some(FoldingRangeKind::Imports))\n                else {\n                    continue;\n                };\n\n                ranges.push(range);\n            }\n\n            for type_ in &module.ast.definitions.custom_types {\n                let span = type_.full_location();\n                let Some(range) = folding_range_for_span(span, &line_numbers, None) else {\n                    continue;\n                };\n                ranges.push(range);\n            }\n\n            for constant in &module.ast.definitions.constants {\n                let span = SrcSpan::new(constant.location.start, constant.value.location().end);\n                let Some(range) = folding_range_for_span(span, &line_numbers, None) else {\n                    continue;\n                };\n                ranges.push(range);\n            }\n\n            for alias in &module.ast.definitions.type_aliases {\n                let span = alias.location;\n                let Some(range) = folding_range_for_span(span, &line_numbers, None) else {\n                    continue;\n                };\n                ranges.push(range);\n            }\n\n            for function in &module.ast.definitions.functions {\n                let Some(body_start) = function.body_start else {\n                    continue;\n                };\n\n                let span = SrcSpan::new(body_start, function.end_position);\n                let Some(range) = folding_range_for_span(span, &line_numbers, None) else {\n                    continue;\n                };\n                ranges.push(range);\n            }\n\n            ranges.sort_by_key(|range| range.start_line);\n            Ok(ranges)\n        })\n    }\n\n    /// Check whether a particular module is in the same package as this one\n    fn is_same_package(&self, current_module: &Module, module_name: &str) -> bool {\n        let other_module = self\n            .compiler\n            .project_compiler\n            .get_importable_modules()\n            .get(module_name);\n        match other_module {\n            // We can't rename values from other packages if we are not aliasing an unqualified import.\n            Some(module) => module.package == current_module.ast.type_info.package,\n            None => false,\n        }\n    }\n\n    pub fn prepare_rename(\n        &mut self,\n        params: lsp::TextDocumentPositionParams,\n    ) -> Response<Option<PrepareRenameResponse>> {\n        self.respond(|this| {\n            let (lines, found) = match this.node_at_position(&params) {\n                Some(value) => value,\n                None => return Ok(None),\n            };\n\n            let Some(current_module) = this.module_for_uri(&params.text_document.uri) else {\n                return Ok(None);\n            };\n\n            let success_response = |location| {\n                Some(PrepareRenameResponse::Range(src_span_to_lsp_range(\n                    location, &lines,\n                )))\n            };\n\n            let byte_index = lines.byte_index(params.position);\n\n            let referenced = reference_for_ast_node(found, &current_module.name);\n\n            Ok(match referenced {\n                Some(Referenced::LocalVariable {\n                    location, origin, ..\n                }) if location.contains(byte_index) => match origin.map(|origin| origin.syntax) {\n                    Some(VariableSyntax::Generated) => None,\n                    Some(\n                        VariableSyntax::Variable(label) | VariableSyntax::LabelShorthand(label),\n                    ) => success_response(SrcSpan {\n                        start: location.start,\n                        end: label\n                            .len()\n                            .try_into()\n                            .map(|len: u32| location.start + len)\n                            .unwrap_or(location.end),\n                    }),\n                    Some(VariableSyntax::AssignmentPattern) | None => success_response(location),\n                },\n                Some(\n                    Referenced::ModuleValue {\n                        module,\n                        location,\n                        target_kind,\n                        ..\n                    }\n                    | Referenced::ModuleType {\n                        module,\n                        location,\n                        target_kind,\n                        ..\n                    },\n                ) if location.contains(byte_index) => {\n                    // We can't rename types or values from other packages if we are not aliasing an unqualified import.\n                    let rename_allowed = match target_kind {\n                        RenameTarget::Qualified => this.is_same_package(current_module, &module),\n                        RenameTarget::Unqualified | RenameTarget::Definition => true,\n                    };\n                    if rename_allowed {\n                        success_response(location)\n                    } else {\n                        None\n                    }\n                }\n                Some(Referenced::ModuleName { location, .. }) => success_response(location),\n\n                _ => None,\n            })\n        })\n    }\n\n    pub fn rename(\n        &mut self,\n        params: lsp::RenameParams,\n    ) -> Response<Result<Option<WorkspaceEdit>, ResponseError>> {\n        self.respond(|this| {\n            let position = &params.text_document_position;\n\n            let (lines, found) = match this.node_at_position(position) {\n                Some(value) => value,\n                None => return Ok(RenameOutcome::NoRenames.into_result()),\n            };\n\n            let Some(module) = this.module_for_uri(&position.text_document.uri) else {\n                return Ok(RenameOutcome::NoRenames.into_result());\n            };\n\n            let referenced = reference_for_ast_node(found, &module.name);\n\n            Ok(match referenced {\n                Some(Referenced::LocalVariable {\n                    origin,\n                    definition_location,\n                    name,\n                    ..\n                }) => {\n                    let rename_kind = match origin.map(|origin| origin.syntax) {\n                        Some(VariableSyntax::Generated) => {\n                            return Ok(RenameOutcome::NoRenames.into_result());\n                        }\n                        Some(VariableSyntax::LabelShorthand(_)) => {\n                            VariableReferenceKind::LabelShorthand\n                        }\n                        Some(\n                            VariableSyntax::AssignmentPattern | VariableSyntax::Variable { .. },\n                        )\n                        | None => VariableReferenceKind::Variable,\n                    };\n                    rename_local_variable(\n                        module,\n                        &lines,\n                        &params,\n                        definition_location,\n                        name,\n                        rename_kind,\n                    )\n                    .into_result()\n                }\n                Some(Referenced::ModuleValue {\n                    module: module_name,\n                    target_kind,\n                    name,\n                    name_kind,\n                    ..\n                }) => rename_module_entity(\n                    &params,\n                    module,\n                    this.compiler.project_compiler.get_importable_modules(),\n                    &this.compiler.sources,\n                    Renamed {\n                        module_name: &module_name,\n                        name: &name,\n                        name_kind,\n                        target_kind,\n                        layer: ast::Layer::Value,\n                    },\n                )\n                .into_result(),\n\n                Some(Referenced::ModuleType {\n                    module: module_name,\n                    target_kind,\n                    name,\n                    ..\n                }) => rename_module_entity(\n                    &params,\n                    module,\n                    this.compiler.project_compiler.get_importable_modules(),\n                    &this.compiler.sources,\n                    Renamed {\n                        module_name: &module_name,\n                        name: &name,\n                        name_kind: Named::Type,\n                        target_kind,\n                        layer: ast::Layer::Type,\n                    },\n                )\n                .into_result(),\n\n                Some(Referenced::ModuleName {\n                    module_name,\n                    module_alias,\n                    ..\n                }) => rename_module_alias(module, &lines, &params, &module_name, &module_alias)\n                    .into_result(),\n\n                None => RenameOutcome::NoRenames.into_result(),\n            })\n        })\n    }\n\n    pub fn find_references(\n        &mut self,\n        params: lsp::ReferenceParams,\n    ) -> Response<Option<Vec<lsp::Location>>> {\n        self.respond(|this| {\n            let position = &params.text_document_position;\n\n            let (lines, found) = match this.node_at_position(position) {\n                Some(value) => value,\n                None => return Ok(None),\n            };\n\n            let uri = position.text_document.uri.clone();\n\n            let Some(module) = this.module_for_uri(&uri) else {\n                return Ok(None);\n            };\n\n            let byte_index = lines.byte_index(position.position);\n\n            let referenced = reference_for_ast_node(found, &module.name);\n\n            Ok(match referenced {\n                Some(Referenced::LocalVariable {\n                    origin,\n                    definition_location,\n                    location,\n                    name,\n                }) if location.contains(byte_index) => match origin.map(|origin| origin.syntax) {\n                    Some(VariableSyntax::Generated) => None,\n                    Some(\n                        VariableSyntax::LabelShorthand(_)\n                        | VariableSyntax::AssignmentPattern\n                        | VariableSyntax::Variable { .. },\n                    )\n                    | None => {\n                        let variable_references =\n                            FindVariableReferences::new(definition_location, name)\n                                .find_in_module(&module.ast);\n\n                        let mut reference_locations =\n                            Vec::with_capacity(variable_references.len() + 1);\n                        reference_locations.push(lsp::Location {\n                            uri: uri.clone(),\n                            range: src_span_to_lsp_range(definition_location, &lines),\n                        });\n\n                        for reference in variable_references {\n                            reference_locations.push(lsp::Location {\n                                uri: uri.clone(),\n                                range: src_span_to_lsp_range(reference.location, &lines),\n                            })\n                        }\n\n                        Some(reference_locations)\n                    }\n                },\n                Some(Referenced::ModuleValue {\n                    module,\n                    name,\n                    location,\n                    ..\n                }) if location.contains(byte_index) => Some(find_module_references(\n                    module,\n                    name,\n                    this.compiler.project_compiler.get_importable_modules(),\n                    &this.compiler.sources,\n                    ast::Layer::Value,\n                )),\n                Some(Referenced::ModuleType {\n                    module,\n                    name,\n                    location,\n                    ..\n                }) if location.contains(byte_index) => Some(find_module_references(\n                    module,\n                    name,\n                    this.compiler.project_compiler.get_importable_modules(),\n                    &this.compiler.sources,\n                    ast::Layer::Type,\n                )),\n                _ => None,\n            })\n        })\n    }\n\n    fn respond<T>(&mut self, handler: impl FnOnce(&mut Self) -> Result<T>) -> Response<T> {\n        let result = handler(self);\n        let warnings = self.take_warnings();\n        // TODO: test. Ensure hover doesn't report as compiled\n        let compilation = if self.compiled_since_last_feedback {\n            let modules = std::mem::take(&mut self.modules_compiled_since_last_feedback);\n            self.compiled_since_last_feedback = false;\n            Compilation::Yes(modules)\n        } else {\n            Compilation::No\n        };\n        Response {\n            result,\n            warnings,\n            compilation,\n        }\n    }\n\n    pub fn hover(&mut self, params: lsp::HoverParams) -> Response<Option<Hover>> {\n        self.respond(|this| {\n            let params = params.text_document_position_params;\n\n            let (lines, found) = match this.node_at_position(&params) {\n                Some(value) => value,\n                None => return Ok(None),\n            };\n\n            let Some(module) = this.module_for_uri(&params.text_document.uri) else {\n                return Ok(None);\n            };\n\n            Ok(match found {\n                Located::Statement(_) => None, // TODO: hover for statement\n                Located::ModuleFunction(function) => {\n                    Some(hover_for_function_head(function, lines, module))\n                }\n                Located::ModuleConstant(constant) => {\n                    Some(hover_for_module_constant(constant, lines, module))\n                }\n                Located::Constant(constant) => Some(hover_for_constant(constant, lines, module)),\n                Located::ModuleImport(import) => {\n                    let Some(module) = this.compiler.get_module_interface(&import.module) else {\n                        return Ok(None);\n                    };\n                    Some(hover_for_module(\n                        module,\n                        import.location,\n                        &lines,\n                        &this.hex_deps,\n                    ))\n                }\n                Located::ModuleCustomType(custom_type) => {\n                    Some(hover_for_custom_type(custom_type, lines))\n                }\n                Located::ModuleTypeAlias(_) => None,\n                Located::VariantConstructorDefinition(constructor) => {\n                    Some(hover_for_constructor(constructor, lines, module))\n                }\n                Located::UnqualifiedImport(UnqualifiedImport {\n                    name,\n                    module: module_name,\n                    is_type,\n                    location,\n                }) => this\n                    .compiler\n                    .get_module_interface(module_name.as_str())\n                    .and_then(|module_interface| {\n                        if is_type {\n                            module_interface.types.get(name).map(|constructor| {\n                                hover_for_annotation(\n                                    *location,\n                                    constructor.type_.as_ref(),\n                                    Some(constructor),\n                                    lines,\n                                    module,\n                                )\n                            })\n                        } else {\n                            module_interface.values.get(name).map(|v| {\n                                let m = if this.hex_deps.contains(&module_interface.package) {\n                                    Some(module_interface)\n                                } else {\n                                    None\n                                };\n                                hover_for_imported_value(v, location, lines, m, name, module)\n                            })\n                        }\n                    }),\n                Located::Pattern(pattern) => Some(hover_for_pattern(pattern, lines, module)),\n                Located::PatternSpread {\n                    spread_location,\n                    pattern,\n                } => {\n                    let range = Some(src_span_to_lsp_range(spread_location, &lines));\n\n                    let mut printer = Printer::new(&module.ast.names);\n\n                    let PatternUnusedArguments {\n                        positional,\n                        labelled,\n                    } = pattern.unused_arguments().unwrap_or_default();\n\n                    let positional = positional\n                        .iter()\n                        .map(|type_| format!(\"- `{}`\", printer.print_type(type_)))\n                        .join(\"\\n\");\n                    let labelled = labelled\n                        .iter()\n                        .map(|(label, type_)| {\n                            format!(\"- `{}: {}`\", label, printer.print_type(type_))\n                        })\n                        .join(\"\\n\");\n\n                    let content = match (positional.is_empty(), labelled.is_empty()) {\n                        (true, false) => format!(\"Unused labelled fields:\\n{labelled}\"),\n                        (false, true) => format!(\"Unused positional fields:\\n{positional}\"),\n                        (_, _) => format!(\n                            \"Unused positional fields:\n{positional}\n\nUnused labelled fields:\n{labelled}\"\n                        ),\n                    };\n\n                    Some(Hover {\n                        contents: HoverContents::Scalar(MarkedString::from_markdown(content)),\n                        range,\n                    })\n                }\n                Located::StringPrefixPatternVariable { location, .. } => Some(\n                    hover_for_string_prefix_pattern_variable(location, &lines, module),\n                ),\n                Located::Expression { expression, .. } => Some(hover_for_expression(\n                    expression,\n                    lines,\n                    module,\n                    &this.hex_deps,\n                )),\n                Located::Arg(arg) => Some(hover_for_function_argument(arg, lines, module)),\n                Located::FunctionBody(_) => None,\n                Located::Annotation { ast, type_ } => {\n                    let type_constructor = type_constructor_from_modules(\n                        this.compiler.project_compiler.get_importable_modules(),\n                        type_.clone(),\n                    );\n                    Some(hover_for_annotation(\n                        ast.location(),\n                        &type_,\n                        type_constructor,\n                        lines,\n                        module,\n                    ))\n                }\n                Located::Label(location, type_) => {\n                    Some(hover_for_label(location, type_, lines, module))\n                }\n                Located::ModuleName {\n                    location,\n                    module_name,\n                    ..\n                } => {\n                    let Some(module) = this.compiler.get_module_interface(&module_name) else {\n                        return Ok(None);\n                    };\n                    Some(hover_for_module(module, location, &lines, &this.hex_deps))\n                }\n\n                Located::ClauseGuard(guard) => Some(hover_for_clause_guard(guard, lines, module)),\n            })\n        })\n    }\n\n    pub(crate) fn signature_help(\n        &mut self,\n        params: lsp_types::SignatureHelpParams,\n    ) -> Response<Option<SignatureHelp>> {\n        self.respond(|this| {\n            let Some(module) =\n                this.module_for_uri(&params.text_document_position_params.text_document.uri)\n            else {\n                return Ok(None);\n            };\n\n            match this.node_at_position(&params.text_document_position_params) {\n                Some((_lines, Located::Expression { expression, .. })) => {\n                    Ok(signature_help::for_expression(expression, module))\n                }\n                Some((_lines, _located)) => Ok(None),\n                None => Ok(None),\n            }\n        })\n    }\n\n    fn module_node_at_position(\n        &self,\n        params: &lsp::TextDocumentPositionParams,\n        module: &'a Module,\n    ) -> Option<(LineNumbers, Located<'a>)> {\n        let line_numbers = LineNumbers::new(&module.code);\n        let byte_index = line_numbers.byte_index(params.position);\n        let node = module.find_node(byte_index);\n        let node = node?;\n        Some((line_numbers, node))\n    }\n\n    fn node_at_position(\n        &self,\n        params: &lsp::TextDocumentPositionParams,\n    ) -> Option<(LineNumbers, Located<'_>)> {\n        let module = self.module_for_uri(&params.text_document.uri)?;\n        self.module_node_at_position(params, module)\n    }\n\n    fn module_for_uri(&self, uri: &Url) -> Option<&Module> {\n        // The to_file_path method is available on these platforms\n        #[cfg(any(unix, windows, target_os = \"redox\", target_os = \"wasi\"))]\n        let path = uri.to_file_path().expect(\"URL file\");\n\n        #[cfg(not(any(unix, windows, target_os = \"redox\", target_os = \"wasi\")))]\n        let path: Utf8PathBuf = uri.path().into();\n\n        let components = path\n            .strip_prefix(self.paths.root())\n            .ok()?\n            .components()\n            .skip(1)\n            .map(|c| c.as_os_str().to_string_lossy());\n        let module_name: EcoString = Itertools::intersperse(components, \"/\".into())\n            .collect::<String>()\n            .strip_suffix(\".gleam\")?\n            .into();\n\n        self.compiler.modules.get(&module_name)\n    }\n}\n\nfn import_folding_spans(\n    imports: &[ast::Import<EcoString>],\n    code: &str,\n    line_numbers: &LineNumbers,\n) -> Vec<SrcSpan> {\n    let mut spans = vec![];\n    let mut imports = imports.iter();\n\n    let Some(first_import) = imports.next() else {\n        return spans;\n    };\n\n    let mut previous_line = src_span_to_lsp_range(\n        SrcSpan::new(first_import.location.start, first_import.location.start),\n        line_numbers,\n    )\n    .start\n    .line;\n    let mut current_start = first_import.location.start;\n    let mut current_end = first_import.location.end;\n    let mut current_len = 1;\n\n    for import in imports {\n        let next_line = src_span_to_lsp_range(\n            SrcSpan::new(import.location.start, import.location.start),\n            line_numbers,\n        )\n        .start\n        .line;\n        let separated_by_blank_line = next_line > previous_line + 1;\n        let between = &code[current_end as usize..import.location.start as usize];\n        let has_non_whitespace_between = between.chars().any(|char| !char.is_whitespace());\n\n        if separated_by_blank_line || has_non_whitespace_between {\n            if current_len > 1 {\n                spans.push(SrcSpan::new(current_start, current_end));\n            }\n            current_start = import.location.start;\n            current_end = import.location.end;\n            current_len = 1;\n        } else {\n            current_end = import.location.end;\n            current_len += 1;\n        }\n\n        previous_line = next_line;\n    }\n\n    if current_len > 1 {\n        spans.push(SrcSpan::new(current_start, current_end));\n    }\n\n    spans\n}\n\nfn folding_range_for_span(\n    span: SrcSpan,\n    line_numbers: &LineNumbers,\n    kind: Option<FoldingRangeKind>,\n) -> Option<FoldingRange> {\n    let range = src_span_to_lsp_range(span, line_numbers);\n\n    if range.start.line >= range.end.line {\n        return None;\n    }\n\n    Some(FoldingRange {\n        start_line: range.start.line,\n        start_character: None,\n        end_line: range.end.line,\n        end_character: None,\n        kind,\n        collapsed_text: None,\n    })\n}\n\nfn custom_type_symbol(\n    type_: &CustomType<Arc<Type>>,\n    line_numbers: &LineNumbers,\n    module: &Module,\n) -> DocumentSymbol {\n    let constructors = type_\n        .constructors\n        .iter()\n        .map(|constructor| {\n            let mut arguments = vec![];\n\n            // List named arguments as field symbols.\n            for argument in &constructor.arguments {\n                let Some((label_location, label)) = &argument.label else {\n                    continue;\n                };\n\n                let full_arg_span = match argument.doc {\n                    Some((doc_position, _)) => {\n                        SrcSpan::new(get_doc_marker_position(doc_position), argument.location.end)\n                    }\n                    None => argument.location,\n                };\n\n                // The 'deprecated' field is deprecated, but we have to specify it anyway\n                // to be able to construct the 'DocumentSymbol' type, so\n                // we suppress the warning. We specify 'None' as specifying 'Some'\n                // is what is actually deprecated.\n                #[allow(deprecated)]\n                arguments.push(DocumentSymbol {\n                    name: label.to_string(),\n                    detail: Some(\n                        Printer::new(&module.ast.names)\n                            .print_type(&argument.type_)\n                            .to_string(),\n                    ),\n                    kind: SymbolKind::FIELD,\n                    tags: None,\n                    deprecated: None,\n                    range: src_span_to_lsp_range(full_arg_span, line_numbers),\n                    selection_range: src_span_to_lsp_range(*label_location, line_numbers),\n                    children: None,\n                });\n            }\n\n            // Start from the documentation if available, otherwise from the constructor's name,\n            // all the way to the end of its arguments.\n            let full_constructor_span = SrcSpan {\n                start: constructor\n                    .documentation\n                    .as_ref()\n                    .map(|(doc_start, _)| get_doc_marker_position(*doc_start))\n                    .unwrap_or(constructor.location.start),\n\n                end: constructor.location.end,\n            };\n\n            // The 'deprecated' field is deprecated, but we have to specify it anyway\n            // to be able to construct the 'DocumentSymbol' type, so\n            // we suppress the warning. We specify 'None' as specifying 'Some'\n            // is what is actually deprecated.\n            #[allow(deprecated)]\n            DocumentSymbol {\n                name: constructor.name.to_string(),\n                detail: None,\n                kind: if constructor.arguments.is_empty() {\n                    SymbolKind::ENUM_MEMBER\n                } else {\n                    SymbolKind::CONSTRUCTOR\n                },\n                tags: make_deprecated_symbol_tag(&constructor.deprecation),\n                deprecated: None,\n                range: src_span_to_lsp_range(full_constructor_span, line_numbers),\n                selection_range: src_span_to_lsp_range(constructor.name_location, line_numbers),\n                children: if arguments.is_empty() {\n                    None\n                } else {\n                    Some(arguments)\n                },\n            }\n        })\n        .collect_vec();\n\n    // The type's location, by default, ranges from \"(pub) type\" to the end of its name.\n    // We need it to range to the end of its constructors instead for the full symbol range.\n    // We also include documentation, if available, by LSP convention.\n    let full_type_span = SrcSpan {\n        start: type_\n            .documentation\n            .as_ref()\n            .map(|(doc_start, _)| get_doc_marker_position(*doc_start))\n            .unwrap_or(type_.location.start),\n\n        end: type_.end_position,\n    };\n\n    // The 'deprecated' field is deprecated, but we have to specify it anyway\n    // to be able to construct the 'DocumentSymbol' type, so\n    // we suppress the warning. We specify 'None' as specifying 'Some'\n    // is what is actually deprecated.\n    #[allow(deprecated)]\n    DocumentSymbol {\n        name: type_.name.to_string(),\n        detail: None,\n        kind: SymbolKind::CLASS,\n        tags: make_deprecated_symbol_tag(&type_.deprecation),\n        deprecated: None,\n        range: src_span_to_lsp_range(full_type_span, line_numbers),\n        selection_range: src_span_to_lsp_range(type_.name_location, line_numbers),\n        children: if constructors.is_empty() {\n            None\n        } else {\n            Some(constructors)\n        },\n    }\n}\n\nfn hover_for_pattern(pattern: &TypedPattern, line_numbers: LineNumbers, module: &Module) -> Hover {\n    let documentation = pattern.get_documentation().unwrap_or_default();\n\n    // Show the type of the hovered node to the user\n    let type_ = Printer::new(&module.ast.names).print_type(pattern.type_().as_ref());\n    let contents = format!(\n        \"```gleam\n{type_}\n```\n{documentation}\"\n    );\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(pattern.location(), &line_numbers)),\n    }\n}\n\nfn get_function_type(fun: &TypedFunction) -> Type {\n    Type::Fn {\n        arguments: fun\n            .arguments\n            .iter()\n            .map(|argument| argument.type_.clone())\n            .collect(),\n        return_: fun.return_type.clone(),\n    }\n}\n\nfn hover_for_function_head(\n    fun: &TypedFunction,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let empty_str = EcoString::from(\"\");\n    let documentation = fun\n        .documentation\n        .as_ref()\n        .map(|(_, doc)| doc)\n        .unwrap_or(&empty_str);\n    let function_type = get_function_type(fun);\n    let formatted_type = Printer::new(&module.ast.names).print_type(&function_type);\n    let contents = format!(\n        \"```gleam\n{formatted_type}\n```\n{documentation}\"\n    );\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(fun.location, &line_numbers)),\n    }\n}\n\nfn hover_for_function_argument(\n    argument: &TypedArg,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let type_ = Printer::new(&module.ast.names).print_type(&argument.type_);\n    let contents = format!(\"```gleam\\n{type_}\\n```\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(argument.location, &line_numbers)),\n    }\n}\n\nfn hover_for_annotation(\n    location: SrcSpan,\n    annotation_type: &Type,\n    type_constructor: Option<&TypeConstructor>,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let empty_str = EcoString::from(\"\");\n    let documentation = type_constructor\n        .and_then(|constructor| constructor.documentation.as_ref())\n        .unwrap_or(&empty_str);\n    // If a user is hovering an annotation, it's not very useful to show the\n    // local representation of that type, since that's probably what they see\n    // in the source code anyway. So here, we print the raw type,\n    // which is probably more helpful.\n    let type_ = Printer::new(&module.ast.names).print_type_without_aliases(annotation_type);\n    let contents = format!(\n        \"```gleam\n{type_}\n```\n{documentation}\"\n    );\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(location, &line_numbers)),\n    }\n}\n\nfn hover_for_label(\n    location: SrcSpan,\n    type_: Arc<Type>,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let type_ = Printer::new(&module.ast.names).print_type(&type_);\n    let contents = format!(\"```gleam\\n{type_}\\n```\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(location, &line_numbers)),\n    }\n}\n\nfn hover_for_module_constant(\n    constant: &ModuleConstant<Arc<Type>, EcoString>,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let empty_str = EcoString::from(\"\");\n    let type_ = Printer::new(&module.ast.names).print_type(&constant.type_);\n    let documentation = constant\n        .documentation\n        .as_ref()\n        .map(|(_, doc)| doc)\n        .unwrap_or(&empty_str);\n    let contents = format!(\"```gleam\\n{type_}\\n```\\n{documentation}\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(constant.location, &line_numbers)),\n    }\n}\n\nfn hover_for_constant(\n    constant: &TypedConstant,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let type_ = Printer::new(&module.ast.names).print_type(&constant.type_());\n    let contents = format!(\"```gleam\\n{type_}\\n```\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(constant.location(), &line_numbers)),\n    }\n}\n\nfn hover_for_clause_guard(\n    guard: &TypedClauseGuard,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let type_ = Printer::new(&module.ast.names).print_type(&guard.type_());\n    let contents = format!(\"```gleam\\n{type_}\\n```\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(guard.location(), &line_numbers)),\n    }\n}\n\nfn hover_for_string_prefix_pattern_variable(\n    location: SrcSpan,\n    lines: &LineNumbers,\n    module: &Module,\n) -> Hover {\n    let type_ = Printer::new(&module.ast.names).print_type(&type_::string());\n    let contents = format!(\"```gleam\\n{type_}\\n```\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(location, lines)),\n    }\n}\n\nfn hover_for_expression(\n    expression: &TypedExpr,\n    line_numbers: LineNumbers,\n    module: &Module,\n    hex_deps: &HashSet<EcoString>,\n) -> Hover {\n    let documentation = expression.get_documentation().unwrap_or_default();\n\n    let link_section = get_expr_qualified_name(expression)\n        .and_then(|(module_name, name)| {\n            get_hexdocs_link_section(module_name, name, &module.ast, hex_deps)\n        })\n        .unwrap_or(\"\".to_string());\n\n    // Show the type of the hovered node to the user\n    let type_ = Printer::new(&module.ast.names).print_type(expression.type_().as_ref());\n    let contents = format!(\n        \"```gleam\n{type_}\n```\n{documentation}{link_section}\"\n    );\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(expression.location(), &line_numbers)),\n    }\n}\n\nfn hover_for_imported_value(\n    value: &ValueConstructor,\n    location: &SrcSpan,\n    line_numbers: LineNumbers,\n    hex_module_imported_from: Option<&ModuleInterface>,\n    name: &EcoString,\n    module: &Module,\n) -> Hover {\n    let documentation = value.get_documentation().unwrap_or_default();\n\n    let link_section = hex_module_imported_from.map_or(\"\".to_string(), |m| {\n        format_hexdocs_link_section(m.package.as_str(), m.name.as_str(), Some(name))\n    });\n\n    // Show the type of the hovered node to the user\n    let type_ = Printer::new(&module.ast.names).print_type(value.type_.as_ref());\n    let contents = format!(\n        \"```gleam\n{type_}\n```\n{documentation}{link_section}\"\n    );\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(*location, &line_numbers)),\n    }\n}\n\nfn hover_for_module(\n    module: &ModuleInterface,\n    location: SrcSpan,\n    line_numbers: &LineNumbers,\n    hex_deps: &HashSet<EcoString>,\n) -> Hover {\n    let documentation = module.documentation.join(\"\\n\");\n    let name = &module.name;\n\n    let link_section = if hex_deps.contains(&module.package) {\n        format_hexdocs_link_section(&module.package, name, None)\n    } else {\n        String::new()\n    };\n\n    let contents = format!(\n        \"```gleam\n{name}\n```\n{documentation}\n{link_section}\",\n    );\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(location, line_numbers)),\n    }\n}\n\nfn hover_for_custom_type(type_: &CustomType<Arc<Type>>, line_numbers: LineNumbers) -> Hover {\n    let name = &type_.name;\n    let documentation = type_\n        .documentation\n        .as_ref()\n        .map(|(_, documentation)| documentation.clone())\n        .unwrap_or_default();\n\n    let contents = format!(\"```gleam\\n{name}\\n```\\n{documentation}\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(type_.full_location(), &line_numbers)),\n    }\n}\n\nfn hover_for_constructor(\n    constructor: &TypedRecordConstructor,\n    line_numbers: LineNumbers,\n    module: &Module,\n) -> Hover {\n    let mut printer = Printer::new(&module.ast.names);\n\n    let arguments = constructor\n        .arguments\n        .iter()\n        .map(|argument| match &argument.label {\n            Some((_, label)) => eco_format!(\"{label}: {}\", printer.print_type(&argument.type_)),\n            None => printer.print_type(&argument.type_),\n        })\n        .join(\", \");\n\n    let documentation = constructor\n        .documentation\n        .as_ref()\n        .map(|(_, documentation)| documentation.clone())\n        .unwrap_or_default();\n\n    let constructor_doc = if arguments.is_empty() {\n        constructor.name.clone()\n    } else {\n        eco_format!(\"{}({arguments})\", constructor.name)\n    };\n\n    let contents = format!(\"```gleam\\n{constructor_doc}\\n```\\n{documentation}\");\n    Hover {\n        contents: HoverContents::Scalar(MarkedString::String(contents)),\n        range: Some(src_span_to_lsp_range(constructor.location, &line_numbers)),\n    }\n}\n\n// Returns true if any part of either range overlaps with the other.\npub fn overlaps(a: Range, b: Range) -> bool {\n    position_within(a.start, b)\n        || position_within(a.end, b)\n        || position_within(b.start, a)\n        || position_within(b.end, a)\n}\n\n// Returns true if a range is contained within another.\npub fn within(a: Range, b: Range) -> bool {\n    position_within(a.start, b) && position_within(a.end, b)\n}\n\n// Returns true if a position is within a range.\nfn position_within(position: Position, range: Range) -> bool {\n    position >= range.start && position <= range.end\n}\n\n/// Builds the code action to assign an unused value to `_`.\n///\nfn code_action_unused_values(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &lsp::CodeActionParams,\n    actions: &mut Vec<CodeAction>,\n) {\n    let uri = &params.text_document.uri;\n    let mut unused_values: Vec<&SrcSpan> = module\n        .ast\n        .type_info\n        .warnings\n        .iter()\n        .filter_map(|warning| {\n            if let type_::Warning::ImplicitlyDiscardedResult { location } = warning {\n                Some(location)\n            } else {\n                None\n            }\n        })\n        .collect();\n\n    if unused_values.is_empty() {\n        return;\n    }\n\n    // Sort spans by start position, with longer spans coming first\n    unused_values.sort_by_key(|span| (span.start, -(span.len() as i64)));\n\n    let mut processed_lsp_range = Vec::new();\n\n    for unused in unused_values {\n        let SrcSpan { start, end } = *unused;\n        let hover_range = src_span_to_lsp_range(SrcSpan::new(start, end), line_numbers);\n\n        // Check if this span is contained within any previously processed span\n        if processed_lsp_range\n            .iter()\n            .any(|&prev_lsp_range| within(hover_range, prev_lsp_range))\n        {\n            continue;\n        }\n\n        // Check if the cursor is within this span\n        if !within(params.range, hover_range) {\n            continue;\n        }\n\n        let edit = TextEdit {\n            range: src_span_to_lsp_range(SrcSpan::new(start, start), line_numbers),\n            new_text: \"let _ = \".into(),\n        };\n\n        CodeActionBuilder::new(\"Assign unused Result value to `_`\")\n            .kind(lsp_types::CodeActionKind::QUICKFIX)\n            .changes(uri.clone(), vec![edit])\n            .preferred(true)\n            .push_to(actions);\n\n        processed_lsp_range.push(hover_range);\n    }\n}\n\nstruct NameCorrection {\n    pub location: SrcSpan,\n    pub correction: EcoString,\n}\n\nfn code_action_fix_names(\n    line_numbers: &LineNumbers,\n    params: &lsp::CodeActionParams,\n    error: &Option<Error>,\n    actions: &mut Vec<CodeAction>,\n) {\n    let uri = &params.text_document.uri;\n    let Some(Error::Type { errors, .. }) = error else {\n        return;\n    };\n    let name_corrections = errors\n        .iter()\n        .filter_map(|error| {\n            if let type_::Error::BadName {\n                location,\n                name,\n                kind,\n            } = error\n            {\n                Some(NameCorrection {\n                    correction: correct_name_case(name, *kind),\n                    location: *location,\n                })\n            } else {\n                None\n            }\n        })\n        .collect_vec();\n\n    if name_corrections.is_empty() {\n        return;\n    }\n\n    for name_correction in name_corrections {\n        let NameCorrection {\n            location,\n            correction,\n        } = name_correction;\n\n        let range = src_span_to_lsp_range(location, line_numbers);\n        // Check if the user's cursor is on the invalid name\n        if overlaps(params.range, range) {\n            let edit = TextEdit {\n                range,\n                new_text: correction.to_string(),\n            };\n\n            CodeActionBuilder::new(&format!(\"Rename to {correction}\"))\n                .kind(lsp_types::CodeActionKind::QUICKFIX)\n                .changes(uri.clone(), vec![edit])\n                .preferred(true)\n                .push_to(actions);\n        }\n    }\n}\n\nfn get_expr_qualified_name(expression: &TypedExpr) -> Option<(&EcoString, &EcoString)> {\n    match expression {\n        TypedExpr::Var {\n            name, constructor, ..\n        } if constructor.publicity.is_importable() => match &constructor.variant {\n            ValueConstructorVariant::ModuleFn {\n                module: module_name,\n                ..\n            } => Some((module_name, name)),\n\n            ValueConstructorVariant::ModuleConstant {\n                module: module_name,\n                ..\n            } => Some((module_name, name)),\n\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::Record { .. } => None,\n        },\n\n        TypedExpr::ModuleSelect {\n            label, module_name, ..\n        } => Some((module_name, label)),\n\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Var { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. }\n        | TypedExpr::Invalid { .. } => None,\n    }\n}\n\nfn format_hexdocs_link_section(\n    package_name: &str,\n    module_name: &str,\n    name: Option<&str>,\n) -> String {\n    let link = match name {\n        Some(name) => format!(\"https://hexdocs.pm/{package_name}/{module_name}.html#{name}\"),\n        None => format!(\"https://hexdocs.pm/{package_name}/{module_name}.html\"),\n    };\n    format!(\"\\nView on [HexDocs]({link})\")\n}\n\nfn get_hexdocs_link_section(\n    module_name: &str,\n    name: &str,\n    ast: &TypedModule,\n    hex_deps: &HashSet<EcoString>,\n) -> Option<String> {\n    let package_name = ast.definitions.imports.iter().find_map(|import| {\n        if import.module == module_name && hex_deps.contains(&import.package) {\n            Some(&import.package)\n        } else {\n            None\n        }\n    })?;\n\n    Some(format_hexdocs_link_section(\n        package_name,\n        module_name,\n        Some(name),\n    ))\n}\n\n/// Converts the source start position of a documentation comment's contents into\n/// the position of the leading slash in its marker ('///').\nfn get_doc_marker_position(content_pos: u32) -> u32 {\n    content_pos.saturating_sub(3)\n}\n\nfn make_deprecated_symbol_tag(deprecation: &Deprecation) -> Option<Vec<SymbolTag>> {\n    deprecation\n        .is_deprecated()\n        .then(|| vec![SymbolTag::DEPRECATED])\n}\n"
  },
  {
    "path": "language-server/src/feedback.rs",
    "content": "use gleam_core::{Error, Warning, diagnostic::Diagnostic};\nuse std::collections::{HashMap, HashSet};\n\nuse camino::Utf8PathBuf;\n\nuse super::engine::Compilation;\n\n#[derive(Debug, Default, PartialEq, Eq)]\npub struct Feedback {\n    pub diagnostics: HashMap<Utf8PathBuf, Vec<Diagnostic>>,\n    pub messages: Vec<Diagnostic>,\n}\n\nimpl Feedback {\n    /// Set the diagnostics for a file to an empty vector. This will overwrite\n    /// any existing diagnostics on the client.\n    pub fn unset_existing_diagnostics(&mut self, path: Utf8PathBuf) {\n        _ = self.diagnostics.insert(path, vec![]);\n    }\n\n    pub fn append_diagnostic(&mut self, path: Utf8PathBuf, diagnostic: Diagnostic) {\n        self.diagnostics.entry(path).or_default().push(diagnostic);\n    }\n\n    /// No feedback at all.\n    ///\n    pub fn none() -> Feedback {\n        Default::default()\n    }\n\n    /// Add all the content of another feedback to this feedback.\n    ///\n    pub fn append_feedback(&mut self, feedback: Feedback) {\n        for (path, diagnostics) in feedback.diagnostics {\n            // Any new diagnostics for a file will overwrite any existing ones.\n            _ = self.diagnostics.insert(path, diagnostics);\n        }\n        for diagnostic in feedback.messages {\n            self.append_message(diagnostic);\n        }\n    }\n\n    fn append_message(&mut self, diagnostic: Diagnostic) {\n        self.messages.push(diagnostic);\n    }\n}\n\n/// When an operation succeeds or fails we want to send diagnostics and\n/// messages to the client for displaying to the user. This object converts\n/// Gleam warnings, errors, etc to these feedback items.\n///\n/// Gleam has incremental compilation so we cannot erase all previous\n/// diagnostics and replace each time new diagnostics are available; if a file\n/// has not been recompiled then any diagnostics it had previously are still\n/// valid and must not be erased.\n/// To do this we keep track of which files have diagnostics and only overwrite\n/// them if the file has been recompiled.\n///\n#[derive(Debug, Default)]\npub struct FeedbackBookKeeper {\n    files_with_warnings: HashSet<Utf8PathBuf>,\n    files_with_errors: HashSet<Utf8PathBuf>,\n}\n\nimpl FeedbackBookKeeper {\n    /// Send diagnostics for any warnings and remove any diagnostics for files\n    /// that have compiled without warnings.\n    ///\n    pub fn response(&mut self, compilation: Compilation, warnings: Vec<Warning>) -> Feedback {\n        let mut feedback = Feedback::default();\n\n        if let Compilation::Yes(compiled_modules) = compilation {\n            // Any existing diagnostics for files that have been compiled are no\n            // longer valid so we set an empty vector of diagnostics for the files\n            // to erase their diagnostics.\n            for path in compiled_modules {\n                let has_existing_diagnostics = self.files_with_warnings.remove(&path);\n                if has_existing_diagnostics {\n                    feedback.unset_existing_diagnostics(path);\n                }\n            }\n\n            // Compilation was attempted and there is no error (which there is not\n            // in this function) then it means that compilation has succeeded, so\n            // there should be no error diagnostics.\n            // We don't limit this to files that have been compiled as a previous\n            // cached version could be used instead of a recompile.\n            self.unset_errors(&mut feedback);\n        }\n\n        for warning in warnings {\n            self.insert_warning(&mut feedback, warning);\n        }\n\n        feedback\n    }\n\n    fn unset_errors(&mut self, feedback: &mut Feedback) {\n        // TODO: avoid clobbering warnings. They should be preserved rather than\n        // removed with the errors here. We will need to store the warnings and\n        // re-send them.\n        for path in self.files_with_errors.drain() {\n            feedback.unset_existing_diagnostics(path);\n        }\n    }\n\n    /// Compilation failed, boo!\n    ///\n    /// Send diagnostics for any warnings and remove any diagnostics for files\n    /// that have compiled without warnings, AND ALSO send diagnostics for the\n    /// error that caused compilation to fail.\n    ///\n    pub fn build_with_error(\n        &mut self,\n        error: Error,\n        compilation: Compilation,\n        warnings: Vec<Warning>,\n    ) -> Feedback {\n        let diagnostics = error.to_diagnostics();\n        let mut feedback = self.response(compilation, warnings);\n\n        // A new error means that any existing errors are no longer valid. Unset them.\n        self.unset_errors(&mut feedback);\n\n        for diagnostic in diagnostics {\n            match diagnostic.location.as_ref().map(|l| l.path.clone()) {\n                Some(path) => {\n                    _ = self.files_with_errors.insert(path.clone());\n                    feedback.append_diagnostic(path, diagnostic);\n                }\n\n                None => {\n                    feedback.append_message(diagnostic);\n                }\n            }\n        }\n\n        feedback\n    }\n\n    pub fn error(&mut self, error: Error) -> Feedback {\n        self.build_with_error(error, Compilation::No, vec![])\n    }\n\n    fn insert_warning(&mut self, feedback: &mut Feedback, warning: Warning) {\n        let diagnostic = warning.to_diagnostic();\n        if let Some(path) = diagnostic.location.as_ref().map(|l| l.path.clone()) {\n            _ = self.files_with_warnings.insert(path.clone());\n            feedback.append_diagnostic(path, diagnostic);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use std::assert_eq;\n\n    use super::*;\n    use gleam_core::{\n        ast::SrcSpan,\n        diagnostic::Level,\n        parse::error::{ParseError, ParseErrorType},\n        type_,\n    };\n\n    #[test]\n    fn feedback() {\n        let mut book_keeper = FeedbackBookKeeper::default();\n        let file1 = Utf8PathBuf::from(\"src/file1.gleam\");\n        let file2 = Utf8PathBuf::from(\"src/file2.gleam\");\n        let file3 = Utf8PathBuf::from(\"src/file3.gleam\");\n\n        let warning1 = Warning::Type {\n            path: file1.clone(),\n            src: \"src\".into(),\n            warning: type_::Warning::NoFieldsRecordUpdate {\n                location: SrcSpan::new(1, 2),\n            },\n        };\n        let warning2 = Warning::Type {\n            path: file2.clone(),\n            src: \"src\".into(),\n            warning: type_::Warning::NoFieldsRecordUpdate {\n                location: SrcSpan::new(1, 2),\n            },\n        };\n\n        let feedback = book_keeper.response(\n            Compilation::Yes(vec![file1.clone()]),\n            vec![warning1.clone(), warning1.clone(), warning2.clone()],\n        );\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([\n                    (\n                        file1.clone(),\n                        vec![warning1.to_diagnostic(), warning1.to_diagnostic(),]\n                    ),\n                    (file2.clone(), vec![warning2.to_diagnostic(),])\n                ]),\n                messages: vec![],\n            },\n            feedback\n        );\n\n        let feedback = book_keeper.response(\n            Compilation::Yes(vec![file1.clone(), file2.clone(), file3]),\n            vec![],\n        );\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([\n                    // File 1 and 2 had diagnostics before so they have been unset\n                    (file1, vec![]),\n                    (file2, vec![]),\n                    // File 3 had no diagnostics so does not need to to be unset\n                ]),\n                messages: vec![],\n            },\n            feedback\n        );\n    }\n\n    #[test]\n    fn locationless_error() {\n        // The failed method sets an additional messages for errors without a\n        // location.\n\n        let mut book_keeper = FeedbackBookKeeper::default();\n        let file1 = Utf8PathBuf::from(\"src/file1.gleam\");\n\n        let warning1 = Warning::Type {\n            path: file1.clone(),\n            src: \"src\".into(),\n            warning: type_::Warning::NoFieldsRecordUpdate {\n                location: SrcSpan::new(1, 2),\n            },\n        };\n\n        let locationless_error = Error::Gzip(\"Hello!\".into());\n\n        let feedback = book_keeper.build_with_error(\n            locationless_error.clone(),\n            Compilation::Yes(vec![]),\n            vec![warning1.clone()],\n        );\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([(file1, vec![warning1.to_diagnostic()])]),\n                messages: locationless_error.to_diagnostics(),\n            },\n            feedback\n        );\n    }\n\n    #[test]\n    fn error() {\n        // The failed method sets an additional diagnostic if the error has a\n        // location.\n\n        let mut book_keeper = FeedbackBookKeeper::default();\n        let file1 = Utf8PathBuf::from(\"src/file1.gleam\");\n        let file3 = Utf8PathBuf::from(\"src/file2.gleam\");\n\n        let warning1 = Warning::Type {\n            path: file1.clone(),\n            src: \"src\".into(),\n            warning: type_::Warning::NoFieldsRecordUpdate {\n                location: SrcSpan::new(1, 2),\n            },\n        };\n        let error = Error::Parse {\n            path: file3.clone(),\n            src: \"blah\".into(),\n            error: Box::new(ParseError {\n                error: ParseErrorType::ConcatPatternVariableLeftHandSide,\n                location: SrcSpan::new(1, 4),\n            }),\n        };\n\n        let feedback = book_keeper.build_with_error(\n            error.clone(),\n            Compilation::Yes(vec![]),\n            vec![warning1.clone()],\n        );\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([\n                    (file1, vec![warning1.to_diagnostic()]),\n                    (file3.clone(), error.to_diagnostics()),\n                ]),\n                messages: vec![],\n            },\n            feedback\n        );\n\n        // The error diagnostic should be removed if the file compiles later.\n\n        let feedback = book_keeper.response(Compilation::Yes(vec![file3.clone()]), vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([(file3, vec![])]),\n                messages: vec![],\n            },\n            feedback\n        );\n    }\n\n    // https://github.com/gleam-lang/gleam/issues/2093\n    #[test]\n    fn successful_compilation_removes_error_diagnostic() {\n        // It is possible for a compile error to be fixed but the module that\n        // had the error to not actually be recompiled.\n        //\n        // 1. File is OK\n        // 2. File is edited to an invalid state\n        // 3. A compile error is emitted\n        // 4. File is edited back to the earlier valid state\n        // 5. File is not recompiled as the cache from step 1 is still valid\n        //\n        // Because of this the compiled files iterator does not contain the\n        // file, so we need to make sure that the error is removed through other\n        // means, such as tracking which files have errors and removing them all\n        // when a successful compilation occurs.\n\n        let mut book_keeper = FeedbackBookKeeper::default();\n        let file1 = Utf8PathBuf::from(\"src/file1.gleam\");\n        let file2 = Utf8PathBuf::from(\"src/file2.gleam\");\n\n        let error = Error::Parse {\n            path: file1.clone(),\n            src: \"blah\".into(),\n            error: Box::new(ParseError {\n                error: ParseErrorType::ConcatPatternVariableLeftHandSide,\n                location: SrcSpan::new(1, 4),\n            }),\n        };\n\n        let feedback =\n            book_keeper.build_with_error(error.clone(), Compilation::Yes(vec![]), vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([(file1.clone(), error.to_diagnostics())]),\n                messages: vec![],\n            },\n            feedback\n        );\n\n        // The error diagnostic should be removed on a successful compilation,\n        // even though the file is not in the compiled files iterator.\n\n        let feedback = book_keeper.response(Compilation::Yes(vec![file2]), vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([(file1, vec![])]),\n                messages: vec![],\n            },\n            feedback\n        );\n    }\n\n    // https://github.com/gleam-lang/gleam/issues/2122\n    #[test]\n    fn second_failure_unsets_previous_error() {\n        let mut book_keeper = FeedbackBookKeeper::default();\n        let file1 = Utf8PathBuf::from(\"src/file1.gleam\");\n        let file2 = Utf8PathBuf::from(\"src/file2.gleam\");\n\n        let error = |file: &camino::Utf8Path| Error::Parse {\n            path: file.to_path_buf(),\n            src: \"blah\".into(),\n            error: Box::new(ParseError {\n                error: ParseErrorType::ConcatPatternVariableLeftHandSide,\n                location: SrcSpan::new(1, 4),\n            }),\n        };\n\n        let feedback =\n            book_keeper.build_with_error(error(&file1), Compilation::Yes(vec![]), vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([(file1.clone(), error(&file1).to_diagnostics())]),\n                messages: vec![],\n            },\n            feedback\n        );\n\n        let feedback =\n            book_keeper.build_with_error(error(&file2), Compilation::Yes(vec![]), vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([\n                    // Unset the previous error\n                    (file1, vec![]),\n                    // Set the new one\n                    (file2.clone(), error(&file2).to_diagnostics()),\n                ]),\n                messages: vec![],\n            },\n            feedback\n        );\n    }\n\n    // https://github.com/gleam-lang/gleam/issues/2105\n    #[test]\n    fn successful_non_compilation_does_not_remove_error_diagnostic() {\n        let mut book_keeper = FeedbackBookKeeper::default();\n        let file1 = Utf8PathBuf::from(\"src/file1.gleam\");\n\n        let error = Error::Parse {\n            path: file1.clone(),\n            src: \"blah\".into(),\n            error: Box::new(ParseError {\n                error: ParseErrorType::ConcatPatternVariableLeftHandSide,\n                location: SrcSpan::new(1, 4),\n            }),\n        };\n\n        let feedback =\n            book_keeper.build_with_error(error.clone(), Compilation::Yes(vec![]), vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::from([(file1, error.to_diagnostics())]),\n                messages: vec![],\n            },\n            feedback\n        );\n\n        // The error diagnostic should not be removed, nothing has been\n        // successfully compiled.\n\n        let feedback = book_keeper.response(Compilation::No, vec![]);\n\n        assert_eq!(\n            Feedback {\n                diagnostics: HashMap::new(),\n                messages: vec![],\n            },\n            feedback\n        );\n    }\n\n    #[test]\n    fn append_feedback_new_file() {\n        let mut feedback = Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file1.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 1\".to_string(),\n                    title: \"Error 1\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![Diagnostic {\n                location: None,\n                hint: None,\n                text: \"Error 2\".to_string(),\n                title: \"Error 2\".to_string(),\n                level: Level::Error,\n            }],\n        };\n        feedback.append_feedback(Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file2.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 3\".to_string(),\n                    title: \"Error 3\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![],\n        });\n        assert_eq!(\n            feedback,\n            Feedback {\n                diagnostics: HashMap::from([\n                    (\n                        Utf8PathBuf::from(\"src/file1.gleam\"),\n                        vec![Diagnostic {\n                            location: None,\n                            hint: None,\n                            text: \"Error 1\".to_string(),\n                            title: \"Error 1\".to_string(),\n                            level: Level::Error,\n                        }],\n                    ),\n                    (\n                        Utf8PathBuf::from(\"src/file2.gleam\"),\n                        vec![Diagnostic {\n                            location: None,\n                            hint: None,\n                            text: \"Error 3\".to_string(),\n                            title: \"Error 3\".to_string(),\n                            level: Level::Error,\n                        }],\n                    ),\n                ]),\n                messages: vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 2\".to_string(),\n                    title: \"Error 2\".to_string(),\n                    level: Level::Error,\n                },],\n            }\n        );\n    }\n\n    #[test]\n    fn append_feedback_same_file() {\n        let mut feedback = Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file1.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 1\".to_string(),\n                    title: \"Error 1\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![Diagnostic {\n                location: None,\n                hint: None,\n                text: \"Error 2\".to_string(),\n                title: \"Error 2\".to_string(),\n                level: Level::Error,\n            }],\n        };\n        feedback.append_feedback(Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file1.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 3\".to_string(),\n                    title: \"Error 3\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![],\n        });\n        assert_eq!(\n            feedback,\n            Feedback {\n                diagnostics: HashMap::from([(\n                    Utf8PathBuf::from(\"src/file1.gleam\"),\n                    vec![Diagnostic {\n                        location: None,\n                        hint: None,\n                        text: \"Error 3\".to_string(),\n                        title: \"Error 3\".to_string(),\n                        level: Level::Error,\n                    }],\n                ),]),\n                messages: vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 2\".to_string(),\n                    title: \"Error 2\".to_string(),\n                    level: Level::Error,\n                },],\n            }\n        );\n    }\n\n    #[test]\n    fn append_feedback_new_message() {\n        let mut feedback = Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file1.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 1\".to_string(),\n                    title: \"Error 1\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![Diagnostic {\n                location: None,\n                hint: None,\n                text: \"Error 2\".to_string(),\n                title: \"Error 2\".to_string(),\n                level: Level::Error,\n            }],\n        };\n        feedback.append_feedback(Feedback {\n            diagnostics: HashMap::from([]),\n            messages: vec![Diagnostic {\n                location: None,\n                hint: None,\n                text: \"Error 3\".to_string(),\n                title: \"Error 3\".to_string(),\n                level: Level::Error,\n            }],\n        });\n        assert_eq!(\n            feedback,\n            Feedback {\n                diagnostics: HashMap::from([(\n                    Utf8PathBuf::from(\"src/file1.gleam\"),\n                    vec![Diagnostic {\n                        location: None,\n                        hint: None,\n                        text: \"Error 1\".to_string(),\n                        title: \"Error 1\".to_string(),\n                        level: Level::Error,\n                    },],\n                ),]),\n                messages: vec![\n                    Diagnostic {\n                        location: None,\n                        hint: None,\n                        text: \"Error 2\".to_string(),\n                        title: \"Error 2\".to_string(),\n                        level: Level::Error,\n                    },\n                    Diagnostic {\n                        location: None,\n                        hint: None,\n                        text: \"Error 3\".to_string(),\n                        title: \"Error 3\".to_string(),\n                        level: Level::Error,\n                    }\n                ],\n            }\n        );\n    }\n\n    #[test]\n    fn append_feedback_new_file_blank() {\n        let mut feedback = Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file1.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 1\".to_string(),\n                    title: \"Error 1\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![Diagnostic {\n                location: None,\n                hint: None,\n                text: \"Error 2\".to_string(),\n                title: \"Error 2\".to_string(),\n                level: Level::Error,\n            }],\n        };\n        feedback.append_feedback(Feedback {\n            diagnostics: HashMap::from([(Utf8PathBuf::from(\"src/file2.gleam\"), vec![])]),\n            messages: vec![],\n        });\n        assert_eq!(\n            feedback,\n            Feedback {\n                diagnostics: HashMap::from([\n                    (\n                        Utf8PathBuf::from(\"src/file1.gleam\"),\n                        vec![Diagnostic {\n                            location: None,\n                            hint: None,\n                            text: \"Error 1\".to_string(),\n                            title: \"Error 1\".to_string(),\n                            level: Level::Error,\n                        },],\n                    ),\n                    (Utf8PathBuf::from(\"src/file2.gleam\"), vec![],),\n                ]),\n                messages: vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 2\".to_string(),\n                    title: \"Error 2\".to_string(),\n                    level: Level::Error,\n                },],\n            }\n        );\n    }\n\n    #[test]\n    fn append_feedback_existing_file_blank() {\n        let mut feedback = Feedback {\n            diagnostics: HashMap::from([(\n                Utf8PathBuf::from(\"src/file1.gleam\"),\n                vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 1\".to_string(),\n                    title: \"Error 1\".to_string(),\n                    level: Level::Error,\n                }],\n            )]),\n            messages: vec![Diagnostic {\n                location: None,\n                hint: None,\n                text: \"Error 2\".to_string(),\n                title: \"Error 2\".to_string(),\n                level: Level::Error,\n            }],\n        };\n        feedback.append_feedback(Feedback {\n            diagnostics: HashMap::from([(Utf8PathBuf::from(\"src/file1.gleam\"), vec![])]),\n            messages: vec![],\n        });\n        assert_eq!(\n            feedback,\n            Feedback {\n                diagnostics: HashMap::from([(Utf8PathBuf::from(\"src/file1.gleam\"), vec![],),]),\n                messages: vec![Diagnostic {\n                    location: None,\n                    hint: None,\n                    text: \"Error 2\".to_string(),\n                    title: \"Error 2\".to_string(),\n                    level: Level::Error,\n                },],\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "language-server/src/files.rs",
    "content": "use std::collections::HashSet;\nuse std::time::SystemTime;\n\nuse debug_ignore::DebugIgnore;\n\nuse gleam_core::{\n    Result,\n    error::Error,\n    io::{\n        BeamCompiler, Command, CommandExecutor, FileSystemReader, FileSystemWriter, ReadDir, Stdio,\n        WrappedReader, memory::InMemoryFileSystem,\n    },\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\n// A proxy intended for `LanguageServer` to use when files are modified in\n// memory but not yet saved to disc by the client.\n//\n// Uses the `IO` for writing directly to disk, or `InMemoryFileSystem` to\n// cache files that were not yet saved. Reading files will always first try the\n// `InMemoryFileSystem` first and fallback to use the `ProjectIO` if the file\n// was not found in the cache.\n//\n#[derive(Debug, Clone)]\npub struct FileSystemProxy<IO> {\n    io: DebugIgnore<IO>,\n    edit_cache: InMemoryFileSystem,\n}\n\nimpl<IO> FileSystemProxy<IO>\nwhere\n    IO: FileSystemWriter + FileSystemReader + CommandExecutor,\n{\n    pub fn new(io: IO) -> Self {\n        Self {\n            io: io.into(),\n            edit_cache: InMemoryFileSystem::new(),\n        }\n    }\n\n    pub fn inner(&self) -> &IO {\n        &self.io\n    }\n\n    pub fn write_mem_cache(&mut self, path: &Utf8Path, content: &str) -> Result<()> {\n        let write_result = self.edit_cache.write(path, content);\n        self.edit_cache\n            .try_set_modification_time(path, SystemTime::now())?;\n        write_result\n    }\n\n    pub fn delete_mem_cache(&self, path: &Utf8Path) -> Result<()> {\n        if self.edit_cache.is_directory(path) {\n            self.edit_cache.delete_directory(path)\n        } else {\n            self.edit_cache.delete_file(path)\n        }\n    }\n}\n\n// All write operations goes to disk (for mem-cache use the dedicated `_mem_cache` methods)\nimpl<IO> FileSystemWriter for FileSystemProxy<IO>\nwhere\n    IO: FileSystemWriter,\n{\n    fn mkdir(&self, path: &Utf8Path) -> Result<()> {\n        self.io.mkdir(path)\n    }\n\n    fn write(&self, path: &Utf8Path, content: &str) -> Result<()> {\n        self.io.write(path, content)\n    }\n\n    fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<()> {\n        self.io.write_bytes(path, content)\n    }\n\n    fn delete_directory(&self, path: &Utf8Path) -> Result<()> {\n        self.io.delete_directory(path)\n    }\n\n    fn copy(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.copy(from, to)\n    }\n\n    fn copy_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.copy_dir(from, to)\n    }\n\n    fn hardlink(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.hardlink(from, to)\n    }\n\n    fn symlink_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.symlink_dir(from, to)\n    }\n\n    fn delete_file(&self, path: &Utf8Path) -> Result<()> {\n        self.io.delete_file(path)\n    }\n\n    fn exists(&self, path: &Utf8Path) -> bool {\n        self.io.exists(path)\n    }\n}\n\nimpl<IO> FileSystemReader for FileSystemProxy<IO>\nwhere\n    IO: FileSystemReader,\n{\n    fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir> {\n        self.io.read_dir(path)\n    }\n\n    fn read(&self, path: &Utf8Path) -> Result<String> {\n        match self.edit_cache.read(path) {\n            result @ Ok(_) => result,\n            Err(_) => self.io.read(path),\n        }\n    }\n\n    fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>> {\n        match self.edit_cache.read_bytes(path) {\n            result @ Ok(_) => result,\n            Err(_) => self.io.read_bytes(path),\n        }\n    }\n\n    fn reader(&self, path: &Utf8Path) -> Result<WrappedReader> {\n        self.io.reader(path)\n    }\n\n    // Cache overrides existence of file\n    fn is_file(&self, path: &Utf8Path) -> bool {\n        self.edit_cache.is_file(path) || self.io.is_file(path)\n    }\n\n    // Cache overrides existence of directory\n    fn is_directory(&self, path: &Utf8Path) -> bool {\n        self.edit_cache.is_directory(path) || self.io.is_directory(path)\n    }\n\n    fn modification_time(&self, path: &Utf8Path) -> Result<SystemTime> {\n        match self.edit_cache.modification_time(path) {\n            result @ Ok(_) => result,\n            Err(_) => self.io.modification_time(path),\n        }\n    }\n\n    fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, Error> {\n        self.io.canonicalise(path)\n    }\n}\n\nimpl<IO> CommandExecutor for FileSystemProxy<IO>\nwhere\n    IO: CommandExecutor,\n{\n    fn exec(&self, _command: Command) -> Result<i32> {\n        panic!(\"The language server is not permitted to create subprocesses\")\n    }\n}\n\nimpl<IO> BeamCompiler for FileSystemProxy<IO>\nwhere\n    IO: BeamCompiler,\n{\n    fn compile_beam(\n        &self,\n        _out: &Utf8Path,\n        _lib: &Utf8Path,\n        _modules: &HashSet<Utf8PathBuf>,\n        _stdio: Stdio,\n    ) -> Result<Vec<String>, Error> {\n        panic!(\"The language server is not permitted to create subprocesses\")\n    }\n}\n"
  },
  {
    "path": "language-server/src/lib.rs",
    "content": "#![warn(\n    clippy::all,\n    clippy::dbg_macro,\n    clippy::todo,\n    clippy::mem_forget,\n    clippy::filter_map_next,\n    clippy::needless_continue,\n    clippy::needless_borrow,\n    clippy::match_wildcard_for_single_variants,\n    clippy::imprecise_flops,\n    clippy::suboptimal_flops,\n    clippy::lossy_float_literal,\n    clippy::rest_pat_in_fully_bound_structs,\n    clippy::fn_params_excessive_bools,\n    clippy::inefficient_to_string,\n    clippy::linkedlist,\n    clippy::macro_use_imports,\n    clippy::option_option,\n    clippy::verbose_file_reads,\n    clippy::unnested_or_patterns,\n    rust_2018_idioms,\n    missing_debug_implementations,\n    missing_copy_implementations,\n    trivial_casts,\n    trivial_numeric_casts,\n    nonstandard_style,\n    unexpected_cfgs,\n    unused_import_braces,\n    unused_qualifications\n)]\n#![deny(\n    clippy::await_holding_lock,\n    clippy::disallowed_methods,\n    clippy::if_let_mutex,\n    clippy::indexing_slicing,\n    clippy::mem_forget,\n    clippy::ok_expect,\n    clippy::unimplemented,\n    clippy::unwrap_used,\n    unsafe_code,\n    unstable_features,\n    unused_results\n)]\n#![allow(\n    clippy::assign_op_pattern,\n    clippy::to_string_trait_impl,\n    clippy::match_single_binding,\n    clippy::match_like_matches_macro,\n    clippy::inconsistent_struct_constructor,\n    clippy::len_without_is_empty\n)]\n\nmod code_action;\nmod compiler;\nmod completer;\nmod edits;\nmod engine;\nmod feedback;\nmod files;\nmod messages;\nmod progress;\nmod reference;\nmod rename;\nmod router;\nmod server;\nmod signature_help;\n\n#[cfg(test)]\nmod tests;\n\npub use server::LanguageServer;\n\nuse camino::Utf8PathBuf;\nuse gleam_core::{\n    Result, ast::SrcSpan, build::Target, line_numbers::LineNumbers, manifest::Manifest,\n    paths::ProjectPaths,\n};\nuse lsp_types::{Position, Range, TextEdit, Url};\nuse std::any::Any;\n\n#[derive(Debug)]\npub struct LockGuard(pub Box<dyn Any>);\n\npub trait Locker {\n    fn lock_for_build(&self) -> Result<LockGuard>;\n}\n\npub trait MakeLocker {\n    fn make_locker(&self, paths: &ProjectPaths, target: Target) -> Result<Box<dyn Locker>>;\n}\n\npub trait DownloadDependencies {\n    fn download_dependencies(&self, paths: &ProjectPaths) -> Result<Manifest>;\n}\n\npub fn src_span_to_lsp_range(location: SrcSpan, line_numbers: &LineNumbers) -> Range {\n    let start = line_numbers.line_and_column_number(location.start);\n    let end = line_numbers.line_and_column_number(location.end);\n\n    Range::new(\n        Position::new(start.line - 1, start.column - 1),\n        Position::new(end.line - 1, end.column - 1),\n    )\n}\n\npub fn lsp_range_to_src_span(range: Range, line_numbers: &LineNumbers) -> SrcSpan {\n    let start = line_numbers.byte_index(range.start);\n    let end = line_numbers.byte_index(range.end);\n    SrcSpan { start, end }\n}\n\n/// A little wrapper around LineNumbers to make it easier to build text edits.\n///\n#[derive(Debug)]\npub struct TextEdits<'a> {\n    line_numbers: &'a LineNumbers,\n    edits: Vec<TextEdit>,\n}\n\nimpl<'a> TextEdits<'a> {\n    pub fn new(line_numbers: &'a LineNumbers) -> Self {\n        TextEdits {\n            line_numbers,\n            edits: vec![],\n        }\n    }\n\n    pub fn src_span_to_lsp_range(&self, location: SrcSpan) -> Range {\n        src_span_to_lsp_range(location, self.line_numbers)\n    }\n\n    pub fn lsp_range_to_src_span(&self, range: Range) -> SrcSpan {\n        lsp_range_to_src_span(range, self.line_numbers)\n    }\n\n    pub fn replace(&mut self, location: SrcSpan, new_text: String) {\n        self.edits.push(TextEdit {\n            range: src_span_to_lsp_range(location, self.line_numbers),\n            new_text,\n        })\n    }\n\n    pub fn insert(&mut self, at: u32, new_text: String) {\n        self.replace(SrcSpan { start: at, end: at }, new_text)\n    }\n\n    pub fn delete(&mut self, location: SrcSpan) {\n        self.replace(location, \"\".to_string())\n    }\n\n    fn delete_range(&mut self, range: Range) {\n        self.edits.push(TextEdit {\n            range,\n            new_text: \"\".into(),\n        })\n    }\n}\n\nfn path(uri: &Url) -> Utf8PathBuf {\n    // The to_file_path method is available on these platforms\n    #[cfg(any(unix, windows, target_os = \"redox\", target_os = \"wasi\"))]\n    return Utf8PathBuf::from_path_buf(uri.to_file_path().expect(\"URL file\"))\n        .expect(\"Non Utf8 Path\");\n\n    #[cfg(not(any(unix, windows, target_os = \"redox\", target_os = \"wasi\")))]\n    return Utf8PathBuf::from_path_buf(uri.path().into()).expect(\"Non Utf8 Path\");\n}\n\nfn url_from_path(path: &str) -> Option<Url> {\n    // The targets for which `from_file_path` is defined\n    #[cfg(any(\n        unix,\n        windows,\n        target_os = \"redox\",\n        target_os = \"wasi\",\n        target_os = \"hermit\"\n    ))]\n    let uri = Url::from_file_path(path).ok();\n\n    #[cfg(not(any(\n        unix,\n        windows,\n        target_os = \"redox\",\n        target_os = \"wasi\",\n        target_os = \"hermit\"\n    )))]\n    let uri = Url::parse(&format!(\"file://{path}\")).ok();\n\n    uri\n}\n"
  },
  {
    "path": "language-server/src/messages.rs",
    "content": "use camino::Utf8PathBuf;\nuse lsp::{\n    notification::{DidChangeWatchedFiles, DidOpenTextDocument},\n    request::GotoDefinition,\n};\nuse lsp_types::{\n    self as lsp,\n    notification::{DidChangeTextDocument, DidCloseTextDocument, DidSaveTextDocument},\n    request::{\n        CodeActionRequest, Completion, DocumentSymbolRequest, FoldingRangeRequest, Formatting,\n        GotoTypeDefinition, HoverRequest, PrepareRenameRequest, References, Rename,\n        SignatureHelpRequest,\n    },\n};\nuse std::time::Duration;\n\n#[derive(Debug)]\npub enum Message {\n    Request(lsp_server::RequestId, Request),\n    Notification(Notification),\n}\n\n#[derive(Debug)]\npub enum Request {\n    Format(lsp::DocumentFormattingParams),\n    Hover(lsp::HoverParams),\n    GoToDefinition(lsp::GotoDefinitionParams),\n    GoToTypeDefinition(lsp::GotoDefinitionParams),\n    Completion(lsp::CompletionParams),\n    CodeAction(lsp::CodeActionParams),\n    SignatureHelp(lsp::SignatureHelpParams),\n    DocumentSymbol(lsp::DocumentSymbolParams),\n    FoldingRange(lsp::FoldingRangeParams),\n    PrepareRename(lsp::TextDocumentPositionParams),\n    Rename(lsp::RenameParams),\n    FindReferences(lsp::ReferenceParams),\n}\n\nimpl Request {\n    fn extract(request: lsp_server::Request) -> Option<Message> {\n        let id = request.id.clone();\n        match request.method.as_str() {\n            \"textDocument/formatting\" => {\n                let params = cast_request::<Formatting>(request);\n                Some(Message::Request(id, Request::Format(params)))\n            }\n            \"textDocument/hover\" => {\n                let params = cast_request::<HoverRequest>(request);\n                Some(Message::Request(id, Request::Hover(params)))\n            }\n            \"textDocument/definition\" => {\n                let params = cast_request::<GotoDefinition>(request);\n                Some(Message::Request(id, Request::GoToDefinition(params)))\n            }\n            \"textDocument/completion\" => {\n                let params = cast_request::<Completion>(request);\n                Some(Message::Request(id, Request::Completion(params)))\n            }\n            \"textDocument/codeAction\" => {\n                let params = cast_request::<CodeActionRequest>(request);\n                Some(Message::Request(id, Request::CodeAction(params)))\n            }\n            \"textDocument/signatureHelp\" => {\n                let params = cast_request::<SignatureHelpRequest>(request);\n                Some(Message::Request(id, Request::SignatureHelp(params)))\n            }\n            \"textDocument/documentSymbol\" => {\n                let params = cast_request::<DocumentSymbolRequest>(request);\n                Some(Message::Request(id, Request::DocumentSymbol(params)))\n            }\n            \"textDocument/foldingRange\" => {\n                let params = cast_request::<FoldingRangeRequest>(request);\n                Some(Message::Request(id, Request::FoldingRange(params)))\n            }\n            \"textDocument/rename\" => {\n                let params = cast_request::<Rename>(request);\n                Some(Message::Request(id, Request::Rename(params)))\n            }\n            \"textDocument/prepareRename\" => {\n                let params = cast_request::<PrepareRenameRequest>(request);\n                Some(Message::Request(id, Request::PrepareRename(params)))\n            }\n            \"textDocument/typeDefinition\" => {\n                let params = cast_request::<GotoTypeDefinition>(request);\n                Some(Message::Request(id, Request::GoToTypeDefinition(params)))\n            }\n            \"textDocument/references\" => {\n                let params = cast_request::<References>(request);\n                Some(Message::Request(id, Request::FindReferences(params)))\n            }\n            _ => None,\n        }\n    }\n}\n\n#[derive(Debug)]\npub enum Notification {\n    /// A Gleam file has been modified in memory, and the new text is provided.\n    SourceFileChangedInMemory { path: Utf8PathBuf, text: String },\n    /// A Gleam file has been saved or closed in the editor.\n    SourceFileMatchesDisc { path: Utf8PathBuf },\n    /// gleam.toml has changed.\n    ConfigFileChanged { path: Utf8PathBuf },\n    /// It's time to compile all open projects.\n    CompilePlease,\n}\n\nimpl Notification {\n    fn extract(notification: lsp_server::Notification) -> Option<Message> {\n        match notification.method.as_str() {\n            \"textDocument/didOpen\" => {\n                let params = cast_notification::<DidOpenTextDocument>(notification);\n                let notification = Notification::SourceFileChangedInMemory {\n                    path: super::path(&params.text_document.uri),\n                    text: params.text_document.text,\n                };\n                Some(Message::Notification(notification))\n            }\n            \"textDocument/didChange\" => {\n                let params = cast_notification::<DidChangeTextDocument>(notification);\n                let notification = Notification::SourceFileChangedInMemory {\n                    path: super::path(&params.text_document.uri),\n                    text: params.content_changes.into_iter().next_back()?.text,\n                };\n                Some(Message::Notification(notification))\n            }\n\n            \"textDocument/didSave\" => {\n                let params = cast_notification::<DidSaveTextDocument>(notification);\n                let notification = Notification::SourceFileMatchesDisc {\n                    path: super::path(&params.text_document.uri),\n                };\n                Some(Message::Notification(notification))\n            }\n            \"textDocument/didClose\" => {\n                let params = cast_notification::<DidCloseTextDocument>(notification);\n                let notification = Notification::SourceFileMatchesDisc {\n                    path: super::path(&params.text_document.uri),\n                };\n                Some(Message::Notification(notification))\n            }\n\n            \"workspace/didChangeWatchedFiles\" => {\n                let params = cast_notification::<DidChangeWatchedFiles>(notification);\n                let notification = Notification::ConfigFileChanged {\n                    path: super::path(&params.changes.into_iter().next_back()?.uri),\n                };\n                Some(Message::Notification(notification))\n            }\n            _ => None,\n        }\n    }\n}\n\npub enum Next {\n    MorePlease,\n    Handle(Vec<Message>),\n    Stop,\n}\n\n/// The message buffer pulls messages from the client until one of the following\n/// happens:\n/// - A shutdown request is received.\n/// - A short pause in messages is detected, indicating the programmer has\n///   stopped typing for a moment and would benefit from feedback.\n/// - A request type message is received, which requires an immediate response.\n///\npub struct MessageBuffer {\n    messages: Vec<Message>,\n}\n\nimpl MessageBuffer {\n    pub fn new() -> Self {\n        Self {\n            messages: Vec::new(),\n        }\n    }\n\n    pub fn receive(&mut self, conn: &lsp_server::Connection) -> Next {\n        let pause = Duration::from_millis(100);\n\n        // If the buffer is empty, wait indefinitely for the first message.\n        // If the buffer is not empty, wait for a short time to see if more messages are\n        // coming before processing the ones we have.\n        let message = if self.messages.is_empty() {\n            Some(conn.receiver.recv().expect(\"Receiving LSP message\"))\n        } else {\n            conn.receiver.recv_timeout(pause).ok()\n        };\n\n        // If have have not received a message then it means there is a pause in the\n        // messages from the client, implying the programmer has stopped typing. Process\n        // the currently enqueued messages.\n        let message = match message {\n            Some(message) => message,\n            None => {\n                // A compile please message it added in the instance of this\n                // pause of activity so that the client gets feedback on the\n                // state of the code as it is now.\n                self.push_compile_please_message();\n                return Next::Handle(self.take_messages());\n            }\n        };\n\n        match message {\n            lsp_server::Message::Request(r) if self.shutdown(conn, &r) => Next::Stop,\n            lsp_server::Message::Request(r) => self.request(r),\n            lsp_server::Message::Response(r) => self.response(r),\n            lsp_server::Message::Notification(n) => self.notification(n),\n        }\n    }\n\n    fn request(&mut self, r: lsp_server::Request) -> Next {\n        let Some(message) = Request::extract(r) else {\n            return Next::MorePlease;\n        };\n\n        // Compile the code prior to attempting to process the response, to\n        // ensure that the response is based on the latest code.\n        self.push_compile_please_message();\n        self.messages.push(message);\n        Next::Handle(self.take_messages())\n    }\n\n    fn notification(&mut self, n: lsp_server::Notification) -> Next {\n        // A new notification telling us that an edit has been made, or\n        // something along those lines.\n        if let Some(message) = Notification::extract(n) {\n            self.messages.push(message);\n        }\n        // Ask for more messages (or a pause), at which point we'll start processing.\n        Next::MorePlease\n    }\n\n    fn response(&mut self, _: lsp_server::Response) -> Next {\n        // We do not use or expect responses from the client currently.\n        Next::MorePlease\n    }\n\n    /// Add a `CompilePlease` message which will prompt the engine to compile\n    /// the projects.\n    ///\n    fn push_compile_please_message(&mut self) {\n        let message = Notification::CompilePlease;\n        let value = Message::Notification(message);\n        self.messages.push(value);\n    }\n\n    fn take_messages(&mut self) -> Vec<Message> {\n        std::mem::take(&mut self.messages)\n    }\n\n    fn shutdown(\n        &mut self,\n        connection: &lsp_server::Connection,\n        request: &lsp_server::Request,\n    ) -> bool {\n        connection.handle_shutdown(request).expect(\"LSP shutdown\")\n    }\n}\n\nfn cast_request<R>(request: lsp_server::Request) -> R::Params\nwhere\n    R: lsp::request::Request,\n    R::Params: serde::de::DeserializeOwned,\n{\n    let (_, params) = request.extract(R::METHOD).expect(\"cast request\");\n    params\n}\n\nfn cast_notification<N>(notification: lsp_server::Notification) -> N::Params\nwhere\n    N: lsp::notification::Notification,\n    N::Params: serde::de::DeserializeOwned,\n{\n    notification\n        .extract::<N::Params>(N::METHOD)\n        .expect(\"cast notification\")\n}\n"
  },
  {
    "path": "language-server/src/progress.rs",
    "content": "use debug_ignore::DebugIgnore;\nuse lsp_types::{\n    InitializeParams, NumberOrString, ProgressParams, ProgressParamsValue, WorkDoneProgress,\n    WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd,\n};\n\nconst DOWNLOADING_TOKEN: &str = \"downloading-dependencies\";\n\npub trait ProgressReporter {\n    fn compilation_started(&self);\n    fn compilation_finished(&self);\n    fn dependency_downloading_started(&self);\n    fn dependency_downloading_finished(&self);\n}\n\n// Used to publish progress notifications to the client without waiting for\n// the usual request-response loop of the language server.\n#[derive(Debug, Clone)]\npub struct ConnectionProgressReporter<'a> {\n    connection: DebugIgnore<&'a lsp_server::Connection>,\n}\n\nimpl<'a> ConnectionProgressReporter<'a> {\n    pub fn new(\n        connection: &'a lsp_server::Connection,\n        // We don't actually need these but we take them anyway to ensure that\n        // this object is only created after the server has been initialised.\n        // If it was created before then the creation of the progress token\n        // would fail.\n        _initialise_params: &InitializeParams,\n    ) -> Self {\n        create_token(DOWNLOADING_TOKEN, connection);\n        Self {\n            connection: connection.into(),\n        }\n    }\n\n    fn send_notification(&self, token: &str, work_done: WorkDoneProgress) {\n        let params = ProgressParams {\n            token: NumberOrString::String(token.to_string()),\n            value: ProgressParamsValue::WorkDone(work_done),\n        };\n        let notification = lsp_server::Notification {\n            method: \"$/progress\".into(),\n            params: serde_json::to_value(params).expect(\"ProgressParams json\"),\n        };\n        self.connection\n            .sender\n            .send(lsp_server::Message::Notification(notification))\n            .expect(\"send_work_done_notification send\")\n    }\n}\n\nimpl ProgressReporter for ConnectionProgressReporter<'_> {\n    fn compilation_started(&self) {\n        // Do nothing. This is only used for tests currently.\n        // In future we could make this emit a message to the client if compilation is taking a\n        // long time.\n    }\n\n    fn compilation_finished(&self) {\n        // Do nothing. This is only used for tests currently.\n    }\n\n    fn dependency_downloading_started(&self) {\n        let title = \"Downloading Gleam dependencies\";\n        self.send_notification(DOWNLOADING_TOKEN, begin_message(title));\n    }\n\n    fn dependency_downloading_finished(&self) {\n        self.send_notification(DOWNLOADING_TOKEN, end_message());\n    }\n}\n\nfn end_message() -> WorkDoneProgress {\n    WorkDoneProgress::End(WorkDoneProgressEnd { message: None })\n}\n\nfn begin_message(title: &str) -> WorkDoneProgress {\n    WorkDoneProgress::Begin(WorkDoneProgressBegin {\n        title: title.into(),\n        cancellable: Some(false),\n        message: None,\n        percentage: None,\n    })\n}\n\nfn create_token(token: &str, connection: &lsp_server::Connection) {\n    let params = WorkDoneProgressCreateParams {\n        token: NumberOrString::String(token.into()),\n    };\n    let request = lsp_server::Request {\n        id: format!(\"create-token--{token}\").into(),\n        method: \"window/workDoneProgress/create\".into(),\n        params: serde_json::to_value(params).expect(\"WorkDoneProgressCreateParams json\"),\n    };\n    connection\n        .sender\n        .send(lsp_server::Message::Request(request))\n        .expect(\"WorkDoneProgressCreate\");\n}\n"
  },
  {
    "path": "language-server/src/reference.rs",
    "content": "use std::collections::{HashMap, HashSet};\n\nuse ecow::EcoString;\nuse lsp_types::Location;\n\nuse gleam_core::{\n    analyse,\n    ast::{\n        self, ArgNames, AssignName, BitArraySize, ClauseGuard, CustomType, Function,\n        ModuleConstant, Pattern, RecordConstructor, SrcSpan, TypedExpr, TypedModule, visit::Visit,\n    },\n    build::Located,\n    type_::{\n        ModuleInterface, ModuleValueConstructor, Type, ValueConstructor, ValueConstructorVariant,\n        error::{Named, VariableOrigin},\n    },\n};\n\nuse super::{\n    compiler::ModuleSourceInformation, rename::RenameTarget, src_span_to_lsp_range, url_from_path,\n};\n\n#[derive(Debug)]\npub enum Referenced {\n    LocalVariable {\n        definition_location: SrcSpan,\n        location: SrcSpan,\n        origin: Option<VariableOrigin>,\n        name: EcoString,\n    },\n    ModuleName {\n        module_name: EcoString,\n        module_alias: EcoString,\n        location: SrcSpan,\n    },\n    ModuleValue {\n        module: EcoString,\n        name: EcoString,\n        location: SrcSpan,\n        name_kind: Named,\n        target_kind: RenameTarget,\n    },\n    ModuleType {\n        module: EcoString,\n        name: EcoString,\n        location: SrcSpan,\n        target_kind: RenameTarget,\n    },\n}\n\npub fn reference_for_ast_node(\n    found: Located<'_>,\n    current_module: &EcoString,\n) -> Option<Referenced> {\n    match found {\n        Located::Expression {\n            expression:\n                TypedExpr::Var {\n                    constructor:\n                        ValueConstructor {\n                            variant:\n                                ValueConstructorVariant::LocalVariable {\n                                    location: definition_location,\n                                    origin,\n                                },\n                            ..\n                        },\n                    location,\n                    name,\n                },\n            ..\n        } => Some(Referenced::LocalVariable {\n            definition_location: *definition_location,\n            location: *location,\n            origin: Some(origin.clone()),\n            name: name.clone(),\n        }),\n        Located::Pattern(Pattern::Variable {\n            location,\n            origin,\n            name,\n            ..\n        }) => Some(Referenced::LocalVariable {\n            definition_location: *location,\n            location: *location,\n            origin: Some(origin.clone()),\n            name: name.clone(),\n        }),\n        Located::Pattern(Pattern::BitArraySize(BitArraySize::Variable {\n            constructor,\n            location,\n            name,\n            ..\n        })) => constructor\n            .as_ref()\n            .and_then(|constructor| match &constructor.variant {\n                ValueConstructorVariant::LocalVariable {\n                    location: definition_location,\n                    origin,\n                } => Some(Referenced::LocalVariable {\n                    definition_location: *definition_location,\n                    location: *location,\n                    origin: Some(origin.clone()),\n                    name: name.clone(),\n                }),\n                ValueConstructorVariant::ModuleConstant { .. }\n                | ValueConstructorVariant::ModuleFn { .. }\n                | ValueConstructorVariant::Record { .. } => None,\n            }),\n        Located::Pattern(Pattern::Assign { location, name, .. }) => {\n            Some(Referenced::LocalVariable {\n                definition_location: *location,\n                location: *location,\n                origin: None,\n                name: name.clone(),\n            })\n        }\n        Located::Arg(arg) => match &arg.names {\n            ArgNames::Named { location, name }\n            | ArgNames::NamedLabelled {\n                name_location: location,\n                name,\n                ..\n            } => Some(Referenced::LocalVariable {\n                definition_location: *location,\n                location: *location,\n                origin: None,\n                name: name.clone(),\n            }),\n            ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None,\n        },\n        Located::Expression {\n            expression:\n                TypedExpr::Var {\n                    constructor:\n                        ValueConstructor {\n                            variant:\n                                ValueConstructorVariant::ModuleConstant { module, .. }\n                                | ValueConstructorVariant::ModuleFn { module, .. },\n                            ..\n                        },\n                    name,\n                    location,\n                    ..\n                },\n            ..\n        } => Some(Referenced::ModuleValue {\n            module: module.clone(),\n            name: name.clone(),\n            location: *location,\n            name_kind: Named::Function,\n            target_kind: RenameTarget::Unqualified,\n        }),\n\n        Located::Expression {\n            expression:\n                TypedExpr::ModuleSelect {\n                    module_name,\n                    label,\n                    constructor:\n                        ModuleValueConstructor::Fn { .. } | ModuleValueConstructor::Constant { .. },\n                    location,\n                    field_start,\n                    ..\n                },\n            ..\n        } => Some(Referenced::ModuleValue {\n            module: module_name.clone(),\n            name: label.clone(),\n            location: SrcSpan::new(*field_start, location.end),\n            name_kind: Named::Function,\n            target_kind: RenameTarget::Qualified,\n        }),\n\n        Located::ModuleFunction(Function {\n            name: Some((location, name)),\n            ..\n        })\n        | Located::ModuleConstant(ModuleConstant {\n            name,\n            name_location: location,\n            ..\n        }) => Some(Referenced::ModuleValue {\n            module: current_module.clone(),\n            name: name.clone(),\n            location: *location,\n            name_kind: Named::Function,\n            target_kind: RenameTarget::Definition,\n        }),\n        Located::Expression {\n            expression:\n                TypedExpr::Var {\n                    constructor:\n                        ValueConstructor {\n                            variant: ValueConstructorVariant::Record { module, name, .. },\n                            ..\n                        },\n                    location,\n                    ..\n                },\n            ..\n        } => Some(Referenced::ModuleValue {\n            module: module.clone(),\n            name: name.clone(),\n            location: *location,\n            name_kind: Named::CustomTypeVariant,\n            target_kind: RenameTarget::Unqualified,\n        }),\n        Located::Expression {\n            expression:\n                TypedExpr::ModuleSelect {\n                    module_name,\n                    label,\n                    constructor: ModuleValueConstructor::Record { .. },\n                    location,\n                    field_start,\n                    ..\n                },\n            ..\n        } => Some(Referenced::ModuleValue {\n            module: module_name.clone(),\n            name: label.clone(),\n            location: SrcSpan::new(*field_start, location.end),\n            name_kind: Named::CustomTypeVariant,\n            target_kind: RenameTarget::Qualified,\n        }),\n        Located::VariantConstructorDefinition(RecordConstructor {\n            name,\n            name_location,\n            ..\n        }) => Some(Referenced::ModuleValue {\n            module: current_module.clone(),\n            name: name.clone(),\n            location: *name_location,\n            name_kind: Named::CustomTypeVariant,\n            target_kind: RenameTarget::Definition,\n        }),\n        Located::Pattern(Pattern::Constructor {\n            constructor: analyse::Inferred::Known(constructor),\n            module: module_select,\n            name_location: location,\n            ..\n        }) => Some(Referenced::ModuleValue {\n            module: constructor.module.clone(),\n            name: constructor.name.clone(),\n            location: *location,\n            name_kind: Named::CustomTypeVariant,\n            target_kind: if module_select.is_some() {\n                RenameTarget::Qualified\n            } else {\n                RenameTarget::Unqualified\n            },\n        }),\n        Located::StringPrefixPatternVariable { location, name, .. } => {\n            Some(Referenced::LocalVariable {\n                definition_location: location,\n                location,\n                origin: None,\n                name: name.clone(),\n            })\n        }\n        Located::Annotation { ast, type_ } => match type_.named_type_name() {\n            Some((module, name)) => {\n                let (target_kind, location) = match ast {\n                    ast::TypeAst::Constructor(constructor) => {\n                        let kind = if constructor.module.is_some() {\n                            RenameTarget::Qualified\n                        } else {\n                            RenameTarget::Unqualified\n                        };\n                        (kind, constructor.name_location)\n                    }\n                    ast::TypeAst::Fn(_)\n                    | ast::TypeAst::Var(_)\n                    | ast::TypeAst::Tuple(_)\n                    | ast::TypeAst::Hole(_) => (RenameTarget::Unqualified, ast.location()),\n                };\n                Some(Referenced::ModuleType {\n                    module,\n                    name,\n                    location,\n                    target_kind,\n                })\n            }\n            None => None,\n        },\n        Located::ModuleCustomType(CustomType {\n            name,\n            name_location,\n            ..\n        }) => Some(Referenced::ModuleType {\n            module: current_module.clone(),\n            name: name.clone(),\n            location: *name_location,\n            target_kind: RenameTarget::Definition,\n        }),\n        Located::ModuleName {\n            location,\n            module_name,\n            module_alias,\n            ..\n        } => Some(Referenced::ModuleName {\n            module_name,\n            module_alias,\n            location,\n        }),\n        Located::ModuleImport(import) => {\n            let module_name = match &import.as_name {\n                Some((\n                    AssignName::Variable(module_alias) | AssignName::Discard(module_alias),\n                    alias_location,\n                )) => Referenced::ModuleName {\n                    module_name: import.module.clone(),\n                    module_alias: module_alias.clone(),\n                    location: SrcSpan {\n                        start: alias_location.end - (module_alias.len() as u32),\n                        end: alias_location.end,\n                    },\n                },\n                None => Referenced::ModuleName {\n                    module_name: import.module.clone(),\n                    module_alias: import\n                        .module\n                        .split('/')\n                        .next_back()\n                        .map(EcoString::from)\n                        .unwrap_or_else(|| import.module.clone()),\n                    location: import.module_location,\n                },\n            };\n\n            Some(module_name)\n        }\n\n        Located::ClauseGuard(ClauseGuard::Var {\n            location,\n            type_: _,\n            name,\n            definition_location,\n            origin,\n        }) => Some(Referenced::LocalVariable {\n            definition_location: *definition_location,\n            location: *location,\n            origin: Some(origin.clone()),\n            name: name.clone(),\n        }),\n\n        Located::ClauseGuard(ClauseGuard::ModuleSelect {\n            location,\n            field_start,\n            label,\n            module_name,\n            ..\n        }) => Some(Referenced::ModuleValue {\n            module: module_name.clone(),\n            name: label.clone(),\n            location: SrcSpan::new(*field_start, location.end),\n            name_kind: Named::Function,\n            target_kind: RenameTarget::Qualified,\n        }),\n\n        Located::Pattern(_)\n        | Located::ClauseGuard(_)\n        | Located::PatternSpread { .. }\n        | Located::Statement(_)\n        | Located::Expression { .. }\n        | Located::FunctionBody(_)\n        | Located::UnqualifiedImport(_)\n        | Located::Label(..)\n        | Located::Constant(_)\n        | Located::ModuleFunction(_)\n        | Located::ModuleTypeAlias(_) => None,\n    }\n}\n\npub fn find_module_references(\n    module_name: EcoString,\n    name: EcoString,\n    modules: &im::HashMap<EcoString, ModuleInterface>,\n    sources: &HashMap<EcoString, ModuleSourceInformation>,\n    layer: ast::Layer,\n) -> Vec<Location> {\n    let mut reference_locations = Vec::new();\n\n    for module in modules.values() {\n        if module.name == module_name || module.references.imported_modules.contains(&module_name) {\n            let Some(source_information) = sources.get(&module.name) else {\n                continue;\n            };\n\n            find_references_in_module(\n                &module_name,\n                &name,\n                module,\n                source_information,\n                &mut reference_locations,\n                layer,\n            );\n        }\n    }\n\n    reference_locations\n}\n\nfn find_references_in_module(\n    module_name: &EcoString,\n    name: &EcoString,\n    module: &ModuleInterface,\n    source_information: &ModuleSourceInformation,\n    reference_locations: &mut Vec<Location>,\n    layer: ast::Layer,\n) {\n    let reference_map = match layer {\n        ast::Layer::Value => &module.references.value_references,\n        ast::Layer::Type => &module.references.type_references,\n    };\n\n    let Some(references) = reference_map.get(&(module_name.clone(), name.clone())) else {\n        return;\n    };\n\n    let Some(uri) = url_from_path(source_information.path.as_str()) else {\n        return;\n    };\n\n    for reference in references {\n        reference_locations.push(Location {\n            uri: uri.clone(),\n            range: src_span_to_lsp_range(reference.location, &source_information.line_numbers),\n        });\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub struct VariableReference {\n    pub location: SrcSpan,\n    pub kind: VariableReferenceKind,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum VariableReferenceKind {\n    Variable,\n    LabelShorthand,\n}\n\n/// How to treat variables defined in alternative patterns\nenum AlternativeVariable {\n    Track,\n    Ignore,\n}\n\npub struct FindVariableReferences {\n    // Due to the structure of some AST nodes (for example, record updates),\n    // when we traverse the AST it is possible to accidentally duplicate references.\n    // To avoid this, we use a `HashSet` instead of a `Vec` here.\n    // See: https://github.com/gleam-lang/gleam/issues/4859 and the linked PR.\n    references: HashSet<VariableReference>,\n    definition_location: DefinitionLocation,\n    alternative_variable: AlternativeVariable,\n    name: EcoString,\n}\n\n/// Where the variable we're finding references for is defined.\n///\nenum DefinitionLocation {\n    /// This is the location where the variable is defined, nothing special is\n    /// going on here. For example:\n    ///\n    /// ```gleam\n    ///    let wibble = 1\n    /// //   ^^^^^^ Definition location for `wibble`\n    ///    wibble + 1\n    ///    ^^^^^^\n    /// // `wibble` used here, defined earlier\n    /// ```\n    ///\n    Regular { location: SrcSpan },\n\n    /// When dealing with alternative patterns and aliases we need special care:\n    /// each usage wil always reference the first alternative where a variable\n    /// is defined and not the following ones. For example:\n    ///\n    /// ```gleam\n    /// case wibble {\n    ///   [] as var | [_] as var -> var\n    ///   //    ^^^                 ^^^ If we look where `var` thinks it's defined\n    ///   //    It will say it's defined here!\n    /// }\n    /// ```\n    ///\n    /// This poses a problem if we start the renaming from the second\n    /// alternative pattern:\n    ///\n    /// ```gleam\n    /// case wibble {\n    ///   [] as var | [_] as var -> var\n    ///   //                 ^^^ Since `var` uses the first alternative as its\n    ///   //                     definition location, this would not be considered\n    ///   //                     a reference to that same var.\n    /// }\n    /// ```\n    ///\n    /// So we keep track of the location of this definition, but we also need\n    /// to store the location of the first definition in the alternative case\n    /// (that's `first_alternative_location`), so that when we look for\n    /// references we can check against this one that is canonically used by\n    /// expressions in the AST\n    ///\n    Alternative {\n        location: SrcSpan,\n        first_alternative_location: SrcSpan,\n    },\n}\n\nimpl FindVariableReferences {\n    pub fn new(variable_definition_location: SrcSpan, variable_name: EcoString) -> Self {\n        Self {\n            references: HashSet::new(),\n            definition_location: DefinitionLocation::Regular {\n                location: variable_definition_location,\n            },\n            alternative_variable: AlternativeVariable::Ignore,\n            name: variable_name,\n        }\n    }\n\n    /// Where the definition for which we're accumulating references is\n    /// originally defined. In case of alternative patterns this will point to\n    /// the first occurrence of that name! Look at the docs for\n    /// `DefinitionLocation` to learn more on why this is needed.\n    ///\n    fn definition_origin_location(&self) -> SrcSpan {\n        match self.definition_location {\n            DefinitionLocation::Regular { location }\n            | DefinitionLocation::Alternative {\n                first_alternative_location: location,\n                ..\n            } => location,\n        }\n    }\n\n    /// This is the location of the definition for which we're accumulating\n    /// references. In most cases you'll want to use `definition_origin_location`.\n    /// The difference between the two is explained in greater detail in the docs\n    /// for `DefinitionLocation`.\n    ///\n    fn definition_location(&self) -> SrcSpan {\n        match self.definition_location {\n            DefinitionLocation::Regular { location }\n            | DefinitionLocation::Alternative { location, .. } => location,\n        }\n    }\n\n    fn update_alternative_origin(&mut self, alternative_location: SrcSpan) {\n        match self.definition_location {\n            // We've found the location of the origin of an alternative pattern.\n            DefinitionLocation::Regular { location } if alternative_location < location => {\n                self.definition_location = DefinitionLocation::Alternative {\n                    location,\n                    first_alternative_location: alternative_location,\n                };\n            }\n\n            // Since the new alternative location we've found is smaller, that\n            // is the actual first one for the alternative pattern!\n            DefinitionLocation::Alternative {\n                location,\n                first_alternative_location,\n            } if alternative_location < first_alternative_location => {\n                self.definition_location = DefinitionLocation::Alternative {\n                    location,\n                    first_alternative_location: alternative_location,\n                };\n            }\n\n            DefinitionLocation::Regular { .. } | DefinitionLocation::Alternative { .. } => (),\n        };\n    }\n\n    pub fn find_in_module(mut self, module: &TypedModule) -> HashSet<VariableReference> {\n        self.visit_typed_module(module);\n        self.references\n    }\n\n    pub fn find(mut self, expression: &TypedExpr) -> HashSet<VariableReference> {\n        self.visit_typed_expr(expression);\n        self.references\n    }\n\n    fn register_alternative_definition(&mut self, name: &EcoString, location: &SrcSpan) {\n        match self.alternative_variable {\n            // If we are inside the same alternative pattern as the target\n            // variable and the name is the same, this is an alternative definition\n            // of the same variable. We don't register the reference if this is\n            // the exact variable though, as that would result in a duplicated\n            // reference.\n            AlternativeVariable::Track\n                if *name == self.name && *location != self.definition_location() =>\n            {\n                self.update_alternative_origin(*location);\n\n                _ = self.references.insert(VariableReference {\n                    location: *location,\n                    kind: VariableReferenceKind::Variable,\n                });\n            }\n            AlternativeVariable::Track | AlternativeVariable::Ignore => {}\n        }\n    }\n}\n\nimpl<'ast> Visit<'ast> for FindVariableReferences {\n    fn visit_typed_function(&mut self, fun: &'ast ast::TypedFunction) {\n        if fun\n            .full_location()\n            .contains(self.definition_origin_location().start)\n        {\n            ast::visit::visit_typed_function(self, fun);\n        }\n    }\n\n    fn visit_typed_expr_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor: &'ast ValueConstructor,\n        _name: &'ast EcoString,\n    ) {\n        match constructor.variant {\n            ValueConstructorVariant::LocalVariable {\n                location: definition_location,\n                ..\n            } if definition_location == self.definition_origin_location() => {\n                _ = self.references.insert(VariableReference {\n                    location: *location,\n                    kind: VariableReferenceKind::Variable,\n                });\n            }\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::ModuleFn { .. }\n            | ValueConstructorVariant::Record { .. } => {}\n        }\n    }\n\n    fn visit_typed_clause_guard_var(\n        &mut self,\n        location: &'ast SrcSpan,\n        _name: &'ast EcoString,\n        _type_: &'ast std::sync::Arc<Type>,\n        definition_location: &'ast SrcSpan,\n        _origin: &'ast VariableOrigin,\n    ) {\n        if *definition_location == self.definition_origin_location() {\n            _ = self.references.insert(VariableReference {\n                location: *location,\n                kind: VariableReferenceKind::Variable,\n            });\n        }\n    }\n\n    fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {\n        // If this alternative pattern contains the variable we are finding\n        // references for, we track that so we can find alternative definitions\n        // of the target variable.\n        if clause\n            .pattern_location()\n            .contains(self.definition_origin_location().start)\n        {\n            self.alternative_variable = AlternativeVariable::Track;\n        }\n\n        for pattern in clause.pattern.iter() {\n            self.visit_typed_pattern(pattern);\n        }\n        for patterns in clause.alternative_patterns.iter() {\n            for pattern in patterns {\n                self.visit_typed_pattern(pattern);\n            }\n        }\n\n        self.alternative_variable = AlternativeVariable::Ignore;\n\n        if let Some(guard) = &clause.guard {\n            self.visit_typed_clause_guard(guard);\n        }\n        self.visit_typed_expr(&clause.then);\n    }\n\n    fn visit_typed_pattern_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        _type_: &'ast std::sync::Arc<Type>,\n        _origin: &'ast VariableOrigin,\n    ) {\n        self.register_alternative_definition(name, location);\n    }\n\n    fn visit_typed_pattern_assign(\n        &mut self,\n        location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        pattern: &'ast ast::TypedPattern,\n    ) {\n        self.register_alternative_definition(name, location);\n\n        ast::visit::visit_typed_pattern_assign(self, location, name, pattern);\n    }\n\n    fn visit_typed_bit_array_size_variable(\n        &mut self,\n        location: &'ast SrcSpan,\n        _name: &'ast EcoString,\n        constructor: &'ast Option<Box<ValueConstructor>>,\n        _type_: &'ast std::sync::Arc<Type>,\n    ) {\n        let variant = match constructor {\n            Some(constructor) => &constructor.variant,\n            None => return,\n        };\n        match variant {\n            ValueConstructorVariant::LocalVariable {\n                location: definition_location,\n                ..\n            } if *definition_location == self.definition_origin_location() => {\n                _ = self.references.insert(VariableReference {\n                    location: *location,\n                    kind: VariableReferenceKind::Variable,\n                });\n            }\n            ValueConstructorVariant::LocalVariable { .. }\n            | ValueConstructorVariant::ModuleConstant { .. }\n            | ValueConstructorVariant::ModuleFn { .. }\n            | ValueConstructorVariant::Record { .. } => {}\n        }\n    }\n\n    fn visit_typed_call_arg(&mut self, arg: &'ast gleam_core::type_::TypedCallArg) {\n        if let TypedExpr::Var {\n            location,\n            constructor,\n            ..\n        } = &arg.value\n        {\n            match &constructor.variant {\n                ValueConstructorVariant::LocalVariable {\n                    location: definition_location,\n                    ..\n                } if arg.uses_label_shorthand()\n                    && *definition_location == self.definition_origin_location() =>\n                {\n                    _ = self.references.insert(VariableReference {\n                        location: *location,\n                        kind: VariableReferenceKind::LabelShorthand,\n                    });\n                    return;\n                }\n                ValueConstructorVariant::LocalVariable { .. }\n                | ValueConstructorVariant::ModuleConstant { .. }\n                | ValueConstructorVariant::ModuleFn { .. }\n                | ValueConstructorVariant::Record { .. } => {}\n            }\n        }\n\n        ast::visit::visit_typed_call_arg(self, arg);\n    }\n\n    fn visit_typed_pattern_string_prefix(\n        &mut self,\n        location: &'ast SrcSpan,\n        left_location: &'ast SrcSpan,\n        left_side_assignment: &'ast Option<(EcoString, SrcSpan)>,\n        right_location: &'ast SrcSpan,\n        left_side_string: &'ast EcoString,\n        right_side_assignment: &'ast AssignName,\n    ) {\n        // Handle the prefix alias in alternative pattern: \"prefix\" as name | \"other_prefix\" as name\n        if let Some((name, left_side_assignment_location)) = left_side_assignment {\n            self.register_alternative_definition(name, left_side_assignment_location);\n        }\n\n        // Handle the suffix in alternative pattern: \"prefix\" <> name | \"other_prefix\" <> name\n        match right_side_assignment {\n            AssignName::Variable(name) => {\n                self.register_alternative_definition(name, right_location)\n            }\n            AssignName::Discard(_) => {}\n        }\n\n        ast::visit::visit_typed_pattern_string_prefix(\n            self,\n            location,\n            left_location,\n            left_side_assignment,\n            right_location,\n            left_side_string,\n            right_side_assignment,\n        );\n    }\n}\n\npub struct ModuleNameReference {\n    pub location: SrcSpan,\n    pub kind: ModuleNameReferenceKind,\n}\n\npub enum ModuleNameReferenceKind {\n    Import,\n    AliasedImport,\n    ModuleSelect,\n}\n\npub struct FindModuleNameReferences<'a> {\n    pub references: Vec<ModuleNameReference>,\n    pub module_name: &'a EcoString,\n    pub module_alias: &'a EcoString,\n}\n\nimpl<'ast> Visit<'ast> for FindModuleNameReferences<'_> {\n    fn visit_typed_module(&mut self, module: &'ast TypedModule) {\n        ast::visit::visit_typed_module(self, module);\n    }\n\n    fn visit_typed_clause_guard(&mut self, guard: &'ast ast::TypedClauseGuard) {\n        ast::visit::visit_typed_clause_guard(self, guard);\n    }\n\n    fn visit_typed_import(&mut self, import: &'ast ast::TypedImport) {\n        match import.as_name.as_ref() {\n            None => {\n                if import.module == *self.module_name {\n                    self.references.push(ModuleNameReference {\n                        location: import.location,\n                        kind: ModuleNameReferenceKind::Import,\n                    })\n                }\n            }\n            Some((AssignName::Variable(alias) | AssignName::Discard(alias), alias_location)) => {\n                if alias == self.module_alias {\n                    self.references.push(ModuleNameReference {\n                        location: *alias_location,\n                        kind: ModuleNameReferenceKind::AliasedImport,\n                    })\n                }\n            }\n        }\n\n        ast::visit::visit_typed_import(self, import);\n    }\n\n    fn visit_typed_clause_guard_module_select(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        definition_location: &'ast SrcSpan,\n        type_: &'ast std::sync::Arc<Type>,\n        label: &'ast EcoString,\n        module_name: &'ast EcoString,\n        module_alias: &'ast EcoString,\n        literal: &'ast ast::TypedConstant,\n    ) {\n        if module_alias == self.module_alias {\n            self.references.push(ModuleNameReference {\n                location: SrcSpan::new(\n                    location.start,\n                    location.start + (module_alias.len() as u32),\n                ),\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            });\n        }\n\n        ast::visit::visit_typed_clause_guard_module_select(\n            self,\n            location,\n            field_start,\n            definition_location,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            literal,\n        );\n    }\n\n    fn visit_typed_expr_module_select(\n        &mut self,\n        location: &'ast SrcSpan,\n        field_start: &'ast u32,\n        type_: &'ast std::sync::Arc<Type>,\n        label: &'ast EcoString,\n        module_name: &'ast EcoString,\n        module_alias: &'ast EcoString,\n        constructor: &'ast ModuleValueConstructor,\n    ) {\n        if module_alias == self.module_alias {\n            self.references.push(ModuleNameReference {\n                location: SrcSpan::new(\n                    location.start,\n                    location.start + (module_alias.len() as u32),\n                ),\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            });\n        }\n\n        ast::visit::visit_typed_expr_module_select(\n            self,\n            location,\n            field_start,\n            type_,\n            label,\n            module_name,\n            module_alias,\n            constructor,\n        );\n    }\n\n    fn visit_type_ast_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast [ast::TypeAst],\n        arguments_types: Option<Vec<std::sync::Arc<Type>>>,\n    ) {\n        if let Some((module_alias, module_location)) = module\n            && module_alias == self.module_alias\n        {\n            self.references.push(ModuleNameReference {\n                location: *module_location,\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            })\n        }\n\n        ast::visit::visit_type_ast_constructor(\n            self,\n            location,\n            name_location,\n            module,\n            name,\n            arguments,\n            arguments_types,\n        );\n    }\n\n    fn visit_typed_constant_record(\n        &mut self,\n        location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<ast::CallArg<ast::TypedConstant>>,\n        tag: &'ast EcoString,\n        type_: &'ast std::sync::Arc<Type>,\n        field_map: &'ast analyse::Inferred<gleam_core::type_::FieldMap>,\n        record_constructor: &'ast Option<Box<ValueConstructor>>,\n    ) {\n        if let Some((module_alias, module_location)) = module\n            && module_alias == self.module_alias\n        {\n            self.references.push(ModuleNameReference {\n                location: *module_location,\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            })\n        }\n\n        ast::visit::visit_typed_constant_record(\n            self,\n            location,\n            module,\n            name,\n            arguments,\n            tag,\n            type_,\n            field_map,\n            record_constructor,\n        );\n    }\n\n    fn visit_typed_constant_record_update(\n        &mut self,\n        location: &'ast SrcSpan,\n        constructor_location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        name: &'ast EcoString,\n        record: &'ast ast::RecordBeingUpdated<ast::TypedConstant>,\n        arguments: &'ast [ast::RecordUpdateArg<ast::TypedConstant>],\n        tag: &'ast EcoString,\n        type_: &'ast std::sync::Arc<Type>,\n        field_map: &'ast analyse::Inferred<gleam_core::type_::FieldMap>,\n    ) {\n        if let Some((module_alias, module_location)) = module\n            && module_alias == self.module_alias\n        {\n            self.references.push(ModuleNameReference {\n                location: *module_location,\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            })\n        }\n\n        ast::visit::visit_typed_constant_record_update(\n            self,\n            location,\n            constructor_location,\n            module,\n            name,\n            record,\n            arguments,\n            tag,\n            type_,\n            field_map,\n        )\n    }\n\n    fn visit_typed_constant_var(\n        &mut self,\n        _location: &'ast SrcSpan,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        _name: &'ast EcoString,\n        _constructor: &'ast Option<Box<ValueConstructor>>,\n        _type_: &'ast std::sync::Arc<Type>,\n    ) {\n        if let Some((module_alias, module_location)) = module\n            && module_alias == self.module_alias\n        {\n            self.references.push(ModuleNameReference {\n                location: *module_location,\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            })\n        }\n    }\n\n    fn visit_typed_pattern_constructor(\n        &mut self,\n        location: &'ast SrcSpan,\n        name_location: &'ast SrcSpan,\n        name: &'ast EcoString,\n        arguments: &'ast Vec<ast::CallArg<ast::TypedPattern>>,\n        module: &'ast Option<(EcoString, SrcSpan)>,\n        constructor: &'ast analyse::Inferred<gleam_core::type_::PatternConstructor>,\n        spread: &'ast Option<SrcSpan>,\n        type_: &'ast std::sync::Arc<Type>,\n    ) {\n        if let Some((module_alias, module_location)) = module\n            && module_alias == self.module_alias\n        {\n            self.references.push(ModuleNameReference {\n                location: *module_location,\n                kind: ModuleNameReferenceKind::ModuleSelect,\n            });\n        }\n\n        ast::visit::visit_typed_pattern_constructor(\n            self,\n            location,\n            name_location,\n            name,\n            arguments,\n            module,\n            constructor,\n            spread,\n            type_,\n        );\n    }\n}\n"
  },
  {
    "path": "language-server/src/rename.rs",
    "content": "use std::collections::HashMap;\n\nuse ecow::EcoString;\nuse lsp_server::ResponseError;\nuse lsp_types::{Range, RenameParams, TextEdit, Url, WorkspaceEdit};\n\nuse gleam_core::{\n    analyse::name,\n    ast::{self, SrcSpan, visit::Visit},\n    build::Module,\n    line_numbers::LineNumbers,\n    reference::ReferenceKind,\n    type_::{ModuleInterface, error::Named},\n};\n\nuse crate::reference::{self, ModuleNameReferenceKind};\n\nuse super::{\n    TextEdits,\n    compiler::ModuleSourceInformation,\n    edits::{self, Newlines, add_newlines_after_import, position_of_first_definition_if_import},\n    reference::FindVariableReferences,\n    reference::VariableReferenceKind,\n    url_from_path,\n};\n\nfn workspace_edit(uri: Url, edits: Vec<TextEdit>) -> WorkspaceEdit {\n    let mut changes = HashMap::new();\n    let _ = changes.insert(uri, edits);\n\n    WorkspaceEdit {\n        changes: Some(changes),\n        document_changes: None,\n        change_annotations: None,\n    }\n}\n\npub enum RenameOutcome {\n    InvalidName { name: EcoString },\n    NoRenames,\n    Renamed { edit: WorkspaceEdit },\n}\n\n/// Error code for when a request has invalid params as described in:\n/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#errorCodes\n///\nconst INVALID_PARAMS: i32 = -32602;\n\nimpl RenameOutcome {\n    /// Turns the outcome of renaming into a value that's suitable to be used as\n    /// a response in the language server engine.\n    ///\n    pub fn into_result(self) -> Result<Option<WorkspaceEdit>, ResponseError> {\n        match self {\n            RenameOutcome::NoRenames => Ok(None),\n            RenameOutcome::Renamed { edit } => Ok(Some(edit)),\n            RenameOutcome::InvalidName { name } => Err(ResponseError {\n                code: INVALID_PARAMS,\n                message: format!(\"{name} is not a valid name\"),\n                data: None,\n            }),\n        }\n    }\n}\n\npub fn rename_local_variable(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &RenameParams,\n    definition_location: SrcSpan,\n    name: EcoString,\n    kind: VariableReferenceKind,\n) -> RenameOutcome {\n    let new_name = EcoString::from(&params.new_name);\n    if name::check_name_case(Default::default(), &new_name, Named::Variable).is_err() {\n        return RenameOutcome::InvalidName { name: new_name };\n    }\n\n    let uri = params.text_document_position.text_document.uri.clone();\n    let mut edits = TextEdits::new(line_numbers);\n\n    let references =\n        FindVariableReferences::new(definition_location, name).find_in_module(&module.ast);\n\n    match kind {\n        VariableReferenceKind::Variable => {\n            edits.replace(definition_location, params.new_name.clone())\n        }\n        VariableReferenceKind::LabelShorthand => {\n            edits.insert(definition_location.end, format!(\" {}\", params.new_name))\n        }\n    }\n\n    for reference in references {\n        match reference.kind {\n            VariableReferenceKind::Variable => {\n                edits.replace(reference.location, params.new_name.clone())\n            }\n            VariableReferenceKind::LabelShorthand => {\n                edits.insert(reference.location.end, format!(\" {}\", params.new_name))\n            }\n        }\n    }\n\n    RenameOutcome::Renamed {\n        edit: workspace_edit(uri, edits.edits),\n    }\n}\n\n#[derive(Debug)]\npub enum RenameTarget {\n    Qualified,\n    Unqualified,\n    Definition,\n}\n\npub struct Renamed<'a> {\n    pub module_name: &'a EcoString,\n    pub name: &'a EcoString,\n    pub name_kind: Named,\n    pub target_kind: RenameTarget,\n    pub layer: ast::Layer,\n}\n\npub fn rename_module_entity(\n    params: &RenameParams,\n    current_module: &Module,\n    modules: &im::HashMap<EcoString, ModuleInterface>,\n    sources: &HashMap<EcoString, ModuleSourceInformation>,\n    renamed: Renamed<'_>,\n) -> RenameOutcome {\n    let new_name = EcoString::from(&params.new_name);\n    if name::check_name_case(\n        // We don't care about the actual error here, just whether the name is valid,\n        // so we just use the default span.\n        SrcSpan::default(),\n        &new_name,\n        renamed.name_kind,\n    )\n    .is_err()\n    {\n        return RenameOutcome::InvalidName { name: new_name };\n    }\n\n    match renamed.target_kind {\n        // When renaming an unqualified import, instead of renaming the original\n        // value, we simply want to alias it in the current module.\n        // It's an unqualified import if we are referencing it using unqualified\n        // syntax, and it is from a different module.\n        RenameTarget::Unqualified if renamed.module_name != &current_module.name => {\n            return alias_references_in_module(\n                params,\n                current_module,\n                renamed.module_name,\n                renamed.name,\n                renamed.layer,\n            );\n        }\n        RenameTarget::Unqualified | RenameTarget::Qualified | RenameTarget::Definition => {}\n    }\n\n    let mut workspace_edit = WorkspaceEdit {\n        changes: Some(HashMap::new()),\n        document_changes: None,\n        change_annotations: None,\n    };\n\n    for module in modules.values() {\n        if &module.name == renamed.module_name\n            || module\n                .references\n                .imported_modules\n                .contains(renamed.module_name)\n        {\n            let Some(source_information) = sources.get(&module.name) else {\n                continue;\n            };\n\n            rename_references_in_module(\n                module,\n                source_information,\n                &mut workspace_edit,\n                renamed.module_name,\n                renamed.name,\n                params.new_name.clone(),\n                renamed.layer,\n            );\n        }\n    }\n\n    RenameOutcome::Renamed {\n        edit: workspace_edit,\n    }\n}\n\nfn rename_references_in_module(\n    module: &ModuleInterface,\n    source_information: &ModuleSourceInformation,\n    workspace_edit: &mut WorkspaceEdit,\n    module_name: &EcoString,\n    name: &EcoString,\n    new_name: String,\n    layer: ast::Layer,\n) {\n    let reference_map = match layer {\n        ast::Layer::Value => &module.references.value_references,\n        ast::Layer::Type => &module.references.type_references,\n    };\n\n    let Some(references) = reference_map.get(&(module_name.clone(), name.clone())) else {\n        return;\n    };\n\n    let mut edits = TextEdits::new(&source_information.line_numbers);\n\n    for reference in references {\n        match reference.kind {\n            // If the reference is an alias, the alias name will remain unchanged.\n            ReferenceKind::Alias => {}\n            ReferenceKind::Qualified\n            | ReferenceKind::Unqualified\n            | ReferenceKind::Import\n            | ReferenceKind::Definition => edits.replace(reference.location, new_name.clone()),\n        }\n    }\n\n    let Some(uri) = url_from_path(source_information.path.as_str()) else {\n        return;\n    };\n\n    if let Some(changes) = workspace_edit.changes.as_mut() {\n        _ = changes.insert(uri, edits.edits);\n    }\n}\n\nfn alias_references_in_module(\n    params: &RenameParams,\n    module: &Module,\n    module_name: &EcoString,\n    name: &EcoString,\n    layer: ast::Layer,\n) -> RenameOutcome {\n    let reference_map = match layer {\n        ast::Layer::Value => &module.ast.type_info.references.value_references,\n        ast::Layer::Type => &module.ast.type_info.references.type_references,\n    };\n\n    let Some(references) = reference_map.get(&(module_name.clone(), name.clone())) else {\n        return RenameOutcome::NoRenames;\n    };\n\n    let mut edits = TextEdits::new(&module.ast.type_info.line_numbers);\n    let mut found_import = false;\n\n    for reference in references {\n        match reference.kind {\n            ReferenceKind::Qualified => {}\n            ReferenceKind::Unqualified | ReferenceKind::Alias => {\n                edits.replace(reference.location, params.new_name.clone())\n            }\n            ReferenceKind::Import => {\n                edits.insert(reference.location.end, format!(\" as {}\", params.new_name));\n                found_import = true;\n            }\n            ReferenceKind::Definition => {}\n        }\n    }\n\n    // If we didn't find the import for the aliased type or value, then this is\n    // a prelude value and we need to add the import so we can alias it.\n    if !found_import {\n        let unqualified_import = match layer {\n            ast::Layer::Value => format!(\"{name} as {}\", params.new_name),\n            ast::Layer::Type => format!(\"type {name} as {}\", params.new_name),\n        };\n\n        let import = module\n            .ast\n            .definitions\n            .imports\n            .iter()\n            .find(|import| import.module == *module_name);\n\n        if let Some(import) = import {\n            let (position, new_text) =\n                edits::insert_unqualified_import(import, &module.code, unqualified_import);\n            edits.insert(position, new_text);\n        } else {\n            add_import(module, module_name, unqualified_import, &mut edits);\n        }\n    }\n\n    RenameOutcome::Renamed {\n        edit: workspace_edit(\n            params.text_document_position.text_document.uri.clone(),\n            edits.edits,\n        ),\n    }\n}\n\nfn add_import(\n    module: &Module,\n    module_name: &EcoString,\n    unqualified_import: String,\n    edits: &mut TextEdits<'_>,\n) {\n    let position_of_first_import_if_present =\n        position_of_first_definition_if_import(module, &module.ast.type_info.line_numbers);\n    let first_is_import = position_of_first_import_if_present.is_some();\n    let import_location = position_of_first_import_if_present.unwrap_or_default();\n\n    let after_import_newlines = add_newlines_after_import(\n        import_location,\n        first_is_import,\n        &module.ast.type_info.line_numbers,\n        &module.code,\n    );\n\n    let newlines = match after_import_newlines {\n        Newlines::Single => \"\\n\",\n        Newlines::Double => \"\\n\\n\",\n    };\n\n    edits.edits.push(TextEdit {\n        range: Range {\n            start: import_location,\n            end: import_location,\n        },\n        new_text: format!(\"import {module_name}.{{{unqualified_import}}}{newlines}\",),\n    });\n}\n\npub fn rename_module_alias(\n    module: &Module,\n    line_numbers: &LineNumbers,\n    params: &RenameParams,\n    module_name: &EcoString,\n    module_alias: &EcoString,\n) -> RenameOutcome {\n    let new_name = EcoString::from(&params.new_name);\n    if name::check_name_case(SrcSpan::default(), &new_name, Named::Variable).is_err() {\n        return RenameOutcome::InvalidName { name: new_name };\n    }\n\n    let uri = params.text_document_position.text_document.uri.clone();\n    let mut edits = TextEdits::new(line_numbers);\n\n    let mut finder = reference::FindModuleNameReferences {\n        references: Vec::new(),\n        module_name,\n        module_alias,\n    };\n    finder.visit_typed_module(&module.ast);\n\n    let original_module_name = module_name.split('/').next_back().unwrap_or(\"\");\n\n    for reference in finder.references {\n        match reference.kind {\n            ModuleNameReferenceKind::Import => {\n                edits.insert(reference.location.end, format!(\" as {}\", &params.new_name))\n            }\n            ModuleNameReferenceKind::AliasedImport => {\n                if params.new_name == original_module_name {\n                    edits.delete(SrcSpan::new(\n                        reference.location.start - 1,\n                        reference.location.end,\n                    ));\n                } else {\n                    edits.replace(reference.location, format!(\"as {}\", &params.new_name))\n                }\n            }\n            ModuleNameReferenceKind::ModuleSelect => {\n                edits.replace(reference.location, params.new_name.to_string())\n            }\n        }\n    }\n\n    RenameOutcome::Renamed {\n        edit: workspace_edit(uri, edits.edits),\n    }\n}\n"
  },
  {
    "path": "language-server/src/router.rs",
    "content": "use gleam_core::{\n    Error, Result,\n    build::SourceFingerprint,\n    error::{FileIoAction, FileKind},\n    io::{BeamCompiler, CommandExecutor, FileSystemReader, FileSystemWriter},\n    paths::ProjectPaths,\n};\nuse std::{\n    collections::{HashMap, hash_map::Entry},\n    time::SystemTime,\n};\n\nuse camino::{Utf8Path, Utf8PathBuf};\n\nuse super::{\n    DownloadDependencies, MakeLocker, engine::LanguageServerEngine, feedback::FeedbackBookKeeper,\n    files::FileSystemProxy, progress::ProgressReporter,\n};\n\n/// The language server instance serves a language client, typically a text\n/// editor. The editor could have multiple Gleam projects open at once, so run\n/// an instance of the language server engine for each project.\n///\n/// This router is responsible for finding or creating an engine for a given\n/// file using the nearest parent `gleam.toml` file.\n///\n#[derive(Debug)]\npub(crate) struct Router<IO, Reporter> {\n    io: FileSystemProxy<IO>,\n    engines: HashMap<Utf8PathBuf, Project<IO, Reporter>>,\n    progress_reporter: Reporter,\n}\n\nimpl<IO, Reporter> Router<IO, Reporter>\nwhere\n    // IO to be supplied from outside of gleam-core\n    IO: FileSystemReader\n        + FileSystemWriter\n        + BeamCompiler\n        + CommandExecutor\n        + DownloadDependencies\n        + MakeLocker\n        + Clone,\n    // IO to be supplied from inside of gleam-core\n    Reporter: ProgressReporter + Clone,\n{\n    pub fn new(progress_reporter: Reporter, io: FileSystemProxy<IO>) -> Self {\n        Self {\n            io,\n            engines: HashMap::new(),\n            progress_reporter,\n        }\n    }\n\n    pub fn project_path(&self, path: &Utf8Path) -> Option<Utf8PathBuf> {\n        find_gleam_project_parent(&self.io, path)\n    }\n\n    pub fn project_for_path(\n        &mut self,\n        path: Utf8PathBuf,\n    ) -> Result<Option<&mut Project<IO, Reporter>>> {\n        // If the path is the root of a known project then return it. Otherwise\n        // find the nearest parent project.\n        let path = if self.engines.contains_key(&path) {\n            path\n        } else {\n            let Some(path) = find_gleam_project_parent(&self.io, &path) else {\n                return Ok(None);\n            };\n            path\n        };\n\n        // If the gleam.toml has changed or the build directory is missing\n        // (e.g. `gleam clean`), then discard the project as the target,\n        // deps, etc may have changed and we need to rebuild taking them into\n        // account.\n        if let Some(project) = self.engines.get(&path) {\n            let paths = ProjectPaths::new(path.clone());\n\n            if !self.io.exists(&paths.build_directory())\n                || Self::gleam_toml_changed(&paths, project, &self.io)?\n            {\n                let _ = self.engines.remove(&path);\n            }\n        }\n\n        // Look up the project, creating a new one if it does not exist.\n        Ok(Some(match self.engines.entry(path.clone()) {\n            Entry::Occupied(entry) => entry.into_mut(),\n            Entry::Vacant(entry) => {\n                let project =\n                    Self::new_project(path, self.io.clone(), self.progress_reporter.clone())?;\n                entry.insert(project)\n            }\n        }))\n    }\n\n    /// Has gleam.toml changed since the last time we saw this project?\n    fn gleam_toml_changed(\n        paths: &ProjectPaths,\n        project: &Project<IO, Reporter>,\n        io: &FileSystemProxy<IO>,\n    ) -> Result<bool, Error> {\n        // Get the location of gleam.toml for this project\n        let config_path = paths.root_config();\n\n        // See if the file modification time has changed.\n        if io.modification_time(&config_path)? == project.gleam_toml_modification_time {\n            return Ok(false); // Not changed\n        }\n\n        // The mtime has changed. This might not be a content change, so let's\n        // check the hash.\n        let toml = io.read(&config_path)?;\n        let gleam_toml_changed = project.gleam_toml_fingerprint != SourceFingerprint::new(&toml);\n        Ok(gleam_toml_changed)\n    }\n\n    pub fn delete_engine_for_path(&mut self, path: &Utf8Path) {\n        if let Some(path) = find_gleam_project_parent(&self.io, path) {\n            _ = self.engines.remove(&path);\n        }\n    }\n\n    fn new_project(\n        path: Utf8PathBuf,\n        io: FileSystemProxy<IO>,\n        progress_reporter: Reporter,\n    ) -> Result<Project<IO, Reporter>, Error> {\n        tracing::info!(?path, \"creating_new_language_server_engine\");\n        let paths = ProjectPaths::new(path);\n        let config_path = paths.root_config();\n        let modification_time = io.modification_time(&config_path)?;\n        let toml = io.read(&config_path)?;\n        let config = toml::from_str(&toml).map_err(|e| Error::FileIo {\n            action: FileIoAction::Parse,\n            kind: FileKind::File,\n            path: config_path,\n            err: Some(e.to_string()),\n        })?;\n        let engine = LanguageServerEngine::new(config, progress_reporter, io, paths)?;\n        let project = Project {\n            engine,\n            feedback: FeedbackBookKeeper::default(),\n            gleam_toml_modification_time: modification_time,\n            gleam_toml_fingerprint: SourceFingerprint::new(&toml),\n        };\n        Ok(project)\n    }\n}\n\n/// Given a given path, find the nearest parent directory containing a\n/// `gleam.toml` file.\n///\n/// The file must be in either the `src`, `test` or `dev` directory if it is not a\n/// `.gleam` file.\nfn find_gleam_project_parent<IO>(io: &IO, path: &Utf8Path) -> Option<Utf8PathBuf>\nwhere\n    IO: FileSystemReader,\n{\n    let is_module = path.extension().map(|x| x == \"gleam\").unwrap_or(false);\n    let mut directory = path.to_path_buf();\n\n    // If we are finding the gleam project of a directory then we want to check the directory itself\n    let is_directory = path.extension().is_none();\n    if is_directory {\n        directory.push(\"src\");\n    }\n\n    while let Some(root) = directory.parent() {\n        // If there's no gleam.toml in the root then we continue to the next parent.\n        if !io.is_file(&root.join(\"gleam.toml\")) {\n            _ = directory.pop();\n            continue;\n        }\n\n        // If it is a Gleam module then it must reside in the src, test dev directory.\n        if is_module\n            && !(directory.ends_with(\"test\")\n                || directory.ends_with(\"src\")\n                || directory.ends_with(\"dev\"))\n        {\n            _ = directory.pop();\n            continue;\n        }\n\n        return Some(root.to_path_buf());\n    }\n    None\n}\n\n#[derive(Debug)]\npub(crate) struct Project<A, B> {\n    pub engine: LanguageServerEngine<A, B>,\n    pub feedback: FeedbackBookKeeper,\n    pub gleam_toml_modification_time: SystemTime,\n    pub gleam_toml_fingerprint: SourceFingerprint,\n}\n\n#[cfg(test)]\nmod find_gleam_project_parent_tests {\n    use super::*;\n    use gleam_core::io::{FileSystemWriter, memory::InMemoryFileSystem};\n\n    #[test]\n    fn root() {\n        let io = InMemoryFileSystem::new();\n        assert_eq!(find_gleam_project_parent(&io, Utf8Path::new(\"/\")), None);\n    }\n\n    #[test]\n    fn outside_a_project() {\n        let io = InMemoryFileSystem::new();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/src/one.gleam\")),\n            None\n        );\n    }\n\n    #[test]\n    fn gleam_toml_itself() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/gleam.toml\")),\n            Some(Utf8PathBuf::from(\"/app\"))\n        );\n    }\n\n    #[test]\n    fn directory_with_gleam_toml() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app\")),\n            Some(Utf8PathBuf::from(\"/app\"))\n        );\n    }\n\n    #[test]\n    fn test_module() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/test/one/two/three.gleam\")),\n            Some(Utf8PathBuf::from(\"/app\"))\n        );\n    }\n\n    #[test]\n    fn src_module() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/src/one/two/three.gleam\")),\n            Some(Utf8PathBuf::from(\"/app\"))\n        );\n    }\n\n    #[test]\n    fn dev_module() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/dev/one/two/three.gleam\")),\n            Some(Utf8PathBuf::from(\"/app\"))\n        );\n    }\n\n    // https://github.com/gleam-lang/gleam/issues/2121\n    #[test]\n    fn module_in_project_but_not_src_or_test_or_dev() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/other/one/two/three.gleam\")),\n            None,\n        );\n    }\n\n    #[test]\n    fn nested_projects() {\n        let io = InMemoryFileSystem::new();\n        io.write(Utf8Path::new(\"/app/gleam.toml\"), \"\").unwrap();\n        io.write(Utf8Path::new(\"/app/examples/wibble/gleam.toml\"), \"\")\n            .unwrap();\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/src/one.gleam\")),\n            Some(Utf8PathBuf::from(\"/app\"))\n        );\n        assert_eq!(\n            find_gleam_project_parent(&io, Utf8Path::new(\"/app/examples/wibble/src/one.gleam\")),\n            Some(Utf8PathBuf::from(\"/app/examples/wibble\"))\n        );\n    }\n}\n"
  },
  {
    "path": "language-server/src/server.rs",
    "content": "use super::{\n    DownloadDependencies, MakeLocker,\n    engine::{self, LanguageServerEngine},\n    feedback::{Feedback, FeedbackBookKeeper},\n    files::FileSystemProxy,\n    messages::{Message, MessageBuffer, Next, Notification, Request},\n    progress::ConnectionProgressReporter,\n    router::Router,\n    src_span_to_lsp_range,\n};\nuse camino::{Utf8Path, Utf8PathBuf};\nuse debug_ignore::DebugIgnore;\nuse gleam_core::{\n    Result,\n    diagnostic::{Diagnostic, ExtraLabel, Level},\n    io::{BeamCompiler, CommandExecutor, FileSystemReader, FileSystemWriter},\n    line_numbers::LineNumbers,\n};\nuse lsp_server::ResponseError;\nuse lsp_types::{\n    self as lsp, HoverProviderCapability, InitializeParams, Position, PublishDiagnosticsParams,\n    Range, RenameOptions, TextEdit, Url,\n};\nuse serde_json::Value as Json;\nuse std::collections::{HashMap, HashSet};\n\n/// This class is responsible for handling the language server protocol and\n/// delegating the work to the engine.\n///\n/// - Configuring watching of the `gleam.toml` file.\n/// - Decoding requests.\n/// - Encoding responses.\n/// - Sending diagnostics and messages to the client.\n/// - Tracking the state of diagnostics and messages.\n/// - Performing the initialisation handshake.\n///\n#[derive(Debug)]\npub struct LanguageServer<'a, IO> {\n    initialise_params: InitializeParams,\n    connection: DebugIgnore<&'a lsp_server::Connection>,\n    outside_of_project_feedback: FeedbackBookKeeper,\n    router: Router<IO, ConnectionProgressReporter<'a>>,\n    changed_projects: HashSet<Utf8PathBuf>,\n    io: FileSystemProxy<IO>,\n}\n\nimpl<'a, IO> LanguageServer<'a, IO>\nwhere\n    IO: FileSystemReader\n        + FileSystemWriter\n        + BeamCompiler\n        + CommandExecutor\n        + DownloadDependencies\n        + MakeLocker\n        + Clone,\n{\n    pub fn new(connection: &'a lsp_server::Connection, io: IO) -> Result<Self> {\n        let initialise_params = initialisation_handshake(connection);\n        let reporter = ConnectionProgressReporter::new(connection, &initialise_params);\n        let io = FileSystemProxy::new(io);\n        let router = Router::new(reporter, io.clone());\n        Ok(Self {\n            connection: connection.into(),\n            initialise_params,\n            changed_projects: HashSet::new(),\n            outside_of_project_feedback: FeedbackBookKeeper::default(),\n            router,\n            io,\n        })\n    }\n\n    pub fn run(&mut self) -> Result<()> {\n        self.start_watching_gleam_toml();\n        let mut buffer = MessageBuffer::new();\n\n        loop {\n            match buffer.receive(*self.connection) {\n                Next::Stop => break,\n                Next::MorePlease => (),\n                Next::Handle(messages) => {\n                    for message in messages {\n                        self.handle_message(message);\n                    }\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn handle_message(&mut self, message: Message) {\n        match message {\n            Message::Request(id, request) => self.handle_request(id, request),\n            Message::Notification(notification) => self.handle_notification(notification),\n        }\n    }\n\n    fn handle_request(&mut self, id: lsp_server::RequestId, request: Request) {\n        let (outcome, feedback) = match request {\n            Request::Format(param) => self.format(param),\n            Request::Hover(param) => self.hover(param),\n            Request::GoToDefinition(param) => self.goto_definition(param),\n            Request::Completion(param) => self.completion(param),\n            Request::CodeAction(param) => self.code_action(param),\n            Request::SignatureHelp(param) => self.signature_help(param),\n            Request::DocumentSymbol(param) => self.document_symbol(param),\n            Request::FoldingRange(param) => self.folding_range(param),\n            Request::PrepareRename(param) => self.prepare_rename(param),\n            Request::Rename(param) => self.rename(param),\n            Request::GoToTypeDefinition(param) => self.goto_type_definition(param),\n            Request::FindReferences(param) => self.find_references(param),\n        };\n\n        self.publish_feedback(feedback);\n\n        let response = match outcome {\n            Ok(payload) => lsp_server::Response {\n                id,\n                error: None,\n                result: Some(payload),\n            },\n            Err(error) => lsp_server::Response {\n                id,\n                error: Some(error),\n                result: None,\n            },\n        };\n\n        self.connection\n            .sender\n            .send(lsp_server::Message::Response(response))\n            .expect(\"channel send LSP response\")\n    }\n\n    fn handle_notification(&mut self, notification: Notification) {\n        let feedback = match notification {\n            Notification::CompilePlease => self.compile_please(),\n            Notification::SourceFileMatchesDisc { path } => self.discard_in_memory_cache(path),\n            Notification::SourceFileChangedInMemory { path, text } => {\n                self.cache_file_in_memory(path, text)\n            }\n            Notification::ConfigFileChanged { path } => self.watched_files_changed(path),\n        };\n        self.publish_feedback(feedback);\n    }\n\n    fn publish_feedback(&self, feedback: Feedback) {\n        self.publish_diagnostics(feedback.diagnostics);\n        self.publish_messages(feedback.messages);\n    }\n\n    fn publish_diagnostics(&self, diagnostics: HashMap<Utf8PathBuf, Vec<Diagnostic>>) {\n        for (path, diagnostics) in diagnostics {\n            let diagnostics = diagnostics\n                .into_iter()\n                .flat_map(diagnostic_to_lsp)\n                .collect::<Vec<_>>();\n            let uri = path_to_uri(path);\n\n            // Publish the diagnostics\n            let diagnostic_params = PublishDiagnosticsParams {\n                uri,\n                diagnostics,\n                version: None,\n            };\n            let notification = lsp_server::Notification {\n                method: \"textDocument/publishDiagnostics\".into(),\n                params: serde_json::to_value(diagnostic_params)\n                    .expect(\"textDocument/publishDiagnostics to json\"),\n            };\n            self.connection\n                .sender\n                .send(lsp_server::Message::Notification(notification))\n                .expect(\"send textDocument/publishDiagnostics\");\n        }\n    }\n\n    fn start_watching_gleam_toml(&mut self) {\n        let supports_watch_files = self\n            .initialise_params\n            .capabilities\n            .workspace\n            .as_ref()\n            .and_then(|w| w.did_change_watched_files)\n            .map(|wf| wf.dynamic_registration.unwrap_or(false))\n            .unwrap_or(false);\n\n        if !supports_watch_files {\n            tracing::warn!(\"lsp_client_cannot_watch_gleam_toml\");\n            return;\n        }\n\n        // Register gleam.toml as a watched file so we get a notification when\n        // it changes and thus know that we need to rebuild the entire project.\n        let watch_config = lsp::Registration {\n            id: \"watch-gleam-toml\".into(),\n            method: \"workspace/didChangeWatchedFiles\".into(),\n            register_options: Some(\n                serde_json::value::to_value(lsp::DidChangeWatchedFilesRegistrationOptions {\n                    watchers: vec![lsp::FileSystemWatcher {\n                        glob_pattern: \"**/gleam.toml\".to_string().into(),\n                        kind: Some(lsp::WatchKind::Change),\n                    }],\n                })\n                .expect(\"workspace/didChangeWatchedFiles to json\"),\n            ),\n        };\n        let request = lsp_server::Request {\n            id: 1.into(),\n            method: \"client/registerCapability\".into(),\n            params: serde_json::value::to_value(lsp::RegistrationParams {\n                registrations: vec![watch_config],\n            })\n            .expect(\"client/registerCapability to json\"),\n        };\n        self.connection\n            .sender\n            .send(lsp_server::Message::Request(request))\n            .expect(\"send client/registerCapability\");\n    }\n\n    fn publish_messages(&self, messages: Vec<Diagnostic>) {\n        for message in messages {\n            let params = lsp::ShowMessageParams {\n                typ: match message.level {\n                    Level::Error => lsp::MessageType::ERROR,\n                    Level::Warning => lsp::MessageType::WARNING,\n                },\n                message: message.text,\n            };\n            let notification = lsp_server::Notification {\n                method: \"window/showMessage\".into(),\n                params: serde_json::to_value(params).expect(\"window/showMessage to json\"),\n            };\n            self.connection\n                .sender\n                .send(lsp_server::Message::Notification(notification))\n                .expect(\"send window/showMessage\");\n        }\n    }\n\n    fn respond_with_engine<T, Handler>(\n        &mut self,\n        path: Utf8PathBuf,\n        handler: Handler,\n    ) -> (Result<Json, ResponseError>, Feedback)\n    where\n        T: serde::Serialize,\n        Handler: FnOnce(\n            &mut LanguageServerEngine<IO, ConnectionProgressReporter<'a>>,\n        ) -> engine::Response<T>,\n    {\n        self.fallible_respond_with_engine(path, |engine| {\n            let response = handler(engine);\n            engine::Response {\n                result: response.result.map(Ok),\n                warnings: response.warnings,\n                compilation: response.compilation,\n            }\n        })\n    }\n\n    fn fallible_respond_with_engine<T, Handler>(\n        &mut self,\n        path: Utf8PathBuf,\n        handler: Handler,\n    ) -> (Result<Json, ResponseError>, Feedback)\n    where\n        T: serde::Serialize,\n        Handler: FnOnce(\n            &mut LanguageServerEngine<IO, ConnectionProgressReporter<'a>>,\n        ) -> engine::Response<Result<T, ResponseError>>,\n    {\n        match self.router.project_for_path(path) {\n            Ok(Some(project)) => {\n                let engine::Response {\n                    result,\n                    warnings,\n                    compilation,\n                } = handler(&mut project.engine);\n                match result {\n                    Ok(Ok(value)) => {\n                        let feedback = project.feedback.response(compilation, warnings);\n                        let json = serde_json::to_value(value).expect(\"response to json\");\n                        (Ok(json), feedback)\n                    }\n                    Ok(Err(error)) => {\n                        let feedback = project.feedback.response(compilation, warnings);\n                        (Err(error), feedback)\n                    }\n                    Err(e) => {\n                        let feedback = project.feedback.build_with_error(e, compilation, warnings);\n                        (Ok(Json::Null), feedback)\n                    }\n                }\n            }\n\n            Ok(None) => (Ok(Json::Null), Feedback::default()),\n\n            Err(error) => (\n                Ok(Json::Null),\n                self.outside_of_project_feedback.error(error),\n            ),\n        }\n    }\n\n    fn path_error_response(\n        &mut self,\n        path: Utf8PathBuf,\n        error: gleam_core::Error,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let feedback = match self.router.project_for_path(path) {\n            Ok(Some(project)) => project.feedback.error(error),\n            Ok(None) | Err(_) => self.outside_of_project_feedback.error(error),\n        };\n        (Ok(Json::Null), feedback)\n    }\n\n    fn format(\n        &mut self,\n        params: lsp::DocumentFormattingParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document.uri);\n        let mut new_text = String::new();\n\n        let src = match self.io.read(&path) {\n            Ok(src) => src.into(),\n            Err(error) => return self.path_error_response(path, error),\n        };\n\n        if let Err(error) = gleam_core::format::pretty(&mut new_text, &src, &path) {\n            return self.path_error_response(path, error);\n        }\n\n        let line_count = src.lines().count() as u32;\n\n        let edit = TextEdit {\n            range: Range::new(Position::new(0, 0), Position::new(line_count, 0)),\n            new_text,\n        };\n        let json = serde_json::to_value(vec![edit]).expect(\"to JSON value\");\n\n        (Ok(json), Feedback::default())\n    }\n\n    fn hover(&mut self, params: lsp::HoverParams) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position_params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.hover(params))\n    }\n\n    fn goto_definition(\n        &mut self,\n        params: lsp::GotoDefinitionParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position_params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.goto_definition(params))\n    }\n\n    fn goto_type_definition(\n        &mut self,\n        params: lsp_types::GotoDefinitionParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position_params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.goto_type_definition(params))\n    }\n\n    fn completion(\n        &mut self,\n        params: lsp::CompletionParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position.text_document.uri);\n\n        let src = match self.io.read(&path) {\n            Ok(src) => src.into(),\n            Err(error) => return self.path_error_response(path, error),\n        };\n        self.respond_with_engine(path, |engine| {\n            engine.completion(params.text_document_position, src)\n        })\n    }\n\n    fn signature_help(\n        &mut self,\n        params: lsp_types::SignatureHelpParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position_params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.signature_help(params))\n    }\n\n    fn code_action(\n        &mut self,\n        params: lsp::CodeActionParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.code_actions(params))\n    }\n\n    fn document_symbol(\n        &mut self,\n        params: lsp::DocumentSymbolParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.document_symbol(params))\n    }\n\n    fn folding_range(\n        &mut self,\n        params: lsp::FoldingRangeParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.folding_range(params))\n    }\n\n    fn prepare_rename(\n        &mut self,\n        params: lsp::TextDocumentPositionParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.prepare_rename(params))\n    }\n\n    fn rename(&mut self, params: lsp::RenameParams) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position.text_document.uri);\n        self.fallible_respond_with_engine(\n            path,\n            |engine: &mut LanguageServerEngine<IO, ConnectionProgressReporter<'a>>| {\n                engine.rename(params)\n            },\n        )\n    }\n\n    fn find_references(\n        &mut self,\n        params: lsp_types::ReferenceParams,\n    ) -> (Result<Json, ResponseError>, Feedback) {\n        let path = super::path(&params.text_document_position.text_document.uri);\n        self.respond_with_engine(path, |engine| engine.find_references(params))\n    }\n\n    fn cache_file_in_memory(&mut self, path: Utf8PathBuf, text: String) -> Feedback {\n        self.project_changed(&path);\n        if let Err(error) = self.io.write_mem_cache(&path, &text) {\n            return self.outside_of_project_feedback.error(error);\n        }\n        Feedback::none()\n    }\n\n    fn discard_in_memory_cache(&mut self, path: Utf8PathBuf) -> Feedback {\n        self.project_changed(&path);\n        if let Err(error) = self.io.delete_mem_cache(&path) {\n            return self.outside_of_project_feedback.error(error);\n        }\n        Feedback::none()\n    }\n\n    fn watched_files_changed(&mut self, path: Utf8PathBuf) -> Feedback {\n        self.router.delete_engine_for_path(&path);\n        Feedback::none()\n    }\n\n    fn compile_please(&mut self) -> Feedback {\n        let mut accumulator = Feedback::none();\n        let projects = std::mem::take(&mut self.changed_projects);\n        for path in projects {\n            let (_, feedback) = self.respond_with_engine(path, |this| this.compile_please());\n            accumulator.append_feedback(feedback);\n        }\n        accumulator\n    }\n\n    fn project_changed(&mut self, path: &Utf8Path) {\n        let project_path = self.router.project_path(path);\n        if let Some(project_path) = project_path {\n            _ = self.changed_projects.insert(project_path);\n        }\n    }\n}\n\nfn initialisation_handshake(connection: &lsp_server::Connection) -> InitializeParams {\n    let server_capabilities = lsp::ServerCapabilities {\n        text_document_sync: Some(lsp::TextDocumentSyncCapability::Options(\n            lsp::TextDocumentSyncOptions {\n                open_close: Some(true),\n                change: Some(lsp::TextDocumentSyncKind::FULL),\n                will_save: None,\n                will_save_wait_until: None,\n                save: Some(lsp::TextDocumentSyncSaveOptions::SaveOptions(\n                    lsp::SaveOptions {\n                        include_text: Some(false),\n                    },\n                )),\n            },\n        )),\n        selection_range_provider: None,\n        hover_provider: Some(HoverProviderCapability::Simple(true)),\n        completion_provider: Some(lsp::CompletionOptions {\n            resolve_provider: None,\n            trigger_characters: Some(vec![\".\".into()]),\n            all_commit_characters: None,\n            work_done_progress_options: lsp::WorkDoneProgressOptions {\n                work_done_progress: None,\n            },\n            completion_item: None,\n        }),\n        signature_help_provider: Some(lsp::SignatureHelpOptions {\n            trigger_characters: Some(vec![\"(\".into(), \",\".into(), \":\".into()]),\n            retrigger_characters: None,\n            work_done_progress_options: lsp::WorkDoneProgressOptions {\n                work_done_progress: None,\n            },\n        }),\n        definition_provider: Some(lsp::OneOf::Left(true)),\n        type_definition_provider: Some(lsp::TypeDefinitionProviderCapability::Simple(true)),\n        implementation_provider: None,\n        references_provider: Some(lsp::OneOf::Left(true)),\n        document_highlight_provider: None,\n        document_symbol_provider: Some(lsp::OneOf::Left(true)),\n        workspace_symbol_provider: None,\n        code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),\n        code_lens_provider: None,\n        document_formatting_provider: Some(lsp::OneOf::Left(true)),\n        document_range_formatting_provider: None,\n        document_on_type_formatting_provider: None,\n        rename_provider: Some(lsp::OneOf::Right(RenameOptions {\n            prepare_provider: Some(true),\n            work_done_progress_options: lsp::WorkDoneProgressOptions {\n                work_done_progress: None,\n            },\n        })),\n        document_link_provider: None,\n        color_provider: None,\n        folding_range_provider: Some(lsp::FoldingRangeProviderCapability::Simple(true)),\n        declaration_provider: None,\n        execute_command_provider: None,\n        workspace: None,\n        call_hierarchy_provider: None,\n        semantic_tokens_provider: None,\n        moniker_provider: None,\n        linked_editing_range_provider: None,\n        experimental: None,\n        position_encoding: None,\n        inline_value_provider: None,\n        inlay_hint_provider: None,\n        diagnostic_provider: None,\n    };\n    let server_capabilities_json =\n        serde_json::to_value(server_capabilities).expect(\"server_capabilities_serde\");\n    let initialise_params_json = connection\n        .initialize(server_capabilities_json)\n        .expect(\"LSP initialize\");\n    let initialise_params: InitializeParams =\n        serde_json::from_value(initialise_params_json).expect(\"LSP InitializeParams from json\");\n    initialise_params\n}\n\nfn diagnostic_to_lsp(diagnostic: Diagnostic) -> Vec<lsp::Diagnostic> {\n    let severity = match diagnostic.level {\n        Level::Error => lsp::DiagnosticSeverity::ERROR,\n        Level::Warning => lsp::DiagnosticSeverity::WARNING,\n    };\n    let hint = diagnostic.hint;\n    let mut text = diagnostic.title;\n\n    if let Some(label) = diagnostic\n        .location\n        .as_ref()\n        .and_then(|location| location.label.text.as_deref())\n    {\n        text.push_str(\"\\n\\n\");\n        text.push_str(label);\n        if !label.ends_with(['.', '?']) {\n            text.push('.');\n        }\n    }\n\n    if !diagnostic.text.is_empty() {\n        text.push_str(\"\\n\\n\");\n        text.push_str(&diagnostic.text);\n    }\n\n    // TODO: Redesign the diagnostic type so that we can be sure there is always\n    // a location. Locationless diagnostics would be handled separately.\n    let location = diagnostic\n        .location\n        .expect(\"Diagnostic given to LSP without location\");\n    let line_numbers = LineNumbers::new(&location.src);\n    let path = path_to_uri(location.path);\n    let range = src_span_to_lsp_range(location.label.span, &line_numbers);\n\n    let main = lsp::Diagnostic {\n        range,\n        severity: Some(severity),\n        code: None,\n        code_description: None,\n        source: None,\n        message: text,\n        related_information: related_information(\n            &hint,\n            &location.extra_labels,\n            &path,\n            &line_numbers,\n            range,\n        ),\n        tags: None,\n        data: None,\n    };\n\n    match hint {\n        Some(hint) => {\n            let hint = lsp::Diagnostic {\n                severity: Some(lsp::DiagnosticSeverity::HINT),\n                message: hint,\n                // Some editors require this kind of \"link\" to group diagnostics.\n                // For example, in Zed \"go to next diagnostic\" would move you from\n                // the warning to the hint in the same location without this.\n                related_information: Some(vec![lsp::DiagnosticRelatedInformation {\n                    location: lsp::Location { uri: path, range },\n                    message: String::new(),\n                }]),\n                ..main.clone()\n            };\n            vec![main, hint]\n        }\n        None => vec![main],\n    }\n}\n\nfn related_information(\n    hint: &Option<String>,\n    extra_labels: &[ExtraLabel],\n    path: &Url,\n    line_numbers: &LineNumbers,\n    range: Range,\n) -> Option<Vec<lsp::DiagnosticRelatedInformation>> {\n    let mut related_info = Vec::with_capacity(extra_labels.len() + 1);\n\n    // The hint is included as a dedicated diagnostic _and_ the related information\n    // to maximize compatibility\n    if let Some(hint) = hint {\n        let hint = lsp::DiagnosticRelatedInformation {\n            message: hint.clone(),\n            location: lsp::Location {\n                uri: path.clone(),\n                range,\n            },\n        };\n        related_info.push(hint);\n    }\n\n    let additional_info = extra_labels.iter().map(|extra| {\n        let message = extra.label.text.clone().unwrap_or_default();\n        let location = match &extra.src_info {\n            Some((src, path)) => {\n                let line_numbers = LineNumbers::new(src);\n                lsp::Location {\n                    uri: path_to_uri(path.clone()),\n                    range: src_span_to_lsp_range(extra.label.span, &line_numbers),\n                }\n            }\n            _ => lsp::Location {\n                uri: path.clone(),\n                range: src_span_to_lsp_range(extra.label.span, line_numbers),\n            },\n        };\n        lsp::DiagnosticRelatedInformation { location, message }\n    });\n    related_info.extend(additional_info);\n\n    if related_info.is_empty() {\n        None\n    } else {\n        Some(related_info)\n    }\n}\n\nfn path_to_uri(path: Utf8PathBuf) -> Url {\n    let mut file: String = \"file://\".into();\n    file.push_str(&path.as_os_str().to_string_lossy());\n    Url::parse(&file).expect(\"path_to_uri URL parse\")\n}\n"
  },
  {
    "path": "language-server/src/signature_help.rs",
    "content": "use std::{\n    collections::{HashMap, HashSet},\n    sync::Arc,\n};\n\nuse ecow::EcoString;\nuse lsp_types::{\n    Documentation, MarkupContent, MarkupKind, ParameterInformation, ParameterLabel, SignatureHelp,\n    SignatureInformation,\n};\n\nuse gleam_core::{\n    ast::{CallArg, ImplicitCallArgOrigin, TypedExpr},\n    build::Module,\n    type_::{FieldMap, ModuleValueConstructor, Type, printer::Printer},\n};\n\npub fn for_expression(expr: &TypedExpr, module: &Module) -> Option<SignatureHelp> {\n    // If we're inside a function call we can provide signature help,\n    // otherwise we don't want anything to pop up.\n    let TypedExpr::Call { fun, arguments, .. } = expr else {\n        return None;\n    };\n\n    match fun.as_ref() {\n        // If the thing being called is a local variable then we want to\n        // use it's name as the function name to be used in the signature\n        // help.\n        TypedExpr::Var {\n            constructor, name, ..\n        } => signature_help(\n            name.clone(),\n            fun,\n            arguments,\n            constructor.field_map(),\n            module,\n        ),\n\n        // If we're making a qualified call to another module's function\n        // then we want to show its type, documentation and the exact name\n        // being used (that is \"<module_name>.<function_name>\").\n        //\n        //   eg. list.map(|)\n        //                ^ When the cursor is here we are going to show\n        //                  \"list.map(List(a), with: fn(a) -> b) -> List(b)\"\n        //                  as the help signature.\n        //\n        TypedExpr::ModuleSelect {\n            module_alias,\n            label,\n            constructor,\n            ..\n        } => {\n            let field_map = match constructor {\n                ModuleValueConstructor::Constant { .. } => None,\n                ModuleValueConstructor::Record { field_map, .. }\n                | ModuleValueConstructor::Fn { field_map, .. } => field_map.into(),\n            };\n            let name = format!(\"{module_alias}.{label}\").into();\n            signature_help(name, fun, arguments, field_map, module)\n        }\n\n        // If the function being called is an invalid node we don't want to\n        // provide any hint, otherwise one might be under the impression that\n        // that function actually exists somewhere.\n        //\n        TypedExpr::Invalid { .. } => None,\n\n        // In all other cases we can't figure out a good name to show in the\n        // signature help so we use an anonymous `fn` as the name to be\n        // shown.\n        //\n        //     eg. fn(a){a}(|)\n        //                  ^ When the cursor is here we are going to show\n        //                    \"fn(a: a) -> a\" as the help signature.\n        //\n        TypedExpr::Int { .. }\n        | TypedExpr::Float { .. }\n        | TypedExpr::String { .. }\n        | TypedExpr::Block { .. }\n        | TypedExpr::Pipeline { .. }\n        | TypedExpr::Fn { .. }\n        | TypedExpr::List { .. }\n        | TypedExpr::Call { .. }\n        | TypedExpr::BinOp { .. }\n        | TypedExpr::Case { .. }\n        | TypedExpr::RecordAccess { .. }\n        | TypedExpr::PositionalAccess { .. }\n        | TypedExpr::Tuple { .. }\n        | TypedExpr::TupleIndex { .. }\n        | TypedExpr::Todo { .. }\n        | TypedExpr::Panic { .. }\n        | TypedExpr::Echo { .. }\n        | TypedExpr::BitArray { .. }\n        | TypedExpr::RecordUpdate { .. }\n        | TypedExpr::NegateBool { .. }\n        | TypedExpr::NegateInt { .. } => signature_help(\"fn\".into(), fun, arguments, None, module),\n    }\n}\n\n/// Show the signature help of a function with the given name.\n/// Besides the function's typed expression `fun`, this function needs a bit of\n/// additional data to properly display a useful help signature:\n///\n/// - `fun_name` is used as the display name of the function in the help\n///   signature.\n/// - `supplied_arguments` are arguments being passed to the function call, those\n///   might not be of the correct arity or have wrong types but are used to\n///   deduce which argument should be highlighted next in the help signature.\n/// - `field_map` is the function's field map (if any) that will be used to\n///   display labels and understand which labelled argument should be\n///   highlighted next in the help signature.\n///\nfn signature_help(\n    fun_name: EcoString,\n    fun: &TypedExpr,\n    supplied_arguments: &[CallArg<TypedExpr>],\n    field_map: Option<&FieldMap>,\n    module: &Module,\n) -> Option<SignatureHelp> {\n    let (arguments, return_) = fun.type_().fn_types()?;\n\n    // If the function has no arguments, we don't want to show any help.\n    let arity = arguments.len() as u32;\n    if arity == 0 {\n        return None;\n    }\n\n    let index_to_label = match field_map {\n        Some(field_map) => field_map\n            .fields\n            .iter()\n            .map(|(name, index)| (*index, name))\n            .collect(),\n        None => HashMap::new(),\n    };\n\n    let printer = Printer::new(&module.ast.names);\n    let (label, parameters) =\n        print_signature_help(printer, fun_name, arguments, return_, &index_to_label);\n\n    let active_parameter = active_parameter_index(arity, supplied_arguments, index_to_label)\n        // If we don't want to highlight any arg in the suggestion we have to\n        // explicitly provide an out of bound index.\n        .or(Some(arity));\n\n    Some(SignatureHelp {\n        signatures: vec![SignatureInformation {\n            label,\n            documentation: fun.get_documentation().map(|d| {\n                Documentation::MarkupContent(MarkupContent {\n                    kind: MarkupKind::Markdown,\n                    value: d.into(),\n                })\n            }),\n            parameters: Some(parameters),\n            active_parameter: None,\n        }],\n        active_signature: Some(0),\n        active_parameter,\n    })\n}\n\nfn active_parameter_index(\n    arity: u32,\n    supplied_arguments: &[CallArg<TypedExpr>],\n    mut index_to_label: HashMap<u32, &EcoString>,\n) -> Option<u32> {\n    let mut is_use_call = false;\n    let mut found_labelled_argument = false;\n    let mut used_labels = HashSet::new();\n\n    let mut supplied_unlabelled_arguments = 0;\n    let unlabelled_arguments = arity - index_to_label.len() as u32;\n\n    for (i, arg) in supplied_arguments.iter().enumerate() {\n        // If there's an unlabelled argument after a labelled one, we can't\n        // figure out what to suggest since arguments were passed in a wrong\n        // order.\n        if found_labelled_argument && arg.label.is_none() && !arg.is_implicit() {\n            return None;\n        }\n\n        // Once we reach to an implicit use argument (be it the callback or the\n        // missing implicitly inserted ones) we can break since those must be\n        // the last arguments of the function and are not explicitly supplied by\n        // the programmer.\n        if let Some(ImplicitCallArgOrigin::Use | ImplicitCallArgOrigin::IncorrectArityUse) =\n            arg.implicit\n        {\n            is_use_call = true;\n            break;\n        }\n\n        match &arg.label {\n            Some(label) => {\n                found_labelled_argument = true;\n                let _ = used_labels.insert(label);\n            }\n\n            // If the argument is unlabelled we just remove the label\n            // corresponding to it from the field map since it has already been\n            // passed as an unlabelled argument.\n            None => {\n                supplied_unlabelled_arguments += 1;\n                let _ = index_to_label.remove(&(i as u32));\n            }\n        }\n    }\n\n    let active_index = if supplied_unlabelled_arguments < unlabelled_arguments {\n        if found_labelled_argument {\n            // If I have supplied some labelled args but I haven't supplied all\n            // unlabelled args before a labelled one then we can't safely\n            // suggest anything as the next argument.\n            None\n        } else {\n            // If I haven't supplied enough unlabelled arguments then I have to\n            // set the next one as active (be it labelled or not).\n            Some(supplied_unlabelled_arguments)\n        }\n    } else {\n        // If I have supplied all the unlabelled arguments (and we could have\n        // also supplied some labelled ones as unlabelled!) then we pick the\n        // leftmost labelled argument that hasn't been supplied yet.\n        index_to_label\n            .into_iter()\n            .filter(|(_index, label)| !used_labels.contains(label))\n            .map(|(index, _label)| index)\n            .min()\n            .or(Some(supplied_arguments.len() as u32))\n    };\n\n    // If we're showing hints for a use call and we end up deciding that the\n    // only index we can suggest is the one of the use callback then we do not\n    // highlight it or it would lead people into believing they can manually\n    // pass that argument in.\n    if is_use_call && active_index == Some(arity - 1) {\n        None\n    } else {\n        active_index\n    }\n}\n\n/// To produce a signature that can be used by the LS, we need to also keep\n/// track of the arguments' positions in the printed signature. So this function\n/// prints the signature help producing at the same time a list of correct\n/// `ParameterInformation` for all its arguments.\n///\nfn print_signature_help(\n    mut printer: Printer<'_>,\n    function_name: EcoString,\n    arguments: Vec<Arc<Type>>,\n    return_: Arc<Type>,\n    index_to_label: &HashMap<u32, &EcoString>,\n) -> (String, Vec<ParameterInformation>) {\n    let arguments_count = arguments.len();\n    let mut signature = format!(\"{function_name}(\");\n    let mut parameter_informations = Vec::with_capacity(arguments_count);\n\n    for (i, argument) in arguments.iter().enumerate() {\n        let arg_start = signature.len();\n        if let Some(label) = index_to_label.get(&(i as u32)) {\n            signature.push_str(label);\n            signature.push_str(\": \");\n        }\n        signature.push_str(&printer.print_type(argument));\n        let arg_end = signature.len();\n        let label = ParameterLabel::LabelOffsets([arg_start as u32, arg_end as u32]);\n\n        parameter_informations.push(ParameterInformation {\n            label,\n            documentation: None,\n        });\n\n        let is_last = i == arguments_count - 1;\n        if !is_last {\n            signature.push_str(\", \");\n        }\n    }\n\n    signature.push_str(\") -> \");\n    signature.push_str(&printer.print_type(&return_));\n    (signature, parameter_informations)\n}\n"
  },
  {
    "path": "language-server/src/tests/action.rs",
    "content": "use itertools::Itertools;\nuse lsp_types::{\n    CodeActionContext, CodeActionParams, PartialResultParams, Position, Range, Url,\n    WorkDoneProgressParams,\n};\n\nuse super::*;\n\nfn code_actions(tester: &TestProject<'_>, range: Range) -> Option<Vec<lsp_types::CodeAction>> {\n    let position = Position {\n        line: 0,\n        character: 0,\n    };\n\n    tester.at(position, |engine, params, _| {\n        let params = CodeActionParams {\n            text_document: params.text_document,\n            range,\n            context: CodeActionContext::default(),\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n        };\n        engine.code_actions(params).result.unwrap()\n    })\n}\n\nfn actions_with_title(\n    titles: Vec<&str>,\n    tester: &TestProject<'_>,\n    range: Range,\n) -> Vec<lsp_types::CodeAction> {\n    code_actions(tester, range)\n        .into_iter()\n        .flatten()\n        .filter(|action| titles.contains(&action.title.as_str()))\n        .collect_vec()\n}\n\nfn owned_actions_with_title(\n    titles: Vec<&str>,\n    tester: TestProject<'_>,\n    range: Range,\n) -> Vec<lsp_types::CodeAction> {\n    actions_with_title(titles, &tester, range)\n}\n\nfn apply_code_action(title: &str, tester: TestProject<'_>, range: Range) -> String {\n    let titles = vec![title];\n    let changes = actions_with_title(titles, &tester, range)\n        .pop()\n        .expect(\"No action with the given title\")\n        .edit\n        .expect(\"No workspace edit found\")\n        .changes\n        .expect(\"No text edit found\");\n    apply_code_edit(tester, changes)\n}\n\nfn apply_code_edit(\n    tester: TestProject<'_>,\n    changes: HashMap<Url, Vec<lsp_types::TextEdit>>,\n) -> String {\n    let mut changed_files: HashMap<Url, String> = HashMap::new();\n    for (uri, change) in changes {\n        let code = match changed_files.get(&uri) {\n            Some(code) => code,\n            None => tester\n                .src_from_module_url(&uri)\n                .unwrap_or_else(|| panic!(\"no src for url {uri:?}\")),\n        };\n        let code = super::apply_code_edit(code, change);\n        let _ = changed_files.insert(uri, code);\n    }\n\n    show_code_edits(tester, changed_files)\n}\n\nfn show_code_edits(tester: TestProject<'_>, changed_files: HashMap<Url, String>) -> String {\n    let format_code = |url: &Url, code: &String| {\n        format!(\n            \"// --- Edits applied to module '{}'\\n{}\",\n            tester.module_name_from_url(url).expect(\"a module\"),\n            code\n        )\n    };\n\n    // If the file that changed is the main one we just show its code.\n    if changed_files.len() == 1 {\n        let mut changed = changed_files.iter().peekable();\n        let (url, code) = changed.peek().unwrap();\n        if tester.module_name_from_url(url) == Some(\"app\".into()) {\n            code.to_string()\n        } else {\n            format_code(url, code)\n        }\n    } else {\n        // If more than a single file changed we want to add the name of the\n        // file before each!\n        changed_files\n            .iter()\n            .map(|(url, code)| format_code(url, code))\n            .join(\"\\n\")\n    }\n}\n\nconst REMOVE_UNUSED_IMPORTS: &str = \"Remove unused imports\";\nconst REMOVE_REDUNDANT_TUPLES: &str = \"Remove redundant tuples\";\nconst CONVERT_TO_CASE: &str = \"Convert to case\";\nconst USE_LABEL_SHORTHAND_SYNTAX: &str = \"Use label shorthand syntax\";\nconst FILL_LABELS: &str = \"Fill labels\";\nconst ASSIGN_UNUSED_RESULT: &str = \"Assign unused Result value to `_`\";\nconst ADD_MISSING_PATTERNS: &str = \"Add missing patterns\";\nconst ADD_ANNOTATION: &str = \"Add type annotation\";\nconst ADD_ANNOTATIONS: &str = \"Add type annotations\";\nconst ANNOTATE_TOP_LEVEL_DEFINITIONS: &str = \"Annotate all top level definitions\";\nconst CONVERT_FROM_USE: &str = \"Convert from `use`\";\nconst CONVERT_TO_USE: &str = \"Convert to `use`\";\nconst EXTRACT_VARIABLE: &str = \"Extract variable\";\nconst EXTRACT_CONSTANT: &str = \"Extract constant\";\nconst EXPAND_FUNCTION_CAPTURE: &str = \"Expand function capture\";\nconst GENERATE_DYNAMIC_DECODER: &str = \"Generate dynamic decoder\";\nconst GENERATE_TO_JSON_FUNCTION: &str = \"Generate to-JSON function\";\nconst PATTERN_MATCH_ON_ARGUMENT: &str = \"Pattern match on argument\";\nconst PATTERN_MATCH_ON_VARIABLE: &str = \"Pattern match on variable\";\nconst GENERATE_FUNCTION: &str = \"Generate function\";\nconst CONVERT_TO_FUNCTION_CALL: &str = \"Convert to function call\";\nconst INLINE_VARIABLE: &str = \"Inline variable\";\nconst CONVERT_TO_PIPE: &str = \"Convert to pipe\";\nconst INTERPOLATE_STRING: &str = \"Interpolate string\";\nconst FILL_UNUSED_FIELDS: &str = \"Fill unused fields\";\nconst REMOVE_ALL_ECHOS_FROM_THIS_MODULE: &str = \"Remove all `echo`s from this module\";\nconst WRAP_IN_BLOCK: &str = \"Wrap in block\";\nconst GENERATE_VARIANT: &str = \"Generate variant\";\nconst REMOVE_BLOCK: &str = \"Remove block\";\nconst REMOVE_OPAQUE_FROM_PRIVATE_TYPE: &str = \"Remove opaque from private type\";\nconst COLLAPSE_NESTED_CASE: &str = \"Collapse nested case\";\nconst REMOVE_UNREACHABLE_CLAUSES: &str = \"Remove unreachable clauses\";\nconst ADD_OMITTED_LABELS: &str = \"Add omitted labels\";\nconst EXTRACT_FUNCTION: &str = \"Extract function\";\nconst MERGE_CASE_BRANCHES: &str = \"Merge case branches\";\nconst ADD_MISSING_TYPE_PARAMETER: &str = \"Add missing type parameter\";\nconst REPLACE_UNDERSCORE_WITH_TYPE: &str = \"Replace `_` with type\";\n\nmacro_rules! assert_code_action {\n    ($title:expr, $code:literal, $range:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_code_action!($title, project, $range);\n    };\n\n    ($title:expr, $project:expr, $range:expr $(,)?) => {\n        let src = $project.src;\n        let range = $range.find_range(src);\n        let result = apply_code_action($title, $project, range);\n        let output = format!(\n            \"----- BEFORE ACTION\\n{}\\n\\n----- AFTER ACTION\\n{}\",\n            hover::show_hover(src, range, range.end),\n            result\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\nmacro_rules! assert_no_code_actions {\n    ($title:ident $(| $titles:ident)*, $code:literal, $range:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_no_code_actions!($title $(| $titles)*, project, $range);\n    };\n\n    ($title:ident $(| $titles:ident)*, $project:expr, $range:expr $(,)?) => {\n        let src = $project.src;\n        let range = $range.find_range(src);\n        let all_titles = vec![$title $(, $titles)*];\n        let expected: Vec<lsp_types::CodeAction> = vec![];\n        let result = owned_actions_with_title(all_titles, $project, range);\n        assert_eq!(expected, result);\n    };\n}\n\n#[test]\nfn fix_truncated_segment_1() {\n    let name = \"Replace with `1`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  <<1, 257, 259:size(1)>>\n}\"#,\n        find_position_of(\"257\").to_selection()\n    );\n}\n\n#[test]\nfn fix_truncated_segment_2() {\n    let name = \"Replace with `0`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  <<1, 1024:size(10)>>\n}\"#,\n        find_position_of(\"size\").to_selection()\n    );\n}\n\n#[test]\nfn generate_variant_with_fields_in_same_module() {\n    assert_code_action!(\n        GENERATE_VARIANT,\n        r#\"\npub type Wibble {\n  Wibble\n}\n\npub fn main() -> Wibble {\n  Wobble(1)\n}\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_variant_with_no_fields_in_same_module() {\n    assert_code_action!(\n        GENERATE_VARIANT,\n        r#\"\npub type Wibble {\n  Wibble\n}\n\npub fn main() -> Wibble {\n  Wobble\n}\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_variant_with_labels_in_same_module() {\n    assert_code_action!(\n        GENERATE_VARIANT,\n        r#\"\npub type Wibble {\n  Wibble\n}\n\npub fn main() -> Wibble {\n  Wobble(\"hello\", label: 1)\n}\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_variant_from_pattern_with_fields() {\n    assert_code_action!(\n        GENERATE_VARIANT,\n        r#\"\npub type Wibble {\n  Wibble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble(1) = new()\n}\n\n\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_variant_from_pattern_with_labelled_fields() {\n    assert_code_action!(\n        GENERATE_VARIANT,\n        r#\"\npub type Wibble {\n  Wibble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble(\"hello\", label: 1) = new()\n}\n\n\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_variant_from_pattern_with_no_fields() {\n    assert_code_action!(\n        GENERATE_VARIANT,\n        r#\"\npub type Wibble {\n  Wibble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble = new()\n}\n\n\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_unqualified_variant_in_other_module() {\n    let src = r#\"\nimport other\n\npub fn main() -> other.Wibble {\n  let assert Wobble = new()\n}\n\npub fn new() -> other.Wibble { todo }\n\"#;\n\n    assert_code_action!(\n        GENERATE_VARIANT,\n        TestProject::for_source(src).add_module(\"other\", \"pub type Wibble\"),\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_qualified_variant_in_other_module() {\n    let src = r#\"\nimport other\n\npub fn main() -> other.Wibble {\n  let assert other.Wobble = new()\n}\n\npub fn new() -> other.Wibble { todo }\n\"#;\n    assert_code_action!(\n        GENERATE_VARIANT,\n        TestProject::for_source(src).add_module(\"other\", \"pub type Wibble\"),\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_generate_variant_if_one_with_the_same_name_exists() {\n    assert_no_code_actions!(\n        GENERATE_VARIANT,\n        r#\"\npub fn main() -> Wibble {\n  let assert Wobble = new()\n}\n\npub type Wibble {\n  Wobble(n: Int)\n}\n\npub fn new() -> Wibble { todo }\n\"#,\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_generate_variant_if_one_with_the_same_name_exists_in_other_module() {\n    let src = r#\"\nimport other.{type Wibble}\n\npub fn main() -> Wibble {\n  let assert Wobble = new()\n}\n\npub fn new() -> Wibble { todo }\n\"#;\n    assert_no_code_actions!(\n        GENERATE_VARIANT,\n        TestProject::for_source(src).add_module(\"other\", \"pub type Wibble { Wobble(String) }\"),\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_generate_qualified_variant_if_one_with_the_same_name_exists_in_other_module() {\n    let src = r#\"\nimport other.{type Wibble}\n\npub fn main() -> Wibble {\n  let assert other.Wobble = new()\n}\n\npub fn new() -> Wibble { todo }\n\"#;\n    assert_no_code_actions!(\n        GENERATE_VARIANT,\n        TestProject::for_source(src).add_module(\"other\", \"pub type Wibble { Wobble(String) }\"),\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn fill_unused_fields_with_ignored_labelled_fields() {\n    assert_code_action!(\n        FILL_UNUSED_FIELDS,\n        r#\"\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(_, ..) = todo\n}\"#,\n        find_position_of(\"..\").to_selection()\n    );\n}\n\n#[test]\nfn fill_unused_fields_with_ignored_positional_fields() {\n    assert_code_action!(\n        FILL_UNUSED_FIELDS,\n        r#\"\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(label1:, label2:, ..) = todo\n}\"#,\n        find_position_of(\"..\").to_selection()\n    );\n}\n\n#[test]\nfn fill_unused_fields_with_all_positional_fields() {\n    assert_code_action!(\n        FILL_UNUSED_FIELDS,\n        r#\"\npub type Wibble { Wibble(Int, String) }\n\npub fn main() {\n  let Wibble(..) = todo\n}\"#,\n        find_position_of(\"..\").to_selection()\n    );\n}\n\n#[test]\nfn fill_unused_fields_with_ignored_mixed_fields() {\n    assert_code_action!(\n        FILL_UNUSED_FIELDS,\n        r#\"\npub type Wibble { Wibble(Int, String, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(_, label2:, ..) = todo\n}\"#,\n        find_position_of(\"..\").to_selection()\n    );\n}\n\n#[test]\nfn fill_unused_fields_with_all_ignored_fields() {\n    assert_code_action!(\n        FILL_UNUSED_FIELDS,\n        r#\"\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(..) = todo\n}\"#,\n        find_position_of(\"..\").to_selection()\n    );\n}\n\n#[test]\nfn fill_unused_fields_with_ignored_fields_never_calls_a_positional_arg_as_a_labelled_one() {\n    assert_code_action!(\n        FILL_UNUSED_FIELDS,\n        r#\"\npub type Wibble { Wibble(Int, int: Int) }\n\npub fn main() {\n  let Wibble(..) = todo\n}\"#,\n        find_position_of(\"..\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo 1 + 2\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_with_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 + 2 as \"message\"\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_with_message_and_comment() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 + 2\n    // Hello!\n    as \"message\"\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_with_message_and_comment_2() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 + 2 as\n    // Hello!\n    \"message\"\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_with_message_and_comment_3() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 + 2 as\n    // Hello!\n    \"message\"\n\n  Nil\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_selecting_expression() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo 1 + 2\n}\",\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn remove_echo_selecting_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 + 2 as \"message\"\n}\"#,\n        find_position_of(\"message\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_as_function_arg() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  wibble([], echo 1 + 2)\n}\",\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_in_pipeline_step() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  [1, 2, 3]\n  |> echo\n  |> wibble\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_in_pipeline_step_with_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  [1, 2, 3]\n  |> echo as message\n  |> wibble\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_in_single_line_pipeline_step() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  [1, 2, 3] |> echo |> wibble\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_in_single_line_pipeline_step_with_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  [1, 2, 3] |> echo as \"message\" |> wibble\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_last_in_long_pipeline_step() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> echo\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_last_in_long_pipeline_step_with_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> echo as \"message\"\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_last_in_short_pipeline_step() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  [1, 2, 3]\n  |> echo\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_last_in_short_pipeline_step_with_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  [1, 2, 3]\n  |> echo as \"message\"\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_before_pipeline() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo [1, 2, 3] |> wibble\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_before_pipeline_selecting_step() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo [1, 2, 3] |> wibble\n}\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_all_echos() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo wibble(echo 1, 2)\n}\",\n        find_position_of(\"echo\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_all_echos_1() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo 1 |> echo |> echo |> wibble |> echo\n  echo wibble(echo 1, echo 2)\n  echo 1\n}\",\n        find_position_of(\"echo\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_entire_echo_statement_used_with_literals() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo 1\n  Nil\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_entire_echo_statement_used_with_literals_and_message() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 as \"message\"\n  Nil\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_entire_echo_statement_used_with_a_var() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  let a = 1\n  echo a\n  Nil\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_multiple_entire_echo_statement_used_with_literals() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1\n  echo \"wibble\"\n  Nil\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_but_stops_at_comments() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1\n\n  // Oh no I hope I'm not deleted by the code action!!\n  Nil\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_entire_echo_statement_used_with_literals_in_a_fn() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  fn() {\n    echo 1\n    Nil\n  }\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_in_a_fn() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  fn() {\n    echo 1\n    echo \"wibble\"\n    Nil\n  }\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        \"pub fn main() {\n  echo 1\n}\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_with_message_removes_does_not_remove_entire_echo_statement_if_its_the_return() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  echo 1 as \"message\"\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return_of_a_fn() {\n    assert_code_action!(\n        REMOVE_ALL_ECHOS_FROM_THIS_MODULE,\n        r#\"pub fn main() {\n  fn() {\n    echo 1\n  }\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn split_string() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn no_split_string_right_at_the_start() {\n    assert_no_code_actions!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn no_split_string_right_at_the_end() {\n    assert_no_code_actions!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"\\\"\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn no_split_string_before_the_start() {\n    assert_no_code_actions!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"\\\"\").to_selection()\n    );\n}\n\n#[test]\nfn no_split_string_after_the_end() {\n    assert_no_code_actions!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"//we need this comment so we can put the cursor _after_ the closing quote\n}\"#,\n        find_position_of(\"\\\"/\").under_last_char().to_selection()\n    );\n}\n\n#[test]\nfn interpolate_string_inside_string() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"wobble\").select_until(find_position_of(\"wobble \").under_last_char()),\n    );\n}\n\n#[test]\nfn splitting_string_as_first_pipeline_step_inserts_brackets() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble  wobble\" |> io.println\n}\"#,\n        find_position_of(\" wobble\").to_selection(),\n    );\n}\n\n#[test]\nfn interpolating_string_as_first_pipeline_step_inserts_brackets() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\" |> io.println\n}\"#,\n        find_position_of(\"wobble \").select_until(find_position_of(\"wobble \").under_last_char()),\n    );\n}\n\n#[test]\nfn test_remove_unused_simple() {\n    let src = \"\n// test\nimport // comment\nlist as lispy\nimport result\nimport option\n\npub fn main() {\n  result.is_ok\n}\n\";\n\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src)\n            .add_hex_module(\"list\", \"\")\n            .add_hex_module(\"result\", \"\")\n            .add_hex_module(\"option\", \"\"),\n        find_position_of(\"// test\").select_until(find_position_of(\"option\")),\n    );\n}\n\n#[test]\nfn test_remove_unused_start_of_file() {\n    let src = \"import option\nimport result\n\npub fn main() {\n  result.is_ok\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"\")\n            .add_hex_module(\"result\", \"\"),\n        find_position_of(\"import\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_unused_alias() {\n    let src = \"\n// test\nimport result.{is_ok} as res\nimport option\n\npub fn main() {\n  is_ok\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src)\n            .add_hex_module(\"result\", \"pub fn is_ok() {}\")\n            .add_hex_module(\"option\", \"\"),\n        find_position_of(\"// test\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_unused_value() {\n    let src = \"\n// test\nimport result.{is_ok}\nimport option\n\npub fn main() {\n  result.is_ok\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src)\n            .add_hex_module(\"result\", \"pub fn is_ok() {}\")\n            .add_hex_module(\"option\", \"\"),\n        find_position_of(\"// test\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_aliased_unused_value() {\n    let src = \"\n// test\nimport result.{is_ok as ok}\nimport option\n\npub fn main() {\n  result.is_ok\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src)\n            .add_hex_module(\"result\", \"pub fn is_ok() {}\")\n            .add_hex_module(\"option\", \"\"),\n        find_position_of(\"// test\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_multiple_unused_values() {\n    let src = \"\n// test\nimport result.{type Unused, used, unused, unused_again, type Used, used_again}\n\npub fn main(x: Used) {\n  #(used, used_again)\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src).add_hex_module(\n            \"result\",\n            \"\npub const used = 1\npub const unused = 2\npub const unused_again = 3\npub const used_again = 4\npub type Unused\npub type Used\n\"\n        ),\n        find_position_of(\"// test\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_multiple_unused_values_2() {\n    let src = \"\n// test\nimport result.{type Unused, used, unused, type Used, unused_again}\n\npub fn main(x: Used) {\n  used\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src).add_hex_module(\n            \"result\",\n            \"\npub const used = 1\npub const unused = 2\npub const unused_again = 3\npub type Unused\npub type Used\n\"\n        ),\n        find_position_of(\"// test\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_entire_unused_import() {\n    let src = \"\n// test\nimport result.{unused, unused_again}\n\npub fn main() {\n  todo\n}\n\";\n    assert_code_action!(\n        REMOVE_UNUSED_IMPORTS,\n        TestProject::for_source(src).add_hex_module(\n            \"result\",\n            \"\npub const used = 1\npub const unused = 2\npub const unused_again = 3\npub type Unused\npub type Used\n\"\n        ),\n        find_position_of(\"// test\").select_until(find_position_of(\"pub\")),\n    );\n}\n\n#[test]\nfn test_remove_redundant_tuple_in_case_subject_simple() {\n    assert_code_action!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"pub fn main() {\n  case #(1) { #(a) -> 0 }\n  case #(1, 2) { #(a, b) -> 0 }\n}\",\n        find_position_of(\"case\").select_until(find_position_of(\"#(1, 2)\").under_last_char())\n    );\n}\n\n#[test]\nfn test_remove_redundant_tuple_with_catch_all_pattern() {\n    assert_code_action!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"pub fn main() {\n  case #(1, 2) {\n    #(1, 2) -> 0\n    _ -> 1\n  }\n}\",\n        find_position_of(\"case\").select_until(find_position_of(\"#(1, 2)\").under_last_char())\n    );\n}\n\n#[test]\nfn test_remove_multiple_redundant_tuple_with_catch_all_pattern() {\n    assert_code_action!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"pub fn main() {\n  case #(1, 2), #(3, 4) {\n    #(2, 2), #(2, 2) -> 0\n    #(1, 2), _ -> 0\n    _, #(1, 2) -> 0\n    _, _ -> 1\n  }\n}\",\n        find_position_of(\"case\").select_until(find_position_of(\"#(3, 4)\"))\n    );\n}\n\n#[test]\nfn test_remove_redundant_tuple_in_case_subject_nested() {\n    assert_code_action!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"pub fn main() {\n  case #(case #(0) { #(a) -> 0 }) { #(b) -> 0 }\n}\",\n        find_position_of(\"case\").select_until(find_position_of(\"#(b)\"))\n    );\n}\n\n#[test]\nfn test_remove_redundant_tuple_in_case_retain_extras() {\n    assert_code_action!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"\npub fn main() {\n  case\n    #(\n      // first comment\n      1,\n      // second comment\n      2,\n      3 // third comment before comma\n\n      ,\n\n      // fourth comment after comma\n\n    )\n  {\n    #(\n      // first comment\n      a,\n      // second comment\n      b,\n      c // third comment before comma\n\n      ,\n\n      // fourth comment after comma\n\n    ) -> 0\n  }\n}\n\",\n        find_position_of(\"#\").select_until(find_position_of(\"// first\"))\n    );\n}\n\n#[test]\nfn test_remove_redundant_tuple_in_case_subject_ignore_empty_tuple() {\n    assert_no_code_actions!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"\npub fn main() {\n  case #() { #() -> 0 }\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"0\"))\n    );\n}\n\n#[test]\nfn test_remove_redundant_tuple_in_case_subject_only_safe_remove() {\n    assert_code_action!(\n        REMOVE_REDUNDANT_TUPLES,\n        \"\npub fn main() {\n  case #(0), #(1) {\n    #(1), #(b) -> 0\n    a, #(0) -> 1 // The first of this clause is not a tuple\n    #(a), #(b) -> 2\n  }\n}\n\",\n        find_position_of(\"#(0)\").select_until(find_position_of(\"#(1)\"))\n    );\n}\n\n#[test]\nfn rename_invalid_const() {\n    assert_code_action!(\n        \"Rename to my_invalid_constant\",\n        \"const myInvalid_Constant = 42\",\n        find_position_of(\"_Constant\").to_selection(),\n    );\n}\n\n#[test]\nfn rename_invalid_parameter() {\n    assert_code_action!(\n        \"Rename to num_a\",\n        \"fn add(numA: Int, num_b: Int) { numA + num_b }\",\n        find_position_of(\"numA\").to_selection()\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_name2() {\n    assert_code_action!(\n        \"Rename to param_name\",\n        \"fn pass(label paramName: Bool) { paramName }\",\n        find_position_of(\"paramName\").to_selection()\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_name3() {\n    assert_code_action!(\n        \"Rename to num_a\",\n        \"pub fn main() {\n    let add = fn(numA: Int, num_b: Int) { numA + num_b }\n}\",\n        find_position_of(\"let add\").select_until(find_position_of(\"num_b\"))\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_discard() {\n    assert_code_action!(\n        \"Rename to _ignore_me\",\n        \"fn ignore(_ignoreMe: Bool) { 98 }\",\n        find_position_of(\"ignore\").select_until(find_position_of(\"98\"))\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_discard_name2() {\n    assert_code_action!(\n        \"Rename to _ignore_me\",\n        \"fn ignore(labelled_discard _ignoreMe: Bool) { 98 }\",\n        find_position_of(\"ignore\").select_until(find_position_of(\"98\"))\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_discard_name3() {\n    assert_code_action!(\n        \"Rename to _ignore_me\",\n        \"pub fn main() {\n    let ignore = fn(_ignoreMe: Bool) { 98 }\n}\",\n        find_position_of(\"ignore\").select_until(find_position_of(\"98\"))\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_label() {\n    assert_code_action!(\n        \"Rename to this_is_a_label\",\n        \"fn func(thisIsALabel param: Int) { param }\",\n        find_position_of(\"thisIs\").select_until(find_position_of(\"Int\"))\n    );\n}\n\n#[test]\nfn rename_invalid_parameter_label2() {\n    assert_code_action!(\n        \"Rename to this_is_a_label\",\n        \"fn ignore(thisIsALabel _ignore: Int) { 25 }\",\n        find_position_of(\"thisIs\").under_char('i').to_selection()\n    );\n}\n\n#[test]\nfn rename_invalid_constructor() {\n    assert_code_action!(\n        \"Rename to TheConstructor\",\n        \"type MyType { The_Constructor(Int) }\",\n        find_position_of(\"The_\").under_char('h').to_selection(),\n    );\n}\n\n#[test]\nfn rename_invalid_constructor_arg() {\n    assert_code_action!(\n        \"Rename to inner_int\",\n        \"type IntWrapper { IntWrapper(innerInt: Int) }\",\n        find_position_of(\"IntWrapper\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\": Int\"))\n    );\n}\n\n#[test]\nfn rename_invalid_custom_type() {\n    assert_code_action!(\n        \"Rename to BoxedValue\",\n        \"type Boxed_value { Box(Int) }\",\n        find_position_of(\"Box\").select_until(find_position_of(\"_value\"))\n    );\n}\n\n#[test]\nfn rename_invalid_type_alias() {\n    assert_code_action!(\n        \"Rename to FancyBool\",\n        \"type Fancy_Bool = Bool\",\n        find_position_of(\"Fancy\")\n            .under_char('a')\n            .select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn rename_invalid_function() {\n    assert_code_action!(\n        \"Rename to do_stuff\",\n        \"fn doStuff() {}\",\n        find_position_of(\"fn\").select_until(find_position_of(\"{}\"))\n    );\n}\n\n#[test]\nfn rename_invalid_variable() {\n    assert_code_action!(\n        \"Rename to the_answer\",\n        \"pub fn main() {\n    let theAnswer = 42\n}\",\n        find_position_of(\"theAnswer\").select_until(find_position_of(\"Answer\"))\n    );\n}\n\n#[test]\nfn rename_invalid_variable_discard() {\n    assert_code_action!(\n        \"Rename to _boring_number\",\n        \"pub fn main() {\n    let _boringNumber = 72\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"72\"))\n    );\n}\n\n#[test]\nfn rename_invalid_use() {\n    assert_code_action!(\n        \"Rename to use_var\",\n        \"fn use_test(f) { f(Nil) }\npub fn main() {use useVar <- use_test()}\",\n        find_position_of(\"use\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"use_test()\"))\n    );\n}\n\n#[test]\nfn rename_invalid_use_discard() {\n    assert_code_action!(\n        \"Rename to _discard_var\",\n        \"fn use_test(f) { f(Nil) }\npub fn main() {use _discardVar <- use_test()}\",\n        find_position_of(\"_discardVar\")\n            .under_last_char()\n            .to_selection()\n    );\n}\n\n#[test]\nfn rename_invalid_pattern_assignment() {\n    assert_code_action!(\n        \"Rename to the_answer\",\n        \"pub fn main() {\n    let assert 42 as theAnswer = 42\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"= 42\"))\n    );\n}\n\n#[test]\nfn rename_invalid_list_pattern() {\n    assert_code_action!(\n        \"Rename to the_element\",\n        \"pub fn main() {\n    let assert [theElement] = [9.4]\n}\",\n        find_position_of(\"assert\").select_until(find_position_of(\"9.4\"))\n    );\n}\n\n#[test]\nfn rename_invalid_list_pattern_discard() {\n    assert_code_action!(\n        \"Rename to _elem_one\",\n        \"pub fn main() {\n    let assert [_elemOne] = [False]\n}\",\n        find_position_of(\"[_elemOne]\")\n            .under_char('O')\n            .to_selection()\n    );\n}\n\n#[test]\nfn rename_invalid_constructor_pattern() {\n    assert_code_action!(\n        \"Rename to inner_value\",\n        \"pub type Box { Box(Int) }\npub fn main() {\n    let Box(innerValue) = Box(203)\n}\",\n        find_position_of(\"innerValue\").to_selection()\n    );\n}\n\n#[test]\nfn rename_invalid_constructor_pattern_discard() {\n    assert_code_action!(\n        \"Rename to _ignored_inner\",\n        \"pub type Box { Box(Int) }\npub fn main() {\n    let Box(_ignoredInner) = Box(203)\n}\",\n        find_position_of(\"_\").select_until(find_position_of(\"203\"))\n    );\n}\n\n#[test]\nfn rename_invalid_tuple_pattern() {\n    assert_code_action!(\n        \"Rename to second_value\",\n        \"pub fn main() {\n    let #(a, secondValue) = #(1, 2)\n}\",\n        find_position_of(\"secondValue\")\n            .select_until(find_position_of(\"secondValue\").under_char('n'))\n    );\n}\n\n#[test]\nfn rename_invalid_tuple_pattern_discard() {\n    assert_code_action!(\n        \"Rename to _second_value\",\n        \"pub fn main() {\n    let #(a, _secondValue) = #(1, 2)\n}\",\n        find_position_of(\"_secondValue\")\n            .under_char('_')\n            .select_until(find_position_of(\"#(1, 2)\"))\n    );\n}\n\n#[test]\nfn rename_invalid_bit_array_pattern() {\n    assert_code_action!(\n        \"Rename to bit_value\",\n        \"pub fn main() {\n    let assert <<bitValue>> = <<73>>\n}\",\n        find_position_of(\"<<\").select_until(find_position_of(\">>\"))\n    );\n}\n\n#[test]\nfn rename_invalid_bit_array_pattern_discard() {\n    assert_code_action!(\n        \"Rename to _i_dont_care\",\n        \"pub fn main() {\n    let assert <<_iDontCare>> = <<97>>\n}\",\n        find_position_of(\"<<\").select_until(find_position_of(\"Care\"))\n    );\n}\n\n#[test]\nfn rename_invalid_string_prefix_pattern() {\n    assert_code_action!(\n        \"Rename to cool_suffix\",\n        r#\"pub fn main() {\n    let assert \"prefix\" <> coolSuffix = \"prefix-suffix\"\n}\"#,\n        find_position_of(\"<>\").select_until(find_position_of(\"-suffix\"))\n    );\n}\n\n#[test]\nfn rename_invalid_string_prefix_pattern_discard() {\n    assert_code_action!(\n        \"Rename to _boring_suffix\",\n        r#\"pub fn main() {\n    let assert \"prefix\" <> _boringSuffix = \"prefix-suffix\"\n}\"#,\n        find_position_of(\"<>\").select_until(find_position_of(\"Suffix\"))\n    );\n}\n\n#[test]\nfn rename_invalid_string_prefix_pattern_alias() {\n    assert_code_action!(\n        \"Rename to the_prefix\",\n        r#\"pub fn main() {\n    let assert \"prefix\" as thePrefix <> _suffix = \"prefix-suffix\"\n}\"#,\n        find_position_of(\"prefix\").select_until(find_position_of(\"-suffix\"))\n    );\n}\n\n#[test]\nfn rename_invalid_case_variable() {\n    assert_code_action!(\n        \"Rename to twenty_one\",\n        \"pub fn main() {\n    case 21 { twentyOne -> {Nil} }\n}\",\n        find_position_of(\"case\").select_until(find_position_of(\"Nil\"))\n    );\n}\n\n#[test]\nfn rename_invalid_case_variable_discard() {\n    assert_code_action!(\n        \"Rename to _twenty_one\",\n        \"pub fn main() {\n    case 21 { _twentyOne -> {Nil} }\n}\",\n        find_position_of(\"21\").select_until(find_position_of(\"->\"))\n    );\n}\n\n#[test]\nfn rename_invalid_type_parameter_name() {\n    assert_code_action!(\n        \"Rename to inner_type\",\n        \"type Wrapper(innerType) {}\",\n        find_position_of(\"innerType\").select_until(find_position_of(\")\"))\n    );\n}\n\n#[test]\nfn rename_invalid_type_alias_parameter_name() {\n    assert_code_action!(\n        \"Rename to phantom_type\",\n        \"type Phantom(phantomType) = Int\",\n        find_position_of(\"phantomType\").select_until(find_position_of(\")\"))\n    );\n}\n\n#[test]\nfn rename_invalid_function_type_parameter_name() {\n    assert_code_action!(\n        \"Rename to some_type\",\n        \"fn identity(value: someType) { value }\",\n        find_position_of(\"someType\").select_until(find_position_of(\")\"))\n    );\n}\n\n#[test]\nfn test_convert_assert_result_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let assert Ok(value) = Ok(1)\n}\",\n        find_position_of(\"assert\").select_until(find_position_of(\"assert\").under_char('r')),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_to_case_indented() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  {\n    let assert Ok(value) = Ok(1)\n  }\n}\",\n        find_position_of(\"Ok\").to_selection()\n    );\n}\n\n#[test]\nfn test_convert_let_assert_to_case_multi_variables() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let assert [var1, var2, _var3, var4] = [1, 2, 3, 4]\n}\",\n        find_position_of(\"var1\").select_until(find_position_of(\"_var\").under_last_char())\n    );\n}\n\n#[test]\nfn test_convert_let_assert_to_case_discard() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let assert [_elem] = [6]\n}\",\n        find_position_of(\"assert\").select_until(find_position_of(\"[6]\").under_last_char()),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_to_case_no_variables() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let assert [] = []\n}\",\n        find_position_of(\"[]\").to_selection(),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_alias_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let assert 10 as ten = 10\n}\",\n        find_position_of(\"as\").select_until(find_position_of(\"ten\")),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_tuple_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n   let assert #(first, 10, third) = #(5, 10, 15)\n}\n\",\n        find_position_of(\"let\").to_selection(),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_bit_array_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let assert <<bits1, bits2>> = <<73, 98>>\n}\",\n        find_position_of(\"bits\").select_until(find_position_of(\"2\")),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_string_prefix_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main() {\n  let assert \"_\" <> thing = \"_Hello\"\n}\"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn test_convert_let_assert_string_prefix_pattern_alias_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main() {\n    let assert \"123\" as one_two_three <> rest = \"123456\"\n}\"#,\n        find_position_of(\"123\").select_until(find_position_of(\"123456\")),\n    );\n}\n\n#[test]\nfn test_convert_inner_let_assert_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main() {\n    let assert [wibble] = {\n        let assert Ok(wobble) = {\n            Ok(1)\n        }\n        [wobble]\n    }\n}\"#,\n        find_position_of(\"wobble\").under_char('l').to_selection()\n    );\n}\n\n#[test]\nfn test_convert_outer_let_assert_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main() {\n    let assert [wibble] = {\n        let assert Ok(wobble) = {\n            Ok(1)\n        }\n        [wobble]\n    }\n}\"#,\n        find_position_of(\"wibble\")\n            .under_char('i')\n            .select_until(find_position_of(\"= {\")),\n    );\n}\n\n#[test]\nfn test_convert_let_assert_with_message_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"\npub fn expect(value, message) {\n  let assert Ok(inner) = value as message\n  inner\n}\n\"#,\n        find_position_of(\"assert\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn test_convert_assert_custom_type_with_label_shorthands_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"\npub type Wibble { Wibble(arg: Int, arg2: Float) }\npub fn main() {\n  let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0)\n}\n\",\n        find_position_of(\"arg2:,\").select_until(find_position_of(\"1.0\")),\n    );\n}\n\n#[test]\nfn test_convert_assert_does_not_appear_if_the_entire_module_is_selected() {\n    assert_no_code_actions!(\n        CONVERT_TO_CASE,\n        \"\npub type Wibble { Wibble(arg: Int, arg2: Float) }\npub fn main() {\n  let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0)\n  let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0)\n}\n// end\n\",\n        find_position_of(\"pub\").select_until(find_position_of(\"// end\")),\n    );\n}\n\n#[test]\nfn label_shorthand_action_works_on_labelled_call_args() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    wibble(arg2: arg2, arg1: arg1)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n\"#,\n        find_position_of(\"wibble\")\n            .under_char('i')\n            .select_until(find_position_of(\"arg1: arg1\")),\n    );\n}\n\n#[test]\nfn label_shorthand_action_works_on_labelled_constructor_call_args() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    Wibble(arg2: arg2, arg1: arg1)\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\"#,\n        find_position_of(\"Wibble\").select_until(find_position_of(\"arg1: arg1\").under_char(':')),\n    );\n}\n\n#[test]\nfn label_shorthand_action_only_applies_to_selected_args() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    Wibble(arg2: arg2, arg1: arg1)\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\"#,\n        find_position_of(\"Wibble\").select_until(find_position_of(\"arg2: arg2\").under_char(':')),\n    );\n}\n\n#[test]\nfn label_shorthand_action_works_on_labelled_update_call_args() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn main() {\n    let arg1 = 1\n    Wibble(..todo, arg1: arg1)\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\"#,\n        find_position_of(\"..todo\").select_until(find_position_of(\"arg1: arg1\").under_last_char()),\n    );\n}\n\n#[test]\nfn label_shorthand_action_works_on_labelled_pattern_call_args() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn main() {\n    let Wibble(arg1: arg1, arg2: arg2) = todo\n    arg1 + arg2\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"todo\").under_last_char()),\n    );\n}\n\n#[test]\nfn label_shorthand_action_doesnt_come_up_for_arguments_with_different_label() {\n    assert_no_code_actions!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn main() {\n  let Wibble(arg1: arg_1, arg2: arg_2) = todo\n  arg_1 + arg_2\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\"#,\n        find_position_of(\"arg_1\").select_until(find_position_of(\"arg_2\").under_last_char())\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_with_some_arguments_already_supplied() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  wibble(1,)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble(\").under_char('b').to_selection(),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_with_some_arguments_already_supplied_2() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  wibble(arg2: 1)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble(\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_with_some_arguments_already_supplied_3() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  wibble(1, arg3: 2)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n \"#,\n        find_position_of(\"wibble(\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_regular_function() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  wibble()\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble(\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_record_constructor() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  Wibble()\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \"#,\n        find_position_of(\"Wibble\").select_until(find_position_of(\"Wibble()\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_pattern_and_no_parentheses() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  let assert Ok(Wibble) = Wibble(1, \"2\")\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \"#,\n        find_position_of(\"Wibble\").select_until(find_position_of(\"Wibble\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_pattern_and_parentheses() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  let assert Ok(Wibble()) = Wibble(1, \"2\")\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \"#,\n        find_position_of(\"Wibble\").select_until(find_position_of(\"Wibble\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_pattern_and_parentheses_with_spaces() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  let assert Ok(Wibble   ()) = Wibble(1, \"2\")\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \"#,\n        find_position_of(\"Wibble\").select_until(find_position_of(\"Wibble\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_pipes() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  1 |> wibble()\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble()\")\n            .under_last_char()\n            .to_selection(),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_pipes_2() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  1 |> wibble()\n}\n\npub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble()\")\n            .under_last_char()\n            .to_selection(),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_use() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  use <- wibble()\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble(\").select_until(find_position_of(\"wibble()\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_use_2() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  use <- wibble(arg1: 1)\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n \"#,\n        find_position_of(\"wibble(\").select_until(find_position_of(\"1\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_works_with_use_3() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  use <- wibble(arg2: 2)\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n \"#,\n        find_position_of(\"wibble(\").select_until(find_position_of(\"2\").under_last_char()),\n    );\n}\n\n#[test]\nfn fill_in_labelled_args_selects_innermost_function() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub fn main() {\n  wibble(\n    wibble()\n  )\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \"#,\n        find_position_of(\"wibble()\")\n            .under_last_char()\n            .to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_uses_variable_in_scope_with_matching_type() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    Player(team: \"BLU\")\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_falls_back_to_todo_when_type_does_not_match() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = 1\n    Player(team: \"BLU\")\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_uses_function_argument_in_scope() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn create_player(name: String) {\n    Player(team: \"BLU\")\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_ignores_variable_defined_after_call() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    Player(team: \"BLU\")\n    let name = \"Priya\"\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_multiple_fields_some_matching() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, age: Int, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    let age = \"not an int\"\n    Player()\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_all_fields_have_matching_variables() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, age: Int, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    let age = 25\n    let team = \"BLU\"\n    Player()\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_inside_anonymous_function() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Outer\"\n    let callback = fn() {\n        let name = \"Inner\"\n        Player(team: \"BLU\")\n    }\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_variable_from_outer_scope_not_shadowed() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Outer\"\n    let callback = fn() {\n        Player(team: \"BLU\")\n    }\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_inside_assignment_with_same_name_as_field() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = Player(team: \"BLU\")\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_ignores_underscore_prefixed_variables() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let _name = \"Priya\"\n    Player(team: \"BLU\")\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_variable_out_of_scope_in_block() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    {\n        let name = \"Priya\"\n    }\n    Player(team: \"BLU\")\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_variable_in_scope_from_case_pattern() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main(result: Result(String, Nil)) {\n    case result {\n        Ok(name) -> Player(team: \"BLU\")\n        Error(_) -> Player(team: \"RED\", name: \"Unknown\")\n    }\n}\n\"#,\n        find_position_of(\"Player\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_generic_type_matching() {\n    assert_code_action!(\n        FILL_LABELS,\n        r#\"\npub type Container(a) {\n    Container(value: a, label: String)\n}\n\npub fn main() {\n    let value = 42\n    let label = \"test\"\n    Container()\n}\n\"#,\n        find_position_of(\"Container\")\n            .nth_occurrence(3)\n            .to_selection(),\n    );\n}\n\n#[test]\nfn use_label_shorthand_works_for_nested_calls() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub fn wibble(arg arg: Int) -> Int { arg }\n\npub fn main() {\n  let arg = 1\n  wibble(wibble(arg: arg))\n}\n \"#,\n        find_position_of(\"main\").select_until(find_position_of(\"}\").nth_occurrence(2)),\n    );\n}\n\n#[test]\nfn use_label_shorthand_works_for_nested_record_updates() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\npub type Wobble { Wobble(arg: Int, arg2: String) }\n\npub fn main() {\n  let arg = 1\n  let arg2 = \"a\"\n  Wibble(..todo, arg2: Wobble(arg: arg, arg2: arg2))\n}\n \"#,\n        find_position_of(\"todo\").select_until(find_position_of(\"arg2: arg2\")),\n    );\n}\n\n#[test]\nfn use_label_shorthand_works_for_nested_patterns() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\npub type Wobble { Wobble(arg: Int, arg2: String) }\n\npub fn main() {\n  let Wibble(arg2: Wobble(arg: arg, arg2: arg2), ..) = todo\n}\n \"#,\n        find_position_of(\"main\").select_until(find_position_of(\"todo\")),\n    );\n}\n\n#[test]\nfn use_label_shorthand_works_for_alternative_patterns() {\n    assert_code_action!(\n        USE_LABEL_SHORTHAND_SYNTAX,\n        r#\"\npub type Wibble { Wibble(arg: Int, arg2: String) }\n\npub fn main() {\n  case Wibble(1, \"wibble\") {\n    Wibble(arg2: arg2, ..) | Wibble(arg: 1, arg2: arg2) -> todo\n  }\n}\n \"#,\n        find_position_of(\"main\").select_until(find_position_of(\"todo\")),\n    );\n}\n\n#[test]\nfn test_assign_unused_result() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    let x = 1\n    Ok(x)\n    Nil\n}\n\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"(x)\")),\n    );\n}\n\n#[test]\nfn test_assign_unused_result_in_block() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    {\n        let x = 1\n        Ok(x)\n        Nil\n    }\n    Nil\n}\n\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"(x)\")),\n    );\n}\n\n#[test]\nfn test_assign_unused_result_on_block_start() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    {\n        let x = 1\n        Ok(x)\n        Ok(x)\n    }\n    Nil\n}\n\"#,\n        find_position_of(\"{\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn test_assign_unused_result_on_block_end() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    {\n        let x = 1\n        Ok(x)\n        Ok(x)\n    }\n    Nil\n}\n\"#,\n        find_position_of(\"}\").to_selection()\n    );\n}\n\n#[test]\n#[should_panic(expected = \"No action with the given title\")]\nfn test_assign_unused_result_inside_block() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    {\n        let x = 1\n        Nil\n        Ok(x)\n    }\n}\n\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"(x)\"))\n    );\n}\n\n#[test]\nfn test_assign_unused_result_only_first_action() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    let x = 1\n    Ok(x)\n    Ok(x)\n    Nil\n}\n\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"(x)\"))\n    );\n}\n\n#[test]\n#[should_panic(expected = \"No action with the given title\")]\nfn test_assign_unused_result_not_on_return_value() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    let x = 1\n    Ok(x)\n}\n\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"(x)\"))\n    );\n}\n\n#[test]\n#[should_panic(expected = \"No action with the given title\")]\nfn test_assign_unused_result_not_on_return_value_in_block() {\n    assert_code_action!(\n        ASSIGN_UNUSED_RESULT,\n        r#\"\npub fn main() {\n    let _ = {\n        let x = 1\n        Ok(x)\n    }\n    Nil\n}\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"(x)\"))\n    );\n}\n\n#[test]\nfn test_import_module_from_function() {\n    let src = \"\npub fn main() {\n  result.is_ok()\n}\n\";\n\n    assert_code_action!(\n        \"Import `result`\",\n        TestProject::for_source(src).add_hex_module(\"result\", \"pub fn is_ok() {}\"),\n        find_position_of(\"result\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_import_path_module_from_function() {\n    let src = r#\"\npub fn main() {\n  io.println(\"Hello, world!\")\n}\n\"#;\n\n    assert_code_action!(\n        \"Import `gleam/io`\",\n        TestProject::for_source(src)\n            .add_hex_module(\"gleam/io\", \"pub fn println(message: String) {}\"),\n        find_position_of(\"io\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_import_module_from_type() {\n    let src = \"type Wobble = wibble.Wubble\";\n\n    assert_code_action!(\n        \"Import `mod/wibble`\",\n        TestProject::for_source(src).add_hex_module(\"mod/wibble\", \"pub type Wubble { Wubble }\"),\n        find_position_of(\"wibble\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_import_module_from_constructor() {\n    let src = \"\npub fn main() {\n  let value = values.Value(10)\n}\n\";\n\n    assert_code_action!(\n        \"Import `values`\",\n        TestProject::for_source(src).add_hex_module(\"values\", \"pub type Value { Value(Int) }\"),\n        find_position_of(\"values\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_rename_module_for_imported() {\n    let src = r#\"\nimport gleam/io\n\npub fn main() {\n  i.println(\"Hello, world!\")\n}\n\"#;\n\n    assert_code_action!(\n        \"Did you mean `io`\",\n        TestProject::for_source(src)\n            .add_hex_module(\"gleam/io\", \"pub fn println(message: String) {}\"),\n        find_position_of(\"i.\").select_until(find_position_of(\"println\"))\n    );\n}\n\n#[test]\nfn test_import_similar_module() {\n    let src = \"\npub fn main() {\n  reult.is_ok()\n}\n\";\n\n    assert_code_action!(\n        \"Import `result`\",\n        TestProject::for_source(src).add_hex_module(\"result\", \"pub fn is_ok() {}\"),\n        find_position_of(\"reult\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_no_action_to_import_module_without_value() {\n    // The language server should not suggest a code action\n    // to import a module if it doesn't have a value with\n    // the same name as we are trying to access\n    let src = \"\npub fn main() {\n  io.hello_world()\n}\n\";\n\n    let title = \"Import `io`\";\n\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\"io\", \"pub fn println() {}\"),\n        find_position_of(\"io\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_no_action_to_import_module_without_type() {\n    let src = \"type Name = int.String\";\n\n    let title = \"Import `int`\";\n\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\"int\", \"\"),\n        find_position_of(\"int\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_no_action_to_import_module_with_private_value() {\n    // The language server should not suggest a code action\n    // to import a module if the value we are trying to\n    // access is private.\n    let src = \"\npub fn main() {\n  mod.internal()\n}\n\";\n\n    let title = \"Import `mod`\";\n\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\"mod\", \"fn internal() {}\"),\n        find_position_of(\"mod\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_no_action_to_import_module_with_private_type() {\n    let src = \"type T = module.T\";\n\n    let title = \"Import `module`\";\n\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\"module\", \"type T { T }\"),\n        find_position_of(\"module\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn test_no_action_to_import_module_with_constructor_named_same_as_type() {\n    let src = \"type NotAType = shapes.Rectangle\";\n\n    let title = \"Import `shapes`\";\n\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"shapes\", \"pub type Shape { Rectangle, Circle }\"),\n        find_position_of(\"shapes\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_bool() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        \"\npub fn main(bool: Bool) {\n  case bool {}\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"bool {\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_custom_type() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        \"\ntype Wibble {\n  Wibble\n  Wobble\n  Wubble\n}\n\npub fn main(wibble: Wibble) {\n  case wibble {\n    Wobble -> Nil\n  }\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"wibble {\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_tuple() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        \"\npub fn main(two_at_once: #(Bool, Result(Int, Nil))) {\n  case two_at_once {\n    #(False, Error(_)) -> Nil\n  }\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"two_at_once {\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_list() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        \"\npub fn main() {\n  let list = [1, 2, 3]\n  case list {\n    [a, b, c, 4 as d] -> d\n  }\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"list {\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_infinite() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        r#\"\npub fn main() {\n  let value = 3\n  case value {\n    1 -> \"one\"\n    2 -> \"two\"\n    3 -> \"three\"\n  }\n}\n\"#,\n        find_position_of(\"case\").select_until(find_position_of(\"value {\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_multi() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        r#\"\npub fn main(a: Bool) {\n  let b = 1\n  case a, b {\n\n  }\n}\n\"#,\n        find_position_of(\"case\").select_until(find_position_of(\"b {\"))\n    );\n}\n\n#[test]\nfn add_missing_patterns_inline() {\n    // Ensure we correctly detect the indentation, if the case expression\n    // does not start at the beginning of the line\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        r#\"\npub fn main(a: Bool) {\n  let value = case a {}\n}\n\"#,\n        find_position_of(\"case\").select_until(find_position_of(\"a {\"))\n    );\n}\n\n#[test]\nfn import_module_from_pattern() {\n    let src = \"\npub fn main(res) {\n  case res {\n    result.Ok(_) -> Nil\n    result.Error(_) -> Nil\n  }\n}\n\";\n\n    assert_code_action!(\n        \"Import `result`\",\n        TestProject::for_source(src)\n            .add_hex_module(\"result\", \"pub type Result(v, e) { Ok(v) Error(e) }\"),\n        find_position_of(\"result\").select_until(find_position_of(\".\"))\n    );\n}\n\n#[test]\nfn annotate_function() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn add_one(thing) {\n  thing + 1\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_function_with_annotated_return_type() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn add_one(thing) -> Int {\n  thing + 1\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_function_with_partially_annotated_parameters() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn add(a: Float, b) -> Float {\n  a +. b\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn no_code_action_for_fully_annotated_function() {\n    assert_no_code_actions!(\n        ADD_ANNOTATION | ADD_ANNOTATIONS,\n        r#\"\npub fn do_a_thing(a: Int, b: Float) -> String {\n  todo\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_anonymous_function() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn add_curry(a) {\n  fn(b) { a + b }\n}\n\"#,\n        find_position_of(\"fn(\").select_until(find_position_of(\"b)\"))\n    );\n}\n\n#[test]\nfn annotate_anonymous_function_with_annotated_return_type() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn add_curry(a) {\n  fn(b) -> Int { a + b }\n}\n\"#,\n        find_position_of(\"fn(\").select_until(find_position_of(\"b)\"))\n    );\n}\n\n#[test]\nfn annotate_anonymous_function_with_partially_annotated_parameters() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn main() {\n  fn(a, b: Int, c) { a + b + c }\n}\n\"#,\n        find_position_of(\"fn(\").select_until(find_position_of(\"c)\"))\n    );\n}\n\n#[test]\nfn no_code_action_for_fully_annotated_anonymous_function() {\n    assert_no_code_actions!(\n        ADD_ANNOTATION | ADD_ANNOTATIONS,\n        r#\"\npub fn main() {\n  fn(a: Int, b: Int) -> Int { a - b }\n}\n\"#,\n        find_position_of(\"fn(\").select_until(find_position_of(\"Int)\"))\n    );\n}\n\n#[test]\nfn annotate_use() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a, b <- wibble\n  a + b\n}\n\"#,\n        find_position_of(\"use\").select_until(find_position_of(\"<-\"))\n    );\n}\n\n#[test]\nfn annotate_use_with_partially_annotated_parameters() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a: Int, b <- wibble\n  a + b\n}\n\"#,\n        find_position_of(\"use\").select_until(find_position_of(\"<-\"))\n    );\n}\n\n#[test]\nfn no_code_action_for_fully_annotated_use() {\n    assert_no_code_actions!(\n        ADD_ANNOTATION | ADD_ANNOTATIONS,\n        r#\"\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a: Int, b: Int <- wibble\n  a + b\n}\n\"#,\n        find_position_of(\"use\").select_until(find_position_of(\"<-\"))\n    );\n}\n\n#[test]\nfn annotate_constant() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub const my_constant = 20\n\"#,\n        find_position_of(\"const\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn no_code_action_for_annotated_constant() {\n    assert_no_code_actions!(\n        ADD_ANNOTATION | ADD_ANNOTATIONS,\n        r#\"\npub const PI: Float = 3.14159\n\"#,\n        find_position_of(\"const\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn annotate_local_variable() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn main() {\n  let my_value = 10\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn annotate_local_variable_with_pattern() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let Wibble(a, b, c) = Wibble(1, 2, 3)\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn annotate_local_variable_with_pattern2() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn main(values) {\n  let #(left, right) = values\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn annotate_local_variable_let_assert() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn fallible() -> Result(Int, Nil) {\n  todo\n}\n\npub fn main() {\n  let assert Ok(value) = fallible()\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn annotate_nested_local_variable() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub fn main() {\n  let a = {\n    let b = 10\n    b + 1\n  }\n}\n\"#,\n        find_position_of(\"let b\").select_until(find_position_of(\"b =\"))\n    );\n}\n\n#[test]\nfn no_code_action_for_annotated_local_variable() {\n    assert_no_code_actions!(\n        ADD_ANNOTATION | ADD_ANNOTATIONS,\n        r#\"\npub fn main() {\n  let typed: Int = 1.2\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn adding_annotations_correctly_prints_type_variables() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn map_result(input, function) {\n  case input {\n    Ok(value) -> Ok(function(value))\n    Error(error) -> Error(error)\n  }\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn add_multiple_annotations() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub const my_constant = 20\n\npub fn add_my_constant(value) {\n  let result = value + my_constant\n  result\n}\n\"#,\n        find_position_of(\"pub const\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn different_annotations_create_compatible_type_variables() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn do_generic_things(a, b) {\n  let a_value = a\n  let b_value = b\n  let other_value = a_value\n}\n\"#,\n        find_position_of(\"let a_value\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn adding_annotations_prints_type_variable_names() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        r#\"\npub fn do_generic_things(a: type_a, b: type_b) {\n  let a_value = a\n  let b_value = b\n  let other_value = a_value\n}\n\"#,\n        find_position_of(\"let a_value\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn adding_annotations_prints_contextual_types() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub type IntAlias = Int\n\npub fn main() {\n  let value = 20\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"value\"))\n    );\n}\n\n#[test]\nfn adding_annotations_prints_contextual_types2() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\npub type Result\n\npub fn main() {\n  let value = Ok(12)\n}\n\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn adding_annotations_prints_contextual_types3() {\n    let src = r#\"\nimport wibble\n\npub fn main() {\n  let value = wibble.Wibble\n}\n\"#;\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn add_annotation_triggers_on_function_curly_brace() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        \"pub fn main() { 1 }\",\n        find_position_of(\"{\").to_selection(),\n    );\n}\n\n#[test]\nfn add_annotation_triggers_on_empty_space_before_function_curly_brace() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        \"pub fn main() { 1 }\",\n        find_position_of(\" \").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn adding_annotations_prints_contextual_types4() {\n    let src = r#\"\nimport wibble as wobble\n\npub fn main() {\n  let value = wobble.Wibble\n}\n\"#;\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn adding_annotations_prints_contextual_types5() {\n    let src = r#\"\nimport wibble.{type Wibble as Wobble}\n\npub fn main() {\n  let value = wibble.Wibble\n}\n\"#;\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"let\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3789\nfn no_code_actions_to_add_annotations_for_pipe() {\n    assert_no_code_actions!(\n        ADD_ANNOTATION | ADD_ANNOTATIONS,\n        r#\"\nfn do_something(a: Int) { a }\n\npub fn main() {\n  10 |> do_something\n}\n\"#,\n        find_position_of(\"10\").select_until(find_position_of(\"|>\"))\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/3789#issuecomment-2455805734\nfn add_correct_type_annotation_for_non_variable_use() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        r#\"\nfn usable(f) {\n  f(#(1, 2))\n}\n\npub fn main() {\n  use #(a, b) <- usable\n  a + b\n}\n\"#,\n        find_position_of(\"use\").select_until(find_position_of(\"b)\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_basic_with_argument() {\n    let src = r#\"\nimport option\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_basic_record_without_argument() {\n    let src = r#\"\nimport wobble\n\npub fn main() {\n  wobble.Wibble\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src).add_hex_module(\"wobble\", \"pub type Wobble { Wibble }\"),\n        find_position_of(\".W\").select_until(find_position_of(\"ibble\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_custom_type_record_declaration() {\n    let src = r#\"\nimport wobble\n\npub type Wibble {\n  Wibble(wibble: wobble.Wobble)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wobble\",\n        TestProject::for_source(src).add_hex_module(\"wobble\", \"pub type Wobble { Wibble }\"),\n        find_position_of(\".\").select_until(find_position_of(\"Wobble\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_basic_type_without_argument() {\n    let src = r#\"\nimport wobble\n\npub fn identity(x: wobble.Wobble) -> wobble.Wobble {\n    x\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wobble\",\n        TestProject::for_source(src).add_hex_module(\"wobble\", \"pub type Wobble { Wibble }\"),\n        find_position_of(\".\").select_until(find_position_of(\"Wobble\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_record_value_constructor_module_name() {\n    let src = r#\"\nimport option\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"option\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_basic_multiple() {\n    let src = r#\"\nimport option\n\npub fn main() {\n  option.Some(1)\n  option.Some(1)\n  todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_when_unqualified_exists() {\n    let src = r#\"\nimport option.{Some}\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_with_comma() {\n    let src = r#\"\nimport option.{None, }\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_with_comma_pos_not_end() {\n    let src = r#\"\nimport option.{None,   } as opt\n\npub fn main() {\n  opt.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify opt.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_different_constructors() {\n    let src = r#\"\nimport option\n\npub fn main() {\n  option.Some(1)\n  option.None\n}\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_no_action_when_already_unqualified() {\n    let src = r#\"\nimport option.{Some, None}\n\npub fn main() {\n  Some(1)\n  Some(1)\n  todo\n}\n\"#;\n    let title = \"Unqualify option.Some\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some(\").select_until(find_position_of(\"1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_with_alias() {\n    let src = r#\"\nimport option as opt\n\npub fn main() {\n  opt.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify opt.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_with_alias_multiple() {\n    let src = r#\"\nimport option as opt\n\npub fn main() {\n  opt.Some(1)\n  opt.Some(1)\n}\n\npub fn identity(x: opt.Option(Int)) -> opt.Option(Int) {\n    opt.Some(1)\n    x\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify opt.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_multiple_imports() {\n    let src = r#\"\nimport option\nimport wobble\n\npub fn main() {\n  option.Some(2)\n  wobble.Wibble(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"wobble\", \"pub type Wobble { Wibble(Int)} \"),\n        find_position_of(\".Wibble\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_case_with_argument() {\n    let src = r#\"\nimport option\n\npub fn main(x) {\n  case option.Some(1) {\n    option.Some(value) -> value\n    option.None -> 0\n  }\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some(\").select_until(find_position_of(\"(1)\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_case_without_argument() {\n    let src = r#\"\nimport wobble\n\npub fn main() {\n  case wobble.Wibble {\n    wobble.Wibble -> 1\n    wobble.Wubble(1) -> 2\n  }\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src)\n            .add_hex_module(\"wobble\", \"pub type Wobble { Wibble Wubble(Int) }\"),\n        find_position_of(\".W\").select_until(find_position_of(\"ibble\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_pattern() {\n    let src = r#\"\nimport option\n\npub fn main() -> Int {\n  case option.Some(1) {\n    option.Some(value) -> value\n    option.None -> 0\n  }\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some(va\").select_until(find_position_of(\"lue)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_pattern_without_argument() {\n    let src = r#\"\nimport wobble\n\npub fn main() {\n  case wobble.Wibble {\n    wobble.Wibble -> 1\n    wobble.Wubble(1) -> 2\n  }\n  let wob = wobble.Wibble\n  todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src)\n            .add_hex_module(\"wobble\", \"pub type Wobble { Wibble Wubble(Int) }\"),\n        find_position_of(\"wobble.W\").select_until(find_position_of(\"ibble\"))\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_type() {\n    let src = r#\"\nimport option\n\npub fn main(x) -> option.Option(Int) {\n    option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Option\").select_until(find_position_of(\"(Int)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_nested_type_outer() {\n    let src = r#\"\nimport option\nimport wobble\npub fn main(x) -> option.Option(wobble.Wibble) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"wobble\", \"pub type Wibble { Wobble(Int) }\"),\n        find_position_of(\".O\").select_until(find_position_of(\"ption(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_nested_constructor_outer() {\n    let src = r#\"\nimport option\nimport wobble\npub fn main(x) -> option.Option(wobble.Wibble) {\n    option.Some(wobble.Wobble(1))\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"wobble\", \"pub type Wibble { Wobble(Int) }\"),\n        find_position_of(\".S\").select_until(find_position_of(\"ome(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_nested_constructor_inner() {\n    let src = r#\"\nimport option\nimport wobble\n\npub fn main(x) -> option.Option(wobble.Wibble) {\n    option.Some(wobble.Wobble(1))\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wobble\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"wobble\", \"pub type Wibble { Wobble(Int) }\"),\n        find_position_of(\".Wobble\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_nested_type_inner() {\n    let src = r#\"\nimport option\nimport wobble\n\npub fn main(x) -> option.Option(wobble.Wibble) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"wobble\", \"pub type Wibble { Wobble(Int) }\"),\n        find_position_of(\"wobble.\").select_until(find_position_of(\"Wibble\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_aliased_type() {\n    let src = r#\"\nimport wobble\n\npub fn main(x) -> wobble.Wibble(a) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src).add_hex_module(\"wobble\", \"pub type Wibble(a) = List(a)\"),\n        find_position_of(\"wobble.\").select_until(find_position_of(\"Wibble\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_aliased_type_with_multiple_imports() {\n    let src = r#\"\nimport other/wobble as other\nimport wibble/wobble\n\npub fn main(x) -> wobble.Wibble(a) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wobble.Wibble\",\n        TestProject::for_source(src)\n            .add_hex_module(\"wibble/wobble\", \"pub type Wibble(a) = List(a)\")\n            .add_hex_module(\"other/wobble\", \"pub type Wibble(a) = List(a)\"),\n        find_position_of(\"wobble.\").select_until(find_position_of(\"Wibble\")),\n    );\n}\n\n#[test]\nfn test_qualified_aliased_to_unqualified_aliased_type() {\n    let src = r#\"\nimport wobble as wob\n\npub fn main(x) -> wob.Wibble(a) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify wob.Wibble\",\n        TestProject::for_source(src).add_hex_module(\"wobble\", \"pub type Wibble(a) = List(a)\"),\n        find_position_of(\"wob.\").select_until(find_position_of(\"Wibble\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_below_constructor() {\n    let src = r#\"\n\npub fn main() {\n  option.Some(1)\n}\n\nimport option\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_between_constructors() {\n    let src = r#\"\n\npub fn main() {\n  option.Some(1)\n}\n\nimport option\n\npub fn identity(x: option.Option(Int)) -> option.Option(Int) {\n    option.Some(1)\n    x\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_multiple_line() {\n    let src = r#\"\nimport option.{\n    type Option,\n    None,\n}\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_multiple_line_bad_format_with_trailing_comma() {\n    let src = r#\"\nimport option.{type Option,\n    None,\n\n}\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_multiple_line_bad_format_multiple_whitespace() {\n    let src = r#\"\nimport option.{    }\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n#[test]\nfn test_qualified_to_unqualified_import_multiple_line_bad_format_without_trailing_comma() {\n    let src = r#\"\nimport option.{type Option,\n    None\n\n}\n\npub fn main() {\n  option.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n#[test]\nfn test_qualified_to_unqualified_import_multiple_line_aliased() {\n    let src = r#\"\nimport option.{\n    type Option,\n    None} as opt\n\npub fn main() {\n  opt.Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify opt.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\".Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_list_and_tuple() {\n    let src = r#\"\nimport option\n\npub fn main() {\n    let list = [option.Some(1), option.None]\n    let tuple = #(option.Some(2), option.None)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"option.Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_multiple_generic_type() {\n    let src = r#\"\nimport result\n\npub fn main() -> result.Result(Int, String) {\n    result.Ok(1)\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify result.Result\",\n        TestProject::for_source(src)\n            .add_hex_module(\"result\", \"pub type Result(a, e) { Ok(a) Error(e) }\"),\n        find_position_of(\".Result\").select_until(find_position_of(\"(Int\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_constructor_as_argument() {\n    let src = r#\"\nimport option\n\npub fn main() {\n    option.map(option.Some(1), fn(x) { x + 1 })\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src).add_hex_module(\n            \"option\",\n            \"\n            pub type Option(v) { Some(v) None }\n            pub fn map(a, f) { todo }\n            \"\n        ),\n        find_position_of(\"option.Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_constructor_different_module_same_type_inner() {\n    let src = r#\"\nimport option\nimport opt\n\npub fn main() -> option.Option(opt.Option(Int)) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify opt.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.Option\").select_until(find_position_of(\"(Int)\")),\n    );\n}\n#[test]\nfn test_qualified_to_unqualified_import_constructor_different_module_same_type_outer() {\n    let src = r#\"\nimport option\nimport opt\n\npub fn main() -> option.Option(opt.Option(Int)) {\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"option.\").select_until(find_position_of(\"Option(\")),\n    );\n}\n#[test]\nfn test_qualified_to_unqualified_import_constructor_different_module_same_name_inner() {\n    let src = r#\"\nimport option\nimport opt\n\npub fn main() {\n    option.Some(opt.Some(1))\n    todo\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify opt.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.Some\").select_until(find_position_of(\"(1)\")),\n    );\n}\n#[test]\nfn test_qualified_to_unqualified_import_constructor_different_module_same_name_outer() {\n    let src = r#\"\nimport option\nimport opt\n\npub fn main() {\n    option.Some(opt.Some(1))\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"option.\").select_until(find_position_of(\"Some(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_constructor_complex_pattern() {\n    let src = r#\"\nimport option\n\npub fn main() {\n    case [option.Some(1), option.None] {\n        [option.None, ..] -> todo\n        [option.Some(_), ..] -> todo\n        _ -> todo\n    }\n    case option.Some(1), option.Some(2) {\n        option.None, option.Some(_) -> todo\n        option.Some(_), option.Some(val) -> todo\n        _ -> todo\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Unqualify option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"option.\").select_until(find_position_of(\"Some(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_constructor_constructor_name_exists() {\n    let src = r#\"\nimport option.{Some}\nimport opt\n\npub fn main() -> option.Option(opt.Option(Int)) {\n    Some(opt.Some(1))\n}\n\"#;\n    let title = \"Unqualify opt.Some\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.\").select_until(find_position_of(\".Some(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_constructor_constructor_name_exists_below() {\n    let src = r#\"\nimport opt\n\npub fn main() -> option.Option(opt.Option(Int)) {\n    Some(opt.Some(1))\n}\nimport option.{Some}\n\"#;\n    let title = \"Unqualify opt.Some\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.\").select_until(find_position_of(\".Some(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists() {\n    let src = r#\"\nimport option.{type Option}\nimport opt\n\npub fn main() -> Option(opt.Option(Int)) {\n    option.Some(opt.Some(1))\n}\n\"#;\n    let title = \"Unqualify opt.Option\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.\").select_until(find_position_of(\".Option(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists_below() {\n    let src = r#\"\nimport opt\n\npub fn main() -> Option(opt.Option(Int)) {\n    option.Some(opt.Some(1))\n}\nimport option.{type Option}\n\"#;\n    let title = \"Unqualify opt.Option\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\")\n            .add_hex_module(\"opt\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"opt.\").select_until(find_position_of(\".Option(\")),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_constant_var() {\n    let src = r#\"\nimport option\n\nconst none = option.None\n\"#;\n    let title = \"Unqualify option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_constant_record() {\n    let src = r#\"\nimport option\n\nconst some = option.Some(1)\n\"#;\n    let title = \"Unqualify option.Some\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some\").to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_in_nested_constant() {\n    let src = r#\"\nimport option\n\ntype Result(a) {\n  Result(expected: a, actual: option.Option(a))\n}\n\nconst zero = Result(0, option.None)\n\"#;\n    let title = \"Unqualify option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_constant_multiple_occurrences() {\n    let src = r#\"\nimport option\n\nconst a = option.None\nconst b = option.Some(option.None)\n\"#;\n    let title = \"Unqualify option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").nth_occurrence(1).to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_not_offered_for_function_in_constant() {\n    let src = r#\"\nimport list\n\nconst mapper = list.map\n\"#;\n\n    let title = \"Unqualify list.map\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\"list\", \"pub fn map(list, f) { todo }\"),\n        find_position_of(\"list.map\").to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_not_offered_for_module_constant_in_constant() {\n    let src = r#\"\nimport mymath\n\nconst x = mymath.pi\n\"#;\n\n    let title = \"Unqualify mymath.pi\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\"mymath\", \"pub const pi = 3.14159\"),\n        find_position_of(\"pi\").to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_from_constant_also_updates_functions() {\n    let src = r#\"\nimport option\n\nconst default = option.None\n\npub fn get_or_default(value: a) {\n  case value {\n    option.Some(x) -> x\n    option.None -> value\n  }\n}\n\"#;\n    let title = \"Unqualify option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").nth_occurrence(1).to_selection(),\n    );\n}\n\n#[test]\nfn test_qualified_to_unqualified_import_from_function_also_updates_constants() {\n    let src = r#\"\nimport option\n\nconst default = option.None\n\npub fn get_or_default(value: a) {\n  case value {\n    option.Some(x) -> x\n    option.None -> value\n  }\n}\n\"#;\n    let title = \"Unqualify option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").nth_occurrence(2).to_selection(),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_function() {\n    let src = r#\"\nimport list.{map}\n\npub fn main() {\n    let identity = map([1, 2, 3], fn(x) { x })\n    let double = map([1, 2, 3], fn(x) { x * 2 })\n}\n\"#;\n    assert_code_action!(\n        \"Qualify map as list.map\",\n        TestProject::for_source(src).add_hex_module(\"list\", \"pub fn map(list, f) { todo }\"),\n        find_position_of(\"map(\").select_until(find_position_of(\"[1, 2, 3]\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_constant() {\n    let src = r#\"\nimport mymath.{pi}\n\npub fn circle_area(radius: Float) -> Float {\n    pi *. radius *. radius\n}\n\npub fn circle_circumference(radius: Float) -> Float {\n    2. *. pi *. radius\n}\n\"#;\n    assert_code_action!(\n        \"Qualify pi as mymath.pi\",\n        TestProject::for_source(src).add_hex_module(\"mymath\", \"pub const pi = 3.14159\"),\n        find_position_of(\"pi *.\").select_until(find_position_of(\" radius\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_record_constructor() {\n    let src = r#\"\nimport user.{type User, User}\n\npub fn create_user(name: String) -> User {\n    User(name: name, id: 1)\n}\n\"#;\n    assert_code_action!(\n        \"Qualify User as user.User\",\n        TestProject::for_source(src)\n            .add_hex_module(\"user\", \"pub type User { User(name: String, id: Int) }\"),\n        find_position_of(\"User(\").select_until(find_position_of(\"name: name\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_after_constructor() {\n    let src = r#\"\npub fn create_user(name: String) -> User {\n    User(name: name, id: 1)\n}\n\nimport user.{type User, User}\n\"#;\n    assert_code_action!(\n        \"Qualify User as user.User\",\n        TestProject::for_source(src)\n            .add_hex_module(\"user\", \"pub type User { User(name: String, id: Int) }\"),\n        find_position_of(\"User(\").select_until(find_position_of(\"name: name\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_between_constructors() {\n    let src = r#\"\npub fn create_user(name: String) -> User {\n    User(name: name, id: 1)\n}\n\nimport user.{type User, User}\n\npub fn user_list(users: List(User)) -> List(String) {\n    [User(name: \"John\", id: 1),\n    User(name: \"Jane\", id: 2)]\n}\n\n\"#;\n    assert_code_action!(\n        \"Qualify User as user.User\",\n        TestProject::for_source(src)\n            .add_hex_module(\"user\", \"pub type User { User(name: String, id: Int) }\"),\n        find_position_of(\"User(\").select_until(find_position_of(\"name: name\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_multiple_occurrences() {\n    let src = r#\"\nimport list.{map, filter}\n\npub fn process_list(items: List(Int)) -> List(Int) {\n    items\n    |> map(fn(x) { x + 1 })\n    |> map(fn(x) { x * 2 })\n}\n\"#;\n    assert_code_action!(\n        \"Qualify map as list.map\",\n        TestProject::for_source(src).add_hex_module(\n            \"list\",\n            \"pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }\"\n        ),\n        find_position_of(\"|> map\").select_until(find_position_of(\"(fn(x)\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_in_pattern_matching() {\n    let src = r#\"\nimport result.{type Result, Ok, Error}\n\npub fn process_result(res: Result(Int, String)) -> Int {\n    case res {\n        Ok(value) -> value\n        Error(_) -> 0\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Ok as result.Ok\",\n        TestProject::for_source(src)\n            .add_hex_module(\"result\", \"pub type Result(a, e) { Ok(a) Error(e) }\"),\n        find_position_of(\"Ok(\").select_until(find_position_of(\"value)\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_type_annotation() {\n    let src = r#\"\nimport option.{type Option, Some}\n\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Option as option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        find_position_of(\"Opt\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"ion(\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_nested_function_call() {\n    let src = r#\"\nimport list.{map, flatten}\nimport operation.{double}\n\npub fn process_names(names: List(List(Int))) -> List(Int) {\n    names\n    |> flatten\n    |> map(double)\n}\n\"#;\n    assert_code_action!(\n        \"Qualify double as operation.double\",\n        TestProject::for_source(src)\n            .add_hex_module(\n                \"list\",\n                \"pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }\npub fn flatten(lists: List(List(a))) -> List(a) { todo }\"\n            )\n            .add_hex_module(\"operation\", \"pub fn double(s: Int) -> Int { todo }\"),\n        find_position_of(\"(dou\").select_until(find_position_of(\"ble)\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_with_alias() {\n    let src = r#\"\nimport list.{map as transform}\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    transform(items, fn(x) { x * 2 })\n}\n\"#;\n    assert_code_action!(\n        \"Qualify transform as list.map\",\n        TestProject::for_source(src).add_hex_module(\n            \"list\",\n            \"pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }\"\n        ),\n        find_position_of(\"transform(\").select_until(find_position_of(\"items,\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_with_alias_and_module_alias() {\n    let src = r#\"\nimport list.{map as transform} as lst\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    transform(items, fn(x) { x * 2 })\n}\n\"#;\n    assert_code_action!(\n        \"Qualify transform as lst.map\",\n        TestProject::for_source(src).add_hex_module(\n            \"list\",\n            \"pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }\"\n        ),\n        find_position_of(\"transform(\").select_until(find_position_of(\"items,\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_import_discarded() {\n    let src = r#\"\nimport list.{map as transform} as _\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    transform(items, fn(x) { x * 2 })\n}\n\"#;\n    let title = \"Qualify transform as list.map\";\n    assert_no_code_actions!(\n        title,\n        TestProject::for_source(src).add_hex_module(\n            \"list\",\n            \"pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }\"\n        ),\n        find_position_of(\"transform(\").select_until(find_position_of(\"items,\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_bad_formatted_type_constructor() {\n    let src = r#\"\nimport option.{type    Option, Some}\n\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Option as option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        find_position_of(\"Opt\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"ion(\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_bad_formatted_type_constructor_with_alias() {\n    let src = r#\"\nimport option.{type    Option    as Maybe, Some}\n\npub fn maybe_increment(x: Maybe(Int)) -> Maybe(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Maybe as option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        find_position_of(\"May\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"be(\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_bad_formatted_comma() {\n    let src = r#\"\nimport option.{type    Option    , Some}\n\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Option as option.Option\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        find_position_of(\"Opt\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"ion(\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_in_list_and_tuple() {\n    let src = r#\"\nimport option.{Some}\n\npub fn main() {\n    let list = [Some(1), option.None]\n    let tuple = #(Some(2), option.None)\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Some as option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some(\").select_until(find_position_of(\"1)\")),\n    );\n}\n#[test]\nfn test_unqualified_to_qualified_import_constructor_complex_pattern() {\n    let src = r#\"\nimport option.{None, Some}\n\npub fn main() {\n    case [Some(1), None] {\n        [None, ..] -> todo\n        [Some(_), ..] -> todo\n        _ -> todo\n    }\n    case Some(1), Some(2) {\n        None, Some(_) -> todo\n        Some(_), Some(val) -> todo\n        _ -> todo\n    }\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Some as option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some(\").select_until(find_position_of(\"1)\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_multiple_line_aliased() {\n    let src = r#\"\nimport option.{\n    type Option,\n    None,\n    Some\n} as opt\n\npub fn main() {\n  Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Some as opt.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_multiple_line_bad_format_without_trailing_comma() {\n    let src = r#\"\nimport option.{type Option,\n    Some\n\n}\n\npub fn main() {\n  Some(1)\n}\n\"#;\n    assert_code_action!(\n        \"Qualify Some as option.Some\",\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"(1)\")),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_variable_shadowing() {\n    let src = r#\"\n\nimport wibble.{wobble}\n\npub fn example() {\n  echo wobble\n\n  let wobble = 1\n\n  echo wobble\n\n  let _ = fn(wobble) {\n    echo wobble\n  }\n\n  todo\n}\n\"#;\n\n    assert_code_action!(\n        \"Qualify wobble as wibble.wobble\",\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub fn wobble() { todo }\"),\n        find_position_of(\"wob\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"ble\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_in_constant_var() {\n    let src = r#\"\nimport option.{None}\n\nconst none = None\n\"#;\n    let title = \"Qualify None as option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").nth_occurrence(2).to_selection(),\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_in_constant_record() {\n    let src = r#\"\nimport option.{Some}\n\nconst some = Some(1)\n\"#;\n    let title = \"Qualify Some as option.Some\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"Some\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn test_unqualified_to_qualified_import_in_nested_constant() {\n    let src = r#\"\nimport option.{type Option, None}\n\ntype Result(a) {\n  Result(expected: a, actual: Option(a))\n}\n\nconst zero = Result(0, None)\n\"#;\n    let title = \"Qualify None as option.None\";\n    assert_code_action!(\n        title,\n        TestProject::for_source(src)\n            .add_hex_module(\"option\", \"pub type Option(v) { Some(v) None }\"),\n        find_position_of(\"None\").nth_occurrence(2).to_selection(),\n    );\n}\n\n/* TODO: implement qualified unused location\n#[test]\nfn test_remove_unused_qualified_action() {\n    let code = \"\n// test\nimport map.{Map, delete}\n\";\n    let expected = \"\n// test\n\n\";\n    assert_eq!(remove_unused_action(code), expected.to_string())\n}\n\n#[test]\nfn test_remove_unused_qualified_partial_action() {\n    let code = \"\n// test\nimport result.{is_ok, is_err}\n\npub fn main() {\n  is_ok\n}\n\";\n    let expected = \"\n// test\nimport result.{is_ok}\n\npub fn main() {\n  is_ok\n}\n\";\n    assert_eq!(remove_unused_action(code), expected.to_string())\n}\n\n#[test]\nfn test_remove_unused_qualified_partial2_action() {\n    let code = \"\n// test\nimport result.{all, is_ok, is_err}\n\npub fn main() {\n  is_ok\n}\n\";\n    let expected = \"\n// test\nimport result.{ is_ok}\n\npub fn main() {\n  is_ok\n}\n\";\n    assert_eq!(remove_unused_action(code), expected.to_string())\n}\n\n#[test]\nfn test_remove_unused_qualified_partial3_action() {\n    let code = \"\n// test\nimport result.{all, is_ok, is_err} as res\n\npub fn main() {\n  is_ok\n}\n\";\n    let expected = \"\n// test\nimport result.{ is_ok} as res\n\npub fn main() {\n  is_ok\n}\n\";\n    assert_eq!(remove_unused_action(code), expected.to_string())\n}\n*/\n\n#[test]\nfn convert_from_use_expression_with_no_parens() {\n    let src = r#\"\npub fn main() {\n  use <- wibble\n  todo\n  todo\n}\n\nfn wibble(f) {\n    f()\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_expression_with_empty_parens() {\n    let src = r#\"\npub fn main() {\n  use <- wibble()\n  todo\n  todo\n}\n\nfn wibble(f) {\n    f()\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").to_selection(),\n    );\n}\n\n#[test]\nfn convert_from_use_expression_with_parens_and_other_args() {\n    let src = r#\"\npub fn main() {\n  use <- wibble(1, 2)\n  todo\n  todo\n}\n\nfn wibble(n, m, f) {\n    f()\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"wibble\").select_until(find_position_of(\"1\")),\n    );\n}\n\n#[test]\nfn convert_from_use_expression_with_single_pattern() {\n    let src = r#\"\npub fn main() {\n  use a <- wibble(1, 2)\n  todo\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"a <-\").to_selection(),\n    );\n}\n\n#[test]\nfn convert_from_use_expression_with_multiple_patterns() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(1, 2)\n  todo\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"wibble\").to_selection(),\n    );\n}\n\n#[test]\nfn desugar_nested_use_expressions_picks_inner_under_cursor() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(1, 2)\n  use a, b <- wibble(a, b)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").nth_occurrence(2).to_selection(),\n    );\n}\n\n#[test]\nfn convert_from_use_only_triggers_on_the_use_line() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(1, 2)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\"#;\n    assert_no_code_actions!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"todo\").to_selection(),\n    );\n}\n\n#[test]\nfn desugar_nested_use_expressions_picks_inner_under_cursor_2() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(1, 2)\n  use a, b <- wibble(a, b)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_expression_with_type_annotations() {\n    let src = r#\"\npub fn main() {\n  use a: Int, b: Int <- wibble(1, 2)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_expression_doesnt_work_with_complex_patterns() {\n    let src = r#\"\npub fn main() {\n  use #(a, b), 1 <- wibble(1, 2)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\"#;\n    assert_no_code_actions!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_with_labels() {\n    let src = r#\"\npub fn main() {\n  use a <- wibble(one: 1, two: 2)\n  todo\n}\n\nfn wibble(one _, two _, three f) {\n    f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").to_selection(),\n    );\n}\n\n#[test]\nfn convert_from_use_with_labels_2() {\n    let src = r#\"\npub fn main() {\n  use a <- wibble(1, two: 2)\n  todo\n}\n\nfn wibble(one _, two _, three f) {\n    f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").to_selection(),\n    );\n}\n\n#[test]\nfn convert_from_use_with_labels_3() {\n    let src = r#\"\npub fn main() {\n  use a <- wibble(1, three: 3)\n  todo\n}\n\nfn wibble(one _, two f, three _) {\n    f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").to_selection(),\n    );\n}\n\n#[test]\nfn convert_from_use_with_labels_4() {\n    let src = r#\"\npub fn main() {\n  use a <- wibble(two: 2, three: 3)\n  todo\n}\n\nfn wibble(one f, two _, three _) {\n    f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").to_selection(),\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/4149\nfn convert_from_use_with_trailing_comma() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(1, 2,)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_with_trailing_comma_2() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(\n    1,\n    2,\n  )\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_with_trailing_comma_and_label() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(\n    1,\n    wibble: 2,\n  )\n  todo\n}\n\nfn wibble(n, wibble m, wobble f) {\n    f(todo, todo)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn convert_from_use_multiline_with_no_trailing_comma() {\n    let src = r#\"\npub fn main() {\n  use a, b <- wibble(\n    1,\n    2\n  )\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_FROM_USE,\n        TestProject::for_source(src),\n        find_position_of(\"<-\").select_until(find_position_of(\"wibble\")),\n    );\n}\n\n#[test]\nfn turn_call_into_use_with_single_line_body() {\n    let src = r#\"\npub fn main() {\n  wibble(fn(a, b) { todo })\n}\n\nfn wibble(f) {\n  f(todo, todo)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"wibble\").to_selection(),\n    );\n}\n\n#[test]\nfn turn_call_into_use_with_fn_with_no_args() {\n    let src = r#\"\npub fn main() {\n  wibble(fn() { todo })\n}\n\nfn wibble(f) {\n  f()\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"wibble\").to_selection(),\n    );\n}\n\n#[test]\nfn turn_call_with_multiple_arguments_into_use() {\n    let src = r#\"\npub fn main() {\n  wibble(1, 2, fn(a) { todo })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"todo\").to_selection(),\n    );\n}\n\n#[test]\nfn turn_call_with_multiline_fn_into_use() {\n    let src = r#\"\npub fn main() {\n  wibble(1, 2, fn(a) {\n    todo\n    case todo {\n      _ -> todo\n    }\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"1, 2\").select_until(find_position_of(\"fn(a)\")),\n    );\n}\n\n#[test]\nfn turn_call_with_fn_with_type_annotations_into_use() {\n    let src = r#\"\npub fn main() {\n  wibble(1, 2, fn(a: Int) {\n    todo\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"wibble\").select_until(find_position_of(\"a: \")),\n    );\n}\n\n#[test]\nfn turn_call_into_use_only_works_on_last_call_in_a_block() {\n    let src = r#\"\npub fn main() {\n  wibble(10, 20, fn(a) { todo })\n  wibble(1, 2, fn(a) { todo })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_no_code_actions!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"10\").to_selection(),\n    );\n}\n\n#[test]\nfn turn_call_into_use_only_works_on_last_call_in_a_block_2() {\n    let src = r#\"\npub fn main() {\n  {\n    wibble(10, 20, fn(a) { todo })\n    wibble(1, 2, fn(a) { todo })\n  }\n  Nil\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_no_code_actions!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"10\").to_selection(),\n    );\n}\n\n#[test]\nfn turn_call_into_use_with_last_function_in_a_block() {\n    let src = r#\"\npub fn main() {\n  {\n    wibble(10, 20, fn(a) { todo })\n    wibble(1, 11, fn(a) { todo })\n  }\n  Nil\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"wibble(1,\").select_until(find_position_of(\"11\")),\n    );\n}\n\n#[test]\nfn turn_call_into_use_starts_from_innermost_function() {\n    let src = r#\"\npub fn main() {\n  wibble(10, 20, fn(a) {\n    wibble(30, 40, fn(b) {\n      a + b\n    })\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"30\").select_until(find_position_of(\"40\")),\n    );\n}\n\n#[test]\nfn turn_call_into_use_with_another_use_in_the_way() {\n    let src = r#\"\npub fn main() {\n  wibble(10, 20, fn(a) {\n    use b <- wibble(30, 40)\n    a + b\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src),\n        find_position_of(\"use\").to_selection(),\n    );\n}\n\n#[test]\nfn turn_call_into_use_with_module_function() {\n    let src = r#\"\nimport other\npub fn main() {\n  other.wibble(10, 20, fn(a) {\n    todo\n    a + b\n  })\n}\n\"#;\n    assert_code_action!(\n        CONVERT_TO_USE,\n        TestProject::for_source(src).add_module(\"other\", \"pub fn wibble(n, m, f) { todo }\"),\n        find_position_of(\"wibble\").to_selection(),\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/4498\nfn turn_call_into_use_with_out_of_order_arguments() {\n    assert_code_action!(\n        CONVERT_TO_USE,\n        r#\"\npub fn main() {\n  fold(0, over: [], with: fn (a, b) { todo })\n}\n\nfn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {\n  todo\n}\n\"#,\n        find_position_of(\"fold\").to_selection(),\n    );\n}\n\n#[test]\nfn inexhaustive_let_result_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main(result) {\n  let Ok(value) = result\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_to_case_indented() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main(result) {\n  {\n    let Ok(value) = result\n  }\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_to_case_multi_variables() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let [var1, var2, _var3, var4] = [1, 2, 3, 4]\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_to_case_discard() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let [_elem] = [6]\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_to_case_no_variables() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let [] = []\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_alias_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let 10 as ten = 10\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_tuple_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let #(first, 10, third) = #(5, 10, 15)\n}\n\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_bit_array_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        \"pub fn main() {\n  let <<bits1, bits2>> = <<73, 98>>\n}\",\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_string_prefix_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main() {\n  let \"_\" <> thing = \"_Hello\"\n}\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inexhaustive_let_string_prefix_pattern_alias_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main() {\n  let \"123\" as one_two_three <> rest = \"123456\"\n}\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn inner_inexhaustive_let_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main(result) {\n  let [wibble] = {\n    let Ok(wobble) = {\n      result\n    }\n    [wobble]\n  }\n}\"#,\n        find_position_of(\"let Ok\").select_until(find_position_of(\") =\")),\n    );\n}\n\n#[test]\nfn outer_inexhaustive_let_to_case() {\n    assert_code_action!(\n        CONVERT_TO_CASE,\n        r#\"pub fn main(result) {\n  let [wibble] = {\n    let Ok(wobble) = {\n      result\n    }\n    [wobble]\n  }\n}\"#,\n        find_position_of(\"let [\").select_until(find_position_of(\"] =\")),\n    );\n}\n\n#[test]\nfn no_code_action_for_exhaustive_let_to_case() {\n    assert_no_code_actions!(\n        CONVERT_TO_CASE,\n        r#\"pub fn first(pair) {\n  let #(first, second) = pair\n  first\n}\"#,\n        find_position_of(\"let\").select_until(find_position_of(\"=\")),\n    );\n}\n\n#[test]\nfn extract_variable() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  list.map([1, 2, 3], int.add(1, _))\n}\"#,\n        find_position_of(\"[1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn extract_variable_ignores_names_in_other_branches() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n      let int = 1\n      int + 2\n    }\n    Error(_) -> wibble(11)\n  }\n\n}\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_ignores_names_in_other_branches_2() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n      let int = 1\n      int + 2\n    }\n    Error(_) -> {\n        wibble(11)\n    }\n  }\n}\n\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_ignores_names_in_other_blocks() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"\npub fn main() {\n  {\n    let int = 1\n    int + 2\n  }\n  wibble(11)\n}\n\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_ignores_names_in_anonymous_functions() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"\npub fn main() {\n  let fun = fn() {\n    let int = 1\n    int + 2\n  }\n\n  wibble(11)\n}\n\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_shadow_names_in_anonymous_function() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"\npub fn main() {\n  let fun = fn() {\n    let int = 1\n    wibble(11)\n  }\n  fun()\n}\n\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_shadow_name_in_same_branch() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n        let int = 1\n        wibble(11)\n    }\n    Error(_) -> {\n        panic\n    }\n  }\n}\n\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_shadow_name_in_same_block() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"\npub fn main() {\n  let result = {\n    let int = 1\n    wibble(11)\n  }\n  result\n}\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_a_variable() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    let z = 1\n    let a = [1, 2, z]\n}\"#,\n        find_position_of(\"z\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_top_level_statement() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  let wibble = 1\n}\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_top_level_statement_inside_block() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  let x = {\n    let y = \"y\"\n    let w = \"w\" <> y\n    w\n  }\n}\"#,\n        find_position_of(\"y\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_top_level_statement_inside_use() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  use x <- try(Ok(1))\n  let y = 2\n  Ok(y + x)\n}\npub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo }\n\",\n        find_position_of(\"2\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_use() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  use x <- try(Ok(1))\n  Ok(x)\n}\npub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo }\n\",\n        find_position_of(\"use\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_panic() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  let x = 1\n  panic\n}\"#,\n        find_position_of(\"panic\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_echo() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  let x = 1\n  echo x\n}\"#,\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_assignment() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  let x = 1\n}\"#,\n        find_position_of(\"x\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_record_variable_in_record_update() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"\ntype Wibble { Wibble(one: Int, two: Int) }\n\npub fn main() {\n  let wibble = todo\n  Wibble(..wibble, one: 1)\n}\"#,\n        find_position_of(\"wibble\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_from_arg_in_pipelined_call() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  let adder = add\n  let x = [4, 5, 6] |> map2([1, 2, 3], adder)\n  x\n}\npub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\n\",\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_from_arg_in_pipelined_call_to_capture() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  let adder = add\n  let x = adder |> reduce([1, 2, 3], _)\n  x\n}\npub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\n\",\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_from_arg_in_pipelined_call_of_function_to_capture() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  fn(total, item) { total + item }\n  |> fold(with: _, from: 0, over: [1, 2, 3])\n}\npub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo }\n\",\n        find_position_of(\"fold\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_from_arg_in_nested_function_called_in_pipeline() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  let result =\n    [1, 2, 3]\n    |> map(add(_, 1))\n    |> map(subtract(_, 9))\n\n  result\n}\npub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\npub fn subtract(a: Int, b: Int) -> Int { todo }\n\",\n        find_position_of(\"9\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_an_entire_pipeline_step() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(todo)\n  |> map(todo)\n}\n\nfn map(list, fun) { todo }\n\",\n        find_position_of(\"map\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_does_not_extract_the_last_pipeline_step() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    [1, 2, 3]\n    |> map(todo)\n    |> map(todo)\n}\n\nfn map(list, fun) { todo }\n\"#,\n        find_position_of(\"map\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_2() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  map([1, 2, 3], add(1, _))\n}\npub fn add(n, m) { todo }\npub fn map(l, f) { todo }\n\",\n        find_position_of(\"add\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_from_capture_arguments() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  int.add(1, _)\n}\"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_from_capture_arguments_2() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  int.add(11, _)\n}\"#,\n        find_position_of(\"11\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_3() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  list.map([1, 2, 3], todo, todo)\n}\"#,\n        find_position_of(\"todo\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"todo)\").under_last_char())\n    );\n}\n\n#[test]\nfn extract_variable_inside_multiline_function_call() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  list.map(\n    [1, 2, 3],\n    int.add(1, _),\n  )\n}\"#,\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_case_branch() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    case wibble {\n      _ -> [1, 2, 3]\n    }\n}\"#,\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_multiline_case_subject_branch() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    case\n        list.map(\n          [1, 2, 3],\n          int.add(1, _)\n        )\n    {\n      _ -> todo\n    }\n}\"#,\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_case_branch_using_var() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  case todo {\n    Ok(value) -> 2 * value + 1\n    Error(_) -> panic\n  }\n}\"#,\n        find_position_of(\"2\").select_until(find_position_of(\"value\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_variable_in_case_branch_from_second_arg() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  case todo {\n    Ok(_) -> #(Ok(1), Error(\"s\"))\n    Error(_) -> panic\n  }\n}\"#,\n        find_position_of(\"E\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_use() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    use <- wibble([1, 2, 3])\n    todo\n}\"#,\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_inside_use_body() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    use <- wibble(todo)\n    list.map([1, 2, 3], int.add(1, _))\n    todo\n}\"#,\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_multiline_use() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    use <- wibble(\n        [1, 2, 3]\n    )\n    todo\n}\"#,\n        find_position_of(\"[1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_after_nested_anonymous_function() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let y = 5 + 6\n    f()\n}\"#,\n        find_position_of(\"6\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_nested_anonymous_function() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let y = 5 + 6\n    f()\n}\"#,\n        find_position_of(\"4\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_double_nested_anonymous_function() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let y = 5 + 6\n    f()\n}\"#,\n        find_position_of(\"3\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_block() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n  {\n    todo\n    wibble([1, 2, 3])\n    todo\n  }\n}\"#,\n        find_position_of(\"2\").select_until(find_position_of(\"3\"))\n    );\n}\n\n#[test]\nfn extract_variable_and_dont_shadow_existing_variable_in_operator() {\n    let src = \"import gleam/int\nimport random_import as int_2\n\nconst int_3 = 3\n\nfn int_4() { 4 }\n\nfn isolated_scope() {\n    let int_6 = 6\n    int_6 + 1\n}\n\npub fn main() {\n  let int_5 = 5\n  let result = int_5 + 6\n  result\n}\n\";\n\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        TestProject::for_source(src)\n            .add_hex_module(\"gleam/int\", \"\")\n            .add_hex_module(\"random_import\", \"\"),\n        find_position_of(\"6\").nth_occurrence(4).to_selection(),\n    );\n}\n\n#[test]\nfn extract_variable_and_dont_shadow_existing_variable_in_argument() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        r#\"fn wibble(a, b) {\n  a + b\n}\n\nfn main() {\n  let int = 1\n  wibble(int, 2)\n}\"#,\n        find_position_of(\"2\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_bit_array() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  io.debug(<<3:size(8)>>)\n}\"#,\n        find_position_of(\"<\").select_until(find_position_of(\"<\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_float() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/float\n\npub fn main() {\n  float.ceiling(1.9998)\n}\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"8\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_int() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/list\n\npub fn main() {\n  list.sample([4, 5, 6], 2)\n}\"#,\n        find_position_of(\"2\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_list() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  io.debug([\"constant\", \"another constant\"])\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_nested_inside() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/list\n\npub fn main() {\n  list.unzip([#(1, 2), #(3, 4)])\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_nested_outside() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/list\n\npub fn main() {\n  list.unzip([#(1, 2), #(3, 4)])\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_string() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  io.print(\"constant\")\n}\"#,\n        find_position_of(\"\\\"\").select_until(find_position_of(\"\\\"\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_call_argument_with_tuple() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  io.debug(#(1, 2, 3))\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_float() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = 3.1415\n}\"#,\n        find_position_of(\"3\").select_until(find_position_of(\"5\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_float() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let c = 3.1415\n  io.debug(c)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_bit_array() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let b = <<\"arr\":utf32>>\n}\"#,\n        find_position_of(\"u\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\">\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_bit_array() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\nconst n = 24\n\npub fn main() {\n  let bits = <<8080:size(n)>>\n  bits\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"s\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_bin_op() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let twelve = \"1\" <> \"2\"\n}\"#,\n        find_position_of(\"<\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_bin_op() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let twelve = \"1\" <> \"2\"\n  io.print(twelve)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"e\").nth_occurrence(4))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_int() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = 125\n}\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"5\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_int() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let c = 125\n  io.debug(c)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_list() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = [3.1415, 0.33333333]\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_list() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let c = [3.1415, 0.33333333]\n  io.debug(c)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_nested_inside() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = #([1, 2, 3], [3, 2, 1])\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_nested_outside() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = #([1, 2, 3], [3, 2, 1])\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_nested() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let c = #([1, 2, 3], [3, 2, 1])\n  io.debug(c)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_string() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = \"constant\"\n}\"#,\n        find_position_of(\"\\\"\").select_until(find_position_of(\"\\\"\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_string() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let c = \"constant\"\n  io.debug(c)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_declaration_of_tuple() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let #(one, two, three) = #(\"one\", \"two\", \"three\")\n}\"#,\n        find_position_of(\"#\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"(\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn extract_constant_from_whole_declaration_of_tuple() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let c = #(\"one\", \"two\", \"three\")\n  io.debug(c)\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_literal_within_list() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = [\"constant\", todo]\n}\"#,\n        find_position_of(\"\\\"\").select_until(find_position_of(\"\\\"\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_list_containing_constant() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"const something = \"something\"\n\npub fn main() {\n  let c = [\"constant\", something]\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_literal_within_tuple() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = #(0.333334, todo)\n}\"#,\n        find_position_of(\"0\").select_until(find_position_of(\"4\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_tuple_containing_constant() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"const something = \"something\"\n\npub fn main() {\n  let c = #(0.333334, something)\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_nested_inside_in_expr() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n  |> key_filter(\"a\")\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_nested_outside_in_expr() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n  |> key_filter(\"a\")\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_return_of_float() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  0.25\n}\"#,\n        find_position_of(\"0\").select_until(find_position_of(\"5\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_return_of_int() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  100\n}\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"0\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_return_of_list() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  [1, 2, 3, 4]\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_return_of_nested_outside() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  [#(0.25, 0.75), #(0.5, 1.5)]\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_return_of_string() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  \"constant\"\n}\"#,\n        find_position_of(\"\\\"\").select_until(find_position_of(\"\\\"\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_return_of_tuple() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  #(0.25, 0.75)\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_constant_from_taken_name_by_function() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"fn floats() {\n    [1.0, 2.0]\n}\n\npub fn main() {\n  [0.25, 0.75]\n}\"#,\n        find_position_of(\"[\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_taken_name_by_constant() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"const ints = [1, 2]\n\npub fn main() {\n  [5, 50]\n}\"#,\n        find_position_of(\"[\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_in_correct_position_1() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"\nfn first() {\n    1\n}\n\nfn second() {\n    2\n}\n\nfn third() {\n    3\n}\n\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_in_correct_position_2() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"\nfn first() {\n    1\n}\n\nfn second() {\n    2\n}\n\nfn third() {\n    3\n}\n\"#,\n        find_position_of(\"2\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_in_correct_position_3() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"\nfn first() {\n    1\n}\n\nfn second() {\n    2\n}\n\nfn third() {\n    3\n}\n\"#,\n        find_position_of(\"3\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_declaration_with_proper_indentation() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"\npub fn main() {\n  let fahrenheit = {\n    let degrees = 64\n    degrees\n  }\n  fahrenheit\n}\n\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"s\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_nil() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let x = Nil\n  x\n}\n\"#,\n        find_position_of(\"l\").select_until(find_position_of(\"x\"))\n    );\n}\n\n#[test]\nfn extract_constant_from_non_record_variant_1() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub type Auth {\n  Verified\n  Unverified\n}\n\npub fn main() {\n  let a = Unverified\n  let a = verify(something, a)\n\n  a\n}\n\"#,\n        find_position_of(\"U\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"d\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn extract_constant_from_non_record_variant_2() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub type Auth {\n  Verified\n  Unverified\n}\n\npub fn main() {\n  let a = verify(something, Unverified)\n\n  a\n}\n\"#,\n        find_position_of(\"U\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"d\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn extract_constant_from_record_variant_1() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub type Auth {\n  Verified(String)\n  Unverified\n}\n\npub fn main() {\n  let u = Verified(\"User\")\n  let v = verify(something, u)\n\n  v\n}\"#,\n        find_position_of(\"l\").select_until(find_position_of(\"u\").nth_occurrence(4))\n    );\n}\n\n#[test]\nfn extract_constant_from_record_variant_2() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub type Auth {\n  Verified(Int)\n  Unverified\n}\n\nconst auth = True\n\nconst id = 1234\n\npub fn main() {\n  let v = verify(auth, Verified(id))\n\n  v\n}\"#,\n        find_position_of(\"V\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"(\").nth_occurrence(4))\n    );\n}\n\n#[test]\nfn extract_constant_from_inside_block() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let fahrenheit = {\n    let degrees = 64 + 32\n    degrees\n  }\n}\"#,\n        find_position_of(\"32\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_inside_case() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main(result) {\n  case result {\n    Ok(value) -> value + 1\n    Error(_) -> panic\n  }\n}\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_inside_use_1() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  use x <- result.try(todo)\n  Ok(123)\n}\"#,\n        find_position_of(\"Ok\").to_selection()\n    );\n}\n\n#[test]\nfn extract_constant_from_inside_use_2() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"const number = 123\n\npub fn main() {\n  use x <- result.try(todo)\n  Ok(number)\n}\"#,\n        find_position_of(\"Ok\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_pattern() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let #(one, two) = #(1, 2)\n  one\n}\"#,\n        find_position_of(\"l\").select_until(find_position_of(\"(\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_fn_call_1() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  io.print(\"constant\")\n}\"#,\n        find_position_of(\"p\")\n            .nth_occurrence(3)\n            .select_until(find_position_of(\"t\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_fn_call_2() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/list\n\npub fn main() {\n  let first = list.first([1, 2, 3])\n  first\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(3)\n            .select_until(find_position_of(\"t\").nth_occurrence(4))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_bin_op() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let res = 64 < 32\n  res\n}\"#,\n        find_position_of(\"<\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_bit_array_1() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = \"constant\"\n  let res = <<c:utf16>>\n  res\n}\"#,\n        find_position_of(\"<\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_bit_array_2() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let n = 1234\n  io.debug(<<8080:size(n)>>)\n}\"#,\n        find_position_of(\"<\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_bit_array_3() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/io\n\npub fn main() {\n  let l = 1234\n  let r = 1234\n  let result = <<l:size(r)>>\n  result\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(5)\n            .select_until(find_position_of(\"t\").nth_occurrence(5))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_list_1() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = [\"constant\", todo]\n  c\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_list_2() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  [10, todo]\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_list_3() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = [0.25, todo]\n  c\n}\"#,\n        find_position_of(\"l\").select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_tuple_1() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = #(\"constant\", todo)\n  c\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_tuple_2() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  #(10, todo)\n}\"#,\n        find_position_of(\"#\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_tuple_3() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = #(0.25, todo)\n  c\n}\"#,\n        find_position_of(\"l\").select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_nested_1() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  let c = list.unzip([#(1, 2), #(3, todo)])\n  c\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_nested_2() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"pub fn main() {\n  [[1.25, 1], [0.25, todo]]\n}\"#,\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_nested_3() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"import gleam/list\n\npub fn main() {\n  let c = [#(1, 2), #(3, todo)]\n  c\n}\"#,\n        find_position_of(\"l\")\n            .nth_occurrence(3)\n            .select_until(find_position_of(\"c\"))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_record_1() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"type Pair {\n  Pair(Int, Int)\n}\n\npub fn main() {\n  let c = list.unzip([Pair(1, 2), Pair(3, todo)])\n  c\n}\"#,\n        find_position_of(\"P\").nth_occurrence(4).to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_record_2() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"type Couple {\n  Couple(l: Float, r: Float)\n}\n\npub fn main() {\n  #(Couple(1.25, 1.0), Couple(0.25, todo))\n}\"#,\n        find_position_of(\"C\").nth_occurrence(4).to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_record_update() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"type Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c = Couple(1, 2)\n  let cc = Couple(..c, 2)\n  cc\n}\"#,\n        find_position_of(\"C\")\n            .nth_occurrence(4)\n            .select_until(find_position_of(\"e\").nth_occurrence(7))\n    );\n}\n\n#[test]\nfn do_not_extract_constant_from_record_capture() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"type Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c = Couple(1, _)\n  c\n}\"#,\n        find_position_of(\"C\")\n            .nth_occurrence(3)\n            .select_until(find_position_of(\"e\").nth_occurrence(5))\n    );\n}\n\n#[test]\nfn do_not_extract_top_level_expression_statement() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    1\n}\n\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_top_level_expression_in_let_statement() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        r#\"pub fn main() {\n    let a = 1\n}\n\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_extract_top_level_module_call() {\n    let src = r#\"\nimport list\npub fn main() {\n  list.map([1, 2, 3], todo)\n}\"#;\n\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        TestProject::for_source(src).add_module(\"list\", \"pub fn map(l, f) { todo }\"),\n        find_position_of(\"map\").to_selection()\n    );\n}\n\n#[test]\nfn expand_function_capture() {\n    assert_code_action!(\n        EXPAND_FUNCTION_CAPTURE,\n        r#\"pub fn main() {\n  wibble(_, 1)\n}\"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn expand_function_capture_2() {\n    assert_code_action!(\n        EXPAND_FUNCTION_CAPTURE,\n        r#\"pub fn main() {\n  wibble(1, _)\n}\"#,\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn expand_function_capture_does_not_shadow_variables() {\n    assert_code_action!(\n        EXPAND_FUNCTION_CAPTURE,\n        r#\"pub fn main() {\n  let value = 1\n  let value_2 = 2\n  wibble(value, _, value_2)\n}\"#,\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn expand_function_capture_picks_a_name_based_on_the_type_of_the_hole() {\n    assert_code_action!(\n        EXPAND_FUNCTION_CAPTURE,\n        r#\"pub fn main() {\n  [1, 2, 3]\n  |> map(add(_, 1))\n}\n\npub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo }\npub fn add(n, m) { n + m }\n\"#,\n        find_position_of(\"add\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Person {\n  Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray)\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_complex_types() {\n    let src = \"\nimport gleam/option\nimport gleam/dynamic\nimport gleam/dict\n\npub type Something\n\npub type Wibble(value) {\n  Wibble(\n    maybe: option.Option(Something),\n    map: dict.Dict(String, List(value)),\n    unknown: List(dynamic.Dynamic),\n  )\n}\n\";\n\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src)\n            .add_module(\"gleam/option\", \"pub type Option(a)\")\n            .add_module(\"gleam/dynamic\", \"pub type Dynamic\")\n            .add_module(\"gleam/dict\", \"pub type Dict(k, v)\"),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_already_imported_module() {\n    let src = \"\nimport gleam/dynamic/decode as dyn_dec\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\";\n\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src).add_module(\"gleam/dynamic/decode\", \"pub type Decoder(a)\"),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_tuple() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  Wibble(tuple: #(Int, Float, #(String, Bool)))\n}\n\",\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_recursive_type() {\n    let src = \"\nimport gleam/option\n\npub type LinkedList {\n  LinkedList(value: Int, next: option.Option(LinkedList))\n}\n\";\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src).add_module(\"gleam/option\", \"pub type Option(a)\"),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_for_multi_variant_type() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  Wibble(wibble: Int, next: Wibble)\n  Wobble(wobble: Float, text: String, values: List(Bool))\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_for_multi_variant_type_multi_word_name() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  OneTwo(wibble: Int, next: Wibble)\n  ThreeFour(wobble: Float, text: String, values: List(Bool))\n  FiveSixSeven(one_two: Int)\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_for_variant_with_no_fields() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  Wibble\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_for_variants_with_no_fields() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  Wibble\n  Wobble\n  Woo\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_for_variants_with_mixed_fields() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  Wibble\n  Wobble(field: String, field2: Int)\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_generate_dynamic_decoder_for_type_without_labels() {\n    assert_no_code_actions!(\n        GENERATE_DYNAMIC_DECODER,\n        \"\npub type Wibble {\n  Wibble(Int, Int, String)\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_empty_tuple() {\n    assert_no_code_actions!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub fn main(tuple: #()) {\n  todo\n}\n\",\n        find_position_of(\"tuple\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_single_item_tuple() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub fn main(tuple: #(Int)) {\n  todo\n}\n\",\n        find_position_of(\":\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_multi_item_tuple() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub fn main(tuple: #(Int, String, Bool)) {\n  todo\n}\n\",\n        find_position_of(\"tuple\").select_until(find_position_of(\"Int\"))\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_uses_case_with_multiple_constructors() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub type CannotBeDestructured {\n  One(one: String)\n  Two(two: Int)\n}\n\npub fn main(arg: CannotBeDestructured) {\n  todo\n}\n\",\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_with_multiple_constructors_is_nicely_formatted_in_function_with_empty_body()\n {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub type CannotBeDestructured {\n  One(one: String)\n  Two(two: Int)\n}\n\npub fn main(arg: CannotBeDestructured) {}\n\",\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_uses_label_shorthand_syntax_for_labelled_arguments() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub type Wibble {\n  Wobble(Int, String, i_want_to_see_this: String, and_this: Bool)\n}\n\npub fn main(arg: Wibble) {\n  todo\n}\n\",\n        find_position_of(\"arg\").select_until(find_position_of(\"Wibble\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_with_private_type_from_same_module() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\ntype Wibble {\n  Wobble(Int, String)\n}\n\npub fn main(arg: Wibble) {\n  todo\n}\n\",\n        find_position_of(\"arg\").select_until(find_position_of(\"Wibble\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn pattern_match_on_value_with_private_type_from_same_module() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\ntype Wibble {\n  Wobble(Int, String)\n}\n\npub fn main() {\n  let wibble = Wobble(1, \\\"Hello\\\")\n  todo\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_clause_variable() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  case maybe_wibble() {\n    Ok(something) -> 1\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble\n  Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n\n\",\n        find_position_of(\"something\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_clause_variable_with_label() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  case wibble() {\n    Wobble(wibble: something) -> 1\n    _ -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(wibble: Wibble)\n  Woo\n}\n\nfn new() { Wobble }\n\n\",\n        find_position_of(\"something\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_clause_variable_with_label_shorthand() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  case new() {\n    Wobble(wibble:) -> 1\n    _ -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(wibble: Wibble)\n  Woo\n}\n\nfn new() { Wobble }\n\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_clause_variable_nested_pattern() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  case maybe_wibble() {\n    Ok(Wobble(something)) -> 1\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(Wibble)\n  Woo\n}\n\nfn maybe_wibble() { Ok(Woo) }\n\n\",\n        find_position_of(\"something\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_clause_variable_with_block_body() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  case maybe_wibble() {\n    Ok(something) -> {\n      1\n      2\n    }\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble\n  Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n\n\",\n        find_position_of(\"something\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_will_use_qualified_name() {\n    let src = \"\nimport wibble\n\npub fn main(arg: wibble.Wibble) {\n  todo\n}\n\";\n\n    let dep = \"\npub type Wibble {\n  ThisShouldBeQualified(label: Int)\n}\n\";\n\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src).add_module(\"wibble\", dep),\n        find_position_of(\"wibble\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_will_use_unqualified_name() {\n    let src = \"\nimport wibble.{ThisShouldBeUnqualified}\n\npub fn main(arg: wibble.Wibble) {\n  todo\n}\n\";\n\n    let dep = \"\npub type Wibble {\n  ThisShouldBeUnqualified(label: Int)\n}\n\";\n\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src).add_module(\"wibble\", dep),\n        find_position_of(\"Wibble\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_will_use_aliased_constructor_name() {\n    let src = \"\nimport wibble.{Wobble as IWantToSeeThisName}\n\npub fn main(arg: wibble.Wibble) {\n  todo\n}\n\";\n\n    let dep = \"\npub type Wibble {\n  Wobble(label: Int)\n}\n\";\n\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src).add_module(\"wibble\", dep),\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_will_use_aliased_module_name() {\n    let src = \"\nimport wibble as i_want_to_see_this_name\n\npub fn main(arg: i_want_to_see_this_name.Wibble) {\n  todo\n}\n\";\n\n    let dep = \"\npub type Wibble {\n  Wobble(label: Int)\n}\n\";\n\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src).add_dep_module(\"wibble\", dep),\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_not_available_for_internal_type() {\n    let src = \"\nimport wibble\n\npub fn main(arg: wobble.Wibble) {\n  todo\n}\n\";\n\n    let dep = \"\n@internal\npub type Wibble {\n  Wobble(label: Int)\n}\n\";\n\n    assert_no_code_actions!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src).add_module(\"wibble\", dep),\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_available_for_internal_type_defined_in_current_module() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\n@internal\npub type Wibble {\n  Wobble(label: Int)\n}\n\npub fn main(arg: Wibble) {\n  todo\n}\n\",\n        find_position_of(\"arg\").select_until(find_position_of(\"Wibble\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_preserves_indentation_of_statement_following_inserted_let() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"pub fn main(arg: #(Int, String)) {\n  todo\n//^^^^ This should still have two spaces of indentation!\n}\",\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_nicely_formats_code_when_used_on_function_with_empty_body() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"pub fn main(arg: #(Int, String)) {}\",\n        find_position_of(\"arg\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_single_unlabelled_field_is_not_numbered() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn main(arg: Wibble) {}\n\",\n        find_position_of(\":\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_let_assignment() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  let var = #(1, 2)\n}\n\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_let_assignment_with_multiple_constructors() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub type Wibble {\n  Wobble\n  Woo\n}\n\npub fn main() {\n  let var = Woo\n  todo\n}\n\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_use_assignment() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  use var <- f\n}\n\nfn f(g) { g(#(1, 2)) }\n\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_use_assignment_with_multiple_constructors() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub type Wibble {\n  Wobble\n  Woo\n}\n\npub fn main() {\n  use var <- f\n}\n\nfn f(g) { g(Wobble) }\n\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_pattern_use_assignment() {\n    assert_no_code_actions!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"\npub fn main() {\n  use #(a, b) <- f\n}\n\nfn f(g) { g(#(1, 2)) }\n\",\n        find_position_of(\"#\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_works_on_fn_arguments() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub fn main() {\n  [#(1, 2)]\n  |> map(fn(tuple) {})\n}\n\nfn map(list: List(a), fun: fn(a) -> b) { todo }\n\",\n        find_position_of(\"tuple\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_works_on_nested_fn_arguments() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub fn main() {\n  map([[#(1, 2)]], fn(list) {\n    map(list, fn(tuple) {\n      todo\n    })\n  })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) { todo }\n\",\n        find_position_of(\"tuple\").to_selection()\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/5042\nfn pattern_match_on_variable_crashes() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        r#\"\npub type Wibble {\n    Wibble(Wobble)\n}\n\npub type Wobble {\n    Wobble\n    Wubble\n}\n\npub fn main() {\n    let Wibble(wobble) = todo\n\n    case todo {\n      _ -> todo\n    }\n}\n\"#,\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_works_with_invalid_call() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() -> Bool {\n  wibble(1, True, 2.3)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_works_with_constants() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"const wibble: fn(Int) -> String = wobble\",\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_works_with_constants_2() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\ntype Wibble(a) {\n    Wibble(fun: fn(Int) -> a)\n}\n\nconst wibble: Wibble(Int) = Wibble(missing)\n\",\n        find_position_of(\"missing\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_works_with_pipeline_steps() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> sum\n  |> int_to_string\n}\n\nfn int_to_string(n: Int) -> String {\n  todo\n}\n\",\n        find_position_of(\"sum\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_works_with_pipeline_steps_1() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(int_to_string)\n  |> join\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {\n  todo\n}\n\nfn join(n: List(String)) -> String {\n  todo\n}\n\",\n        find_position_of(\"int_to_string\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4177#event-15968345230\n#[test]\nfn generate_function_picks_argument_name_based_on_type() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  wibble(\\\"Hello\\\", 1)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_picks_argument_name_based_on_record_access() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub type User {\n    User(id: Int, name: String)\n}\n\npub fn go(user: User) {\n  authenticate(user.id, user.name)\n}\n\",\n        find_position_of(\"authenticate\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_wont_generate_two_arguments_with_the_same_name_if_they_have_the_same_type() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  wibble(2, 1)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_takes_labels_into_account() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  wibble(2, n: 1)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_does_not_trigger_if_labels_are_in_the_wrong_order() {\n    assert_no_code_actions!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  wibble(n: 2, 1)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_does_not_trigger_if_there_are_repeated_labels() {\n    assert_no_code_actions!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  wibble(n: 2, n: 1)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_generates_argument_names_from_labels() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  add(1, addend: 10)\n}\n\",\n        find_position_of(\"add\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_generates_argument_names_from_variables() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  let wibble = 10\n  let wobble = 20\n\n  wubble(wibble, wobble, 14)\n}\n\",\n        find_position_of(\"wubble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_labels_and_arguments_can_share_the_same_name() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  let wibble = 10\n  wubble(wibble, wibble: 14)\n}\n\",\n        find_position_of(\"wubble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_arguments_with_same_name_get_renamed() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  let wibble = 10\n  wubble(wibble, wibble)\n}\n\",\n        find_position_of(\"wubble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_arguments_with_labels_and_variables_uses_different_names() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\npub fn main() {\n  let list = [2, 4, 5]\n  let value = 1\n  find(each: value, in: list)\n}\n\",\n        find_position_of(\"find\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_generates_unique_names_even_with_labels() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"\npub type Wibble {\n  Wibble(String, string: String)\n}\n\npub fn main(wibble: Wibble) {\n  todo\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_with_list_with_plural_name_does_not_add_another_s() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  wibble([Names, Names])\n}\n\npub type Names {\n  Names\n}\n\",\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_argument_in_first_position() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n\",\n        find_position_of(\"map\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder() {\n    let src = \"\npub type Person {\n  Person(name: String, age: Int, height: Float, is_cool: Bool)\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_argument_in_first_position_2() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3] |> wibble\n}\n\nfn wibble(a) { todo }\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_complex_types() {\n    let src = \"\nimport gleam/option\nimport gleam/dict\n\npub type Something\n\npub type Wibble(value) {\n  Wibble(\n    maybe: option.Option(Int),\n    something: Something,\n    map: dict.Dict(String, List(Float)),\n    unknown: List(value),\n  )\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src)\n            .add_module(\"gleam/option\", \"pub type Option(a)\")\n            .add_module(\"gleam/dict\", \"pub type Dict(k, v)\")\n            .add_package_module(\"gleam_json\", \"gleam/json\", \"pub type Json\"),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_argument_in_first_position_3() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3] |> wibble()\n}\n\nfn wibble(a) { todo }\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_already_imported_module() {\n    let src = \"\nimport gleam/json as json_encoding\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_argument_in_first_position_4() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3] |> wibble.wobble\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_tuple() {\n    let src = \"\npub type Wibble {\n  Wibble(tuple: #(Int, Float, #(String, Bool)))\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_for_variant_with_no_fields() {\n    let src = \"\npub type Wibble {\n  Wibble\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_for_type_with_multiple_variants_with_no_fields() {\n    let src = \"\npub type Wibble {\n  Wibble\n  Wobble\n  Woo\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_for_variants_with_mixed_fields() {\n    let src = \"\npub type Wibble {\n  Wibble\n  Wobble(field: String, field1: Int)\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type W\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_function_producing_another_function() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  1 |> wibble(2)\n}\n\nfn wibble(c) -> fn(a) -> Nil {\n  fn(_) { Nil }\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_recursive_type() {\n    let src = \"\nimport gleam/option.{Some}\n\npub type LinkedList {\n  LinkedList(value: Int, next: option.Option(LinkedList))\n}\n\";\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src)\n            .add_module(\"gleam/option\", \"pub type Option(a) { Some(a) None }\")\n            .add_package_module(\"gleam_json\", \"gleam/json\", \"pub type Json\"),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_hole_in_first_position() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(_, todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n\",\n        find_position_of(\"[\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_list_of_tuples() {\n    let src = \"\npub type Wibble {\n  Wibble(values: List(#(Int, String)))\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_for_multi_variant_type() {\n    let src = \"\npub type Wibble {\n  Wibble(wibble: Int, next: Wibble)\n  Wobble(wobble: Float, text: String, values: List(Bool))\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn generate_json_encoder_for_multi_variant_type_multi_word_name() {\n    let src = \"\npub type Wibble {\n  OneTwoThree(wibble: Int, next: Wibble)\n  FourFive(wobble: Float, text: String, values: List(Bool))\n  SixSevenEight(one_two: Float)\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_hole_not_in_first_position() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  fn(a) { todo }\n  |> map([1, 2, 3], _)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n\",\n        find_position_of(\"fn(a)\").select_until(find_position_of(\"map\"))\n    );\n}\n\n#[test]\nfn convert_to_function_call_always_inlines_the_first_step() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(todo)\n  |> filter(todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo }\n\",\n        find_position_of(\"[1, 2, 3]\").select_until(find_position_of(\"map\"))\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_labelled_argument() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3] |> wibble(wobble: _, woo:)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_labelled_argument_2() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  [1, 2, 3] |> wibble(wobble:, woo: _)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_when_piping_an_invalid_module_select() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  wibble.wobble |> woo(_)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_when_piping_a_module_select() {\n    let src = \"\nimport wibble\n\npub fn main() {\n  wibble.wobble |> woo(_)\n}\n\nfn woo(n) { todo }\n\";\n\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        TestProject::for_source(src).add_module(\"wibble\", \"pub const wobble = 1\"),\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_function_call_works_with_echo() {\n    assert_code_action!(\n        CONVERT_TO_FUNCTION_CALL,\n        \"\npub fn main() {\n  wibble.wobble |> echo\n}\n\",\n        find_position_of(\"echo\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_generate_json_encoder_for_type_without_labels() {\n    let src = \"\npub type Wibble {\n  Wibble(Int, Int, String)\n}\n    \";\n\n    assert_no_code_actions!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src).add_package_module(\n            \"gleam_json\",\n            \"gleam/json\",\n            \"pub type Json\"\n        ),\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_generate_json_encoder_without_gleam_json_dependency() {\n    assert_no_code_actions!(\n        GENERATE_TO_JSON_FUNCTION,\n        \"\npub type Wibble {\n  Wibble(w: Int)\n}\n\",\n        find_position_of(\"type\").to_selection()\n    );\n}\n\n#[test]\nfn inline_variable() {\n    let src = r#\"\nimport gleam/io\n\npub fn main() {\n  let message = \"Hello!\"\n  io.println(message)\n}\n\"#;\n    assert_code_action!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\"gleam/io\", \"pub fn println(value) {}\"),\n        find_position_of(\"message)\").to_selection()\n    );\n}\n\n#[test]\nfn inline_variable_from_definition() {\n    let src = r#\"\nimport gleam/io\n\npub fn main() {\n  let message = \"Hello!\"\n  io.println(message)\n}\n\"#;\n    assert_code_action!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\"gleam/io\", \"pub fn println(value) {}\"),\n        find_position_of(\"message =\").to_selection()\n    );\n}\n\n#[test]\nfn inline_variable_in_nested_scope() {\n    let src = r#\"\nimport gleam/io\n\npub fn main() {\n  let _ = {\n    let message = \"Hello!\"\n    io.println(message)\n  }\n}\n\"#;\n    assert_code_action!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\"gleam/io\", \"pub fn println(value) {}\"),\n        find_position_of(\"message =\").to_selection()\n    );\n}\n\n#[test]\nfn inline_variable_in_case_scope() {\n    let src = r#\"\nimport gleam/io\n\npub fn main(x) {\n  case x {\n    True -> {\n      let message = \"Hello!\"\n      io.println(message)\n    }\n    False -> Nil\n  }\n}\n\"#;\n    assert_code_action!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\"gleam/io\", \"pub fn println(value) {}\"),\n        find_position_of(\"message =\").to_selection()\n    );\n}\n\n#[test]\nfn inline_variable_when_over_let_keyword() {\n    assert_code_action!(\n        INLINE_VARIABLE,\n        r#\"\npub fn main() {\n  let x = 123\n  x + 1\n}\n\"#,\n        find_position_of(\"let\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_inline_variable_used_multiple_times() {\n    let src = r#\"\nimport gleam/io\n\npub fn main() {\n  let message = \"Hello!\"\n  io.println(message)\n  io.debug(message)\n}\n\"#;\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\n            \"gleam/io\",\n            \"pub fn println(value) {} pub fn debug(value) {}\"\n        ),\n        find_position_of(\"message =\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_inline_variable_defined_in_complex_pattern() {\n    let src = r#\"\nimport gleam/io\n\npub fn main() {\n  let #(message, second, _) = todo\n  io.println(message)\n}\n\"#;\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\"gleam/io\", \"pub fn println(value) {}\"),\n        find_position_of(\"message)\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_inline_variable_defined_in_case_clause() {\n    let src = r#\"\nimport gleam/io\n\npub fn main(result) {\n  case result {\n    Ok(value) -> value\n    Error(message) -> {\n      io.println(message)\n      panic\n    }\n  }\n}\n\"#;\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        TestProject::for_source(src).add_module(\"gleam/io\", \"pub fn println(value) {}\"),\n        find_position_of(\"message\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_on_first_argument() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble, woo)\n}\n\",\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_on_second_argument() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble, woo)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_on_function_name_extracts_first_argument() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble, woo)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_works_in_anonymous_function_inside_a_pipeline() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble |> wobble(fn() { woo(1) })\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_works_in_final_step_of_a_pipeline() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble |> wobble(woo(1))\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble: 1, woo: 2)\n}\n\",\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole_2() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble: 1, woo: 2)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble:, woo:)\n}\n\",\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole_2() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble:, woo:)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_on_first_step_of_pipeline() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble, woo) |> wobble\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_not_allowed_on_other_pipeline_steps() {\n    assert_no_code_actions!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble) |> wobble(woo)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_function_returning_other_function() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble)(woo)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use() {\n    assert_no_code_actions!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  use <- wibble(wobble)\n  todo\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use_2() {\n    assert_no_code_actions!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  use <- wibble(wobble)\n  todo\n}\n\",\n        find_position_of(\"todo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_does_not_work_on_function_with_capture() {\n    assert_no_code_actions!(\n        CONVERT_TO_PIPE,\n        \"import gleam/int\n\npub fn main() {\n  let sum = int.add(1, _)\n  sum\n}\n\",\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_does_not_work_on_record_with_capture() {\n    assert_no_code_actions!(\n        CONVERT_TO_PIPE,\n        \"pub fn main() {\n  Ok(_)\n}\n\",\n        find_position_of(\"O\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_works_inside_body_of_use() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  use <- wibble(wobble)\n  woo(123)\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_pipes_the_outermost_argument() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble(woo))\n}\n\",\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_when_first_arg_is_a_pipe_itself() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble |> woo, waa)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_string_concat_adds_braces() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble <> woo, waa)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_bool_operator_adds_braces() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(wobble != woo, waa)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_sum_adds_no_braces() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(1 + 1, waa)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_comparison_adds_braces() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\npub fn main() {\n  wibble(1.0 >=. 0.0, waa)\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_complex_binop_adds_braces() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\nfn bug() {\n    bool.guard(1 == 2 || 2 == 3, Nil, fn() { Nil })\n}\n\",\n        find_position_of(\"||\").to_selection()\n    );\n}\n\n#[test]\nfn convert_to_pipe_with_nested_calls_picks_the_innermost_one() {\n    assert_code_action!(\n        CONVERT_TO_PIPE,\n        \"\nfn bug() {\n    wibble(Wobble(\n      field: woo(other_call(last))\n    ))\n}\n\",\n        find_position_of(\"woo\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4342\n#[test]\nfn inline_variable_in_record_update() {\n    assert_code_action!(\n        INLINE_VARIABLE,\n        \"\ntype Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c1 = Couple(l: 1, r: 1)\n  let c2 = Couple(..c1, r: 1)\n}\n\",\n        find_position_of(\"c1,\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4430\n#[test]\nfn inline_variable_with_record_field() {\n    assert_code_action!(\n        INLINE_VARIABLE,\n        \"\ntype Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c1 = Couple(l: 1, r: 1)\n  let c2 = c1.l\n  echo c2\n}\n\",\n        find_position_of(\"c2\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn wrap_case_clause_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        \"\npub fn f(option) {\n  case option {\n    Some(content) -> content\n    None -> panic\n  }\n}\",\n        find_position_of(\"content\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn wrap_nested_case_clause_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        \"\npub fn f(result) {\n  case result {\n    Ok(reresult) -> {\n      case reresult {\n        Ok(w) -> w\n        Error(_) -> panic\n      }\n    }\n    Error(_) -> panic\n  }\n}\",\n        find_position_of(\"w\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn wrap_case_clause_with_guard_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        \"\npub fn f(option) {\n  case option {\n    Some(integer) if integer > 0 -> integer\n    Some(integer) -> 0\n    None -> panic\n  }\n}\",\n        find_position_of(\"integer\").nth_occurrence(3).to_selection()\n    );\n}\n\n#[test]\nfn wrap_case_clause_with_multiple_patterns_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        \"pub type PokemonType {\n  Air\n  Water\n  Fire\n}\n\n  pub fn f(pokemon_type: PokemonType) {\n    case pokemon_type {\n      Water | Air -> soak()\n      Fire -> burn()\n    }\n  }\",\n        find_position_of(\"soak\").to_selection()\n    );\n}\n\n#[test]\nfn wrap_case_clause_inside_assignment_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        r#\"pub type PokemonType {\n  Air\n  Water\n  Fire\n}\n\n  pub fn f(pokemon_type: PokemonType) {\n    let damage = case pokemon_type {\n      Water -> soak()\n      Fire -> burn()\n    }\n\n    \"Pokemon did \" <> damage\n  }\"#,\n        find_position_of(\"burn\").to_selection()\n    );\n}\n\n#[test]\nfn wrap_case_assignment_of_record_access_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        r#\"\npub type Record {\n  R(left: Int, right: Int)\n}\n\npub fn main() {\n  let r = R(1, 2)\n  let l = r.left\n  l\n}\n\"#,\n        find_position_of(\"left\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn do_not_wrap_case_clause_in_block_1() {\n    assert_no_code_actions!(\n        WRAP_IN_BLOCK,\n        \"\npub fn f(option) {\n  case option {\n    Some(content) -> {\n      content\n    }\n    None -> panic\n  }\n}\",\n        find_position_of(\"content\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn do_not_wrap_case_clause_in_block_2() {\n    assert_no_code_actions!(\n        WRAP_IN_BLOCK,\n        \"\npub fn f(result) {\n  case result {\n    Ok(reresult) -> {\n      case reresult {\n        Ok(w) -> {\n          w\n        }\n        Error(_) -> panic\n      }\n    }\n    Error(_) -> panic\n  }\n}\",\n        find_position_of(\"w\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn do_not_wrap_case_clause_in_block_3() {\n    assert_no_code_actions!(\n        WRAP_IN_BLOCK,\n        \"\npub fn f(option) {\n  case option {\n    Some(content) -> content\n    None -> panic\n  }\n}\",\n        find_position_of(\"Some(content)\").to_selection()\n    );\n}\n\n#[test]\nfn wrap_assignment_value_in_block() {\n    assert_code_action!(\n        WRAP_IN_BLOCK,\n        r#\"pub fn main() {\n  let var = \"value\"\n}\"#,\n        find_position_of(\"value\").select_until(find_position_of(\"e\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn do_not_wrap_assignment_value_in_block() {\n    assert_no_code_actions!(\n        WRAP_IN_BLOCK,\n        r#\"pub fn main() {\n  let var = \"value\"\n}\"#,\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4427\n#[test]\nfn extract_constant_function() {\n    assert_no_code_actions!(\n        EXTRACT_CONSTANT,\n        r#\"\nfn print(x) {\n  Nil\n}\n\npub fn main() {\n  print(\"Hello\")\n}\n\"#,\n        find_position_of(\"print\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn fix_float_operator_on_ints() {\n    let name = \"Use `>=`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  1 >=. 2\n}\n\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn fix_float_operator_on_ints_2() {\n    let name = \"Use `-`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  1 -. 2\n}\n\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn fix_float_operator_on_ints_3() {\n    let name = \"Use `*`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  1 *. wobble()\n}\n\nfn wobble() { 3 }\n\"#,\n        find_position_of(\"*.\").to_selection()\n    );\n}\n\n#[test]\nfn fix_int_operator_on_floats() {\n    let name = \"Use `>=.`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  1.0 >= 2.3\n}\n\"#,\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn fix_int_operator_on_floats_2() {\n    let name = \"Use `-.`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  1.12 - 2.0\n}\n\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2.0\"))\n    );\n}\n\n#[test]\nfn fix_int_operator_on_floats_3() {\n    let name = \"Use `*.`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  1.3 * wobble()\n}\n\nfn wobble() { 3.2 }\n\"#,\n        find_position_of(\"*\").to_selection()\n    );\n}\n\n#[test]\nfn fix_plus_operator_on_strings() {\n    let name = \"Use `<>`\";\n    assert_code_action!(\n        name,\n        r#\"\npub fn main() {\n  \"hello, \" + name()\n}\n\nfn name() { \"Jak\" }\n\"#,\n        find_position_of(\"hello\").select_until(find_position_of(\"name()\"))\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4454\n#[test]\nfn unqualify_already_imported_type() {\n    let src = \"\nimport wibble.{type Wibble}\n\npub fn main() -> wibble.Wibble {\n  todo\n}\n\";\n\n    assert_code_action!(\n        \"Unqualify wibble.Wibble\",\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble\"),\n        find_position_of(\"wibble.Wibble\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_pattern_constructor() {\n    assert_code_action!(\n        FILL_LABELS,\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wibble(..) -> todo\n    Wobble() -> todo\n  }\n}\n\",\n        find_position_of(\"Wobble()\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_pattern_constructor_let_assignment() {\n    assert_code_action!(\n        FILL_LABELS,\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\npub fn main() {\n  let Wibble() = todo\n}\n\",\n        find_position_of(\"Wibble()\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_pattern_constructor_with_some_labels() {\n    assert_code_action!(\n        FILL_LABELS,\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wobble(e: <<>>) -> todo\n    _ -> todo\n  }\n}\n\",\n        find_position_of(\"Wobble(e\").to_selection(),\n    );\n}\n\n#[test]\nfn fill_labels_nested_pattern_constructor() {\n    assert_code_action!(\n        FILL_LABELS,\n        \"\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main() {\n  case todo {\n    #([Wobble()], 2, 3) -> todo\n    _ -> todo\n  }\n}\n\",\n        find_position_of(\"Wobble()\").to_selection(),\n    );\n}\n\n#[test]\n// https://github.com/gleam-lang/gleam/issues/4499\nfn fill_labels_with_function_with_unlabelled_arguments() {\n    assert_no_code_actions!(\n        FILL_LABELS,\n        \"\npub fn main() {\n    fold(0, over: [], with: fn(acc, item) { acc + item })\n}\n\npub fn fold(over list, from initial, with fun) { todo }\",\n        find_position_of(\"fold\").to_selection(),\n    );\n}\n\n#[test]\nfn add_missing_patterns_with_labels() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        \"\npub type Wibble {\n  Wibble(integer: Int, float: Float)\n  Wobble(string: String, bool: Bool)\n}\n\npub fn main(w: Wibble) {\n  case w {}\n}\n\",\n        find_position_of(\"case w\").select_until(find_position_of(\"{}\")),\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3628#issuecomment-2543342212\n#[test]\nfn add_missing_patterns_multibyte_grapheme() {\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        r#\"\n// ä\nfn wibble() {\n  case True {}\n}\n\"#,\n        find_position_of(\"case\").select_until(find_position_of(\"True {\"))\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4626\n#[test]\nfn add_missing_patterns_opaque_type() {\n    let src = \"\nimport mod\n\npub fn main(w: mod.Wibble) {\n  case w {}\n}\n\";\n\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        TestProject::for_source(src).add_hex_module(\n            \"mod\",\n            \"pub opaque type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        find_position_of(\"{}\").to_selection(),\n    );\n}\n\n#[test]\nfn pattern_match_on_variable_does_not_add_patterns_for_internal_type() {\n    let src = \"\nimport wibble\n\npub type Type {\n  Type(wibble: wibble.Wibble, list: List(Int))\n}\n\npub fn main(thing: Type) {\n  case thing {\n    Type(wibble:, ..) -> todo\n  }\n}\n\";\n\n    assert_no_code_actions!(\n        PATTERN_MATCH_ON_VARIABLE,\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"@internal pub type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        find_position_of(\"wibble\").nth_occurrence(3).to_selection(),\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_does_not_add_patterns_for_internal_type() {\n    let src = \"\nimport wibble\n\npub fn main(thing: wibble.Wibble) {}\n\";\n\n    assert_no_code_actions!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"@internal pub type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        find_position_of(\"thing\").to_selection(),\n    );\n}\n\n#[test]\nfn pattern_match_on_argument_adds_patterns_for_internal_type_inside_module_where_it_is_defined() {\n    let src = \"\n@internal\npub type Wibble {\n  Wibble(Int)\n  Wobble(String)\n}\n\npub fn main(thing: Wibble) {}\n\";\n\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        TestProject::for_source(src),\n        find_position_of(\"thing\").to_selection(),\n    );\n}\n\n#[test]\nfn add_missing_patterns_adds_a_discard_for_opaque_type() {\n    let src = \"\nimport wibble\n\npub fn main(w: wibble.Wibble) {\n  case w {}\n}\n\";\n\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"@internal pub type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        find_position_of(\"{}\").to_selection(),\n    );\n}\n\n#[test]\nfn add_missing_patterns_adds_a_discard_for_opaque_type_1() {\n    let src = \"\nimport wibble\n\npub type Type {\n  Type(wibble: wibble.Wibble, list: List(Int))\n}\n\npub fn main(thing: Type) {\n  case thing {}\n}\n\";\n\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"@internal pub type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        find_position_of(\"{}\").to_selection(),\n    );\n}\n\n#[test]\nfn add_missing_patterns_adds_a_discard_for_opaque_type_2() {\n    let src = \"\nimport wibble\n\npub type Type {\n  Type(wibble.Wibble)\n}\n\npub fn main(thing: Type) {\n  case thing {}\n}\n\";\n\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"@internal pub type Wibble { Wibble(Int) Wobble(String) }\"\n        ),\n        find_position_of(\"{}\").to_selection(),\n    );\n}\n\n#[test]\nfn add_missing_patterns_adds_patterns_for_internal_type_inside_same_module_where_it_is_defined() {\n    let src = \"\n@internal\npub type Wibble {\n  Wibble(Int)\n  Wobble(String)\n}\n\npub fn main(thing: Wibble) {\n  case thing {}\n}\n\";\n\n    assert_code_action!(\n        ADD_MISSING_PATTERNS,\n        TestProject::for_source(src),\n        find_position_of(\"thing\").nth_occurrence(2).to_selection(),\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4653\n#[test]\nfn generate_function_capture() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\nfn map(list: List(a), f: fn(a) -> b) -> List(b) {\n  todo\n}\n\npub fn main() {\n  map([1, 2, 3], add(_, 1))\n}\n\",\n        find_position_of(\"add\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4660#issuecomment-2932371619\n#[test]\nfn inline_variable_label_shorthand() {\n    assert_code_action!(\n        INLINE_VARIABLE,\n        \"\npub type Example {\n  Example(sum: Int, nil: Nil)\n}\n\npub fn main() {\n  let sum = 1 + 1\n\n  Example(Nil, sum:)\n}\n\",\n        find_position_of(\"sum = \").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4660\n#[test]\nfn no_inline_variable_action_for_parameter() {\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        \"\npub fn main() {\n  let x = fn(something) {\n    something\n  }\n\n  x\n}\n\",\n        find_position_of(\"something\")\n            .nth_occurrence(2)\n            .to_selection()\n    );\n}\n\n#[test]\nfn no_inline_variable_action_when_spanning_multiple_items() {\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        \"\npub fn main(x: Int, y: Int) {\n  let a = 1\n  let b = 2\n  main(a, b)\n}\n\",\n        find_position_of(\"main\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\")\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn no_inline_variable_action_for_use_pattern() {\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        \"\npub fn main() {\n  let x = {\n    use something <- todo\n    something\n  }\n\n  x\n}\n\",\n        find_position_of(\"something\").to_selection()\n    );\n}\n\n#[test]\nfn no_inline_variable_action_for_case_pattern() {\n    assert_no_code_actions!(\n        INLINE_VARIABLE,\n        \"\npub fn main() {\n  let x = case todo {\n    something -> something\n  }\n\n  x\n}\n\",\n        find_position_of(\"something\")\n            .nth_occurrence(2)\n            .to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4675\n#[test]\nfn extract_variable_use() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        \"\npub fn main() {\n  #({\n    use <- todo\n    todo\n  })\n}\n  \",\n        find_position_of(\"use\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_in_anonymous_fn_in_argument() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"fn map(value, fn_over_value) { todo }\n\npub fn main() {\n  1\n  |> Ok\n  |> map(fn(value) { value + 2 })\n}\",\n        find_position_of(\"2\").to_selection()\n    );\n}\n\n#[test]\nfn extract_variable_starting_pipeline_steps() {\n    assert_code_action!(\n        EXTRACT_VARIABLE,\n        \"fn map(value, fn_over_value) { todo }\n\npub fn main() {\n  1\n  |> Ok\n  |> map(fn(value) { value + 2 })\n}\",\n        find_position_of(\"1\").select_until(find_position_of(\"Ok\"))\n    );\n}\n\n#[test]\nfn do_not_extract_top_level_variable_in_anonymous_fn_in_argument() {\n    assert_no_code_actions!(\n        EXTRACT_VARIABLE,\n        \"fn map(value, fn_over_value) { todo }\n\npub fn main() {\n  1\n  |> Ok\n  |> map(fn(value) { value + 1 })\n}\",\n        find_position_of(\"value\").nth_occurrence(4).to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4739\n#[test]\nfn do_not_import_internal_modules() {\n    const IMPORT_MODULE: &str = \"Import `package/internal`\";\n    let code = \"\npub fn main() {\n  internal.some_internal_function()\n}\n\";\n\n    assert_no_code_actions!(\n        IMPORT_MODULE,\n        TestProject::for_source(code).add_package_module(\n            \"package\",\n            \"package/internal\",\n            \"pub fn some_internal_function() { todo }\"\n        ),\n        find_position_of(\"internal\").to_selection()\n    );\n}\n\n#[test]\nfn import_internal_module_from_same_package() {\n    let code = \"\npub fn main() {\n  internal.some_internal_function()\n}\n\";\n\n    assert_code_action!(\n        \"Import `app/internal`\",\n        TestProject::for_source(code).add_package_module(\n            \"app\",\n            \"app/internal\",\n            \"pub fn some_internal_function() { todo }\"\n        ),\n        find_position_of(\"internal\").to_selection()\n    );\n}\n\n#[test]\nfn remove_block_1() {\n    assert_code_action!(\n        REMOVE_BLOCK,\n        \"pub fn main() {\n    { 1 }\n}\n\",\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn remove_block_2() {\n    assert_code_action!(\n        REMOVE_BLOCK,\n        \"pub fn main() {\n    { main() <> 2 }\n}\n\",\n        find_position_of(\"}\").to_selection()\n    );\n}\n\n#[test]\nfn remove_block_3() {\n    assert_code_action!(\n        REMOVE_BLOCK,\n        \"pub fn main() {\n    case 1 {\n      _ -> { main() <> 2 }\n    }\n}\n\",\n        find_position_of(\"{\").nth_occurrence(3).to_selection()\n    );\n}\n\n#[test]\nfn remove_block_triggers_on_the_innermost_selected_block() {\n    assert_code_action!(\n        REMOVE_BLOCK,\n        \"pub fn main(x) {\n    {\n      main({\n        1\n      })\n    }\n}\n\",\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn remove_block_does_not_unwrap_a_let_assignment() {\n    assert_no_code_actions!(\n        REMOVE_BLOCK,\n        \"pub fn main(x) {\n    {\n      let a = 1\n    }\n}\n\",\n        find_position_of(\"let\").to_selection()\n    );\n}\n\n#[test]\nfn remove_block_unwraps_a_single_expression_in_a_binop() {\n    assert_code_action!(\n        REMOVE_BLOCK,\n        \"pub fn main(x) {\n    { main(1) } * 3\n}\n\",\n        find_position_of(\"main\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn remove_block_does_not_unwrap_a_binop() {\n    assert_no_code_actions!(\n        REMOVE_BLOCK,\n        \"pub fn main(x) {\n    { 1 * 2 } + 3\n}\n\",\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn remove_block_does_not_unwrap_a_block_with_multiple_statements() {\n    assert_no_code_actions!(\n        REMOVE_BLOCK,\n        \"pub fn main(x) {\n    {\n      main(1)\n      main(2)\n    }\n}\n\",\n        find_position_of(\"1\").to_selection()\n    );\n}\n\n#[test]\nfn remove_opaque_from_private_type() {\n    assert_code_action!(\n        REMOVE_OPAQUE_FROM_PRIVATE_TYPE,\n        \"opaque type Wibble {\n  Wobble\n}\n\",\n        find_position_of(\"Wibble\").to_selection()\n    );\n}\n\n#[test]\nfn allow_further_pattern_matching_on_let_tuple_destructuring() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(x) {\n  let #(one, other) = #(Ok(1), Error(Nil))\n}\n\",\n        find_position_of(\"one\").to_selection()\n    );\n}\n\n#[test]\nfn allow_further_pattern_matching_on_let_record_destructuring() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(x) {\n  let Wibble(field:) = Wibble(Ok(Nil))\n}\n\npub type Wibble { Wibble(field: Result(Nil, String)) }\n\",\n        find_position_of(\"field\").to_selection()\n    );\n}\n\n#[test]\nfn allow_further_pattern_matching_on_asserted_result() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(x) {\n  let assert Ok(one) = Ok(Error(Nil))\n}\n\",\n        find_position_of(\"one\").to_selection()\n    );\n}\n\n#[test]\nfn allow_further_pattern_matching_on_asserted_list() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(x) {\n  let assert [first, ..] = [Ok(Nil), ..todo]\n  todo\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_list_variable() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_ARGUMENT,\n        \"pub fn main(a_list: List(a)) {\n  todo\n}\",\n        find_position_of(\"a_list\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_list_tail() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..rest] -> todo\n  }\n}\",\n        find_position_of(\"rest\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_list_tail_with_strange_whitespace() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..        rest] -> todo\n  }\n}\",\n        find_position_of(\"        \").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_list_tail_used_in_a_branch() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..rest] -> rest\n  }\n}\",\n        find_position_of(\"rest\").to_selection()\n    );\n}\n\n#[test]\nfn pattern_match_on_list_tail_with_shadowed_name() {\n    assert_code_action!(\n        PATTERN_MATCH_ON_VARIABLE,\n        \"pub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [rest, ..else_] -> todo\n  }\n}\",\n        find_position_of(\"else_\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    Ok(var) -> case var {\n      1 -> 2\n      2 -> 4\n      _ -> -1\n    }\n    _ -> todo\n  }\n}\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_works_with_blocks() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    Ok(var) -> {\n      case var {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n    }\n    _ -> todo\n  }\n}\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_works_with_patterns_defining_multiple_variables() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    Wibble(var, var2) ->\n      case var {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(Int, String)\n  Wobble\n}\n\",\n        find_position_of(\"var\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_does_not_remove_labels() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    Wibble(field2:, field: wibble) ->\n      case wibble {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(field: Int, field2: String)\n  Wobble\n}\n\",\n        find_position_of(\"field\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_does_not_remove_labels_with_shorthand_syntax() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    Wibble(field2:, field:) ->\n      case field {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(field: Int, field2: String)\n  Wobble\n}\n\",\n        find_position_of(\"field\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_works_with_alternative_patterns() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    [first, ..rest] ->\n      case first {\n        1 | 2 -> True\n        3 | 4 | 5 -> False\n        _ -> False\n      }\n\n    [] -> True\n  }\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_aliases_variable_if_it_is_used() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    [first, ..rest] ->\n      case first {\n        1 | 2 -> first\n        3 | 4 | 5 -> 5\n        _ -> 0\n      }\n\n    [] -> -1\n  }\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_does_not_ignore_outer_guards() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    [first, ..rest] if True ->\n      case first {\n        1 -> 1.1\n        _ -> 0.0 *. 10.0\n      }\n\n    [] -> 1.1\n  }\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_does_not_ignore_inner_guards() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    [first, ..rest] ->\n      case first {\n        1 -> 1.1\n        _ if True -> 0.0 *. 10.0\n        _ -> 0.0\n      }\n\n    [] -> 1.1\n  }\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_combines_inner_and_outer_guards() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    [first, ..rest] if False ->\n      case first {\n        1 if False -> 1.1\n        _ if True -> 0.0 *. 10.0\n        _ -> 0.0\n      }\n\n    [] -> 1.1\n  }\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_combines_inner_and_outer_guards_and_adds_parentheses_when_needed() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        \"pub fn main(x) {\n  case x {\n    [first, ..rest] if False || True ->\n      case first {\n        1 if False && True -> 1.1\n        _ if True || False -> 0.0 *. 10.0\n        _ -> 0.0\n      }\n\n    [] -> 1.1\n  }\n}\n\",\n        find_position_of(\"first\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_combines_list_with_unformatted_tail() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        r#\"pub fn main(elems: List(String)) {\n  case elems {\n    [first, .. rest_of_list] ->\n      case rest_of_list {\n        [] -> 0\n        [\"first\"] -> 1\n        [_, \"second\"] -> 2\n        [_, \"second\", \"third\", _] -> 4\n        _ -> -1\n      }\n    _ -> -1\n  }\n}\"#,\n        find_position_of(\"rest\").to_selection()\n    );\n}\n\n#[test]\nfn collapse_nested_case_combines_list_with_tail() {\n    assert_code_action!(\n        COLLAPSE_NESTED_CASE,\n        r#\"pub fn main(elems: List(List(Int))) {\n  case elems {\n    [] -> 0\n    [_, ..tail] ->\n      case tail {\n        [] -> -1\n        [[1]] -> 1\n        [_, [3, 4]] -> 3\n        [_, _, [5, 6, 7], _] -> 5\n        tail_list -> {\n            echo tail_list\n            -1\n        }\n      }\n    _ -> -1\n  }\n}\"#,\n        find_position_of(\"tail\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3786\n#[test]\nfn type_variables_from_other_functions_do_not_change_annotations() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        \"\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn pair(a, b) {\n  #(a, b)\n}\n\",\n        find_position_of(\"pair\").to_selection()\n    );\n}\n\n#[test]\nfn type_variables_from_other_functions_do_not_change_annotations_constant() {\n    assert_code_action!(\n        ADD_ANNOTATION,\n        \"\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nconst empty = []\n\",\n        find_position_of(\"empty\").to_selection()\n    );\n}\n\n#[test]\nfn type_variables_are_not_duplicated_when_adding_annotations() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        \"\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn many_args(a, b, c, d: d, e: a, f, g) {\n  todo\n}\n\",\n        find_position_of(\"many_args\").to_selection()\n    );\n}\n\n#[test]\nfn type_variables_in_let_bindings_are_considered_when_adding_annotations() {\n    assert_code_action!(\n        ADD_ANNOTATIONS,\n        \"\nfn wibble(a, b, c) {\n  let x: a = todo\n  fn(a: b, b: c) -> d {\n    todo\n  }\n}\n\",\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn generated_function_annotations_are_not_affected_by_other_functions() {\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        \"\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\npub fn main() {\n  let x = todo\n  let y = todo\n  let #(a, b) = something(x, y)\n  b\n}\n\",\n        find_position_of(\"something\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_in_other_module() {\n    let src = \"\nimport wibble\n\npub fn main() {\n  wibble.wibble()\n  wibble.wobble()\n}\n\";\n\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        TestProject::for_source(src).add_module(\"wibble\", \"pub fn wibble() {}\"),\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generate_function_is_not_offered_for_variants() {\n    assert_no_code_actions!(\n        GENERATE_FUNCTION,\n        \"\npub type Wibble\n\npub fn main() -> Wibble {\n  Wobble(1)\n}\n\",\n        find_position_of(\"Wobble\").to_selection()\n    );\n}\n\n#[test]\nfn generating_function_in_other_module_uses_local_names() {\n    let src = r#\"\nimport wibble\n\npub fn main() -> List(Nil) {\n  wibble.wibble(1, #(True, \"Hello\"))\n}\n\"#;\n\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"import gleam.{type Int as Number, type Bool as Boolean, type String as Text, type Nil as Nothing}\"\n        ),\n        find_position_of(\"wibble(\").to_selection()\n    );\n}\n\n#[test]\nfn generating_function_in_other_module_uses_labels() {\n    let src = r#\"\nimport wibble\n\npub fn main() {\n  wibble.wibble(\"Unlabelled\", int: 1, bool: True)\n}\n\"#;\n\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        TestProject::for_source(src).add_module(\"wibble\", \"\"),\n        find_position_of(\"wibble(\").to_selection()\n    );\n}\n\n#[test]\nfn no_code_action_to_generate_existing_function_in_other_module() {\n    let src = r#\"\nimport wibble\n\npub fn main() {\n  wibble.wibble(1, 2, 3)\n}\n\"#;\n\n    assert_no_code_actions!(\n        GENERATE_FUNCTION,\n        TestProject::for_source(src).add_module(\"wibble\", \"pub fn wibble(a, b, c) { a + b + c }\"),\n        find_position_of(\"wibble(\").to_selection()\n    );\n}\n\n#[test]\nfn do_not_generate_function_in_other_package() {\n    let src = r#\"\nimport maths\n\npub fn main() {\n  maths.add(1, 2)\n  maths.subtract(1, 2)\n}\n\"#;\n\n    assert_no_code_actions!(\n        GENERATE_FUNCTION,\n        TestProject::for_source(src).add_dep_module(\"maths\", \"pub fn add(a, b) { a + b }\"),\n        find_position_of(\"subtract\").to_selection()\n    );\n}\n\n#[test]\nfn remove_unreachable_clauses() {\n    assert_code_action!(\n        REMOVE_UNREACHABLE_CLAUSES,\n        \"pub fn main(x) {\n  case x {\n    Ok(n) -> 1\n    Ok(_) -> 2\n    Error(_) -> todo\n    Ok(1) -> 3\n  }\n}\n\",\n        find_position_of(\"Ok(1)\").to_selection()\n    );\n}\n\n#[test]\nfn remove_unreachable_branches_does_not_pop_up_if_all_branches_are_reachable() {\n    assert_no_code_actions!(\n        REMOVE_UNREACHABLE_CLAUSES,\n        \"pub fn main(x) {\n  case x {\n    Ok(n) -> 1\n    Error(_) -> todo\n  }\n\n  case x {\n    Ok(n) -> todo\n    Ok(_) -> todo\n    _ -> todo\n  }\n}\n\",\n        find_position_of(\"Ok(n)\").to_selection()\n    );\n}\n\n#[test]\nfn add_type_annotations_public_alias_to_internal_type_aliased_module() {\n    let src = \"\nimport package as pkg\n\npub fn main() {\n  pkg.make_wibble()\n}\n\";\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src)\n            .add_package_module(\n                \"package\",\n                \"package\",\n                \"\nimport package/internal\n\npub type Wibble = internal.Wibble\n\npub fn make_wibble() {\n  internal.Wibble\n}\n\"\n            )\n            .add_package_module(\"package\", \"package/internal\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"main\").to_selection(),\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3898\n#[test]\nfn add_type_annotations_public_alias_to_internal_type() {\n    let src = \"\nimport package\n\npub fn main() {\n  package.make_wibble()\n}\n\";\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src)\n            .add_package_module(\n                \"package\",\n                \"package\",\n                \"\nimport package/internal\n\npub type Wibble = internal.Wibble\n\npub fn make_wibble() {\n  internal.Wibble\n}\n\"\n            )\n            .add_package_module(\"package\", \"package/internal\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"main\").to_selection(),\n    );\n}\n\n#[test]\nfn add_type_annotations_public_alias_to_internal_generic_type() {\n    let src = \"\nimport package\n\npub fn main() {\n  package.make_wibble(10)\n}\n\";\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src)\n            .add_package_module(\n                \"package\",\n                \"package\",\n                \"\nimport package/internal\n\npub type Wibble(a, b) = internal.Wibble(a, b)\n\npub fn make_wibble(x) {\n  internal.Wibble(x)\n}\n\"\n            )\n            .add_package_module(\n                \"package\",\n                \"package/internal\",\n                \"pub type Wibble(a, b) { Wibble(a) }\"\n            ),\n        find_position_of(\"main\").to_selection(),\n    );\n}\n\n#[test]\nfn add_type_annotations_uses_internal_name_for_same_package() {\n    let src = \"\nimport thepackage/internal\n\npub fn main() {\n  internal.Constructor\n}\n\";\n\n    assert_code_action!(\n        ADD_ANNOTATION,\n        TestProject::for_source(src)\n            .add_module(\n                \"thepackage/internal\",\n                \"\npub type Internal { Constructor }\n\"\n            )\n            .add_module(\n                \"thepackage/external\",\n                \"\nimport thepackage/internal\n\npub type External = internal.Internal\n\"\n            ),\n        find_position_of(\"main\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_in_function_call() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  labelled(1, 2)\n}\n\npub fn labelled(a a, b b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_in_function_call_with_some_labels() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  labelled(1, 2)\n}\n\npub fn labelled(a, b b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_in_function_call_uses_shorthand_syntax() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  let a = 1\n  labelled(a, 2)\n}\n\npub fn labelled(a a, b b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_works_with_innermost_function_call() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  let a = 1\n  labelled(a, labelled(1, 2))\n}\n\npub fn labelled(a a, b b) { todo }\n    \",\n        find_position_of(\"labelled\")\n            .nth_occurrence(2)\n            .to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_works_with_constructors_calls() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  Labelled(1, 2)\n}\n\npub type Labelled {\n  Labelled(Int, b: Int)\n}\n    \",\n        find_position_of(\"Labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_works_with_constructors_calls_with_some_labels_1() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  labelled(3, 1, b: 2)\n}\n\npub fn labelled(a a, b b, c c) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_works_with_constructors_calls_with_some_labels() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  let a = 1\n  labelled(a, b: 2)\n}\n\npub fn labelled(a a, b b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_works_on_call_with_wrongly_placed_labels() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  labelled(3, b: 2, 1)\n}\n\npub fn labelled(a a, b b, c c) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_does_not_work_on_call_with_wrong_labels_2() {\n    assert_no_code_actions!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  labelled(3, 1, d: 2)\n}\n\npub fn labelled(a a, b b, c c) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_does_not_pop_up_if_called_function_has_no_labels() {\n    assert_no_code_actions!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  let a = 1\n  labelled(a, 2)\n}\n\npub fn labelled(a, b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_does_not_label_piped_argument() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  1 |> labelled(2)\n}\n\npub fn labelled(a a, b b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn add_omitted_labels_does_not_label_use() {\n    assert_code_action!(\n        ADD_OMITTED_LABELS,\n        \"\npub fn main() {\n  use <- labelled(1)\n  todo\n}\n\npub fn labelled(a a, b b) { todo }\n    \",\n        find_position_of(\"labelled\").to_selection(),\n    );\n}\n\n#[test]\nfn extract_function() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let result = {\n    let a = 10 + a\n    let b = 10 + b\n    a * b\n  }\n  result + 3\n}\n\",\n        find_position_of(\"{\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_function_from_statements() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let a = 10 + a\n  let b = 10 + b\n  let result = a * b\n  result + 3\n}\n\",\n        find_position_of(\"let\").select_until(find_position_of(\"* b\"))\n    );\n}\n\n#[test]\nfn extract_function_which_use_variables_defined_in_the_extracted_span() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let new_a = 10 + a\n  let new_b = 10 + b\n  let result = new_a * new_b\n  result + 3\n}\n\",\n        find_position_of(\"let\").select_until(find_position_of(\"* new_b\"))\n    );\n}\n\n#[test]\nfn extract_function_which_use_variables_shadowed_in_an_inner_scope() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let first_part = {\n    let a = a + 10\n    let b = b + 10\n    a * b\n  }\n  let result = first_part + a * b\n  result + 3\n}\n\",\n        find_position_of(\"let\").select_until(find_position_of(\"+ a * b\"))\n    );\n}\n\n#[test]\nfn extract_function_which_uses_multiple_extracted_variables() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let wibble = a + b\n  let wobble = a * b\n  wobble / wibble\n}\n\",\n        find_position_of(\"let\").select_until(find_position_of(\"* b\"))\n    );\n}\n\n#[test]\nfn extract_function_which_uses_no_extracted_variables() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let x = a + b\n  echo x\n  a\n}\n\",\n        find_position_of(\"let\").select_until(find_position_of(\"echo x\"))\n    );\n}\n\n#[test]\nfn extract_function_which_uses_variable_in_guard() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn do_things(a, b) {\n  let result = case Nil {\n    _ if a > b -> 17\n    _ if a < b -> 12\n    _ -> panic\n  }\n\n  result % 4\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_function_which_uses_variable_in_bit_array_pattern() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn main() {\n  let bits = todo\n  let size = todo\n\n  let segment = case bits {\n    <<x:size(size), _:bits>> -> Ok(x)\n    _ -> Error(Nil)\n  }\n\n  case segment {\n    Ok(value) -> echo value\n    Error(_) -> panic\n  }\n}\n\",\n        find_position_of(\"case\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_function_which_uses_constant() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\nconst pi = 3.14\n\npub fn main() {\n  let radius = 4.5\n\n  let circumference = radius *. pi *. 2.0\n\n  echo circumference\n}\n\",\n        find_position_of(\"radius *.\").select_until(find_position_of(\"2.0\"))\n    );\n}\n\n#[test]\nfn extract_function_which_uses_constant_in_guard() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\nconst pi = 3.14\n\npub fn main() {\n  let value = 3.15\n\n  let string = case value {\n    0.0 -> \"Zero\"\n    1.0 -> \"One\"\n    _ if value == pi -> \"PI\"\n    _ -> \"Something else\"\n  }\n\n  echo string\n}\n\"#,\n        find_position_of(\"case\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn no_code_action_to_extract_function_when_expression_is_not_fully_selected() {\n    assert_no_code_actions!(\n        EXTRACT_FUNCTION,\n        r#\"\nfn print(text: String) { todo }\n\npub fn main() {\n  let arguments = todo\n\n  case arguments {\n    [\"help\"] -> print(\"USAGE TEXT HERE\")\n    _ -> panic as \"Invalid args\"\n  }\n}\n\"#,\n        find_position_of(\"print\")\n            .under_char('i')\n            .select_until(find_position_of(\"TEXT\"))\n    );\n}\n\n#[test]\nfn extract_function_when_name_already_in_scope() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\nfn function() { todo }\n\npub fn do_things(a, b) {\n  let result = {\n    let a = 10 + a\n    let b = 10 + b\n    a * b\n  }\n  result + 3\n}\n\"#,\n        find_position_of(\"= {\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_function_when_multiple_names_already_in_scope() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\nfn function() { todo }\nfn function_2() { todo }\nfn function_3() { todo }\nfn function_4() { todo }\n\npub fn do_things(a, b) {\n  let result = {\n    let a = 10 + a\n    let b = 10 + b\n    a * b\n  }\n  result + 3\n}\n\"#,\n        find_position_of(\"= {\").select_until(find_position_of(\"}\").nth_occurrence(5))\n    );\n}\n\n#[test]\nfn extract_function_partially_selected() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  let a = 10\n  let b = 20\n  let c = a + b\n\n  echo c\n}\n\"#,\n        find_position_of(\"a =\").select_until(find_position_of(\"c =\"))\n    );\n}\n\n#[test]\nfn selected_statements_do_not_select_outer_block() {\n    // We want to make sure only the statements within the block are extracted,\n    // and not the block itself.\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  let c = {\n    let a = 10\n    let b = 20\n    a + b\n  }\n\n  echo c\n}\n\"#,\n        find_position_of(\"let a\").select_until(find_position_of(\"+ b\"))\n    );\n}\n\n#[test]\nfn no_code_action_to_extract_when_multiple_functions_are_selected() {\n    assert_no_code_actions!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  let a = 10\n  a + 1\n}\n\npub fn other() {\n  let b = 20\n  b * 2\n}\n\"#,\n        find_position_of(\"let a\").select_until(find_position_of(\"let b\"))\n    );\n}\n\n#[test]\nfn extract_statements_in_tail_position() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  let a = 1\n  let b = 2\n  let c = 3\n  let d = 4\n  a * b + c * d\n}\n\"#,\n        find_position_of(\"let c\").select_until(find_position_of(\"* d\"))\n    );\n}\n\n#[test]\nfn extract_use_in_tail_position() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  use <- wibble\n  123\n}\n\nfn wibble(f: fn() -> Int) -> Int { f() }\n\"#,\n        find_position_of(\"use\").select_until(find_position_of(\"wibble\"))\n    );\n}\n\n#[test]\nfn extract_use_in_tail_position_2() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  use <- wibble\n  use <- wobble\n  123\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\nfn wobble(f: fn() -> Int) -> Float { 1.1 }\n\"#,\n        find_position_of(\"use\")\n            .nth_occurrence(2)\n            .select_until(find_position_of(\"wobble\"))\n    );\n}\n\n#[test]\nfn extract_block_tail_position_3() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  case 1 {\n    _ -> {\n      use <- wibble\n      123\n    }\n    _ -> todo\n  }\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\n\"#,\n        find_position_of(\"{\")\n            .nth_occurrence(3)\n            .select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_block_tail_position_4() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        r#\"\npub fn main() {\n  case 1 {\n    _ -> {\n      use <- wibble\n      use <- wibble\n      123\n    }\n    _ -> todo\n  }\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\n\"#,\n        find_position_of(\"{\")\n            .nth_occurrence(3)\n            .select_until(find_position_of(\"}\"))\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5036\n#[test]\nfn generate_function_in_other_module_correctly_appends() {\n    let src = \"import module_breaker/another\n\npub fn main() -> Nil {\n  another.function()\n}\n\";\n\n    assert_code_action!(\n        GENERATE_FUNCTION,\n        TestProject::for_source(src).add_module(\n            \"module_breaker/another\",\n            \"pub fn useless() {\n  Nil\n}\n\"\n        ),\n        find_position_of(\"function\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4904\n#[test]\nfn no_code_action_to_generate_function_on_unsupported_target() {\n    assert_no_code_actions!(\n        GENERATE_FUNCTION,\n        r#\"\npub fn main() {\n  wibble()\n}\n\n@external(javascript, \"./ffi.mjs\", \"wibble\")\nfn wibble() -> Nil\n\"#,\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn merge_case_branch() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> todo\n    2 -> todo\n    _ -> todo\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_todo_keeps_the_non_todo_body() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> todo\n    2 -> n * 2\n    3 -> todo\n    _ -> todo\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"3\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_todo_keeps_the_non_todo_body_1() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> todo\n    2 -> todo\n    3 -> n * 2\n    _ -> todo\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"3\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_todo_keeps_the_non_todo_body_2() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> n * 2\n    2 -> todo\n    3 -> todo\n    _ -> todo\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"3\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_complex_bodies_1() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> Ok(\"one or two\")\n    2 -> Ok(\"one or two\")\n    _ -> Error(\"neither one or two\")\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_complex_bodies_2() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> n\n    2 -> n\n    _ -> panic as \"neither one nor two\"\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_complex_bodies_3() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> go(n - 1)\n    2 -> go(n - 1)\n    _ -> 10\n  }\n}\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_with_complex_bodies_4() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 -> {\n      let a = go(n - 1)\n      a * 10\n    }\n    2 -> {\n      let a = go(n - 1)\n      a * 10\n    }\n    _ -> 10\n  }\n}\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_will_not_merge_branches_with_guards() {\n    assert_no_code_actions!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(n: Int) {\n  case n {\n    1 if True -> todo\n    2 -> todo\n    _ -> todo\n  }\n  }\"#,\n        find_position_of(\"1\").select_until(find_position_of(\"2\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_will_not_merge_branches_defining_different_variables() {\n    assert_no_code_actions!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(result: Result(Int, Int)) {\n  case result {\n    Ok(value) -> todo\n    Error(error) -> todo\n    _ -> todo\n  }\n  }\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"error\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_can_merge_branches_defining_the_same_variables() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(result) {\n  case result {\n    [Ok(value), ..] -> todo\n    [_, Error(value)] -> todo\n    _ -> todo\n  }\n}\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"todo\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn merge_case_branch_can_merge_multiple_branches() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(result) {\n  case result {\n    [_] -> 1\n    [Ok(value), ..] -> todo\n    [_, Error(value)] -> todo\n    [_, _, Error(value)] -> todo\n    [_, _] -> 1\n    _ -> 2\n  }\n}\"#,\n        find_position_of(\"todo\").select_until(find_position_of(\"todo\").nth_occurrence(3))\n    );\n}\n\n#[test]\nfn merge_case_branch_does_not_pop_up_with_a_single_selected_branch() {\n    assert_no_code_actions!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(result) {\n  case result {\n    [] -> todo\n    _ -> 2\n  }\n}\"#,\n        find_position_of(\"[]\").to_selection()\n    );\n}\n\n#[test]\nfn merge_case_branch_works_with_existing_alternative_patterns() {\n    assert_code_action!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(result) {\n  case result {\n    [] | [_, _, ..]-> todo\n    [_] -> todo\n    _ -> 2\n  }\n}\"#,\n        find_position_of(\"[]\").select_until(find_position_of(\"[_]\"))\n    );\n}\n\n#[test]\nfn merge_case_branch_does_not_merge_branches_with_variables_with_same_name_and_different_types() {\n    assert_no_code_actions!(\n        MERGE_CASE_BRANCHES,\n        r#\"pub fn go(result: Result(Int, String)) {\n  case result {\n    Ok(one) -> todo\n    Error(one) -> todo\n  }\n}\"#,\n        find_position_of(\"Ok\").select_until(find_position_of(\"Error\"))\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_dont_affect_local_vars() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub const answer = 42\n\npub fn add_two(thing) {\n  thing + 2\n}\n\npub fn add_one(thing) {\n  let result = thing + 1\n  result\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_constant() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub const answer = 42\n\npub fn add_two(thing) {\n  thing + 2\n}\n\npub fn add_one(thing) {\n  thing + 1\n}\n\"#,\n        find_position_of(\"const\").select_until(find_position_of(\"=\"))\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_function() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub fn add_two(thing) {\n  thing + 2\n}\n\npub fn add_one(thing) {\n  thing + 1\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_already_annotated() {\n    assert_no_code_actions!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub const answer: Int = 42\n\npub fn add_two(thing: Int) -> Int {\n  thing + 2\n}\n\npub fn add_one(thing: Int) -> Int {\n  thing + 1\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_inside_body() {\n    assert_no_code_actions!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub fn add_one(thing) {\n  thing + 1\n}\n\"#,\n        find_position_of(\"thing + 1\").to_selection()\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_partially_annotated() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub const answer: Int = 42\npub const another_answer = 43\n\npub fn add_two(thing) -> Int {\n  thing + 2\n}\n\npub fn add_one(thing: Int) {\n  thing + 1\n}\n\"#,\n        find_position_of(\"fn\").select_until(find_position_of(\"(\"))\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_with_partially_annotated_generic_function() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\npub fn wibble(a: a, b, c: c, d) {\n  todo\n}\n\"#,\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_with_two_generic_functions() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\nfn wibble(one) { todo }\n\nfn wobble(other) { todo }\n\"#,\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_with_constant_and_generic_functions() {\n    assert_code_action!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\nconst answer = 42\n\nfn wibble(one) { todo }\n\nfn wobble(other) { todo }\n\"#,\n        find_position_of(\"wobble\").to_selection()\n    );\n}\n\n#[test]\nfn annotate_all_top_level_definitions_not_suggested_if_annotations_present() {\n    assert_no_code_actions!(\n        ANNOTATE_TOP_LEVEL_DEFINITIONS,\n        r#\"\nfn wibble(one: Int) -> Int { one }\n\nfn wobble(one) { wibble(one) }\n\"#,\n        find_position_of(\"wibble\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5273\n#[test]\nfn extract_constant_doesnt_place_constant_below_documentation() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"\n/// Wibble does some wobbling\npub fn wibble() {\n    let x = \"wobble\"\n    x\n}\n\"#,\n        find_position_of(\"x\").to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5273\n#[test]\nfn extract_constant_doesnt_place_constant_below_large_documentation() {\n    assert_code_action!(\n        EXTRACT_CONSTANT,\n        r#\"\n/// Wibble does some wobbling\n/// Note that it doesn't perform wibbling\npub fn wibble() {\n    let x = \"wobble\"\n    x\n}\n\"#,\n        find_position_of(\"x\").to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_for_single_constructor() {\n    assert_code_action!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble {\n  Wibble(field: t)\n}\n\"#,\n        find_position_of(\"t\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_to_exising_parameter() {\n    assert_code_action!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble(t) {\n  Wibble(field: t)\n  Wobble(field: u)\n}\n\"#,\n        find_position_of(\"u\").to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_preserves_comments() {\n    assert_code_action!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble(\n  // Comment 1\n  b,\n  // Comment 2\n) {\n  Wibble(a, b, c)\n}\n\"#,\n        find_position_of(\"c\").to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_sorted_alphabetically() {\n    assert_code_action!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble(b) {\n  Wibble(c, b, a)\n}\n\"#,\n        find_position_of(\"a\").to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_not_suggested_when_nothing_missing() {\n    assert_no_code_actions!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble(t) {\n  Wibble(field: t)\n}\n\"#,\n        find_position_of(\"t\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_not_suggested_when_no_parameters() {\n    assert_no_code_actions!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble {\n  Wibble\n}\n\"#,\n        find_position_of(\"Wibble\").nth_occurrence(2).to_selection()\n    );\n}\n\n#[test]\nfn add_missing_type_parameter_does_not_add_types_that_do_not_exist() {\n    assert_no_code_actions!(\n        ADD_MISSING_TYPE_PARAMETER,\n        r#\"\ntype Wibble {\n  Wibble(Wobble)\n}\n\"#,\n        find_position_of(\"Wibble\").nth_occurrence(2).to_selection()\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5288\n#[test]\nfn extract_anonymous_function_without_variable_capture_1() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn main() {\n  let int_pow = fn(base, exp) {\n    case exp {\n      exp if exp < 0 -> 0\n      0 -> base\n      exp -> int_pow(base * exp, exp - 1)\n    }\n  }\n}\n        \",\n        find_position_of(\"fn(\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn extract_anonymous_function_without_variable_capture_2() {\n    let src = r#\"\nimport gleam/io\nimport gleam/list\n\npub fn main() {\n  list.each(list.range(0, 10), fn(_) { io.println(\"wibble wobble\") })\n}\n        \"#;\n\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        TestProject::for_source(src)\n            .add_hex_module(\n                \"gleam/io\",\n                \"\n                    pub fn println(string: String) -> Nil { todo }\n                \"\n            )\n            .add_hex_module(\n                \"gleam/list\",\n                \"\n                    pub fn each(list: List(a), f: fn(a) -> b) -> Nil { todo }\n                    pub fn range(from start: Int, to stop: Int) -> List(Int) { todo }\n                \"\n            ),\n        find_position_of(\"fn(\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_unary_anonymous_function_with_variable_capture_1() {\n    let src = \"\nimport gleam/list\n\npub fn main() {\n  let needle = 42\n  let haystack = [25, 81, 74, 42, 33]\n  list.filter(haystack, fn(x) { x == needle })\n}\n        \";\n\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        TestProject::for_source(src).add_hex_module(\n            \"gleam/list\",\n            \"\n                pub fn filter(\n                  list: List(a),\n                  keeping predicate: fn(a) -> Bool,\n                ) -> List(a) { todo }\n            \"\n        ),\n        find_position_of(\"fn(\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_unary_anonymous_function_with_variable_capture_2() {\n    let src = \"\nimport gleam/list\n\npub fn main() {\n  let needle = 42\n  let haystack = [25, 81, 74, 42, 33]\n  list.filter(haystack, fn(_) { needle == 42 })\n}\n        \";\n\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        TestProject::for_source(src).add_hex_module(\n            \"gleam/list\",\n            \"\n                pub fn filter(\n                  list: List(a),\n                  keeping predicate: fn(a) -> Bool,\n                ) -> List(a) { todo }\n            \"\n        ),\n        find_position_of(\"fn(\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_anonymous_function_with_variable_capture_1() {\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        \"\npub fn main() {\n  let outer_scope = 3\n  let wibble = fn(a, b) {\n    a + b + outer_scope\n  }\n}\n        \",\n        find_position_of(\"fn(\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn extract_anonymous_function_with_variable_capture_2() {\n    let src = \"\nimport gleam/list\n\npub fn main() {\n  let shorter = [1, 2, 3]\n  let longer = [4, 5, 6, 7, 8]\n  let offset = 5\n  list.map2(shorter, longer, fn(_left, right) { right + offset })\n}\n        \";\n\n    assert_code_action!(\n        EXTRACT_FUNCTION,\n        TestProject::for_source(src).add_hex_module(\n            \"gleam/list\",\n            \"\n                pub fn map2(\n                  list1: List(a),\n                  list2: List(b),\n                  with fun: fn(a, b) -> c,\n                ) -> List(c) { todo }\n            \"\n        ),\n        find_position_of(\"fn(\").select_until(find_position_of(\"}\"))\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5263\n#[test]\nfn interpolate_string_allows_extracting_record_access_syntax() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble.some_field woo\"\n}\"#,\n        find_position_of(\"wobble\").select_until(find_position_of(\"some_field \").under_last_char()),\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5299\n#[test]\nfn generate_dynamic_decoder_produces_zero_values_for_prelude_and_stdlib_types() {\n    let src = r#\"\nimport gleam/option\nimport gleam/dict\n\npub type Wobble {\n  Wobble(\n    bit_array: BitArray,\n    int: Int,\n    float: Float,\n    bool: Bool,\n    list: List(Int),\n    string: String,\n    nil: Nil,\n    option: option.Option(String),\n    dict: dict.Dict(Int, Bool),\n  )\n  Dummy(\n    a: Int,\n    b: Int,\n    c: Int,\n    d: Int,\n    e: Int,\n    f: Int,\n    g: Int,\n    h: Int,\n    i: Int,\n    j: Int,\n  )\n}\n    \"#;\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src)\n            .add_hex_module(\"gleam/option\", \"pub type Option(a) { Some(a) None }\")\n            .add_hex_module(\"gleam/dict\", \"pub type Dict(key, value)\"),\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn interpolate_string_does_not_add_empty_string_right_at_the_start() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"wibble \").select_until(find_position_of(\"wibble \").under_last_char()),\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_1() {\n    let src = r#\"\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Int)\n}\n    \"#;\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src).add_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn interpolate_string_does_not_add_empty_string_right_at_the_end() {\n    assert_code_action!(\n        INTERPOLATE_STRING,\n        r#\"pub fn main() {\n  \"wibble wobble woo\"\n}\"#,\n        find_position_of(\"woo\\\"\").select_until(find_position_of(\"woo\\\"\").under_last_char()),\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_2() {\n    let src = r#\"\nimport internal/wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Int)\n}\n    \"#;\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src)\n            .add_module(\n                \"internal/wibble\",\n                r#\"\nimport internal/nested_wibble.{type NestedWibble}\npub type Wibble { Wibble(value: NestedWibble) }\n\"#\n            )\n            .add_module(\n                \"internal/nested_wibble\",\n                r#\"\npub type NestedWibble { NestedWibble }\n\"#\n            ),\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_3() {\n    let src = r#\"\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Int)\n}\n    \"#;\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src)\n            .add_module(\n                \"wibble\",\n                r#\"\nimport gleam/dict.{type Dict}\npub type Wibble { Wibble(map: Dict(Int, Bool)) }\n\"#\n            )\n            .add_hex_module(\n                \"gleam/dict\",\n                r#\"\npub type Dict(key, value)\npub fn new() -> Dict(k, v) { todo }\n\"#\n            ),\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_does_not_produce_zero_values_for_types_from_other_packages() {\n    let src = r#\"\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Wibble)\n}\n    \"#;\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_skips_over_recursive_constructors_when_generating_zero_values() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        r#\"\npub type Wobble {\n  Wobble(inside: Wobble)\n  Dummy(a: Int, b: Int)\n}\n    \"#,\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_skips_over_mutually_recursive_constructors_when_generating_zero_values()\n{\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        r#\"\npub type Wobble {\n  Wobble(inside: Wibble)\n  DummyWobble(a: Int, b: Int)\n}\n\npub type Wibble {\n  Wibble(inside: Wobble)\n  DummyWibble(a: Int, b: Int)\n}\n    \"#,\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_uses_smallest_possible_constructor_for_zero_value() {\n    let src = r#\"\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(impossible: Wobble)\n  WibbleWobble(nope: Wibble)\n  Dummy(a: Int, b: #(Float, Float))\n}\n    \"#;\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_generates_todo_for_zero_value_when_all_constructors_fail() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        r#\"\npub type Wobble {\n  Wobble(nope: Wobble)\n  Wibble(not: Int, again: Wobble)\n}\n    \"#,\n        find_position_of(\"pub type Wobble {\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn generate_dynamic_decoder_uses_decode_success_for_nil() {\n    assert_code_action!(\n        GENERATE_DYNAMIC_DECODER,\n        r#\"\npub type Nothing {\n  No(val: Nil)\n  Nope(val: #(Nil, Nil))\n  Nothing(val: List(Nil))\n}\n    \"#,\n        find_position_of(\"pub type Nothing {\").select_until(find_position_of(\"}\"))\n    );\n}\n\n#[test]\nfn generate_to_json_function_uses_json_null_for_nil() {\n    let src = \"\nimport gleam/json\nimport gleam/dict.{type Dict}\n\n\npub type Nothing {\n  Nope(val: Nil)\n  Nothing(val1: List(Nil), val2: Dict(Int, Nil))\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src)\n            .add_package_module(\"gleam_json\", \"gleam/json\", \"pub type Json\")\n            .add_hex_module(\"gleam/dict\", \"pub type Dict(key, value)\"),\n        find_position_of(\"pub type Nothing {\")\n            .select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn generate_to_json_function_ignores_nil_and_nil_tuple_fields_with_underscore() {\n    let src = \"\nimport gleam/json\nimport gleam/dict.{type Dict}\n\n\npub type Nothing {\n  No(val: #(Nil), another: #(Nil, #(Nil, Int)))\n  Nope(val: List(#(Nil)))\n}\n\";\n\n    assert_code_action!(\n        GENERATE_TO_JSON_FUNCTION,\n        TestProject::for_source(src)\n            .add_package_module(\"gleam_json\", \"gleam/json\", \"pub type Json\")\n            .add_hex_module(\"gleam/dict\", \"pub type Dict(key, value)\"),\n        find_position_of(\"pub type Nothing {\")\n            .select_until(find_position_of(\"}\").nth_occurrence(2))\n    );\n}\n\n#[test]\nfn replace_underscore_with_function_return_type() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() -> _ {\n    12\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_nested_underscore_with_generic_type() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() -> Result(a, _) {\n    Ok(todo)\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_nested_underscore_with_function_return_type() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() -> Result(Result(_, Nil), Int) {\n    Ok(Ok(\"hello\"))\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_nested_underscore_in_let_annotation() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() {\n    let a: Result(Result(_, Nil), Nil) = Ok(Ok(\"hello\"))\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_underscore_in_let_annotation() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() {\n    let a: _ = Ok(Ok(\"hello\"))\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_nested_underscore_with_tuple_type() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() {\n    let a: #(Int, _, Int) = #(1, \"hello\", 2)\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_underscore_in_function_argument() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble(a: _) -> Int {\n    a + 2\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n\n#[test]\nfn replace_underscore_in_fn_expr_argument() {\n    assert_code_action!(\n        REPLACE_UNDERSCORE_WITH_TYPE,\n        r#\"\npub fn wibble() {\n    fn(a: _) { a + 2 }\n}\n    \"#,\n        find_position_of(\"_\").to_selection()\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/compilation.rs",
    "content": "use crate::engine::Compilation;\n\nuse super::*;\n\n#[test]\nfn compile_please() {\n    let io = LanguageServerTestIO::new();\n    let mut engine = setup_engine(&io);\n\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![]));\n\n    drop(engine);\n    let actions = io.into_actions();\n    assert_eq!(\n        actions,\n        vec![\n            // new\n            Action::DependencyDownloadingStarted,\n            Action::DownloadDependencies,\n            Action::DependencyDownloadingFinished,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n        ]\n    )\n}\n\n#[test]\nfn compile_error_in_src() {\n    let io = LanguageServerTestIO::new();\n    let mut engine = setup_engine(&io);\n\n    _ = io.src_module(\"app/error\", \"pub type Error {\");\n\n    let response = engine.compile_please();\n    assert!(response.result.is_err());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![]));\n\n    drop(engine);\n    let actions = io.into_actions();\n    assert_eq!(\n        actions,\n        vec![\n            // new\n            Action::DependencyDownloadingStarted,\n            Action::DownloadDependencies,\n            Action::DependencyDownloadingFinished,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n        ]\n    )\n}\n\n#[test]\nfn compile_error_in_test() {\n    let io = LanguageServerTestIO::new();\n    let mut engine = setup_engine(&io);\n\n    _ = io.test_module(\"app/error\", \"pub type Error {\");\n\n    let response = engine.compile_please();\n    assert!(response.result.is_err());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![]));\n\n    drop(engine);\n    let actions = io.into_actions();\n    assert_eq!(\n        actions,\n        vec![\n            // new\n            Action::DependencyDownloadingStarted,\n            Action::DownloadDependencies,\n            Action::DependencyDownloadingFinished,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n        ]\n    )\n}\n\n#[test]\nfn compile_error_in_dev() {\n    let io = LanguageServerTestIO::new();\n    let mut engine = setup_engine(&io);\n\n    _ = io.dev_module(\"app/error\", \"pub type Error {\");\n\n    let response = engine.compile_please();\n    assert!(response.result.is_err());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![]));\n\n    drop(engine);\n    let actions = io.into_actions();\n    assert_eq!(\n        actions,\n        vec![\n            // new\n            Action::DependencyDownloadingStarted,\n            Action::DownloadDependencies,\n            Action::DependencyDownloadingFinished,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n        ]\n    )\n}\n\n#[test]\nfn compile_recompile() {\n    let io = LanguageServerTestIO::new();\n    let mut engine = setup_engine(&io);\n\n    let path = io.src_module(\"app\", \"pub fn main() { 0 }\");\n\n    // The first time it compiles.\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![path.clone()]));\n\n    // The source file has been updated, so the file is compiled again.\n    _ = io.src_module(\"app\", \"pub fn main() { 1 }\");\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![path]));\n\n    // This time it does not compile the module again, instead using the\n    // cache from the previous run.\n    let response = engine.compile_please();\n    assert_eq!(response.result, Ok(()));\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![]));\n\n    drop(engine);\n    let actions = io.into_actions();\n    assert_eq!(\n        actions,\n        vec![\n            // new\n            Action::DependencyDownloadingStarted,\n            Action::DownloadDependencies,\n            Action::DependencyDownloadingFinished,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n        ]\n    )\n}\n\n#[test]\nfn dep_compile_recompile() {\n    let io = LanguageServerTestIO::new();\n    let mut engine = setup_engine(&io);\n    add_path_dep(&mut engine, \"mydep\");\n\n    let path = io.path_dep_module(\"mydep\", \"moddy\", \"pub fn main() { 0 }\");\n\n    // The first time it compiles.\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![path.clone()]));\n\n    assert!(!engine.compiler.project_compiler.packages.is_empty());\n\n    // The source file has been updated, so the file is compiled again.\n    _ = io.path_dep_module(\"mydep\", \"moddy\", \"pub fn main() { 1 }\");\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![path]));\n\n    // This time it does not compile the module again, instead using the\n    // cache from the previous run.\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n    assert!(response.warnings.is_empty());\n    assert_eq!(response.compilation, Compilation::Yes(vec![]));\n\n    drop(engine);\n    let actions = io.into_actions();\n    assert_eq!(\n        actions,\n        vec![\n            // new\n            Action::DependencyDownloadingStarted,\n            Action::DownloadDependencies,\n            Action::DependencyDownloadingFinished,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n            // compile_please\n            Action::CompilationStarted,\n            Action::LockBuild,\n            Action::UnlockBuild,\n            Action::CompilationFinished,\n        ]\n    )\n}\n"
  },
  {
    "path": "language-server/src/tests/completion.rs",
    "content": "use insta::assert_debug_snapshot;\nuse itertools::Itertools;\nuse lsp_types::{CompletionItem, Position};\n\nuse super::*;\n\npub fn show_complete(code: &str, position: Position) -> String {\n    let mut str: String = \"\".into();\n    for (line_number, line) in code.lines().enumerate() {\n        let same_line = line_number as u32 == position.line;\n        if !same_line {\n            str.push_str(line);\n        } else {\n            str.push_str(&line[0..position.character as usize]);\n            str.push('|');\n            str.push_str(&line[position.character as usize..]);\n        }\n\n        str.push('\\n');\n    }\n\n    str\n}\n\nfn apply_completion(src: &str, completions: Vec<CompletionItem>, value: &str) -> String {\n    let completion = completions\n        .iter()\n        .find(|c| c.label == value)\n        .unwrap_or_else(|| panic!(\"no completion with value `{value}`\"));\n\n    let mut edits = vec![];\n    if let Some(lsp_types::CompletionTextEdit::Edit(edit)) = &completion.text_edit {\n        edits.push(edit.clone());\n    }\n    apply_code_edit(src, edits)\n}\n\n#[macro_export]\nmacro_rules! assert_apply_completion {\n    ($project:expr, $name:literal, $position:expr) => {\n        let src = $project.src;\n        let completions = completion($project, $position);\n        let output = format!(\n            \"{}\\n\\n----- After applying completion -----\\n{}\",\n            show_complete(src, $position),\n            apply_completion(src, completions, $name)\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_completion {\n    ($project:expr) => {\n        let src = $project.src;\n        let result = completion_with_prefix($project, \"\");\n        let output = format!(\n            \"{}\\n\\n----- Completion content -----\\n{}\",\n            show_complete(src, Position::new(0, 0)),\n            format_completion_results(result)\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n    ($project:expr, $position:expr) => {\n        let src = $project.src;\n        let result = completion($project, $position);\n        let output = format!(\n            \"{}\\n\\n----- Completion content -----\\n{}\",\n            show_complete(src, $position),\n            format_completion_results(result)\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_completion_with_prefix {\n    ($project:expr, $prefix:expr) => {\n        let src = $project.src;\n        let result = completion_with_prefix($project, $prefix);\n        let line = 1 + $prefix.lines().count();\n        let output = format!(\n            \"{}\\n\\n----- Completion content -----\\n{}\",\n            show_complete(src, Position::new(line as u32, 0)),\n            format_completion_results(result)\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\nfn format_completion_results(completions: Vec<CompletionItem>) -> EcoString {\n    use std::fmt::Write;\n    let mut buffer: EcoString = \"\".into();\n\n    for CompletionItem {\n        label,\n        label_details,\n        kind,\n        detail,\n        documentation,\n        deprecated,\n        preselect,\n        sort_text,\n        filter_text,\n        insert_text,\n        insert_text_format,\n        insert_text_mode,\n        text_edit,\n        additional_text_edits,\n        command,\n        commit_characters,\n        data,\n        tags,\n    } in completions\n    {\n        assert!(deprecated.is_none());\n        assert!(preselect.is_none());\n        assert!(filter_text.is_none());\n        assert!(insert_text.is_none());\n        assert!(insert_text_format.is_none());\n        assert!(insert_text_mode.is_none());\n        assert!(command.is_none());\n        assert!(commit_characters.is_none());\n        assert!(data.is_none());\n        assert!(tags.is_none());\n\n        buffer.push_str(&label);\n\n        if let Some(kind) = kind {\n            write!(buffer, \"\\n  kind:   {kind:?}\").unwrap();\n        }\n\n        if let Some(detail) = detail {\n            write!(buffer, \"\\n  detail: {detail}\").unwrap();\n        }\n\n        if let Some(sort_text) = sort_text {\n            write!(buffer, \"\\n  sort:   {sort_text}\").unwrap();\n        }\n\n        if let Some(label_details) = label_details {\n            assert!(label_details.detail.is_none());\n            if let Some(desc) = label_details.description {\n                write!(buffer, \"\\n  desc:   {desc}\").unwrap();\n            }\n        }\n\n        if let Some(documentation) = documentation {\n            let lsp_types::Documentation::MarkupContent(m) = documentation else {\n                panic!(\"unexpected docs in test {documentation:?}\");\n            };\n            match m.kind {\n                lsp_types::MarkupKind::Markdown => (),\n                lsp_types::MarkupKind::PlainText => {\n                    panic!(\"unexpected docs markup kind {:?}\", m.kind)\n                }\n            };\n            write!(buffer, \"\\n  docs:   {:?}\", m.value).unwrap();\n        }\n\n        let edit = |buffer: &mut EcoString, e: lsp_types::TextEdit| {\n            let a = e.range.start.line;\n            let b = e.range.start.character;\n            let c = e.range.end.line;\n            let d = e.range.end.character;\n            write!(buffer, \"\\n    [{a}:{b}-{c}:{d}]: {:?}\", e.new_text).unwrap();\n        };\n\n        if let Some(text_edit) = text_edit {\n            let lsp_types::CompletionTextEdit::Edit(e) = text_edit else {\n                panic!(\"unexpected text edit in test {text_edit:?}\");\n            };\n            buffer.push_str(\"\\n  edits:\");\n            edit(&mut buffer, e);\n        }\n\n        for e in additional_text_edits.unwrap_or_default() {\n            edit(&mut buffer, e);\n        }\n\n        buffer.push('\\n');\n    }\n\n    buffer\n}\n\nfn completion(tester: TestProject<'_>, position: Position) -> Vec<CompletionItem> {\n    tester.at(position, |engine, param, src| {\n        let response = engine.completion(param, src);\n\n        let mut completions = response.result.unwrap().unwrap_or_default();\n        completions.sort_by(|a, b| a.label.cmp(&b.label));\n        completions\n    })\n}\n\nfn completion_with_prefix(tester: TestProject<'_>, prefix: &str) -> Vec<CompletionItem> {\n    let src = &format!(\"{}fn typing_in_here() {{\\n  0\\n}}\\n {}\", prefix, tester.src);\n    let tester = TestProject { src, ..tester };\n    // Put the cursor inside the \"typing_in_here\" fn body.\n    let line = 1 + prefix.lines().count();\n    completion(tester, Position::new(line as u32, 0))\n        .into_iter()\n        .filter(|c| c.label != \"typing_in_here\")\n        .collect_vec()\n}\n\n#[test]\nfn completions_for_outside_a_function() {\n    let code = \"\n\npub fn main() {\n  0\n}\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(0, 0));\n}\n\n#[test]\nfn local_public_function() {\n    let code = \"\npub fn main() {\n  0\n}\";\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn local_public_function_with_documentation() {\n    let code = \"\n/// Hello\npub fn main() {\n  0\n}\";\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn local_public_enum() {\n    let code = \"\npub type Direction {\n  Left\n  Right\n}\n\";\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn local_public_record() {\n    let code = \"\npub type Box {\n/// Hello\n  Box(Int, Int, Float)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn local_public_enum_with_documentation() {\n    let code = \"\npub type Direction {\n  /// Hello\n  Left\n  /// Goodbye\n  Right\n}\n\";\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn local_public_record_with_documentation() {\n    let code = \"\npub type Box {\n  Box(Int, Int, Float)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn imported_module_function() {\n    let code = \"\nimport dep\n\";\n    let dep = \"\npub fn wobble() {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn importable_module_function() {\n    let code = \"\n\";\n    let dep = \"\npub fn wobble() {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn importable_module_function_with_existing_imports() {\n    let code = \"\n//// Some module comments\n// Some other whitespace\n\nimport dep2\n\";\n    let dep = \"\npub fn wobble() {\n  Nil\n}\n\";\n    let dep2 = \"\npub fn wobble() {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"dep2\", dep2)\n    );\n}\n\n#[test]\nfn importable_module_function_from_deep_module() {\n    let code = \"\n\";\n    let dep = \"\npub fn wobble() {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"a/b/dep\", dep));\n}\n\n#[test]\nfn completions_for_type_import_completions_without_brackets() {\n    let src = \"import dep.\";\n    let dep = \"\npub opaque type Wibble {\n  Wibble(wibble: String, wobble: Int)\n}\n\";\n    let position = Position::new(0, 11);\n    let tester = TestProject::for_source(\"import dep\").add_module(\"dep\", dep);\n    let mut io = LanguageServerTestIO::new();\n    let mut engine = tester.build_engine(&mut io);\n    // pass a valid src to compile once\n    _ = io.src_module(\"app\", tester.src);\n    let _ = engine.compile_please();\n    // update src to the one we want to test\n    _ = io.src_module(\"app\", src);\n    let param = tester.build_path(position);\n    let response = engine.completion(param, src.into());\n\n    let mut completions = response.result.unwrap().unwrap_or_default();\n    completions.sort_by(|a, b| a.label.cmp(&b.label));\n    let output = format!(\n        \"{}\\n\\n----- Completion content -----\\n{}\",\n        show_complete(src, position),\n        format_completion_results(completions)\n    );\n    insta::assert_snapshot!(insta::internals::AutoName, output, src);\n}\n\n#[test]\nfn importable_adds_extra_new_line_if_no_imports() {\n    let dep = \"pub fn wobble() {\\nNil\\n}\";\n    let code = \"\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn importable_adds_extra_new_line_if_import_exists_below_other_definitions() {\n    let dep = \"pub fn wobble() {\\nNil\\n}\";\n    let code = \"\\nimport dep2\\n\"; // \"code\" goes after \"fn typing_in_here() {}\".\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"dep2\", \"\")\n    );\n}\n\n#[test]\nfn importable_does_not_add_extra_new_line_if_imports_exist() {\n    let dep = \"pub fn wobble() {\\nNil\\n}\";\n    let prefix = \"import wibble\\n\\n\";\n    let code = \"\";\n\n    assert_completion_with_prefix!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"wibble\", \"\"),\n        prefix\n    );\n}\n\n#[test]\nfn importable_does_not_add_extra_new_line_if_newline_exists() {\n    let dep = \"pub fn wobble() {\\nNil\\n}\";\n    let prefix = \"\\n\";\n    let code = \"\";\n\n    assert_completion_with_prefix!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"wibble\", \"\"),\n        prefix\n    );\n}\n\n#[test]\nfn imported_public_enum() {\n    let code = \"\nimport dep\n\";\n    let dep = \"\npub type Direction {\n  Left\n  Right\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn imported_public_record() {\n    let code = \"\nimport dep\n\";\n    let dep = \"\npub type Box {\n  Box(Int)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn imported_unqualified_module_function() {\n    let code = \"\nimport dep.{wobble}\n\";\n    let dep = \"\npub fn wobble() {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn imported_unqualified_public_enum() {\n    let code = \"\nimport dep.{Left}\n\";\n    let dep = \"\npub type Direction {\n  Left\n  Right\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn imported_unqualified_public_record() {\n    let code = \"\nimport dep.{Box}\n\";\n    let dep = \"\npub type Box {\n  Box(Int)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn private_function() {\n    let code = \"\nfn private() {\n  1\n}\n\";\n    let dep = \"\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn private_type() {\n    let code = \"\ntype Wibble {\n  Wobble\n}\n\";\n    let dep = \"\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn opaque_type() {\n    let code = \"\npub opaque type Wibble {\n  Wobble\n}\n\";\n    let dep = \"\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn private_function_in_dep() {\n    let code = \"import dep\";\n    let dep = \"\nfn private() {\n  1\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn private_type_in_dep() {\n    let code = \"import dep\";\n    let dep = \"\ntype Wibble {\n  Wobble\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn in_custom_type_definition() {\n    let code = \"import dep\";\n    let dep = \"\ntype Wibble {\n  Wobble\n}\n\";\n\n    assert_completion!(TestProject::for_source(code).add_module(\"dep\", dep));\n}\n\n#[test]\nfn for_custom_type_definition() {\n    let code = \"\npub type Wibble {\n  Wobble\n}\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 0));\n}\n\n#[test]\nfn for_type_alias() {\n    let code = \"\npub type Wibble = Result(\n  String,\n  String\n)\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 0));\n}\n\n#[test]\nfn for_function_arguments() {\n    let code = \"\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 0));\n}\n\n#[test]\nfn imported_type() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep\n\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn imported_type_cursor_after_dot() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep\n\npub fn wibble(\n  _: dep.Zoo,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(3, 12)\n    );\n}\n\n#[test]\nfn imported_type_cursor_after_dot_other_matching_modules() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let dep2 = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep\nimport dep2\n\npub fn wibble(\n  _: dep.Zoo,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"dep2\", dep2),\n        Position::new(4, 12)\n    );\n}\n\n#[test]\nfn imported_type_cursor_after_dot_other_modules() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let other = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep\n\npub fn wibble(\n  _: dep.Zoo,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"other\", other),\n        Position::new(3, 12)\n    );\n}\n\n#[test]\nfn imported_type_cursor_mid_phrase_other_modules() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let other = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep\n\npub fn wibble(\n  _: dep.Zoo,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"other\", other),\n        Position::new(3, 8)\n    );\n}\n\n#[test]\nfn importable_type() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"\n\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn importable_type_with_existing_imports_at_top() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let dep2 = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep2\n\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"dep2\", dep2),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn importable_type_with_existing_imports() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let dep2 = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"\n//// Some module comments\n// Some other whitespace\n\nimport dep2\n\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_module(\"dep\", dep)\n            .add_module(\"dep2\", dep2),\n        Position::new(7, 0)\n    );\n}\n\n#[test]\nfn importable_type_from_deep_module() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"\n\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"a/b/dep\", dep),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn unqualified_imported_type() {\n    let dep = \"\npub type Zoo = List(String)\ntype Private = List(String)\n\";\n    let code = \"import dep.{type Zoo}\n\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn local_private_type() {\n    let code = \"\ntype Zoo = Int\n\npub fn wibble(\n  x: String,\n) -> String {\n  \\\"ok\\\"\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 0));\n}\n\n#[test]\nfn local_variable() {\n    let code = \"\npub fn main(wibble: Int) {\n  let wobble = 1\n  w\n\n  let wabble = 2\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 3));\n}\n\n#[test]\nfn local_variable_anonymous_function() {\n    let code = \"\npub fn main() {\n  let add_one = fn(wibble: Int) { wibble + 1 }\n  add_one(1)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 40));\n}\n\n#[test]\nfn local_variable_nested_anonymous_function() {\n    let code = \"\npub fn main() {\n  let add_one = fn(wibble: Int) {\n    let wabble = 1\n    let add_two = fn(wobble: Int) { wobble + 2 }\n    wibble + add_two(1)\n  }\n  add_one(1)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 42));\n}\n\n#[test]\nfn local_variable_ignore_anonymous_function_args() {\n    let code = \"\npub fn main() {\n  let add_one = fn(wibble: Int) { wibble + 1 }\n  let wobble = 1\n  w\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 3));\n}\n\n#[test]\nfn local_variable_ignore_anonymous_function_args_nested() {\n    let code = \"\npub fn main() {\n  let add_one = fn(wibble: Int) {\n    let wabble = 1\n    let add_two = fn(wobble: Int) { wobble + 2 }\n    wibble + add_two(1)\n  }\n  add_one(1)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 10));\n}\n\n#[test]\nfn local_variable_ignore_anonymous_function_returned() {\n    let code = \"\npub fn main() {\n  fn(wibble: Int) {\n    let wabble = 1\n    let add_two = fn(wobble: Int) { wobble + 2 }\n    wibble + add_two(1)\n  }\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 10));\n}\n\n#[test]\nfn local_variable_case_expression() {\n    let code = \"\npub fn main() {\n  case True {\n    True as wibble -> { todo }\n    False -> { todo }\n  }\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 25));\n}\n\n#[test]\nfn local_variable_inside_nested_exprs() {\n    let code = r#\"\ntype Wibble { Wobble(List(#(Bool))) }\nfn wibble() {\n  Wobble([#(!{\n    let wibble = True\n    wibble\n  })])\n  todo\n}\n\"#;\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 7));\n}\n\n#[test]\nfn local_variable_pipe() {\n    let code = \"\npub fn main() {\n  let add_one = fn(wibble: Int) { wibble + 1 }\n  let wobble = 1\n  wobble |> add_one\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 19));\n}\n\n#[test]\nfn local_variable_pipe_with_args() {\n    let code = \"\npub fn main() {\n  let add_one = fn(wibble: Int, wobble: Int) { wibble + wobble }\n  let wobble = 1\n  let wibble = 2\n  wobble |> add_one(1, wibble)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 29));\n}\n\n#[test]\nfn local_variable_function_call() {\n    let code = \"\nfn add_one(wibble: Int) -> Int {\n  wibble + 1\n}\n\npub fn main() {\n  let wobble = 1\n  add_one(wobble)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(7, 16));\n}\n\n#[test]\nfn local_variable_ignored() {\n    let code = \"\nfn wibble() {\n  let a = 1\n  let _b = 2\n\n}\n\";\n    assert_completion!(TestProject::for_source(code), Position::new(4, 0));\n}\n\n#[test]\nfn local_variable_as() {\n    let code = \"\nfn wibble() {\n  let b as c = 5\n\n}\n\";\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n#[test]\nfn local_variable_tuple() {\n    let code = \"\nfn wibble() {\n  let assert #([d, e] as f, g) = #([0, 1], 2)\n\n}\n\";\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n#[test]\nfn local_variable_bit_array() {\n    let code = \"\nfn wibble() {\n  let assert <<h:1>> as i = <<1:1>>\n\n}\n\";\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n#[test]\nfn local_variable_string() {\n    let code = r#\"\nfn wibble() {\n  let assert \"a\" <> j = \"ab\"\n\n}\n\"#;\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n#[test]\nfn local_variable_ignore_within_function() {\n    let code = \"\nfn main(a, b, z) {\n    Nil\n}\n\";\n    assert_completion!(TestProject::for_source(code), Position::new(1, 14));\n}\n\n#[test]\nfn internal_values_from_root_package_are_in_the_completions() {\n    let dep = r#\"\n@external(erlang, \"rand\", \"uniform\")\n@internal pub fn random_float() -> Float\n@internal pub fn main() { 0 }\n@internal pub type Wibble { Wobble }\n@internal pub const wibble = 1\n\"#;\n\n    assert_completion!(TestProject::for_source(\"import dep\").add_module(\"dep\", dep));\n}\n\n#[test]\nfn internal_types_from_root_package_are_in_the_completions() {\n    let code = \"import dep\n\npub fn wibble(\n    _: String,\n) -> Nil {\n    Nil\n}\";\n\n    let dep = r#\"\n@internal pub type Alias = Int\n@internal pub type AnotherType { Constructor }\n\"#;\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn internal_values_from_the_same_module_are_in_the_completions() {\n    let code = r#\"\n@external(erlang, \"rand\", \"uniform\")\n@internal pub fn random_float() -> Float\n@internal pub fn main() { 0 }\n@internal pub type Wibble { Wobble }\n@internal pub const wibble = 1\n\"#;\n\n    assert_completion!(TestProject::for_source(code));\n}\n\n#[test]\nfn internal_types_from_the_same_module_are_in_the_completions() {\n    let code = \"\n@internal pub type Alias = Result(Int, String)\n@internal pub type AnotherType {\n  Wibble\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n#[test]\nfn internal_types_from_a_dependency_are_ignored() {\n    let code = \"import dep\n\npub fn wibble(\n    _: String,\n) -> Nil {\n    Nil\n}\";\n\n    let dep = r#\"\n@internal pub type Alias = Int\n@internal pub type AnotherType { Constructor }\n\"#;\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn internal_values_from_a_dependency_are_ignored() {\n    let dep = r#\"\n@external(erlang, \"rand\", \"uniform\")\n@internal pub fn random_float() -> Float\n@internal pub fn main() { 0 }\n@internal pub type Wibble { Wobble }\n@internal pub const wibble = 1\n\"#;\n\n    assert_completion!(TestProject::for_source(\"import dep\").add_dep_module(\"dep\", dep));\n}\n\n#[test]\nfn completions_for_an_import() {\n    let code = \"import dep\n\npub fn main() {\n  0\n}\";\n    let dep = \"\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(0, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_no_test() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let test = \"\nimport gleam\n\npub fn main() {\n  0\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_test_module(\"my_tests\", test),\n        Position::new(0, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_while_in_test() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let test = \"\nimport gleam\n\npub fn main() {\n  0\n}\n\";\n    let test_helper = \"\npub fn test_helper() {\n  0\n}\n\";\n\n    let (mut engine, position_param) = TestProject::for_source(code)\n        .add_test_module(\"my_test\", test)\n        .add_test_module(\"test_helper\", test_helper)\n        .positioned_with_io_in_test(Position::new(0, 10), \"my_test\");\n\n    let response = engine.completion(position_param, code.into());\n\n    let mut completions = response.result.unwrap().unwrap_or_default();\n    completions.sort_by(|a, b| a.label.cmp(&b.label));\n\n    assert_debug_snapshot!(completions,);\n}\n\n#[test]\nfn completions_for_an_import_while_in_dev() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dev_helper = \"\npub fn dev_helper() {\n  0\n}\n\";\n\n    let position = Position::new(0, 12);\n    let (mut engine, position_param) = TestProject::for_source(code)\n        .add_test_module(\"my_test\", code)\n        .add_dev_module(\"my_dev_code\", code)\n        .add_dev_module(\"dev_helper\", dev_helper)\n        .positioned_with_io_in_dev(position, \"my_dev_code\");\n\n    let response = engine.completion(position_param, code.into());\n\n    let mut completions = response.result.unwrap().unwrap_or_default();\n    completions.sort_by(|a, b| a.label.cmp(&b.label));\n\n    let output = format!(\n        \"{}\\n\\n----- Completion content -----\\n{}\",\n        show_complete(code, position),\n        format_completion_results(completions)\n    );\n    insta::assert_snapshot!(insta::internals::AutoName, output, code);\n}\n\n#[test]\nfn completions_for_an_import_with_docs() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"//// Some package\n//// documentation!\n\npub fn main() { 1 }\n    \";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(0, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_from_dependency() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", dep),\n        Position::new(0, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_not_from_indirect_dependency() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_hex_module(\"example_module\", dep)\n            .add_indirect_hex_module(\"indirect_module\", \"\"),\n        Position::new(0, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_not_from_dev_dependency() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_hex_module(\"example_module\", dep)\n            .add_dev_hex_module(\"indirect_module\", \"\"),\n        Position::new(0, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_not_from_dev_dependency_in_test() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let test = \"import gleam\n\npub fn main() {\n  0\n}\n\";\n    let dep = \"\";\n\n    let (mut engine, position_param) = TestProject::for_source(code)\n        .add_test_module(\"my_test\", test)\n        .add_hex_module(\"example_module\", dep)\n        .add_dev_hex_module(\"indirect_module\", \"\")\n        .positioned_with_io_in_test(Position::new(0, 10), \"my_test\");\n\n    let response = engine.completion(position_param, code.into());\n\n    let mut completions = response.result.unwrap().unwrap_or_default();\n    completions.sort_by(|a, b| a.label.cmp(&b.label));\n\n    assert_debug_snapshot!(completions,);\n}\n\n#[test]\nfn completions_for_an_import_not_from_dev_dependency_in_dev() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dev = \"import gleam\n\npub fn main() {\n  0\n}\n\";\n    let dep = \"\";\n\n    let position = Position::new(0, 10);\n    let (mut engine, position_param) = TestProject::for_source(code)\n        .add_dev_module(\"my_dev_module\", dev)\n        .add_hex_module(\"example_module\", dep)\n        .add_dev_hex_module(\"indirect_module\", \"\")\n        .positioned_with_io_in_dev(position, \"my_dev_module\");\n\n    let response = engine.completion(position_param, code.into());\n\n    let mut completions = response.result.unwrap().unwrap_or_default();\n    completions.sort_by(|a, b| a.label.cmp(&b.label));\n\n    let output = format!(\n        \"{}\\n\\n----- Completion content -----\\n{}\",\n        show_complete(dev, position),\n        format_completion_results(completions)\n    );\n    insta::assert_snapshot!(insta::internals::AutoName, output, dev);\n}\n\n#[test]\nfn completions_for_an_import_from_dependency_with_docs() {\n    let code = \"//// Main package\n//// documentation!\n\nimport gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"//// Some package\n//// documentation!\n\npub fn main() { 1 }\n    \";\n\n    assert_completion!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", dep),\n        Position::new(3, 10)\n    );\n}\n\n#[test]\nfn completions_for_an_import_start() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(0, 0)\n    );\n}\n\n#[test]\nfn completions_for_an_import_preceeding_whitespace() {\n    let code = \" import gleam\n\npub fn main() {\n  0\n}\";\n    let dep = \"\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(0, 2)\n    );\n}\n\n#[test]\nfn internal_modules_from_same_package_are_included() {\n    let code = \"import gleam\n\npub fn main() {\n  0\n}\";\n    let internal_name = format!(\"{LSP_TEST_ROOT_PACKAGE_NAME}/internal\");\n\n    assert_completion!(\n        TestProject::for_source(code)\n            // Not included\n            .add_dep_module(\"dep/internal\", \"\")\n            // Included\n            .add_module(&internal_name, \"\"),\n        Position::new(0, 0)\n    );\n}\n\n#[test]\nfn completions_for_an_unqualified_import() {\n    let code = \"\nimport dep.{}\n\npub fn main() {\n  0\n}\";\n    let dep = \"pub const wibble = \\\"wibble\\\"\nconst wobble = \\\"wobble\\\"\n@internal\npub const wabble = \\\"wabble\\\"\n\npub fn myfun() {\n    0\n}\n\npub type Wibble = String\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(1, 12)\n    );\n}\n\n#[test]\nfn completions_for_an_unqualified_import_on_new_line() {\n    let code = \"\nimport dep.{\n  wibble,\n\n}\n\npub fn main() {\n  0\n}\";\n    let dep = \"pub const wibble = \\\"wibble\\\"\n\npub fn myfun() {\n    0\n}\n\npub type Wibble = String\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        // putting cursor at beginning of line because some formatters\n        // remove the empty whitespace in the test code.\n        // Does also work with (3, 2) when empty spaces are not removed.\n        Position::new(3, 0)\n    );\n}\n\n#[test]\nfn completions_for_an_unqualified_import_already_imported() {\n    let code = \"\nimport dep.{wibble,wabble,type Wibble}\n\npub fn main() {\n  0\n}\";\n    let dep = \"pub const wibble = \\\"wibble\\\"\nconst wobble = \\\"wobble\\\"\n@internal\npub const wabble = \\\"wabble\\\"\n\npub fn myfun() {\n    0\n}\n\npub type Wibble = String\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_module(\"dep\", dep),\n        Position::new(1, 12)\n    );\n}\n\n#[test]\nfn completions_for_a_function_arg_annotation() {\n    let code = \"\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 11));\n}\n\n#[test]\nfn completions_for_a_function_return_annotation() {\n    let code = \"\npub fn wibble(\n  _: String,\n) -> Nil {\n  Nil\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 7));\n}\n\n#[test]\nfn completions_for_a_var_annotation() {\n    let code = \"\npub fn main() {\n  let wibble: Int = 7\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 16));\n}\n\n#[test]\nfn completions_for_a_const_annotation() {\n    let code = \"\n\nconst wibble: Int = 7\n\npub fn main() {\n  let wibble: Int = 7\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 16));\n}\n\n#[test]\nfn ignore_completions_in_empty_comment() {\n    // Reproducing issue #2161\n    let code = \"\npub fn main() {\n  case 0 {\n    //\n    _ -> 1\n  }\n}\n\";\n\n    // End of the comment (right after the last `/`)\n    assert_eq!(\n        completion(TestProject::for_source(code), Position::new(3, 6)),\n        vec![],\n    );\n}\n\n#[test]\nfn ignore_completions_in_middle_of_comment() {\n    // Reproducing issue #2161\n    let code = \"\npub fn main() {\n  case 0 {\n    // comment\n    _ -> 1\n  }\n}\n\";\n\n    // At `c`\n    assert_eq!(\n        completion(TestProject::for_source(code), Position::new(3, 7)),\n        vec![],\n    );\n}\n\n#[test]\nfn ignore_completions_in_end_of_comment() {\n    // Reproducing issue #2161\n    let code = \"\npub fn main() {\n  case 0 {\n    // comment\n    _ -> 1\n  }\n}\n\";\n\n    // End of the comment (after `t`)\n    assert_eq!(\n        completion(TestProject::for_source(code), Position::new(3, 14)),\n        vec![],\n    );\n}\n\n#[test]\nfn ignore_completions_inside_empty_string() {\n    let code = \"\npub fn main() {\n  \\\"\\\"\n}\n\";\n\n    assert_eq!(\n        completion(TestProject::for_source(code), Position::new(2, 2)),\n        vec![],\n    );\n}\n\n#[test]\nfn ignore_completions_inside_string() {\n    let code = \"\npub fn main() {\n  \\\"Ok()\\\"\n}\n\";\n\n    assert_eq!(\n        completion(TestProject::for_source(code), Position::new(2, 5)),\n        vec![],\n    );\n}\n\n#[test]\nfn completions_for_record_access() {\n    let code = \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int)\n  Wobble(wabble: Int, wobble: Int)\n}\n\nfn fun() {\n  let wibble = Wibble(1, 2)\n  wibble.wobble\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(8, 15));\n}\n\n#[test]\nfn completions_for_private_record_access() {\n    let code = \"\ntype Wibble {\n  Wibble(wibble: Int, wobble: Int)\n  Wobble(wabble: Int, wobble: Int)\n}\n\nfn fun() {\n  let wibble = Wibble(1, 2)\n  wibble.wobble\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(8, 15));\n}\n\n#[test]\nfn completions_for_record_access_known_variant() {\n    let code = \"\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int, d: Int)\n  Wobble(z: Bool)\n}\n\nfn fun(some_wibble: Wibble) {\n  case some_wibble {\n    Wibble(..) as w -> w.a\n    Wobble(..) -> panic\n  }\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(8, 26));\n}\n\n#[test]\nfn completions_for_record_access_unknown_variant() {\n    let code = \"\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int, d: Int)\n  Wobble(a: Int, z: Bool)\n}\n\nfn fun(some_wibble: Wibble) {\n  some_wibble.a\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(7, 15));\n}\n\n#[test]\nfn completions_for_record_labels() {\n    let code = \"\npub type Wibble {\n  Wibble(wibble: String, wobble: Int)\n}\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = Wibble()\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(6, 22));\n}\n\n#[test]\nfn completions_for_imported_record_labels() {\n    let code = \"\nimport dep\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = dep.Wibble()\n}\n\";\n    let dep = \"\npub type Wibble {\n  Wibble(wibble: String, wobble: Int)\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(4, 26)\n    );\n}\n\n#[test]\nfn no_completions_for_imported_internal_record_fields() {\n    let code = \"\nimport dep\n\nfn fun(wibble: dep.Wibble) {\n  wibble.\n  //     ^ We should see no completions here!\n}\n\";\n    let dep = \"\n@internal\npub type Wibble {\n  Wibble(wibble: String, wobble: Int)\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(4, 9)\n    );\n}\n\n#[test]\nfn completions_for_internal_record_fields_inside_the_same_module() {\n    let code = \"\n@internal\npub type Wibble {\n    Wibble(wibble: String, wobble: Int)\n}\n\nfn fun(wibble: Wibble) {\n  wibble.\n  //     ^ We should see some completions here!\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(7, 9));\n}\n\n#[test]\nfn completions_for_imported_record_fields() {\n    let code = \"\nimport dep\n\nfn fun(wibble: dep.Wibble) {\n  wibble.\n  //     ^ We should see wibble and wobble completions here!\n}\n\";\n    let dep = \"\npub type Wibble {\n  Wibble(wibble: String, wobble: Int)\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(4, 9)\n    );\n}\n\n#[test]\nfn completions_for_function_labels() {\n    let code = \"\nfn wibble(wibble arg1: String, wobble arg2: String) {\n  arg1 <> arg2\n}\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = wibble()\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(6, 22));\n}\n\n#[test]\nfn completions_for_imported_function_labels() {\n    let code = \"\nimport dep\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = dep.wibble()\n}\n\";\n    let dep = \"\npub fn wibble(wibble arg1: String, wobble arg2: String) {\n  arg1 <> arg2\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"dep\", dep),\n        Position::new(4, 26)\n    );\n}\n\n#[test]\nfn no_completion_inside_comment_that_is_more_than_three_lines() {\n    let code = \"import list\n\n// list.\n// list.\nfn fun() {\n  // list.\n  todo\n}\n\";\n\n    let dep = \"pub fn map() {}\";\n    let completions = completion(\n        TestProject::for_source(code).add_dep_module(\"list\", dep),\n        Position::new(5, 10),\n    );\n    assert_eq!(completions, vec![],);\n}\n\n#[test]\nfn completions_for_prelude_values() {\n    let code = \"\npub fn main() {\n  let my_bool = T\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 17));\n}\n\n#[test]\nfn variable_shadowing() {\n    let code = \"\npub fn main() {\n  let x = 1\n  let x = [1, 2]\n\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 0));\n}\n\n#[test]\nfn argument_shadowing() {\n    let code = \"\npub fn main(x: Int) {\n  fn(x: Float) {\n\n  }\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n#[test]\nfn argument_variable_shadowing() {\n    let code = \"\npub fn main(x: Int) {\n  let x = [1, 2]\n\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 0));\n}\n\n// https://github.com/gleam-lang/gleam/issues/3833\n#[test]\nfn autocomplete_doesnt_delete_the_piece_of_code_that_comes_after() {\n    let code = \"\nimport list\npub fn main(x: Int) {\n  list.list.filter([1, 2, 3], todo)\n}\n\";\n    let list = \"\npub fn filter(_, _) { [] }\npub fn map(_, _) { [] }\n\";\n\n    assert_apply_completion!(\n        TestProject::for_source(code).add_dep_module(\"list\", list),\n        \"list.map\",\n        Position::new(3, 7)\n    );\n}\n\n#[test]\nfn autocomplete_doesnt_delete_the_piece_of_code_that_comes_after_2() {\n    let code = \"\nimport list\npub fn main(x: Int) {\n  list.mlist.filter([1, 2, 3], todo)\n}\n\";\n    let list = \"\npub fn filter(_, _) { [] }\npub fn map(_, _) { [] }\n\";\n\n    assert_apply_completion!(\n        TestProject::for_source(code).add_dep_module(\"list\", list),\n        \"list.map\",\n        Position::new(3, 8)\n    );\n}\n\n#[test]\nfn case_subject() {\n    let code = \"\npub fn main(something: Bool) {\n  case so\n}\n\";\n\n    assert_apply_completion!(\n        TestProject::for_source(code),\n        \"something\",\n        Position::new(2, 9)\n    );\n}\n\n#[test]\nfn constant() {\n    let code = \"\nconst hello = 10\nconst world = he\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 16));\n}\n\n#[test]\nfn constant_with_many_options() {\n    let code = \"\nimport wibble.{Wobble}\n\ntype Wibble {\n  Wibble\n}\n\nconst pi = 3.14159\n\nfn some_function() {\n  todo\n}\n\nconst my_constant = a\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_hex_module(\"wibble\", \"pub type Wibble { Wobble Wubble }\"),\n        Position::new(13, 21)\n    );\n}\n\n#[test]\nfn constant_with_module_select() {\n    let code = \"\nimport wibble\n\ntype Wibble {\n  Wibble\n}\n\nconst pi = 3.14159\n\nfn some_function() {\n  todo\n}\n\nconst my_constant = wibble.W\n\";\n\n    assert_completion!(\n        TestProject::for_source(code).add_hex_module(\n            \"wibble\",\n            \"\npub type Wibble { Wobble Wubble }\npub const some_constant = 1\npub fn some_function() { todo }\n\"\n        ),\n        Position::new(13, 28)\n    );\n}\n\n#[test]\nfn labelled_arguments() {\n    let code = \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble(w)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(6, 10));\n}\n\n#[test]\nfn labelled_arguments_with_existing_label() {\n    // This should only suggest the `wobble:` label\n    let code = \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble(wibble: 10, w)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(6, 22));\n}\n\n#[test]\nfn labelled_arguments_after_label() {\n    // This should not suggest any labels, as `wibble: wibble:` is not valid syntax.\n    let code = \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble(wibble: w)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(6, 18));\n}\n\n#[test]\nfn labelled_arguments_function_call() {\n    let code = \"\npub fn divide(x: Int, by y: Int) { x / y }\n\npub fn main() {\n  divide(10, b)\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 14));\n}\n\n#[test]\nfn labelled_arguments_from_different_module() {\n    let code = \"\nimport wibble\n\npub fn main() {\n  wibble.divide(10, b)\n}\n\";\n\n    assert_completion!(\n        TestProject::for_source(code)\n            .add_hex_module(\"wibble\", \"pub fn divide(x: Int, by y: Int) { x / y }\"),\n        Position::new(4, 21)\n    );\n}\n\n#[test]\nfn no_label_completions_in_nested_expression() {\n    // Since we are completing inside a list, labels are no longer available\n    let code = \"\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble([w])\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(6, 11));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_before_declaration_in_block() {\n    let code = \"\npub fn main() {\n  {\n    s\n    let something = 10\n  }\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 5));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_before_declaration_in_anonymous_function() {\n    let code = \"\npub fn main() {\n  fn() {\n    s\n    let something = 10\n  }\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 5));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_after_block_scope() {\n    let code = \"\npub fn main() {\n  {\n    let something = 10\n  }\n  s\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 3));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_after_anonymous_function_scope() {\n    let code = \"\npub fn main() {\n  fn() {\n    let something = 10\n  }\n  s\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 3));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_after_case_scope() {\n    let code = \"\npub fn main() {\n  case todo {\n    something -> Nil\n  }\n  s\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 3));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_after_case_clause_scope() {\n    let code = \"\npub fn main() {\n  case todo {\n    something -> Nil\n    something_else -> s\n  }\n  s\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 23));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4625\n#[test]\nfn no_variable_completions_before_case_clause() {\n    let code = \"\npub fn main() {\n  case todo {\n    something -> s\n    something_else -> Nil\n  }\n  s\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(3, 18));\n}\n\n// https://github.com/gleam-lang/gleam/issues/4652\n#[test]\nfn no_completions_in_constant_string() {\n    let code = r#\"\nconst x = \"io.\"\n\"#;\n\n    let completions = completion(\n        TestProject::for_source(code).add_hex_module(\"gleam/io\", \"pub fn println() {todo}\"),\n        Position::new(1, 14),\n    );\n    assert_eq!(completions, vec![],);\n}\n\n#[test]\nfn prefer_values_matching_expected_type() {\n    let code = \"\npub fn main() -> Bool {\n  let wibble = 123\n  let wubble = True\n  let Wobble = 1.5\n  w\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(5, 3));\n}\n\n#[test]\nfn prefer_function_which_returns_expected_type() {\n    let code = \"\npub fn main() -> Int {\n  a\n}\n\nfn add(a, b) { a + b }\nfn sub(a, b) { a - b }\nfn addf(a, b) { a +. b }\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(2, 3));\n}\n\n#[test]\nfn prefer_function_which_returns_expected_generic_type() {\n    let code = \"\npub fn main() -> Result(Int, Nil) {\n  let result = Ok(12)\n  let result2 = Error(True)\n  r\n}\n\";\n\n    assert_completion!(TestProject::for_source(code), Position::new(4, 3));\n}\n\n#[test]\nfn completion_for_type() {\n    let dep = \"pub type Wibble\";\n    let code = \"pub fn new() -> wibble.Wibble {}\";\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"wibble\", dep),\n        Position::new(0, 23)\n    );\n}\n\n#[test]\nfn completion_for_partially_correct_existing_module_select() {\n    let dep = \"pub fn filter() {}\";\n    let code = \"\nimport gleam/list\n\npub fn new() {\n  list.fer\n//      ^ cursor right after the 'f'\n}\n\";\n    assert_completion!(\n        TestProject::for_source(code).add_dep_module(\"gleam/list\", dep),\n        Position::new(4, 8)\n    );\n}\n\n#[test]\nfn complete_keyword_being_typed() {\n    assert_apply_completion!(\n        TestProject::for_source(\"pub fn main() { t }\"),\n        \"todo\",\n        Position::new(0, 17)\n    );\n}\n\n#[test]\nfn complete_echo_keyword() {\n    assert_apply_completion!(\n        TestProject::for_source(\"pub fn main() { e wibble }\"),\n        \"echo\",\n        Position::new(0, 17)\n    );\n}\n\n#[test]\nfn complete_panic_keyword() {\n    assert_apply_completion!(\n        TestProject::for_source(\"pub fn main() { wibble(p) }\"),\n        \"panic\",\n        Position::new(0, 24)\n    );\n}\n\n#[test]\nfn do_not_show_completions_when_typing_a_number() {\n    assert_completion!(\n        TestProject::for_source(\n            \"\npub fn main() { 2 }\npub fn window_by_2() {}\npub fn to_base_32() {}\n\"\n        ),\n        Position::new(1, 17)\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/definition.rs",
    "content": "use lsp_types::{\n    GotoDefinitionParams, Location, Position, Range, Url, request::GotoTypeDefinitionParams,\n};\n\nuse super::*;\n\nfn definition(tester: &TestProject<'_>, position: Position) -> Option<Location> {\n    tester.at(position, |engine, param, _| {\n        let params = GotoDefinitionParams {\n            text_document_position_params: param,\n            work_done_progress_params: Default::default(),\n            partial_result_params: Default::default(),\n        };\n        let response = engine.goto_definition(params);\n        response.result.unwrap()\n    })\n}\n\nfn pretty_definition(project: TestProject<'_>, position_finder: PositionFinder) -> String {\n    let position = position_finder.find_position(project.src);\n    let location = definition(&project, position).expect(\"a location to jump to\");\n    jump_locations_to_string(project, position, vec![location])\n}\n\nfn type_definition(tester: &TestProject<'_>, position: Position) -> Vec<Location> {\n    tester.at(position, |engine, param, _| {\n        let params = GotoTypeDefinitionParams {\n            text_document_position_params: param,\n            work_done_progress_params: Default::default(),\n            partial_result_params: Default::default(),\n        };\n        let response = engine.goto_type_definition(params);\n\n        response.result.unwrap()\n    })\n}\n\nfn pretty_type_definition(project: TestProject<'_>, position_finder: PositionFinder) -> String {\n    let position = position_finder.find_position(project.src);\n    let location = type_definition(&project, position);\n    format!(\n        \"Jumping to type definition\\n\\n{}\",\n        jump_locations_to_string(project, position, location)\n    )\n}\n\nfn jump_locations_to_string(\n    project: TestProject<'_>,\n    original_position: Position,\n    locations: Vec<Location>,\n) -> String {\n    let src = hover::show_hover(\n        project.src,\n        Range {\n            start: original_position,\n            end: original_position,\n        },\n        original_position,\n    );\n\n    let destinations = locations\n        .iter()\n        .map(|location| {\n            let pretty_destination = location\n                .uri\n                .path_segments()\n                .expect(\"a location to jump to\")\n                // To make snapshots the same both on windows and unix systems we need\n                // to discard windows' `C:` path segment at the beginning of a uri.\n                .skip_while(|segment| *segment == \"C:\")\n                .join(\"/\");\n\n            let destination_code = hover::show_hover(\n                project\n                    .src_from_module_url(&location.uri)\n                    .expect(\"a module to jump to\"),\n                location.range,\n                location.range.start,\n            );\n\n            format!(\n                \"----- Jumped to `{pretty_destination}`\n{destination_code}\"\n            )\n        })\n        .join(\"\\n\\n\");\n\n    format!(\n        \"----- Jumping from `src/app.gleam`\n{src}\n{destinations}\",\n    )\n}\n\n#[macro_export]\nmacro_rules! assert_goto {\n    ($src:literal, $position:expr) => {\n        let project = TestProject::for_source($src);\n        assert_goto!(project, $position);\n    };\n    ($project:expr, $position:expr) => {\n        let output = pretty_definition($project, $position);\n        insta::assert_snapshot!(insta::internals::AutoName, output);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_goto_type {\n    ($src:literal, $position:expr) => {\n        let project = TestProject::for_source($src);\n        assert_goto_type!(project, $position);\n    };\n    ($project:expr, $position:expr) => {\n        let output = pretty_type_definition($project, $position);\n        insta::assert_snapshot!(insta::internals::AutoName, output);\n    };\n}\n\n#[test]\nfn goto_type_definition_in_same_file() {\n    assert_goto_type!(\n        \"\npub type Wibble {\n  Wibble\n}\n\npub fn main() {\n  let x = Wibble\n  x\n}\",\n        find_position_of(\"x\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn goto_type_definition_in_different_file_of_same_project() {\n    let src = \"\nimport wibble.{type Wibble}\n\npub fn main() {\n  use_wibble(todo)\n}\n\npub fn use_wibble(wibble: Wibble) { todo }\n\";\n\n    assert_goto_type!(\n        TestProject::for_source(src).add_module(\"wibble\", \"pub type Wibble\"),\n        find_position_of(\"todo\")\n    );\n}\n\n#[test]\nfn goto_type_definition_in_different_file_of_dependency() {\n    let src = \"\nimport wibble.{type Wibble}\n\npub fn main() {\n  use_wibble(todo)\n}\n\npub fn use_wibble(wibble: Wibble) { todo }\n\";\n\n    assert_goto_type!(\n        TestProject::for_source(src).add_dep_module(\"wibble\", \"pub type Wibble\"),\n        find_position_of(\"todo\")\n    );\n}\n\n#[test]\nfn goto_type_definition_can_jump_to_multiple_types() {\n    let src = \"\nimport wibble.{type Wibble, Wibble}\nimport box.{Box}\n\npub fn main() {\n  let a = Box(Wibble)\n}\n\";\n\n    assert_goto_type!(\n        TestProject::for_source(src)\n            .add_dep_module(\"wibble\", \"pub type Wibble { Wibble }\")\n            .add_dep_module(\"box\", \"pub type Box(a) { Box(a) }\"),\n        find_position_of(\"let a\")\n    );\n}\n\n#[test]\nfn goto_type_definition_can_jump_to_all_types_in_a_tuple() {\n    let src = \"\nimport wibble.{type Wibble}\nimport wobble.{type Wobble}\nimport box.{type Box}\n\npub fn main() {\n  let a: #(Box(Wibble), Wobble) = todo\n}\n\";\n\n    assert_goto_type!(\n        TestProject::for_source(src)\n            .add_dep_module(\"wibble\", \"pub type Wibble { Wibble }\")\n            .add_dep_module(\"wobble\", \"pub type Wobble { Wobble }\")\n            .add_dep_module(\"box\", \"pub type Box(a) { Box(a) }\"),\n        find_position_of(\"let a\")\n    );\n}\n\n#[test]\nfn goto_type_definition_can_jump_to_all_types_in_a_function_type() {\n    let src = \"\nimport wibble.{type Wibble}\nimport wobble.{type Wobble}\nimport box.{type Box}\n\npub fn main() {\n  let a = fn(wibble: Wibble) { box.Box(wobble.Wobble) }\n}\n\";\n\n    assert_goto_type!(\n        TestProject::for_source(src)\n            .add_dep_module(\"wibble\", \"pub type Wibble { Wibble }\")\n            .add_dep_module(\"wobble\", \"pub type Wobble { Wobble }\")\n            .add_dep_module(\"box\", \"pub type Box(a) { Box(a) }\"),\n        find_position_of(\"let a\")\n    );\n}\n\n#[test]\nfn goto_definition_local_variable() {\n    assert_goto!(\n        \"\npub fn main() {\n  let x = 1\n  x\n}\",\n        find_position_of(\"x\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn goto_definition_record_update() {\n    assert_goto!(\n        \"\npub type Wibble { Wibble(one: Int, two: Int) }\n\npub fn main() {\n  Wibble(..todo, one: 1)\n}\",\n        find_position_of(\"Wibble\").nth_occurrence(3)\n    );\n}\n\n#[test]\nfn goto_definition_same_module_constants() {\n    assert_goto!(\n        \"\nconst x = 1\n\npub fn main() {\n  x\n}\",\n        find_position_of(\"x\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn goto_definition_same_module_functions() {\n    assert_goto!(\n        \"\nfn add_2(x) {\n  x + 2\n}\n\npub fn main() {\n  add_2(1)\n}\",\n        find_position_of(\"add_2(1)\")\n    );\n}\n\n#[test]\nfn goto_definition_same_module_records() {\n    assert_goto!(\n        \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\npub fn main() {\n  let a = Var1(1)\n  let b = Var2(2, 3)\n}\",\n        find_position_of(\"Var1(1)\")\n    );\n}\n\n#[test]\nfn goto_definition_imported_module_constants() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_num\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub const my_num = 1\"),\n        find_position_of(\"my_num\")\n    );\n}\n\n#[test]\nfn goto_definition_unqualified_imported_module_constants() {\n    let code = \"\nimport example_module.{my_num}\nfn main() {\n  my_num\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub const my_num = 1\"),\n        find_position_of(\"my_num\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn goto_definition_module_function_calls() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\")\n    );\n}\n\n#[test]\nfn goto_definition_imported_module_records() {\n    let dep_src = \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\";\n\n    let code = \"\nimport example_module\nfn main() {\n  example_module.Var1(1)\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", dep_src),\n        find_position_of(\"Var1(1)\")\n    );\n}\n\n#[test]\nfn goto_definition_unqualified_imported_module_records() {\n    let dep_src = \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\";\n\n    let code = \"\nimport example_module.{Var1}\nfn main() {\n  Var1(1)\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", dep_src),\n        find_position_of(\"Var1(1)\").under_char('a')\n    );\n}\n\n#[test]\nfn goto_definition_external_module_constants() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_num\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub const my_num = 1\"),\n        find_position_of(\"my_num\").under_char('u')\n    );\n}\n\n#[test]\nfn goto_definition_external_module_function_calls() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\")\n    );\n}\n\n#[test]\nfn goto_definition_external_module_function_calls_with_multiple_compiles() {\n    let dep = \"pub fn my_fn() { Nil }\";\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    let (mut engine, position_param) = TestProject::for_source(code)\n        .add_hex_module(\"example_module\", dep)\n        .positioned_with_io(Position::new(3, 20));\n\n    let params = GotoDefinitionParams {\n        text_document_position_params: position_param.clone(),\n        work_done_progress_params: Default::default(),\n        partial_result_params: Default::default(),\n    };\n    let response = engine.goto_definition(params.clone());\n    let response = response.result.unwrap();\n\n    assert_eq!(\n        response,\n        Some(Location {\n            uri: Url::from_file_path(Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n                r\"\\\\?\\C:\\build\\packages\\hex\\src\\example_module.gleam\"\n            } else {\n                \"/build/packages/hex/src/example_module.gleam\"\n            }))\n            .unwrap(),\n            range: Range {\n                start: Position {\n                    line: 0,\n                    character: 0\n                },\n                end: Position {\n                    line: 0,\n                    character: 14\n                }\n            }\n        })\n    );\n\n    engine.compiler.sources.clear();\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n\n    let response = engine.goto_definition(params.clone());\n    let response = response.result.unwrap();\n\n    assert_eq!(\n        response,\n        Some(Location {\n            uri: Url::from_file_path(Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n                r\"\\\\?\\C:\\build\\packages\\hex\\src\\example_module.gleam\"\n            } else {\n                \"/build/packages/hex/src/example_module.gleam\"\n            }))\n            .unwrap(),\n            range: Range {\n                start: Position {\n                    line: 0,\n                    character: 0\n                },\n                end: Position {\n                    line: 0,\n                    character: 14\n                }\n            }\n        })\n    )\n}\n\n#[test]\nfn goto_definition_path_module_function_calls_with_multiple_compiles() {\n    let dep = \"pub fn my_fn() { Nil }\";\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    let (mut engine, position_param) = TestProject::for_source(code)\n        .add_dep_module(\"example_module\", dep)\n        .positioned_with_io(Position::new(3, 20));\n\n    let params = GotoDefinitionParams {\n        text_document_position_params: position_param.clone(),\n        work_done_progress_params: Default::default(),\n        partial_result_params: Default::default(),\n    };\n\n    let response = engine.goto_definition(params.clone());\n    let response = response.result.unwrap();\n\n    assert_eq!(\n        response,\n        Some(Location {\n            uri: Url::from_file_path(Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n                r\"\\\\?\\C:\\dep\\src\\example_module.gleam\"\n            } else {\n                \"/dep/src/example_module.gleam\"\n            }))\n            .unwrap(),\n            range: Range {\n                start: Position {\n                    line: 0,\n                    character: 0\n                },\n                end: Position {\n                    line: 0,\n                    character: 14\n                }\n            }\n        })\n    );\n\n    engine.compiler.sources.clear();\n    let response = engine.compile_please();\n    assert!(response.result.is_ok());\n\n    let response = engine.goto_definition(params.clone());\n    let response = response.result.unwrap();\n\n    assert_eq!(\n        response,\n        Some(Location {\n            uri: Url::from_file_path(Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n                r\"\\\\?\\C:\\dep\\src\\example_module.gleam\"\n            } else {\n                \"/dep/src/example_module.gleam\"\n            }))\n            .unwrap(),\n            range: Range {\n                start: Position {\n                    line: 0,\n                    character: 0\n                },\n                end: Position {\n                    line: 0,\n                    character: 14\n                }\n            }\n        })\n    )\n}\n\n#[test]\nfn goto_definition_external_module_records() {\n    let hex_src = \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\";\n\n    let code = \"\nimport example_module\nfn main() {\n  example_module.Var1(1)\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", hex_src),\n        find_position_of(\"Var1(1)\").under_char('r')\n    );\n}\n\n#[test]\nfn goto_definition_path_module_function_calls() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_dep_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('y')\n    );\n}\n\n#[test]\nfn goto_definition_type() {\n    assert_goto!(\n        \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\npub fn make_var() -> Rec {\n  Var1(1)\n}\",\n        find_position_of(\"Rec\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn goto_definition_type_in_module() {\n    let hex_src = \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\";\n\n    let code = \"\nimport example_module\nfn make_var() -> example_module.Rec {\n  example_module.Var1(1)\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", hex_src),\n        find_position_of(\"Rec\")\n    );\n}\n\n#[test]\nfn goto_definition_type_in_path_dep() {\n    let dep = \"\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\";\n\n    let code = \"\nimport example_module\nfn make_var() -> example_module.Rec {\n  example_module.Var1(1)\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_dep_module(\"example_module\", dep),\n        find_position_of(\"Rec\")\n    );\n}\n\n#[test]\nfn goto_definition_deep_type_in_module() {\n    let hex_src = \"\npub type Wobble {\n  Wobble(Int)\n}\n\npub type Wibble(a) {\n  Wibble(a)\n}\n\npub type Wabble(a) {\n  Wabble(a)\n}\n\";\n\n    let code = \"\nimport example_module\nfn make_var() -> example_module.Wabble(example_module.Wibble(example_module.Wobble)) {\n  example_module.Wabble(example_module.Wibble(example_module.Wobble(1)))\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", hex_src),\n        find_position_of(\"Wobble\").under_char('o')\n    );\n}\n\n#[test]\nfn goto_definition_import() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_num\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub const my_num = 1\"),\n        find_position_of(\"example_module\").under_char('p')\n    );\n}\n\n#[test]\nfn goto_definition_import_aliased() {\n    let code = \"\nimport example_module as example\nfn main() {\n  example.my_num\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub const my_num = 1\"),\n        find_position_of(\"example\")\n            .nth_occurrence(2)\n            .under_char('x')\n    );\n}\n\n#[test]\nfn goto_definition_import_unqualified_value() {\n    let code = \"\nimport example_module.{my_num}\nfn main() {\n  my_num\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub const my_num = 1\"),\n        find_position_of(\"my_num\").under_char('_')\n    );\n}\n\n#[test]\nfn goto_definition_unqualified_function() {\n    let code = \"\nimport wibble.{wobble}\nfn main() {\n  wobble()\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"wibble\", \"pub fn wobble() {}\"),\n        find_position_of(\"wobble\").nth_occurrence(2).under_char('o')\n    );\n}\n\n#[test]\nfn goto_definition_import_unqualified_type() {\n    let code = \"\nimport example_module.{type MyType}\nfn main() -> MyType {\n  0\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub type MyType = Int\"),\n        find_position_of(\"MyType\").under_char('T')\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3610\n#[test]\nfn goto_definition_of_external_function_in_same_module() {\n    let code = \"\n@external(erlang, \\\"wibble\\\", \\\"wobble\\\")\nfn external_function() -> Nil\n\nfn main() {\n  external_function()\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code),\n        find_position_of(\"external_function\")\n            .nth_occurrence(2)\n            .under_char('l')\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3758\n#[test]\nfn goto_definition_from_anonymous_function() {\n    let code = \"\npub type Wibble\n\npub fn main() {\n  fn(w: Wibble) { todo }\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code),\n        find_position_of(\"w: Wibble\").under_char('i')\n    );\n}\n\n#[test]\nfn goto_definition_module() {\n    let code = \"\nimport wibble\n\npub fn main() {\n  wibble.wibble()\n}\n\";\n\n    assert_goto!(\n        TestProject::for_source(code).add_module(\"wibble\", \"pub fn wibble() {}\"),\n        find_position_of(\"wibble.\").under_char('i')\n    );\n}\n\n#[test]\nfn goto_definition_constant() {\n    assert_goto!(\n        \"\nconst value = 25\n\nconst my_constant = value\n\",\n        find_position_of(\"= value\").under_char('a')\n    );\n}\n\n#[test]\nfn goto_definition_constant_record() {\n    assert_goto!(\n        \"\ntype Wibble {\n  Wibble(Int)\n}\n\nconst wibble = Wibble(10)\n\",\n        find_position_of(\"Wibble(10)\").under_char('l')\n    );\n}\n\n#[test]\nfn goto_definition_imported_constant() {\n    let src = \"\nimport wibble\n\nconst my_constant = wibble.value\n\";\n\n    assert_goto!(\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub const value = 10\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n#[test]\nfn goto_definition_constant_imported_record() {\n    let src = \"\nimport wibble\n\nconst my_constant = wibble.Wibble(10)\n\";\n\n    assert_goto!(\n        TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble(Int) }\"),\n        find_position_of(\"Wibble(10)\").under_char('W')\n    );\n}\n\n#[test]\nfn goto_definition_from_alternative_pattern() {\n    assert_goto!(\n        \"\ntype Wibble {\n  Wibble\n  Wobble\n}\n\nfn warble(wibble: Wibble) {\n  case wibble {\n    Wibble | Wobble -> 0\n  }\n}\n\",\n        find_position_of(\"Wobble ->\")\n    );\n}\n\n#[test]\nfn goto_definition_of_local_variable_from_guard() {\n    assert_goto!(\n        \"\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\",\n        find_position_of(\"wobble\").nth_occurrence(2).under_char('o')\n    );\n}\n\n#[test]\nfn goto_definition_of_record_from_guard() {\n    assert_goto!(\n        \"\ntype Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  let wibble = True\n  let wobble = Wibble\n  case wibble {\n    True if wobble == Wibble -> !wibble\n    False if wobble == Wobble -> wibble\n    _ -> Wibble\n  }\n}\n\",\n        find_position_of(\"== Wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn goto_definition_of_module_select_from_guard() {\n    let src = \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\";\n    assert_goto!(\n        TestProject::for_source(src).add_module(\"mod\", \"pub const wibble = 10\"),\n        find_position_of(\"mod.wibble\").under_char('w')\n    );\n}\n\n#[test]\nfn goto_definition_of_record_module_select_from_guard() {\n    let src = \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  let wobble = mod.Wibble\n  case wibble {\n    True if wobble == mod.Wobble -> !wibble\n    False if wobble == mod.Wibble -> wibble\n    _ -> mod.Wibble\n  }\n}\n\";\n    assert_goto!(\n        TestProject::for_source(src).add_module(\"mod\", \"pub type Wobble { Wibble Wobble }\"),\n        find_position_of(\"== mod.Wibble\").under_char('i')\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/document_symbols.rs",
    "content": "use insta::assert_debug_snapshot;\nuse lsp_types::{DocumentSymbol, DocumentSymbolParams};\n\nuse super::*;\n\nfn doc_symbols(tester: TestProject<'_>) -> Vec<DocumentSymbol> {\n    tester.at(Position::default(), |engine, param, _| {\n        let params = DocumentSymbolParams {\n            text_document: param.text_document,\n            work_done_progress_params: Default::default(),\n            partial_result_params: Default::default(),\n        };\n        let response = engine.document_symbol(params);\n\n        response.result.unwrap()\n    })\n}\n\n#[test]\nfn doc_symbols_type_no_constructors() {\n    let code = \"\npub type A\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_no_constructors_starting_at_documentation() {\n    let code = \"\n/// My type\npub type A\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_no_constructors_starting_at_empty_doc() {\n    let code = \"\n// Some prior code...\n\n///\npub type A\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_constructor_no_args() {\n    let code = \"\npub type B {\n    C\n    D\n\n    /// E\n    E\n}\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_constructor_pos_args() {\n    let code = \"\npub type B {\n    C(Int)\n\n    /// D\n    D(List(Int))\n\n    /// E\n    E(\n        Result(Int, Bool)\n    )\n}\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_constructor_labeled_args() {\n    let code = \"\npub type B {\n    C(argc: Int)\n\n    /// D\n    D(argd: List(Int))\n\n    /// E\n    E(\n        /// Arg\n        arge: Result(Int, Bool)\n    )\n}\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_constructor_pos_and_labeled_args() {\n    let code = \"\npub type B {\n    C(Int, argc: Int)\n\n    /// D\n    D(Int, argd: List(Int))\n\n    /// E\n    E(\n        Int,\n\n        /// Arg\n        arge: Result(Int, Bool)\n    )\n}\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_type_alias() {\n    let code = \"\n/// DOC\npub type FFF = Int\n\npub type FFFF = List(Int)\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_function() {\n    let code = \"\n/// DOC\npub fn super_func(a: Int) -> List(Int) {\n    [a + 5]\n}\n\npub fn super_func2(a: Int) -> List(Int) {\n    [a + 5]\n}\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n\n#[test]\nfn doc_symbols_constant() {\n    let code = \"\n/// DOC\npub const my_const = 5\n\npub const my_const2 = [25]\";\n\n    assert_debug_snapshot!(doc_symbols(TestProject::for_source(code)))\n}\n"
  },
  {
    "path": "language-server/src/tests/folding_range.rs",
    "content": "use lsp_types::{FoldingRange, FoldingRangeKind, FoldingRangeParams};\n\nuse super::*;\n\nfn folding_ranges(tester: TestProject<'_>) -> Vec<FoldingRange> {\n    tester.at(Position::default(), |engine, param, _| {\n        let params = FoldingRangeParams {\n            text_document: param.text_document,\n            work_done_progress_params: Default::default(),\n            partial_result_params: Default::default(),\n        };\n        let response = engine.folding_range(params);\n\n        response.result.unwrap()\n    })\n}\n\nfn kind_name(kind: &Option<FoldingRangeKind>) -> &'static str {\n    match kind {\n        Some(FoldingRangeKind::Imports) => \"imports\",\n        Some(FoldingRangeKind::Comment) => \"comment\",\n        Some(FoldingRangeKind::Region) => \"region\",\n        None => \"none\",\n    }\n}\n\nfn apply_fold(code: &str, range: &FoldingRange) -> String {\n    let start = range.start_line as usize;\n    let end = range.end_line as usize;\n    let lines: Vec<&str> = code.lines().collect();\n\n    let mut output = vec![];\n    for (index, line) in lines.iter().enumerate() {\n        if index < start || index > end {\n            output.push((*line).to_string());\n        } else if index == start {\n            output.push(format!(\"{line} ...\"));\n        }\n    }\n\n    output.join(\"\\n\")\n}\n\nfn pretty_folding_output(code: &str, ranges: &[FoldingRange]) -> String {\n    let mut output = format!(\"----- Code -----\\n{code}\\n\\n----- Ranges -----\\n\");\n\n    if ranges.is_empty() {\n        output.push_str(\"(none)\\n\");\n        return output;\n    }\n\n    for (index, range) in ranges.iter().enumerate() {\n        let line = format!(\n            \"{}. lines {}..{} kind: {}\\n\",\n            index + 1,\n            range.start_line,\n            range.end_line,\n            kind_name(&range.kind)\n        );\n        output.push_str(&line);\n    }\n\n    for (index, range) in ranges.iter().enumerate() {\n        let fold = apply_fold(code, range);\n        let section = format!(\n            \"\\n----- Fold {} (lines {}..{}) -----\\n{fold}\\n\",\n            index + 1,\n            range.start_line,\n            range.end_line\n        );\n        output.push_str(&section);\n    }\n\n    output\n}\n\nfn folding_snapshot_output(project: TestProject<'_>) -> String {\n    let src = project.src;\n    let ranges = folding_ranges(project);\n    pretty_folding_output(src, &ranges)\n}\n\nmacro_rules! assert_folding {\n    ($src:literal $(,)?) => {\n        assert_folding!(TestProject::for_source($src));\n    };\n    ($project:expr $(,)?) => {{\n        let project = $project;\n        let src = project.src;\n        let output = folding_snapshot_output(project);\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    }};\n}\n\nmacro_rules! assert_no_folding {\n    ($src:literal $(,)?) => {\n        assert_no_folding!(TestProject::for_source($src));\n    };\n    ($project:expr $(,)?) => {{\n        let ranges = folding_ranges($project);\n        assert!(\n            ranges.is_empty(),\n            \"Expected no folding ranges, got: {ranges:#?}\"\n        );\n    }};\n}\n\n#[test]\nfn folds_multiline_function_body() {\n    assert_folding!(\n        \"pub fn main() {\n  let x = 1\n  x\n}\"\n    );\n}\n\n#[test]\nfn does_not_fold_single_line_function_body() {\n    assert_no_folding!(\"pub fn main() { 1 }\");\n}\n\n#[test]\nfn folds_import_block() {\n    let code = \"import one\nimport two\nimport three\n\npub fn main() { 1 }\";\n\n    assert_folding!(\n        TestProject::for_source(code)\n            .add_dep_module(\"one\", \"pub fn value() { 1 }\")\n            .add_dep_module(\"two\", \"pub fn value() { 2 }\")\n            .add_dep_module(\"three\", \"pub fn value() { 3 }\"),\n    );\n}\n\n#[test]\nfn folds_separated_import_blocks() {\n    let code = \"import one\nimport two\n\nimport three\nimport four\n\npub fn main() { 1 }\";\n\n    assert_folding!(\n        TestProject::for_source(code)\n            .add_dep_module(\"one\", \"pub fn value() { 1 }\")\n            .add_dep_module(\"two\", \"pub fn value() { 2 }\")\n            .add_dep_module(\"three\", \"pub fn value() { 3 }\")\n            .add_dep_module(\"four\", \"pub fn value() { 4 }\"),\n    );\n}\n\n#[test]\nfn folds_multiline_custom_type() {\n    assert_folding!(\n        \"pub type W {\n  W(Int)\n}\"\n    );\n}\n\n#[test]\nfn folds_multiline_constant() {\n    assert_folding!(\n        \"pub const xs = [\n  1,\n  2,\n]\"\n    );\n}\n\n#[test]\nfn folds_multiline_type_alias() {\n    assert_folding!(\n        \"pub type Pair =\n  #(Int, Int)\"\n    );\n}\n\n#[test]\nfn does_not_fold_single_line_custom_type() {\n    assert_no_folding!(\"pub type W { W(Int) }\");\n}\n\n#[test]\nfn does_not_fold_single_line_constant() {\n    assert_no_folding!(\"pub const x = 1\");\n}\n\n#[test]\nfn does_not_fold_single_line_type_alias() {\n    assert_no_folding!(\"pub type Pair = #(Int, Int)\");\n}\n\n#[test]\nfn folds_mixed_definitions_in_source_order() {\n    let code = \"import one\nimport two\n\npub type W {\n  W(Int)\n}\n\npub const xs = [\n  1,\n  2,\n]\n\npub fn main() {\n  1\n}\";\n\n    assert_folding!(\n        TestProject::for_source(code)\n            .add_dep_module(\"one\", \"pub fn value() { 1 }\")\n            .add_dep_module(\"two\", \"pub fn value() { 2 }\"),\n    );\n}\n\n#[test]\nfn folds_only_multiline_functions_in_source_order() {\n    assert_folding!(\n        \"pub fn one() {\n  1\n}\n\npub fn two() { 2 }\n\npub fn three() {\n  3\n}\"\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/hover.rs",
    "content": "use lsp_types::{Hover, HoverContents, HoverParams, MarkedString, Position, Range};\n\nuse super::*;\n\nfn hover(tester: TestProject<'_>, position: Position) -> Option<Hover> {\n    tester.at(position, |engine, param, _| {\n        let params = HoverParams {\n            text_document_position_params: param,\n            work_done_progress_params: Default::default(),\n        };\n        let response = engine.hover(params);\n\n        response.result.unwrap()\n    })\n}\n\npub fn show_hover(code: &str, range: Range, position: Position) -> String {\n    let Range { start, end } = range;\n\n    // When we display the over range the end character is always excluded!\n    let end = Position::new(end.line, end.character);\n\n    let mut buffer: String = \"\".into();\n    for (line_number, line) in code.lines().enumerate() {\n        let mut underline: String = \"\".into();\n        let mut underline_empty = true;\n\n        for (column_number, _) in line.chars().enumerate() {\n            let current_position = Position::new(line_number as u32, column_number as u32);\n            if current_position == position {\n                underline_empty = false;\n                underline.push('↑');\n            } else if start <= current_position && current_position < end {\n                underline_empty = false;\n                underline.push('▔');\n            } else {\n                underline.push(' ');\n            }\n        }\n\n        buffer.push_str(line);\n        if !underline_empty {\n            buffer.push('\\n');\n            buffer.push_str(&underline);\n        }\n        buffer.push('\\n');\n    }\n\n    buffer\n}\n\nfn pretty_hover_contents(contents: HoverContents) -> String {\n    let (kind, content) = match contents {\n        HoverContents::Scalar(marked_string) => (\"markdown\", pretty_marked_string(marked_string)),\n        HoverContents::Array(marked_strings) => (\n            \"markdown array\",\n            marked_strings\n                .into_iter()\n                .map(pretty_marked_string)\n                .join(\"\\n\\n\"),\n        ),\n        HoverContents::Markup(lsp_types::MarkupContent { kind, value }) => match kind {\n            lsp_types::MarkupKind::PlainText => (\"plaintext\", value),\n            lsp_types::MarkupKind::Markdown => (\"markdown\", value),\n        },\n    };\n    format!(\"----- Hover content ({kind}) -----\\n{content}\")\n}\n\nfn pretty_marked_string(marked_string: MarkedString) -> String {\n    match marked_string {\n        MarkedString::String(string) => string,\n        MarkedString::LanguageString(lsp_types::LanguageString { language, value }) => {\n            format!(\"```{language}\\n{value}\\n```\")\n        }\n    }\n}\n\n#[macro_export]\nmacro_rules! assert_hover {\n    ($code:literal, $position:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_hover!(project, $position);\n    };\n\n    ($project:expr, $position:expr $(,)?) => {\n        let src = $project.src;\n        let position = $position.find_position(src);\n        let result = hover($project, position).expect(\"no hover produced\");\n        let pretty_hover = show_hover(src, result.range.expect(\"hover with no range\"), position);\n        let output = format!(\n            \"{}\\n\\n{}\",\n            pretty_hover,\n            pretty_hover_contents(result.contents)\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\n#[test]\nfn hover_function_definition() {\n    assert_hover!(\n        \"\nfn add_2(x) {\n  x + 2\n}\n\",\n        find_position_of(\"add_2\")\n    );\n}\n\n#[test]\nfn hover_local_function() {\n    assert_hover!(\n        \"\nfn my_fn() {\n  Nil\n}\n\nfn main() {\n  my_fn\n}\n\",\n        find_position_of(\"my_fn\").under_char('y').nth_occurrence(2)\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2654\n#[test]\nfn hover_local_function_in_pipe() {\n    assert_hover!(\n        \"\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n  |> add1\n  |> add1\n}\n\",\n        find_position_of(\"add1\")\n            .with_char_offset(1)\n            .nth_occurrence(2)\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2654\n#[test]\nfn hover_local_function_in_pipe_1() {\n    assert_hover!(\n        \"\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n  |> add1\n  |> add1\n}\n\",\n        find_position_of(\"add1\")\n            .with_char_offset(2)\n            .nth_occurrence(3)\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2654\n#[test]\nfn hover_local_function_in_pipe_2() {\n    assert_hover!(\n        \"\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n  |> add1\n  |> add1\n}\n\",\n        find_position_of(\"add1\")\n            .with_char_offset(2)\n            .nth_occurrence(4)\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/2654\n#[test]\nfn hover_local_function_in_pipe_3() {\n    assert_hover!(\n        \"\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n  |> add1\n  |> add1\n}\n\",\n        find_position_of(\"add1\")\n            .with_char_offset(2)\n            .nth_occurrence(5)\n    );\n}\n\n#[test]\nfn hover_imported_function() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('_'),\n    );\n}\n\n#[test]\nfn hover_external_imported_function() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_fn\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('_'),\n    );\n}\n\n#[test]\nfn hover_external_imported_unqualified_function() {\n    let code = \"\nimport example_module.{my_fn}\nfn main() {\n  my_fn\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('f').nth_occurrence(2),\n    );\n}\n\n#[test]\nfn hover_external_imported_function_renamed_module() {\n    let code = \"\nimport example_module as renamed_module\nfn main() {\n    renamed_module.my_fn\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('f'),\n    );\n}\n\n#[test]\nfn hover_external_unqualified_imported_function_renamed_module() {\n    let code = \"\nimport example_module.{my_fn} as renamed_module\nfn main() {\n    my_fn\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('_').nth_occurrence(2),\n    );\n}\n\n#[test]\nfn hover_external_imported_function_nested_module() {\n    // Example of HexDocs link with nested modules: https://hexdocs.pm/lustre/lustre/element/svg.html\n    let code = \"\nimport my/nested/example_module\nfn main() {\n    example_module.my_fn\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code)\n            .add_hex_module(\"my/nested/example_module\", \"pub fn my_fn() { Nil }\"),\n        find_position_of(\"my_fn\").under_char('f'),\n    );\n}\n\n#[test]\nfn hover_external_imported_ffi_renamed_function() {\n    let code = r#\"\nimport example_module\nfn main() {\n    example_module.my_fn\n}\n\"#;\n\n    let hex_module = r#\"\n@external(erlang, \"my_mod_ffi\", \"renamed_fn\")\npub fn my_fn() -> Nil\n\"#;\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", hex_module,),\n        find_position_of(\"my_fn\").under_char('f'),\n    );\n}\n\n#[test]\nfn hover_external_imported_constants() {\n    let code = \"\nimport example_module\nfn main() {\n  example_module.my_const\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub const my_const = 42\"),\n        find_position_of(\"my_const\").under_char('_'),\n    );\n}\n\n#[test]\nfn hover_external_imported_unqualified_constants() {\n    let code = \"\nimport example_module.{my_const}\nfn main() {\n  my_const\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"example_module\", \"pub const my_const = 42\"),\n        find_position_of(\"my_const\")\n            .under_char('c')\n            .nth_occurrence(2),\n    );\n}\n\n#[test]\nfn hover_external_value_with_two_modules_same_name() {\n    let code = \"\nimport a/example_module as _\nimport b/example_module\nfn main() {\n    example_module.my_const\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code)\n            .add_hex_module(\"a/example_module\", \"pub const my_const = 42\")\n            .add_hex_module(\"b/example_module\", \"pub const my_const = 42\"),\n        find_position_of(\"my_const\").under_char('c'),\n    );\n}\n\n#[test]\nfn hover_external_function_with_another_value_same_name() {\n    let code = \"\nimport a/example_module.{my_const as discarded}\nimport b/example_module.{my_const} as _\nfn main() {\n    my_const\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code)\n            .add_hex_module(\"a/example_module\", \"pub const my_const = 42\")\n            .add_hex_module(\"b/example_module\", \"pub const my_const = 42\"),\n        find_position_of(\"my_const\")\n            .under_char('o')\n            .nth_occurrence(3),\n    );\n}\n\n#[test]\nfn hover_function_definition_with_docs() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x, y) {\n  x <> y\n}\n\",\n        find_position_of(\"append\")\n    );\n}\n\n#[test]\nfn hover_function_argument() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x, y) {\n  x <> y\n}\n\",\n        find_position_of(\"append(x, y)\").under_char('x')\n    );\n}\n\n#[test]\nfn hover_function_body() {\n    let code = \"\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x, y) {\n  x <> y\n}\n\";\n\n    assert_eq!(\n        hover(TestProject::for_source(code), Position::new(4, 1)),\n        None\n    );\n}\n\n#[test]\nfn hover_expressions_in_function_body() {\n    assert_hover!(\n        \"\nfn append(x, y) {\n  x <> y\n}\n\",\n        find_position_of(\"x\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_module_constant() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nconst one = 1\n\",\n        find_position_of(\"one\")\n    );\n}\n\n#[test]\nfn hover_variable_in_use_expression() {\n    assert_hover!(\n        \"\nfn b(fun: fn(Int) -> String) {\n  fun(42)\n}\n\nfn do_stuff() {\n  let c = \\\"done\\\"\n\n  use a <- b\n  c\n}\n\",\n        find_position_of(\"use a\").under_last_char()\n    );\n}\n\n#[test]\nfn hover_variable_in_use_expression_1() {\n    assert_hover!(\n        \"\nfn b(fun: fn(Int) -> String) {\n  fun(42)\n}\n\nfn do_stuff() {\n  let c = \\\"done\\\"\n\n  use a <- b\n  c\n}\n\",\n        find_position_of(\"b\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_variable_in_use_expression_2() {\n    assert_hover!(\n        \"\nfn b(fun: fn(Int) -> String) {\n  fun(42)\n}\n\nfn do_stuff() {\n  let c = \\\"done\\\"\n\n  use a <- b\n  c\n}\n\",\n        find_position_of(\"c\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_function_arg_annotation_2() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x: String, y: String) -> String {\n  x <> y\n}\n\",\n        find_position_of(\"String\").under_char('n')\n    );\n}\n\n#[test]\nfn hover_function_return_annotation() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x: String, y: String) -> String {\n  x <> y\n}\n\",\n        find_position_of(\"String\").under_char('n').nth_occurrence(3)\n    );\n}\n\n#[test]\nfn hover_function_return_annotation_with_tuple() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x: String, y: String) -> #(String, String) {\n  #(x, y)\n}\n\",\n        find_position_of(\"String\").under_char('r').nth_occurrence(3)\n    );\n}\n\n#[test]\nfn hover_module_constant_annotation() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\nconst one: Int = 1\n\",\n        find_position_of(\"Int\").under_last_char()\n    );\n}\n\n#[test]\nfn hover_type_constructor_annotation() {\n    assert_hover!(\n        \"\ntype Wibble {\n    Wibble(arg: String)\n}\n\",\n        find_position_of(\"String\").under_char('n')\n    );\n}\n\n#[test]\nfn hover_type_alias_annotation() {\n    assert_hover!(\"type Wibble = Int\", find_position_of(\"Int\").under_char('n'));\n}\n\n#[test]\nfn hover_assignment_annotation() {\n    assert_hover!(\n        \"\nfn wibble() {\n    let wobble: Int = 7\n    wobble\n}\n\",\n        find_position_of(\"Int\").under_last_char()\n    );\n}\n\n#[test]\nfn hover_function_arg_annotation_with_documentation() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    Wibble(arg: String)\n}\n\nfn identity(x: Wibble) -> Wibble {\n  x\n}\n\",\n        find_position_of(\"Wibble\")\n            .under_last_char()\n            .nth_occurrence(3)\n    );\n}\n\n#[test]\nfn hover_import_unqualified_value() {\n    let code = \"\nimport example_module.{my_num}\nfn main() {\n  my_num\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_module(\n            \"example_module\",\n            \"\n/// Exciting documentation\n/// Maybe even multiple lines\npub const my_num = 1\"\n        ),\n        find_position_of(\"my_num\").under_char('n')\n    );\n}\n\n#[test]\nfn hover_import_unqualified_value_from_hex() {\n    let code = \"\nimport example_module.{my_num}\nfn main() {\n  my_num\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\n            \"example_module\",\n            \"\n/// Exciting documentation\n/// Maybe even multiple lines\npub const my_num = 1\"\n        ),\n        find_position_of(\"my_num\").under_char('n')\n    );\n}\n\n#[test]\nfn hover_import_unqualified_type() {\n    let code = \"\nimport example_module.{type MyType, MyType}\nfn main() -> MyType {\n  MyType\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_module(\n            \"example_module\",\n            \"\n/// Exciting documentation\n/// Maybe even multiple lines\npub type MyType {\n  MyType\n}\"\n        ),\n        find_position_of(\"MyType\").under_last_char()\n    );\n}\n\n#[test]\nfn hover_works_even_for_invalid_code() {\n    assert_hover!(\n        \"\nfn invalid() { 1 + Nil }\nfn valid() { Nil }\n\",\n        find_position_of(\"fn valid\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_for_pattern_spread_ignoring_all_fields() {\n    assert_hover!(\n        \"\npub type Model {\n  Model(\n    Int,\n    Float,\n    label1: Int,\n    label2: String,\n  )\n}\n\npub fn main() {\n  case todo {\n    Model(..) -> todo\n  }\n}\n\",\n        find_position_of(\"..\")\n    );\n}\n\n#[test]\nfn hover_for_pattern_spread_ignoring_some_fields() {\n    assert_hover!(\n        \"\npub type Model {\n  Model(\n    Int,\n    Float,\n    label1: Int,\n    label2: String,\n  )\n}\n\npub fn main() {\n  case todo {\n    Model(_, label1: _, ..) -> todo\n  }\n}\n\",\n        find_position_of(\"..\").under_last_char()\n    );\n}\n\n#[test]\nfn hover_for_pattern_spread_ignoring_all_positional_fields() {\n    assert_hover!(\n        \"\npub type Model {\n  Model(\n    Int,\n    Float,\n    label1: Int,\n    label2: String,\n  )\n}\n\npub fn main() {\n  case todo {\n    Model(_, _, _, ..) -> todo\n  }\n}\n\",\n        find_position_of(\"..\")\n    );\n}\n\n#[test]\nfn hover_label_shorthand_in_call_arg() {\n    assert_hover!(\n        \"\nfn wibble(arg1 arg1: Int, arg2 arg2: Bool) { Nil }\n\nfn main() {\n  let arg1 = 1\n  let arg2 = True\n  wibble(arg2:, arg1:)\n}\n\",\n        find_position_of(\"arg2:\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_label_shorthand_in_pattern_call_arg() {\n    assert_hover!(\n        \"\npub type Wibble { Wibble(arg1: Int, arg2: Bool) }\n\npub fn main() {\n  case todo {\n    Wibble(arg2:, ..) -> todo\n  }\n}\n\",\n        find_position_of(\"arg2:\")\n            .nth_occurrence(2)\n            .under_last_char()\n    );\n}\n\n#[test]\nfn hover_label_shorthand_in_pattern_call_arg_2() {\n    assert_hover!(\n        \"\npub type Wibble { Wibble(arg1: Int, arg2: Bool) }\n\npub fn main() {\n  let Wibble(arg2:, ..) = todo\n}\n\",\n        find_position_of(\"arg2:\").nth_occurrence(2).under_char('r')\n    );\n}\n\n#[test]\nfn hover_contextual_type() {\n    let code = \"\nimport wibble/wobble\nconst value = wobble.Wobble\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_contextual_type_aliased_module() {\n    let code = \"\nimport wibble/wobble as wubble\nconst value = wubble.Wobble\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_contextual_type_unqualified() {\n    let code = \"\nimport wibble/wobble.{type Wibble}\nconst value = wobble.Wobble\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_contextual_type_unqualified_aliased() {\n    let code = \"\nimport wibble/wobble.{type Wibble as Wobble}\nconst value = wobble.Wobble\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_contextual_type_aliased() {\n    let code = \"\nimport wibble/wobble\ntype Local = wobble.Wibble\nconst value = wobble.Wobble\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_contextual_type_function() {\n    let code = \"\nimport wibble/wobble\ntype MyInt = Int\nfn func(value: wobble.Wibble) -> MyInt { 1 }\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"func\").under_char('f')\n    );\n}\n\n#[test]\nfn hover_contextual_type_unqualified_import() {\n    let code = \"\nimport wibble/wobble.{type Wibble as Wobble, Wobble}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wobble }\"),\n        find_position_of(\"Wobble}\").under_char('W')\n    );\n}\n\n#[test]\nfn hover_contextual_type_pattern() {\n    let code = \"\nimport wibble/wobble.{Wibble, Wobble, Wubble}\n\npub fn cycle(wibble: wobble.Wibble) {\n  case wibble {\n    Wibble -> Wobble\n    Wobble -> Wubble\n    Wubble -> Wibble\n  }\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code)\n            .add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble Wobble Wubble }\"),\n        find_position_of(\"Wubble ->\").under_char('u')\n    );\n}\n\n#[test]\nfn hover_contextual_type_pattern_spread() {\n    let code = \"\nimport wibble/wobble.{type Wibble as Wobble}\n\ntype Thing {\n  Thing(id: Int, value: Wobble)\n}\n\npub fn main(thing: Thing) {\n  case thing {\n    Thing(id: 0, ..) -> 12\n    _ -> 14\n  }\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"..\").under_char('.')\n    );\n}\n\n#[test]\nfn hover_contextual_type_expression() {\n    let code = \"\nimport wibble/wobble\n\npub fn main() {\n  let wibble = wobble.Wibble\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\".Wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn hover_contextual_type_arg() {\n    let code = \"\nimport wibble/wobble\n\nfn do_things(wibble: wobble.Wibble) { wibble }\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"wibble:\").under_char('w')\n    );\n}\n\n#[test]\nfn hover_print_type_variable_names() {\n    let code = \"\nfn main(value: Result(ok, error)) {\n  let v = value\n  v\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"let v\").under_char('v')\n    );\n}\n\n#[test]\nfn hover_print_unbound_type_variable_names() {\n    let code = \"\nfn make_ok(value: some_type) {\n  let result = Ok(value)\n  result\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"result =\").under_char('s')\n    );\n}\n\n#[test]\nfn hover_print_unbound_type_variable_name_without_conflicts() {\n    let code = \"\nfn make_ok(value: a) {\n  let result = Ok(value)\n  result\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"result =\").under_char('s')\n    );\n}\n\n#[test]\nfn hover_print_imported_alias() {\n    let code = \"\nimport aliases.{type Aliased}\nconst thing: Aliased = 10\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"aliases\", \"pub type Aliased = Int\"),\n        find_position_of(\"thing\").under_char('g')\n    );\n}\n\n#[test]\nfn hover_prelude_type() {\n    let code = \"\nconst number = 100\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"number\").under_char('b')\n    );\n}\n\n#[test]\nfn hover_shadowed_prelude_type() {\n    let code = \"\ntype Int { Int }\nconst number = 100\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"number\").under_char('b')\n    );\n}\n\n#[test]\nfn hover_shadowed_prelude_type_imported() {\n    let code = \"\nimport numbers.{type Int}\nconst number = 100\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"numbers\", \"pub type Int\"),\n        find_position_of(\"number =\").under_char('b')\n    );\n}\n\n#[test]\nfn hover_contextual_type_annotation() {\n    let code = \"\nimport wibble/wobble\n\nfn make_wibble() -> wobble.Wibble { wobble.Wibble }\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"-> wobble.Wibble\").under_char('i')\n    );\n}\n\n#[test]\nfn hover_contextual_type_annotation_prelude() {\n    let code = \"\nfn add_one(a: Int) -> Int {\n  a + 1\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"-> Int\").under_char('I')\n    );\n}\n\n#[test]\nfn hover_contextual_type_annotation_unqualified() {\n    let code = \"\nimport wibble/wobble.{type Wibble}\n\nfn main(wibble: Wibble) {\n  wibble\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\": Wibble\").under_char('W')\n    );\n}\n\n#[test]\nfn hover_contextual_type_annotation_unqualified_aliased() {\n    let code = \"\nimport wibble/wobble.{type Wibble as Wubble}\n\nfn main(wibble: Wubble) {\n  wibble\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\": Wubble\").under_char('W')\n    );\n}\n\n#[test]\nfn hover_contextual_type_annotation_aliased_module() {\n    let code = \"\nimport wibble/wobble as wubble\n\nfn main(wibble: wubble.Wibble) {\n  wibble\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\": wubble.Wibble\").under_char('W')\n    );\n}\n\n#[test]\nfn hover_contextual_type_annotation_aliased() {\n    let code = \"\nimport wibble/wobble\n\ntype Wubble = wobble.Wibble\n\nfn main(wibble: Wubble) {\n  wibble\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"wibble/wobble\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\": Wubble\").under_char('e')\n    );\n}\n\n#[test]\nfn hover_print_underlying_for_alias_with_parameters() {\n    let code = \"\ntype LocalResult = Result(String, Int)\n\nfn do_thing() -> LocalResult {\n  Error(1)\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"do_thing\").under_char('d')\n    );\n}\n\n#[test]\nfn hover_print_alias_when_parameters_match() {\n    let code = \"\ntype MyResult(a, b) = Result(a, b)\n\nfn do_thing() -> MyResult(Int, Int) {\n  Error(1)\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"do_thing\").under_char('d')\n    );\n}\n\n#[test]\nfn hover_print_underlying_for_imported_alias() {\n    let code = \"\nimport alias.{type A}\n\nfn wibble() -> Result(Int, String) {\n  todo\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"alias\", \"pub type A = Result(Int, String)\"),\n        find_position_of(\"wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn hover_print_aliased_imported_generic_type() {\n    let code = \"\nimport gleam/option.{type Option as Maybe}\n\nconst none: Maybe(Int) = option.None\n\";\n\n    assert_hover!(\n        TestProject::for_source(code)\n            .add_hex_module(\"gleam/option\", \"pub type Option(a) { None Some(a) }\"),\n        find_position_of(\"none\").under_char('e')\n    );\n}\n\n#[test]\nfn hover_print_qualified_prelude_type_when_shadowed_by_alias() {\n    let code = \"\ntype Result = #(Bool, String)\nconst ok = Ok(10)\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"ok\").under_char('k')\n    );\n}\n\n#[test]\nfn hover_print_qualified_prelude_type_when_shadowed_by_imported_alias() {\n    let code = \"\nimport alias.{type Bool}\nconst value = True\n\";\n\n    assert_hover!(\n        TestProject::for_source(code).add_hex_module(\"alias\", \"pub type Bool = #(Int, Int)\"),\n        find_position_of(\"value\").under_char('v')\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/3761\n#[test]\nfn hover_over_block_in_list_spread() {\n    let code = \"\npub fn main() {\n  [1, 2, ..{\n    let x = 1\n    [x]\n  }]\n}\n\";\n\n    assert_hover!(TestProject::for_source(code), find_position_of(\"x\"));\n}\n\n// https://github.com/gleam-lang/gleam/issues/3758\n#[test]\nfn hover_for_anonymous_function_annotation() {\n    let code = \"\n/// An example type.\npub type Wibble\n\npub fn main() {\n  fn(w: Wibble) { todo }\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"w: Wibble\").under_char('b')\n    );\n}\n\n#[test]\nfn hover_for_label_in_pattern() {\n    let code = \"\ntype Wibble {\n  Wibble(wibble: Int, wobble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble: _, wobble: _) = todo\n  todo\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"wibble: _\").under_char('l')\n    );\n}\n\n#[test]\nfn hover_for_label_in_expression() {\n    let code = \"\nfn add(wibble a, wobble b) {\n  a + b\n}\n\npub fn main() {\n  add(wibble: 1, wobble: 2)\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"wibble:\").under_char('i')\n    );\n}\n\n#[test]\nfn hover_for_pattern_in_use() {\n    let code = \"\ntype Wibble {\n  Wibble(Int, Float)\n}\n\npub fn main() {\n  use Wibble(int, float) <- todo\n  todo\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"int\").under_char('i')\n    );\n}\n\n#[test]\nfn hover_for_annotation_in_use() {\n    let code = \"\npub fn main() {\n  use something: Int <- todo\n  todo\n}\n\";\n\n    assert_hover!(\n        TestProject::for_source(code),\n        find_position_of(\"Int\").under_char('n')\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\",\n        find_position_of(\"[\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_1() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\",\n        find_position_of(\"1\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_2() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\",\n        find_position_of(\"map\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_3() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\",\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_4() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\",\n        find_position_of(\"filter\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_5() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\n\",\n        find_position_of(\"fn(value)\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_6() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> filter(fn(value) { value })\n}\n\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\n\",\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn hover_on_pipe_with_invalid_step_8() {\n    assert_hover!(\n        \"\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> filter(fn(value) { value })\n}\n\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\n\",\n        find_position_of(\"fn(value)\")\n    );\n}\n\n#[test]\nfn hover_over_module_name() {\n    let src = \"\nimport wibble\n\npub fn main() {\n  wibble.wibble()\n}\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_hex_module(\n            \"wibble\",\n            \"\n//// This is the wibble module.\n//// Here is some documentation about it.\n//// This module does stuff\n\npub fn wibble() {\n  todo\n}\n\"\n        ),\n        find_position_of(\"wibble.\")\n    );\n}\n\n#[test]\nfn hover_over_module_with_path() {\n    let src = \"\nimport wibble/wobble\n\npub fn main() {\n  wobble.wibble()\n}\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_hex_module(\n            \"wibble/wobble\",\n            \"\n//// The module documentation\n\npub fn wibble() {\n  todo\n}\n\"\n        ),\n        find_position_of(\"wobble.\")\n    );\n}\n\n#[test]\nfn hover_over_module_name_in_annotation() {\n    let src = \"\nimport wibble\n\npub fn main(w: wibble.Wibble) {\n  todo\n}\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_hex_module(\n            \"wibble\",\n            \"\n//// This is the wibble module.\n//// Here is some documentation about it.\n//// This module does stuff\n\npub type Wibble\n\"\n        ),\n        find_position_of(\"wibble.\")\n    );\n}\n\n#[test]\nfn hover_over_imported_module() {\n    let src = \"\nimport wibble\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_hex_module(\n            \"wibble\",\n            \"\n//// This is the wibble module.\n//// Here is some documentation about it.\n//// This module does stuff\n\"\n        ),\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn no_hexdocs_link_when_hovering_over_local_module() {\n    let src = \"\nimport wibble\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_module(\n            \"wibble\",\n            \"\n//// This is the wibble module.\n//// Here is some documentation about it.\n//// This module does stuff\n\"\n        ),\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn hover_for_constant_int() {\n    assert_hover!(\n        \"\nconst ten = 10\n\",\n        find_position_of(\"10\")\n    );\n}\n\n#[test]\nfn hover_for_constant_float() {\n    assert_hover!(\n        \"\nconst pi = 3.14\n\",\n        find_position_of(\"3.14\")\n    );\n}\n#[test]\nfn hover_for_constant_string() {\n    assert_hover!(\n        r#\"\nconst message = \"Hello!\"\n\"#,\n        find_position_of(\"!\")\n    );\n}\n\n#[test]\nfn hover_for_constant_other_constant() {\n    assert_hover!(\n        \"\nconst constant1 = 10\nconst constant2 = constant1\n\",\n        find_position_of(\"= constant1\").under_char('s')\n    );\n}\n\n#[test]\nfn hover_for_constant_record() {\n    assert_hover!(\n        \"\ntype Wibble {\n  Wibble(Int)\n}\n\nconst w = Wibble(10)\n\",\n        find_position_of(\"Wibble(10)\").under_char('i')\n    );\n}\n\n#[test]\nfn hover_for_constant_tuple() {\n    assert_hover!(\n        \"\nconst tuple = #(1, 3.5, False)\n\",\n        find_position_of(\"#(\")\n    );\n}\n\n#[test]\nfn hover_for_constant_tuple_element() {\n    assert_hover!(\n        \"\nconst tuple = #(1, 3.5, False)\n\",\n        find_position_of(\"False\")\n    );\n}\n\n#[test]\nfn hover_for_constant_list() {\n    assert_hover!(\n        \"\nconst numbers = [2, 4, 6, 8]\n\",\n        find_position_of(\"[\")\n    );\n}\n\n#[test]\nfn hover_for_constant_list_element() {\n    assert_hover!(\n        \"\nconst numbers = [2, 4, 6, 8]\n\",\n        find_position_of(\"4\")\n    );\n}\n\n#[test]\nfn hover_for_constant_string_concatenation() {\n    assert_hover!(\n        r#\"\nconst name = \"Bob\"\nconst message = \"Hello \" <> name\n\"#,\n        find_position_of(\"<>\")\n    );\n}\n\n#[test]\nfn hover_for_constant_string_concatenation_side() {\n    assert_hover!(\n        r#\"\nconst name = \"Bob\"\nconst message = \"Hello \" <> name\n\"#,\n        find_position_of(\"<> name\").under_char('n')\n    );\n}\n\n#[test]\nfn hover_for_constant_bit_array() {\n    assert_hover!(\n        \"\nconst bits = <<1:2, 3:4>>\n\",\n        find_position_of(\",\")\n    );\n}\n\n#[test]\nfn hover_for_constant_bit_array_segment() {\n    assert_hover!(\n        \"\nconst bits = <<1:2, 3:4>>\n\",\n        find_position_of(\"1\")\n    );\n}\n\n#[test]\nfn hover_for_constant_bit_array_segment_option() {\n    assert_hover!(\n        \"\nconst bits = <<1:size(2), 3:4>>\n\",\n        find_position_of(\"2\")\n    );\n}\n\n#[test]\nfn hover_for_nested_constant() {\n    assert_hover!(\n        \"\ntype Wibble {\n  Wibble\n  Wobble(BitArray)\n}\n\nconst value = #(1, 2, [Wibble, Wobble(<<1, 2, 3>>), Wibble])\n\",\n        find_position_of(\"3\")\n    );\n}\n\n#[test]\nfn record_field_documentation() {\n    assert_hover!(\n        \"\npub type Wibble {\n  Wibble(\n    /// This is some documentation about the wibble field.\n    wibble: Int\n  )\n}\n\npub fn wibble(w: Wibble) {\n  w.wibble\n}\n\",\n        find_position_of(\"w.wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn no_documentation_for_shared_record_field() {\n    assert_hover!(\n        \"\npub type Wibble {\n  Wibble(\n    /// This is some documentation about the wibble field.\n    wibble: Int\n  )\n  Wobble(\n    /// Here's some documentation explaining a field of Wobble\n    wibble: Int\n  )\n}\n\npub fn wibble(w: Wibble) {\n  w.wibble\n}\n\",\n        find_position_of(\"w.wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn documentation_for_shared_record_field_when_variant_is_known() {\n    assert_hover!(\n        \"\npub type Wibble {\n  Wibble(\n    /// This is some documentation about the wibble field.\n    wibble: Int\n  )\n  Wobble(\n    /// This won't show up because it's a Wibble variant\n    wibble: Int\n  )\n}\n\npub fn wibble(w: Wibble) {\n  let assert Wibble(..) = w\n  w.wibble\n}\n\",\n        find_position_of(\"w.wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn hover_for_string_prefix_pattern() {\n    assert_hover!(\n        \"\npub fn main() {\n  case \\\"wibble\\\" {\n    \\\"wib\\\" as alias <> suffix -> alias <> suffix\n    other -> other\n  }\n}\n\",\n        find_position_of(\"<>\")\n    );\n}\n\n#[test]\nfn hover_for_string_prefix_pattern_prefix_alias() {\n    assert_hover!(\n        \"\npub fn main() {\n  case \\\"wibble\\\" {\n    \\\"wib\\\" as alias <> suffix -> alias <> suffix\n    other -> other\n  }\n}\n\",\n        find_position_of(\"alias\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn hover_for_string_prefix_pattern_suffix_variable() {\n    assert_hover!(\n        \"\npub fn main() {\n  case \\\"wibble\\\" {\n    \\\"wib\\\" as alias <> suffix -> alias <> suffix\n    other -> other\n  }\n}\n\",\n        find_position_of(\"suffix\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn hover_for_string_prefix_pattern_prefix_alias_alternative_definition() {\n    assert_hover!(\n        \"\npub fn main() {\n  case \\\"wibble\\\" {\n    \\\"wib\\\" as prefix <> rest | \\\"wob\\\" as prefix <> rest -> prefix <> rest\n    other -> other\n  }\n}\n\",\n        find_position_of(\"prefix\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_for_string_prefix_pattern_suffix_variable_alternative_definition() {\n    assert_hover!(\n        \"\npub fn main() {\n  case \\\"wibble\\\" {\n    \\\"wib\\\" <> rest | \\\"wob\\\" <> rest -> rest\n    other -> other\n  }\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_for_string_prefix_pattern_suffix_variable_discard() {\n    assert_hover!(\n        \"\npub fn main() {\n  case \\\"wibble\\\" {\n    \\\"wib\\\" <> _discard -> Nil\n    other -> Nil\n  }\n}\n\",\n        find_position_of(\"_discard\")\n    );\n}\n\n#[test]\nfn hover_for_custom_type() {\n    assert_hover!(\n        \"/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n  /// Some more exciting documentation\n  Wibble(String)\n  /// The most exciting documentation\n  Wobble(arg: Int)\n}\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n#[test]\nfn hover_type_constructor_with_no_fields() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    /// Some more exciting documentation\n    Wibble\n}\n\",\n        find_position_of(\"Wibble\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_type_constructor_with_label() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    /// Some more exciting documentation\n    Wibble(arg: String)\n    /// The most exciting documentation\n    Wobble(Int)\n}\n\",\n        find_position_of(\"Wibble\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_type_constructor_with_no_label() {\n    assert_hover!(\n        \"\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    /// Some more exciting documentation\n    Wibble(arg: String)\n    /// The most exciting documentation\n    Wobble(Int)\n}\n\",\n        find_position_of(\"Wobble\")\n    );\n}\n\n#[test]\nfn hover_for_local_variable_from_guard() {\n    assert_hover!(\n        \"\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\",\n        find_position_of(\"wobble\").nth_occurrence(2).under_char('o')\n    );\n}\n\n#[test]\nfn hover_for_record_from_guard() {\n    assert_hover!(\n        \"\ntype Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  let wibble = True\n  let wobble = Wibble\n  case wibble {\n    True if wobble == Wibble -> !wibble\n    False if wobble == Wobble -> wibble\n    _ -> Wibble\n  }\n}\n\",\n        find_position_of(\"== Wibble\").under_char('l')\n    );\n}\n\n#[test]\nfn hover_for_module_select_from_guard() {\n    let src = \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_module(\"mod\", \"pub const wibble = 10\"),\n        find_position_of(\"mod.wibble\").under_char('w')\n    );\n}\n\n#[test]\nfn hover_for_record_module_select_from_guard() {\n    let src = \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  let wobble = mod.Wibble\n  case wibble {\n    True if wobble == mod.Wobble -> !wibble\n    False if wobble == mod.Wibble -> wibble\n    _ -> mod.Wibble\n  }\n}\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_module(\"mod\", \"pub type Wobble { Wibble Wobble }\"),\n        find_position_of(\"== mod.Wibble\").under_char('i')\n    );\n}\n\n#[test]\nfn hover_for_module_select_pattern() {\n    let src = \"\nimport mod\npub fn go(x: mod.Wibble) {\n  case x {\n    mod.Wibble -> 1\n  }\n}\n\";\n    assert_hover!(\n        TestProject::for_source(src).add_module(\"mod\", \"pub type Wibble { Wibble }\"),\n        find_position_of(\"mod.Wibble\")\n            .under_char('W')\n            .nth_occurrence(2)\n    );\n}\n\n#[test]\nfn hover_for_invalid_record_update_1() {\n    assert_hover!(\n        \"\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n}\n\",\n        find_position_of(\"True\")\n    );\n}\n\n#[test]\nfn hover_for_invalid_record_update_2() {\n    assert_hover!(\n        \"\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n}\n\",\n        find_position_of(\"1\")\n    );\n}\n\n#[test]\nfn hover_for_invalid_record_update_3() {\n    assert_hover!(\n        \"\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n}\n\",\n        find_position_of(\"Wibble\").nth_occurrence(4)\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/reference.rs",
    "content": "use std::collections::HashMap;\n\nuse lsp_types::{\n    PartialResultParams, Position, Range, ReferenceContext, ReferenceParams,\n    TextDocumentPositionParams, WorkDoneProgressParams,\n};\n\nuse super::{TestProject, find_position_of};\n\nfn find_references(\n    tester: &TestProject<'_>,\n    position: Position,\n) -> Option<HashMap<String, Vec<Range>>> {\n    let locations = tester.at(position, |engine, params, _| {\n        let params = ReferenceParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: params.text_document,\n                position,\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: ReferenceContext {\n                include_declaration: true,\n            },\n        };\n        engine.find_references(params).result.unwrap()\n    })?;\n    let mut references: HashMap<String, Vec<Range>> = HashMap::new();\n\n    for location in locations {\n        let module_name = tester\n            .module_name_from_url(&location.uri)\n            .expect(\"Valid uri\");\n        _ = references\n            .entry(module_name)\n            .or_default()\n            .push(location.range);\n    }\n\n    Some(references)\n}\n\nfn show_references(code: &str, position: Option<Position>, ranges: &[Range]) -> String {\n    let mut buffer = String::new();\n\n    for (line_number, line) in code.lines().enumerate() {\n        let mut underline = String::new();\n        let mut underline_empty = true;\n        let line_number = line_number as u32;\n\n        for (column_number, _) in line.chars().enumerate() {\n            let current_position = Position::new(line_number, column_number as u32);\n\n            // Check if any range covers this specific character\n            let is_in_range = ranges\n                .iter()\n                .any(|range| range.start <= current_position && current_position < range.end);\n\n            if Some(current_position) == position {\n                underline_empty = false;\n                underline.push('↑');\n            } else if is_in_range {\n                underline_empty = false;\n                underline.push('▔');\n            } else {\n                underline.push(' ');\n            }\n        }\n\n        buffer.push_str(line);\n        if !underline_empty {\n            buffer.push('\\n');\n            buffer.push_str(&underline);\n        }\n        buffer.push('\\n');\n    }\n\n    buffer\n}\n\nmacro_rules! assert_references {\n    ($code:literal, $position:expr $(,)?) => {\n        assert_references!(TestProject::for_source($code), $position);\n    };\n\n    (($module_name:literal, $module_src:literal), $code:literal, $position:expr $(,)?) => {\n        assert_references!(\n            TestProject::for_source($code).add_module($module_name, $module_src),\n            $position\n        );\n    };\n\n    ($project:expr, $position:expr $(,)?) => {\n        let project = $project;\n        let src = project.src;\n        let position = $position.find_position(src);\n        let result = find_references(&project, position).expect(\"References not found\");\n\n        let mut output = String::new();\n        for (name, src) in project.root_package_modules.iter() {\n            output.push_str(&format!(\n                \"-- {name}.gleam\\n{}\\n\\n\",\n                show_references(src, None, result.get(*name).unwrap_or(&Vec::new()))\n            ));\n        }\n        output.push_str(&format!(\n            \"-- app.gleam\\n{}\",\n            show_references(\n                src,\n                Some(position),\n                result.get(\"app\").unwrap_or(&Vec::new())\n            )\n        ));\n\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\nmacro_rules! assert_no_references {\n    ($code:literal, $position:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_no_references!(&project, $position);\n    };\n\n    ($project:expr, $position:expr $(,)?) => {\n        let src = $project.src;\n        let position = $position.find_position(src);\n        let result = find_references($project, position);\n        assert_eq!(result, None);\n    };\n}\n\n#[test]\nfn references_for_local_variable() {\n    assert_references!(\n        \"\npub fn main() {\n  let wibble = 10\n  let wobble = wibble + 1\n  wibble + wobble\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_local_variable_from_definition() {\n    assert_references!(\n        \"\npub fn main() {\n  let wibble = 10\n  let wobble = wibble + 1\n  wibble + wobble\n}\n\",\n        find_position_of(\"wibble\"),\n    );\n}\n\n#[test]\nfn references_for_private_function() {\n    assert_references!(\n        \"\nfn wibble() {\n  wibble()\n}\n\npub fn main() {\n  let _ = wibble()\n  wibble() + 4\n}\n\nfn wobble() {\n  wibble() || wobble()\n}\n\",\n        find_position_of(\"wibble\"),\n    );\n}\n\n#[test]\nfn references_for_private_function_from_reference() {\n    assert_references!(\n        \"\nfn wibble() {\n  wibble()\n}\n\npub fn main() {\n  let _ = wibble()\n  wibble() + 4\n}\n\nfn wobble() {\n  wibble() || wobble()\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_public_function() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{wibble}\n\nfn wobble() {\n  app.wibble()\n}\n\nfn other() {\n  wibble()\n}\n\"\n        ),\n        \"\npub fn wibble() {\n  wibble()\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_function_from_qualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub fn wibble() {\n  wibble()\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() {\n  let value = mod.wibble()\n  mod.wibble()\n  value\n}\n\",\n        find_position_of(\"wibble\"),\n    );\n}\n\n#[test]\nfn references_for_function_from_unqualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub fn wibble() {\n  wibble()\n}\n\"\n        ),\n        \"\nimport mod.{wibble}\n\npub fn main() {\n  let value = wibble()\n  mod.wibble()\n  value\n}\n\",\n        find_position_of(\"wibble()\"),\n    );\n}\n\n#[test]\nfn references_for_private_constant() {\n    assert_references!(\n        \"\nconst wibble = 10\n\npub fn main() {\n  let _ = wibble\n  wibble + 4\n}\n\nfn wobble() {\n  wibble + wobble()\n}\n\",\n        find_position_of(\"wibble\"),\n    );\n}\n\n#[test]\nfn references_for_private_constant_from_reference() {\n    assert_references!(\n        \"\nconst wibble = 10\n\npub fn main() {\n  let _ = wibble\n  wibble + 4\n}\n\nfn wobble() {\n  wibble + wobble()\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_public_constant() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{wibble}\n\nfn wobble() {\n  app.wibble\n}\n\nfn other() {\n  wibble\n}\n\"\n        ),\n        \"\npub const wibble = 10\n\npub fn main() {\n  wibble\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_constant_from_qualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub const wibble = 10\n\nfn wobble() {\n  wibble\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() {\n  let value = mod.wibble\n  mod.wibble + value\n}\n\",\n        find_position_of(\"wibble\"),\n    );\n}\n\n#[test]\nfn references_for_constant_from_unqualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub const wibble = 10\n\nfn wobble() {\n  wibble\n}\n\"\n        ),\n        \"\nimport mod.{wibble}\n\npub fn main() {\n  let value = mod.wibble\n  wibble + value\n}\n\",\n        find_position_of(\"wibble +\"),\n    );\n}\n\n#[test]\nfn references_for_private_type_variant() {\n    assert_references!(\n        \"\ntype Wibble { Wibble }\n\nfn main() {\n  let _ = Wibble\n  Wibble\n}\n\nfn wobble() {\n  Wibble\n  wobble()\n}\n\",\n        find_position_of(\"Wibble }\"),\n    );\n}\n\n#[test]\nfn references_for_private_type_variant_from_reference() {\n    assert_references!(\n        \"\ntype Wibble { Wibble }\n\nfn main() {\n  let _ = Wibble\n  Wibble\n}\n\nfn wobble() {\n  Wibble\n  wobble()\n}\n\",\n        find_position_of(\" = Wibble\").under_char('W'),\n    );\n}\n\n#[test]\nfn references_for_public_type_variant() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{Wibble}\n\nfn wobble() {\n  app.Wibble\n}\n\nfn other() {\n  Wibble\n}\n\"\n        ),\n        \"\npub type Wibble { Wibble }\n\npub fn main() {\n  Wibble\n}\n\",\n        find_position_of(\"Wibble }\"),\n    );\n}\n\n#[test]\nfn references_for_type_variant_from_qualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Wibble }\n\nfn wobble() {\n  Wibble\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() {\n  let value = mod.Wibble\n  mod.Wibble\n  value\n}\n\",\n        find_position_of(\"Wibble\"),\n    );\n}\n\n#[test]\nfn references_for_type_variant_from_unqualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Wibble }\n\nfn wobble() {\n  Wibble\n}\n\"\n        ),\n        \"\nimport mod.{Wibble}\n\npub fn main() {\n  let value = mod.Wibble\n  Wibble\n}\n\",\n        find_position_of(\"Wibble\").nth_occurrence(3),\n    );\n}\n\n#[test]\nfn no_references_for_keyword() {\n    assert_no_references!(\n        \"\npub fn wibble() {\n  todo\n}\n\",\n        find_position_of(\"fn\")\n    );\n}\n\n#[test]\nfn references_for_aliased_value() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{Wibble as Wobble}\n\nfn wobble() {\n  Wobble\n}\n\"\n        ),\n        \"\npub type Wibble { Wibble }\n\npub fn main() {\n  Wibble\n}\n\",\n        find_position_of(\"Wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_aliased_const() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{wibble as other}\n\nfn wobble() {\n  other\n}\n\"\n        ),\n        \"\npub const wibble = 123\n\npub fn main() {\n  wibble\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_aliased_function() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{wibble as other}\n\nfn wobble() {\n  other()\n}\n\"\n        ),\n        \"\npub fn wibble() {\n  123\n}\n\npub fn main() {\n  wibble()\n}\n\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_private_type() {\n    assert_references!(\n        \"\ntype Wibble { Wibble }\n\nfn main() -> Wibble {\n  todo\n}\n\nfn wobble(w: Wibble) {\n  todo\n}\n\",\n        find_position_of(\"Wibble\"),\n    );\n}\n\n#[test]\nfn references_for_private_type_from_reference() {\n    assert_references!(\n        \"\ntype Wibble { Wibble }\n\nfn main() -> Wibble {\n  todo\n}\n\nfn wobble(w: Wibble) {\n  todo\n}\n\",\n        find_position_of(\"-> Wibble\").under_char('W'),\n    );\n}\n\n#[test]\nfn references_for_public_type() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{type Wibble}\n\nfn wobble() -> Wibble {\n  todo\n}\n\nfn other(w: app.Wibble) {\n  todo\n}\n\"\n        ),\n        \"\npub type Wibble { Wibble }\n\npub fn main() -> Wibble {\n  todo\n}\n\",\n        find_position_of(\"Wibble\"),\n    );\n}\n\n#[test]\nfn references_for_type_from_qualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Wibble }\n\nfn wobble() -> Wibble {\n  todo\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() -> mod.Wibble {\n  let _: mod.Wibble = todo\n}\n\",\n        find_position_of(\"Wibble\"),\n    );\n}\n\n#[test]\nfn references_for_type_from_unqualified_reference() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Wibble }\n\nfn wobble() -> Wibble {\n  todo\n}\n\"\n        ),\n        \"\nimport mod.{type Wibble}\n\npub fn main() -> Wibble {\n  let _: mod.Wibble = todo\n}\n\",\n        find_position_of(\"Wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_aliased_type() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\nimport app.{type Wibble as Wobble}\n\nfn wobble() -> Wobble {\n  todo\n}\n\nfn other(w: app.Wibble) {\n  todo\n}\n\"\n        ),\n        \"\npub type Wibble { Wibble }\n\npub fn main() -> Wibble {\n  todo\n}\n\",\n        find_position_of(\"-> Wibble\").under_char('W'),\n    );\n}\n\n#[test]\nfn references_for_type_from_let_annotation() {\n    assert_references!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Wibble }\n\nfn wobble() -> Wibble {\n  todo\n}\n\"\n        ),\n        \"\nimport mod.{type Wibble}\n\npub fn main() -> Wibble {\n  let _: mod.Wibble = todo\n}\n\",\n        find_position_of(\"mod.Wibble\").under_char('W'),\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_in_case() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let rest = case wibble {\n    \\\"1\\\" <> rest -> rest\n    other -> other\n  }\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_in_case_triggered_from_usage() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let rest = case wibble {\n    \\\"1\\\" <> rest -> rest\n    other -> other\n  }\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(3)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_with_alternative_definition_in_case() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let rest = case wibble {\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\n    other -> other\n  }\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_with_alternative_definition_triggered_from_second_pattern()\n {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let rest = case wibble {\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\n    other -> other\n  }\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(3),\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_with_alternative_definition_triggered_from_usage() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let rest = case wibble {\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\n    other -> other\n  }\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(4),\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_in_let_assert() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(1),\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_in_let_assert_triggered_from_usage() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\n  rest\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_in_case() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let digit = case wibble {\n    \\\"1\\\" as digit <> _rest -> digit\n    other -> other\n  }\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_in_case_triggered_from_usage() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let digit = case wibble {\n    \\\"1\\\" as digit <> _rest -> digit\n    other -> other\n  }\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(3)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_with_alternative_definitions_in_case() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let digit = case wibble {\n    \\\"1\\\" as digit <> _rest | \\\"2\\\" as digit <> _rest -> digit\n    other -> other\n  }\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_with_alternative_definitions_triggered_from_second_pattern() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let digit = case wibble {\n    \\\"1\\\" as digit <> _rest | \\\"2\\\" as digit <> _rest -> digit\n    other -> other\n  }\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(3)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_with_alternative_definitions_triggered_from_usage() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  let digit = case wibble {\n    \\\"1\\\" as digit <> _rest | \\\"2\\\" as digit <> _rest -> digit\n    other -> other\n  }\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(4)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_in_let_assert() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let assert \\\"1\\\" as digit <> _rest = \\\"1-wibble\\\"\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_in_let_assert_triggered_from_usage() {\n    assert_references!(\n        \"\npub fn main() -> String {\n  let assert \\\"1\\\" as digit <> _rest = \\\"1-wibble\\\"\n  digit\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_variable_nested_in_tuple() {\n    assert_references!(\n        \"\nfn main() {\n  case #(\\\"1-wibble\\\", 0) {\n    #(\\\"1\\\" <> rest, _) -> rest\n    _ -> \\\"\\\"\n  }\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_used_in_guard() {\n    assert_references!(\n        \"\nfn main() {\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" as digit <> _rest if digit == \\\"1\\\" -> digit\n    _ -> \\\"\\\"\n  }\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_used_in_guard() {\n    assert_references!(\n        \"\nfn main() {\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" <> rest if rest == \\\"-wibble\\\" -> rest\n    _ -> \\\"\\\"\n  }\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_suffix_shadowing_outer_variable() {\n    assert_references!(\n        \"\nfn main() {\n  let rest = \\\"outer\\\"\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" <> rest -> rest\n    _ -> rest\n  }\n}\n\",\n        find_position_of(\"rest\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn references_for_prefix_string_alias_and_suffix_complex_guard() {\n    assert_references!(\n        \"\nfn main() {\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" as digit <> rest if digit == \\\"1\\\" && rest == \\\"-wibble\\\" -> #(digit, rest)\n    _ -> #(\\\"\\\", \\\"\\\")\n  }\n}\n\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn references_for_local_variable_from_guard() {\n    assert_references!(\n        \"\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\",\n        find_position_of(\"wobble\").nth_occurrence(2).under_char('o')\n    );\n}\n\n#[test]\nfn references_for_module_select_from_guard() {\n    assert_references!(\n        (\"mod\", \"pub const wibble = 10\"),\n        \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\",\n        find_position_of(\"mod.wibble\").under_char('w')\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/rename.rs",
    "content": "use std::collections::HashMap;\n\nuse lsp_types::{\n    Position, Range, RenameParams, TextDocumentPositionParams, Url, WorkDoneProgressParams,\n};\n\nuse super::{TestProject, find_position_of, hover};\n\n/// Returns the rename range and edit to apply if the rename is valid and can be\n/// carried out.\n/// However if the rename produces an error response from the language server,\n/// the error message is returned.\nfn rename(\n    tester: &TestProject<'_>,\n    new_name: &str,\n    position: Position,\n) -> Result<Option<(Range, lsp_types::WorkspaceEdit)>, String> {\n    let prepare_rename_response = tester.at(position, |engine, params, _| {\n        let params = TextDocumentPositionParams {\n            text_document: params.text_document,\n            position,\n        };\n        engine.prepare_rename(params).result.unwrap()\n    });\n\n    let range = match prepare_rename_response {\n        Some(lsp_types::PrepareRenameResponse::Range(range)) => range,\n        Some(lsp_types::PrepareRenameResponse::RangeWithPlaceholder { range, .. }) => range,\n        _ => return Ok(None),\n    };\n\n    let outcome = tester.at(position, |engine, params, _| {\n        let params = RenameParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: params.text_document,\n                position,\n            },\n            new_name: new_name.to_string(),\n            work_done_progress_params: WorkDoneProgressParams::default(),\n        };\n        engine.rename(params).result.unwrap()\n    });\n\n    match outcome {\n        Ok(Some(edit)) => Ok(Some((range, edit))),\n        Ok(None) => Ok(None),\n        Err(error) => Err(error.message),\n    }\n}\n\nfn apply_rename(\n    tester: &TestProject<'_>,\n    new_name: &str,\n    position: Position,\n) -> (Range, HashMap<String, String>) {\n    let (range, edit) = rename(tester, new_name, position)\n        .expect(\"Rename failed\")\n        .expect(\"No rename produced\");\n    let changes = edit.changes.expect(\"No text edit found\");\n    (range, apply_code_edit(tester, changes))\n}\n\nfn apply_code_edit(\n    tester: &TestProject<'_>,\n    changes: HashMap<Url, Vec<lsp_types::TextEdit>>,\n) -> HashMap<String, String> {\n    let mut modules = HashMap::new();\n    for (uri, change) in changes {\n        let module_name = tester.module_name_from_url(&uri).expect(\"Valid uri\");\n        let module_code = tester.src_from_module_url(&uri).expect(\"Module exists\");\n\n        _ = modules.insert(module_name, super::apply_code_edit(module_code, change));\n    }\n\n    modules\n}\n\nmacro_rules! assert_rename {\n    ($code:literal, $new_name:literal, $position:expr $(,)?) => {\n        assert_rename!(TestProject::for_source($code), $new_name, $position);\n    };\n\n    (($module_name:literal, $module_src:literal), $code:literal, $new_name:literal, $position:expr $(,)?) => {\n        assert_rename!(\n            TestProject::for_source($code).add_module($module_name, $module_src),\n            $new_name,\n            $position\n        );\n    };\n\n    ($project:expr, $new_name:literal, $position:expr $(,)?) => {\n        let project = $project;\n        let src = project.src;\n        let position = $position.find_position(src);\n        let (range, result) = apply_rename(&project, $new_name, position);\n\n        let mut output = String::from(\"----- BEFORE RENAME\\n\");\n        for (name, src) in project.root_package_modules.iter() {\n            output.push_str(&format!(\"-- {name}.gleam\\n{src}\\n\\n\"));\n        }\n        output.push_str(&format!(\n            \"-- app.gleam\\n{}\\n\\n----- AFTER RENAME\\n\",\n            hover::show_hover(src, range, range.start)\n        ));\n        for (name, src) in project.root_package_modules.iter() {\n            output.push_str(&format!(\n                \"-- {name}.gleam\\n{}\\n\\n\",\n                result\n                    .get(*name)\n                    .map(|string| string.as_str())\n                    .unwrap_or(*src)\n            ));\n        }\n        output.push_str(&format!(\n            \"-- app.gleam\\n{}\",\n            result\n                .get(\"app\")\n                .map(|string| string.as_str())\n                .unwrap_or(src)\n        ));\n\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\nmacro_rules! assert_no_rename {\n    ($code:literal, $new_name:literal, $position:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_no_rename!(&project, $new_name, $position);\n    };\n\n    ($project:expr, $new_name:literal, $position:expr $(,)?) => {\n        let src = $project.src;\n        let position = $position.find_position(src);\n        let result = rename($project, $new_name, position);\n        assert_eq!(result, Ok(None));\n    };\n}\n\nmacro_rules! assert_rename_error {\n    ($code:literal, $new_name:literal, $position:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_rename_error!(&project, $new_name, $position);\n    };\n\n    ($project:expr, $new_name:literal, $position:expr $(,)?) => {\n        let src = $project.src;\n        let position = $position.find_position(src);\n        let error = rename($project, $new_name, position).unwrap_err();\n        let snapshot = format!(\"Error response message:\\n\\n{error}\");\n        insta::assert_snapshot!(insta::internals::AutoName, snapshot, src);\n    };\n}\n\n#[test]\nfn rename_local_variable() {\n    assert_rename!(\n        \"\npub fn main() {\n  let wibble = 10\n  wibble\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_shadowed_local_variable() {\n    assert_rename!(\n        \"\npub fn main() {\n  let wibble = 10\n  let wibble = wibble / 2\n  wibble\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble /\"),\n    );\n}\n\n#[test]\nfn rename_shadowing_local_variable() {\n    assert_rename!(\n        \"\npub fn main() {\n  let wibble = 10\n  let wibble = wibble / 2\n  wibble\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble\").nth_occurrence(4),\n    );\n}\n\n#[test]\nfn rename_local_variable_record_access() {\n    assert_rename!(\n        \"\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(wibble: 1)\n  wibble.wibble\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble.\"),\n    );\n}\n#[test]\nfn rename_local_variable_guard_clause() {\n    assert_rename!(\n        \"\npub fn main() {\n  let wibble = True\n  case Nil {\n    Nil if wibble -> todo\n    _ -> panic\n  }\n  wibble || False\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble ||\"),\n    );\n}\n\n#[test]\nfn rename_local_variable_from_definition() {\n    assert_rename!(\n        \"\npub fn main() {\n  let wibble = 10\n  let wobble = wibble + 1\n  wobble - wibble\n}\n\",\n        \"some_value\",\n        find_position_of(\"wibble =\")\n    );\n}\n\n#[test]\nfn rename_local_variable_from_definition_nested_pattern() {\n    assert_rename!(\n        \"\npub fn main() {\n  let assert Ok([_, wibble, ..]) = Error(12)\n  wibble\n}\n\",\n        \"second_element\",\n        find_position_of(\"wibble,\")\n    );\n}\n\n#[test]\nfn rename_local_variable_assignment_pattern() {\n    assert_rename!(\n        \"\npub fn main() {\n  let assert Error(12 as something) = Error(12)\n  something\n}\n\",\n        \"the_error\",\n        find_position_of(\"something\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_local_variable_from_definition_assignment_pattern() {\n    assert_rename!(\n        \"\npub fn main() {\n  let assert Error(12 as something) = Error(12)\n  something\n}\n\",\n        \"the_error\",\n        find_position_of(\"something)\")\n    );\n}\n\n#[test]\nfn rename_local_variable_argument() {\n    assert_rename!(\n        \"\npub fn add(first_number: Int, x: Int) -> Int {\n  x + first_number\n}\n\",\n        \"second_number\",\n        find_position_of(\"x +\")\n    );\n}\n\n#[test]\nfn rename_local_variable_argument_from_definition() {\n    assert_rename!(\n        \"\npub fn wibble(wibble: Float) {\n  wibble /. 0.3\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble:\")\n    );\n}\n\n#[test]\nfn rename_local_variable_label_shorthand() {\n    assert_rename!(\n        \"\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble:) = todo\n  wibble + 1\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble +\")\n    );\n}\n\n#[test]\nfn rename_local_variable_label_shorthand_from_definition() {\n    assert_rename!(\n        \"\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble:) = todo\n  wibble + 1\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble:)\")\n    );\n}\n\n#[test]\nfn rename_local_variable_from_label_shorthand() {\n    assert_rename!(\n        \"\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let wibble = todo\n  Wibble(wibble:)\n}\n\",\n        \"wobble\",\n        find_position_of(\"wibble:)\")\n    );\n}\n\n#[test]\nfn rename_local_variable_in_bit_array_pattern() {\n    assert_rename!(\n        \"\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n  let prefix_size = bit_size(prefix)\n\n  case bits {\n    <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True\n    _ -> False\n  }\n}\n\",\n        \"size_of_prefix\",\n        find_position_of(\"prefix_size =\")\n    );\n}\n\n#[test]\nfn rename_local_variable_from_bit_array_pattern() {\n    assert_rename!(\n        \"\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n  let prefix_size = bit_size(prefix)\n\n  case bits {\n    <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True\n    _ -> False\n  }\n}\n\",\n        \"size_of_prefix\",\n        find_position_of(\"prefix_size)\")\n    );\n}\n\n#[test]\nfn no_rename_keyword() {\n    assert_no_rename!(\n        \"\npub fn main() {}\n\",\n        \"wibble\",\n        find_position_of(\"fn\"),\n    );\n}\n\n#[test]\nfn no_rename_invalid_name() {\n    assert_rename_error!(\n        \"\npub fn main() {\n  let wibble = 10\n  wibble\n}\n\",\n        \"Not_AValid_Name\",\n        find_position_of(\"wibble\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_function_from_definition() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() {\n  app.something()\n}\n\"\n        ),\n        \"\npub fn something() {\n  something()\n}\n\nfn something_else() {\n  something()\n}\n\",\n        \"some_function\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn rename_function_from_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() {\n  app.something()\n}\n\"\n        ),\n        \"\npub fn something() {\n  something()\n}\n\nfn something_else() {\n  something()\n}\n\",\n        \"some_function\",\n        find_position_of(\"something\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_function_from_qualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub fn wibble() {\n  wibble()\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() {\n  mod.wibble()\n}\n\",\n        \"some_function\",\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn rename_function_from_unqualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub fn wibble() {\n  wibble()\n}\n\"\n        ),\n        \"\nimport mod.{wibble}\n\npub fn main() {\n  wibble()\n  mod.wibble()\n}\n\",\n        \"some_function\",\n        find_position_of(\"wibble(\")\n    );\n}\n\n#[test]\nfn rename_aliased_function() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app.{something as something_else}\n\nfn wibble() {\n  something_else()\n}\n\"\n        ),\n        \"\npub fn something() {\n  something()\n}\n\nfn something_else() {\n  something()\n}\n\",\n        \"some_function\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn rename_function_shadowing_module() {\n    let src = \"\nimport gleam/list\n\npub fn list() {\n  []\n}\n\npub fn main() {\n  list.map(todo, todo)\n}\n    \";\n\n    assert_rename!(\n        TestProject::for_source(src).add_hex_module(\"gleam/list\", \"pub fn map(_, _) {}\"),\n        \"empty_list\",\n        find_position_of(\"list()\")\n    );\n}\n\n#[test]\nfn rename_function_shadowed_by_field_access() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\ntype App {\n  App(something: Int)\n}\n\npub fn main() {\n  let app = App(10)\n  app.something\n}\n\"\n        ),\n        \"\npub fn something() {\n  todo\n}\n\",\n        \"function\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn no_rename_function_with_invalid_name() {\n    assert_rename_error!(\n        \"\npub fn main() {\n  let wibble = 10\n  wibble\n}\n\",\n        \"Not_AValid_Name\",\n        find_position_of(\"main\")\n    );\n}\n\n#[test]\nfn no_rename_function_from_other_package() {\n    let src = \"\nimport wibble\n\npub fn main() {\n  wibble.wobble()\n}\n\";\n\n    assert_no_rename!(\n        &TestProject::for_source(src).add_hex_module(\"wibble\", \"pub fn wobble() { todo }\"),\n        \"something\",\n        find_position_of(\"wobble\")\n    );\n}\n\n#[test]\nfn rename_constant_from_definition() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() {\n  app.something\n}\n\"\n        ),\n        \"\npub const something = 10\n\npub fn main() {\n  something + { 4 * something }\n}\n\",\n        \"ten\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn rename_constant_from_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() {\n  app.something\n}\n\"\n        ),\n        \"\npub const something = 10\n\npub fn main() {\n  something + { 4 * something }\n}\n\",\n        \"ten\",\n        find_position_of(\"something\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_constant_from_qualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub const something = 10\n\nfn wibble() {\n  something\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() {\n  mod.something\n}\n\",\n        \"ten\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn rename_constant_from_unqualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub const something = 10\n\nfn wibble() {\n  something\n}\n\"\n        ),\n        \"\nimport mod.{something}\n\npub fn main() {\n  something + mod.something\n}\n\",\n        \"ten\",\n        find_position_of(\"something +\")\n    );\n}\n\n#[test]\nfn rename_aliased_constant() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app.{something as some_constant}\n\nfn wibble() {\n  some_constant\n}\n\"\n        ),\n        \"\npub const something = 10\n\npub fn main() {\n  something + { 4 * something }\n}\n\",\n        \"ten\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn rename_constant_shadowing_module() {\n    let src = \"\nimport gleam/list\n\nconst list = []\n\npub fn main() {\n  list.map(todo, todo)\n}\n    \";\n\n    assert_rename!(\n        TestProject::for_source(src).add_hex_module(\"gleam/list\", \"pub fn map(_, _) {}\"),\n        \"empty_list\",\n        find_position_of(\"list =\")\n    );\n}\n\n#[test]\nfn rename_constant_shadowed_by_field_access() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\ntype App {\n  App(something: Int)\n}\n\npub fn main() {\n  let app = App(10)\n  app.something\n}\n\"\n        ),\n        \"\npub const something = 10\n\",\n        \"constant\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn no_rename_constant_with_invalid_name() {\n    assert_rename_error!(\n        \"\nconst value = 10\n\",\n        \"Ten\",\n        find_position_of(\"value\")\n    );\n}\n\n#[test]\nfn no_rename_constant_from_other_package() {\n    let src = \"\nimport wibble\n\npub fn main() {\n  wibble.wobble\n}\n\";\n\n    assert_no_rename!(\n        &TestProject::for_source(src).add_hex_module(\"wibble\", \"pub const wobble = 2\"),\n        \"something\",\n        find_position_of(\"wobble\")\n    );\n}\n\n#[test]\nfn rename_type_variant_from_definition() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() {\n  app.Constructor(4)\n}\n\"\n        ),\n        \"\npub type Wibble {\n  Constructor(Int)\n}\n\npub fn main() {\n  Constructor(10)\n}\n\",\n        \"Wibble\",\n        find_position_of(\"Constructor(Int\")\n    );\n}\n\n#[test]\nfn rename_type_variant_from_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() {\n  app.Constructor(4)\n}\n\"\n        ),\n        \"\npub type Wibble {\n  Constructor(Int)\n}\n\npub fn main() {\n  Constructor(10)\n}\n\",\n        \"Wibble\",\n        find_position_of(\"Constructor(10\")\n    );\n}\n\n#[test]\nfn rename_type_variant_from_qualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub type Wibble {\n  Constructor(Int)\n}\n\nfn wibble() {\n  Constructor(42)\n}\n\"\n        ),\n        \"\nimport mod\n\npub fn main() {\n  mod.Constructor\n}\n\",\n        \"Variant\",\n        find_position_of(\"Constructor\")\n    );\n}\n\n#[test]\nfn rename_type_variant_from_unqualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub type Wibble {\n  Constructor(Int)\n}\n\nfn wibble() {\n  Constructor(81)\n}\n\"\n        ),\n        \"\nimport mod.{Constructor}\n\npub fn main() {\n  #(Constructor(75), mod.Constructor(57))\n}\n\",\n        \"Number\",\n        find_position_of(\"Constructor(75\")\n    );\n}\n\n#[test]\nfn rename_aliased_type_variant() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app.{Constructor as ValueConstructor}\n\nfn wibble() {\n  ValueConstructor(172)\n}\n\"\n        ),\n        \"\npub type Wibble {\n  Constructor(Int)\n}\n\npub fn main() {\n  Constructor(42)\n}\n\",\n        \"MakeAWibble\",\n        find_position_of(\"Constructor\")\n    );\n}\n\n#[test]\nfn no_rename_type_variant_with_invalid_name() {\n    assert_rename_error!(\n        \"\npub type Wibble {\n  Constructor(Int)\n}\n\",\n        \"name_in_snake_case\",\n        find_position_of(\"Constructor\")\n    );\n}\n\n#[test]\nfn rename_custom_type_variant_pattern() {\n    assert_rename!(\n        \"\npub type Type {\n  X\n  Y\n}\n\npub fn main(t) {\n  case t {\n    X -> 0\n    Y -> 0\n  }\n}\n\",\n        \"Renamed\",\n        find_position_of(\"X\")\n    );\n}\n\n#[test]\nfn rename_imported_custom_type_variant_pattern() {\n    assert_rename!(\n        (\n            \"other\",\n            \"\nimport app\n\npub fn main(t) {\n  case t {\n    app.X -> 0\n    app.Y -> 0\n  }\n}\n\"\n        ),\n        \"\npub type Type {\n  X\n  Y\n}\n\",\n        \"Renamed\",\n        find_position_of(\"X\")\n    );\n}\n\n#[test]\nfn rename_imported_unqualified_custom_type_variant_pattern() {\n    assert_rename!(\n        (\n            \"other\",\n            \"\nimport app.{X, Y}\n\npub fn main(t) {\n  case t {\n    X -> 0\n    Y -> 0\n  }\n}\n\"\n        ),\n        \"\npub type Type {\n  X\n  Y\n}\n\",\n        \"Renamed\",\n        find_position_of(\"X\")\n    );\n}\n\n#[test]\nfn rename_type_variant_pattern_with_arguments() {\n    assert_rename!(\n        \"\npub type Wibble {\n  Wibble(Int)\n  Wobble(Float)\n}\n\nfn wibble() {\n  case Wibble(10) {\n    Wibble(20) -> todo\n    Wibble(_) -> panic\n  }\n}\n\",\n        \"Variant\",\n        find_position_of(\"Wibble(10)\")\n    );\n}\n\n#[test]\nfn rename_type_variant_from_pattern() {\n    assert_rename!(\n        \"\npub type Type {\n  X\n  Y\n}\n\npub fn main(t) {\n  case t {\n    X -> 0\n    Y -> 0\n  }\n}\n\",\n        \"Renamed\",\n        find_position_of(\"X ->\")\n    );\n}\n\n#[test]\nfn no_rename_type_variant_from_other_package() {\n    let src = \"\nimport wibble\n\npub fn main() {\n  wibble.Wibble(10)\n}\n\";\n\n    assert_no_rename!(\n        &TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble(Int) }\"),\n        \"Constructor\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n#[test]\nfn rename_value_in_nested_module() {\n    assert_rename!(\n        (\n            \"sub/mod\",\n            \"\npub fn wibble() {\n  wibble()\n}\n\"\n        ),\n        \"\nimport sub/mod\n\npub fn main() {\n  mod.wibble()\n}\n\",\n        \"some_function\",\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn rename_value_in_aliased_module() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub fn wibble() {\n  wibble()\n}\n\"\n        ),\n        \"\nimport mod as the_module\n\npub fn main() {\n  the_module.wibble()\n}\n\",\n        \"some_function\",\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn rename_aliased_value() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app.{Wibble as Wobble}\n\nfn wobble() {\n  Wobble\n}\n\"\n        ),\n        \"\npub type Wibble { Wibble }\n\npub fn main() {\n  Wibble\n}\n\",\n        \"Wubble\",\n        find_position_of(\"Wibble }\")\n    );\n}\n\n#[test]\nfn rename_type_from_definition() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() -> app.Wibble { todo }\n\"\n        ),\n        \"\npub type Wibble { Constructor }\n\npub fn main(w: Wibble) -> Wibble { todo }\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n#[test]\nfn rename_type_from_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\nfn wibble() -> app.Wibble { todo }\n\"\n        ),\n        \"\npub type Wibble { Constructor }\n\npub fn main(w: Wibble) -> Wibble { todo }\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_type_from_qualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Constructor }\n\nfn wibble(w: Wibble) -> Wibble { todo }\n\"\n        ),\n        \"\nimport mod\n\npub fn main(w: mod.Wibble) -> mod.Wibble { todo }\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n#[test]\nfn rename_type_from_unqualified_reference() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub type Wibble { Constructor }\n\nfn wibble(w: Wibble) -> Wibble { todo }\n\"\n        ),\n        \"\nimport mod.{type Wibble}\n\npub fn main(w: Wibble) -> mod.Wibble { todo }\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble)\")\n    );\n}\n\n#[test]\nfn rename_aliased_type() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app.{type Wibble as Wobble}\n\nfn wibble() -> Wobble { todo }\n\"\n        ),\n        \"\npub type Wibble { Constructor }\n\npub fn main(w: Wibble) -> Wibble { todo }\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n#[test]\nfn no_rename_type_with_invalid_name() {\n    assert_rename_error!(\n        \"\ntype Wibble { Wobble }\n\",\n        \"a_type_name\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n#[test]\nfn no_rename_type_from_other_package() {\n    let src = \"\nimport wibble\n\npub fn main() -> wibble.Wibble { todo }\n\";\n\n    assert_no_rename!(\n        &TestProject::for_source(src).add_hex_module(\"wibble\", \"pub type Wibble { Wibble }\"),\n        \"SomeType\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4372\n#[test]\nfn rename_type_referenced_in_variant_constructor_argument() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\nimport app\n\npub type Wobble {\n  Wobble(w: app.Wibble)\n}\n\"\n        ),\n        \"\npub type Wibble {\n  Wibble\n}\n\npub fn main() {\n  let wibble = Wibble\n}\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4372\n#[test]\nfn rename_type_from_variant_constructor_argument() {\n    assert_rename!(\n        (\n            \"mod\",\n            \"\npub type Wibble {\n  Wibble\n}\n\npub fn main() {\n  let wibble = Wibble\n}\n\"\n        ),\n        \"\nimport mod\n\npub type Wobble {\n  Wobble(w: mod.Wibble)\n}\n\",\n        \"SomeType\",\n        find_position_of(\"Wibble\")\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4553\n#[test]\nfn rename_local_variable_with_label_shorthand() {\n    assert_rename!(\n        \"\npub type Wibble {\n  Wibble(first: Int, second: Int)\n}\n\npub fn main() {\n  let second = 2\n  Wibble(first: 1, second:)\n}\n\",\n        \"something\",\n        find_position_of(\"second =\")\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4748\n#[test]\nfn rename_alternative_pattern() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->\n      wibble + wobble\n    _ -> 0\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"wibble\")\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/5091\n#[test]\nfn rename_alternative_pattern_aliases() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [] as list | [_] as list -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\")\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_aliases_from_alternative() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [] as list | [_] as list -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_aliases_from_usage() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [] as list | [_] as list -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\").nth_occurrence(3)\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_alias_and_variable_1() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [] as list | [_, ..list] -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_alias_and_variable_2() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [] as list | [_, ..list] -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_alias_and_variable_3() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [_, ..list] | [] as list -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_alias_and_variable_4() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    [_, ..list] | [] as list -> list\n    _ -> []\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"list\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_alternative_pattern_from_usage() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  case x {\n    #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->\n      wibble + wobble\n    _ -> 0\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"wibble +\")\n    );\n}\n\n// https://github.com/gleam-lang/gleam/issues/4605\n#[test]\nfn rename_prelude_value() {\n    assert_rename!(\n        \"\npub fn main() {\n  Ok(10)\n}\n\",\n        \"Success\",\n        find_position_of(\"Ok\")\n    );\n}\n#[test]\nfn rename_prelude_type() {\n    assert_rename!(\n        \"\npub fn main() -> Result(Int, Nil) {\n  Ok(10)\n}\n\",\n        \"SuccessOrFailure\",\n        find_position_of(\"Result\")\n    );\n}\n\n#[test]\nfn rename_variable_with_alternative_pattern_with_same_name() {\n    assert_rename!(\n        \"\npub fn main(x) {\n  let some_var = 10\n\n  case x {\n    #(some_var, []) | #(_, [some_var]) ->\n      some_var\n    _ -> 0\n  }\n\n  some_var\n}\n\",\n        \"new_name\",\n        find_position_of(\"some_var\")\n    );\n}\n\n#[test]\nfn rename_prelude_value_with_prelude_already_imported() {\n    assert_rename!(\n        \"\nimport gleam\n\npub fn main() {\n  Ok(gleam.Error(10))\n}\n\",\n        \"Success\",\n        find_position_of(\"Ok\")\n    );\n}\n\n#[test]\nfn rename_prelude_value_with_prelude_import_with_empty_braces() {\n    assert_rename!(\n        \"\nimport gleam.{}\n\npub fn main() {\n  Ok(gleam.Error(10))\n}\n\",\n        \"Success\",\n        find_position_of(\"Ok\")\n    );\n}\n\n#[test]\nfn rename_prelude_value_with_other_prelude_value_imported() {\n    assert_rename!(\n        \"\nimport gleam.{Error}\n\npub fn main() {\n  Ok(Error(10))\n}\n\",\n        \"Success\",\n        find_position_of(\"Ok\")\n    );\n}\n\n#[test]\nfn rename_prelude_type_with_prelude_value_imported_with_trailing_comma() {\n    assert_rename!(\n        \"\nimport gleam.{Error,}\n\npub fn main() -> Result(Int, Nil) {\n  Error(10)\n}\n\",\n        \"OkOrError\",\n        find_position_of(\"Result\")\n    );\n}\n\n#[test]\nfn rename_prelude_value_with_other_module_imported() {\n    assert_rename!(\n        (\"something\", \"pub type Something\"),\n        \"\nimport something\n\npub fn main() {\n  Ok(10)\n}\n\",\n        \"Success\",\n        find_position_of(\"Ok\")\n    );\n}\n\n#[test]\nfn rename_module_access_in_clause_guard() {\n    assert_rename!(\n        (\n            \"wibble\",\n            \"\nimport app\n\npub fn main() {\n  case app.something {\n    thing if thing == app.something -> True\n    _ -> False\n  }\n}\n\"\n        ),\n        \"\npub const something = 10\n\",\n        \"new_name\",\n        find_position_of(\"something\")\n    );\n}\n\n#[test]\nfn rename_variable_used_in_record_update() {\n    assert_rename!(\n        \"\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int)\n}\n\nfn wibble(wibble: Wibble) {\n  Wibble(..wibble, c: 1)\n}\n\",\n        \"value\",\n        find_position_of(\"wibble:\")\n    );\n}\n\n//https://github.com/gleam-lang/gleam/issues/4941\n#[test]\nfn rename_external_function() {\n    assert_rename!(\n        r#\"\npub fn main() { wibble() }\n\n@external(erlang, \"a\", \"a\")\nfn wibble() -> Nil\n\"#,\n        \"new_name\",\n        find_position_of(\"wibble\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_external_javascript_function_with_pure_gleam_fallback() {\n    assert_rename!(\n        r#\"\npub fn main() { wibble() }\n\n@external(javascript, \"a\", \"a\")\nfn wibble() -> Nil {\n  Nil\n}\n\"#,\n        \"new_name\",\n        find_position_of(\"wibble\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_nested_aliased_pattern() {\n    assert_rename!(\n        r#\"\npub fn go(x) {\n  case x {\n    [[nested, ..] as wibble, ..] -> todo\n    _ -> todo\n  }\n}\n        \"#,\n        \"new_name\",\n        find_position_of(\"nested\")\n    );\n}\n\n#[test]\nfn rename_module_from_import() {\n    assert_rename!(\n        TestProject::for_source(\"import      option\")\n            .add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\"),\n    );\n}\n\n#[test]\nfn rename_works_when_error_is_present() {\n    assert_rename!(\n        r#\"\nfn wibble() {\n  \"test string\"\n}\n\npub fn main() {\n  1 + \"1\"\n  echo wibble()\n}\n  \"#,\n        \"wobble\",\n        find_position_of(\"wibble\")\n    );\n}\n\n#[test]\nfn rename_module_from_import_with_alias() {\n    assert_rename!(\n        TestProject::for_source(\"import   option    as      opt\")\n            .add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"o\",\n        find_position_of(\"opt\"),\n    );\n}\n\n#[test]\nfn reanem_module_from_import_with_unqualified_values() {\n    assert_rename!(\n        TestProject::for_source(\"import   option   .   {    Some, None }\")\n            .add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\"),\n    );\n}\n\n#[test]\nfn rename_module_from_import_with_unqualified_value_and_alias() {\n    assert_rename!(\n        TestProject::for_source(\"import   option  .     {Some, None}   as     opt\")\n            .add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"o\",\n        find_position_of(\"opt\"),\n    );\n}\n\n#[test]\nfn rename_module_from_import_namespaced() {\n    assert_rename!(\n        TestProject::for_source(\"import   std /   option  \")\n            .add_module(\"std/option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\"),\n    );\n}\n\n#[test]\nfn rename_module_from_import_namespaced_with_alias() {\n    assert_rename!(\n        TestProject::for_source(\"import   std /   option   as     opt\")\n            .add_module(\"std/option\", \"pub type Option(a) { Some(a) None }\"),\n        \"o\",\n        find_position_of(\"opt\"),\n    );\n}\n\n#[test]\nfn rename_module_from_import_namespaced_with_unqualified_values() {\n    assert_rename!(\n        TestProject::for_source(\"import   std /   option   .   {    Some, None }\")\n            .add_module(\"std/option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\"),\n    );\n}\n\n#[test]\nfn rename_module_from_import_namespaced_with_unqualified_value_and_alias() {\n    assert_rename!(\n        TestProject::for_source(\"import   std /   option   .   {    Some, None }   as     opt\")\n            .add_module(\"std/option\", \"pub type Option(a) { Some(a) None }\"),\n        \"o\",\n        find_position_of(\"opt\"),\n    );\n}\n\n#[test]\nfn rename_module_from_import_with_alias_to_original_name() {\n    assert_rename!(\n        TestProject::for_source(\"import   option   as     opt\")\n            .add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"option\",\n        find_position_of(\"opt\"),\n    );\n}\n\n#[test]\nfn rename_module_from_variant_in_expression() {\n    let src = r#\"\nimport option\n\npub fn main() {\n  echo option     . None\n}\n\"#;\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_in_case() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" <> rest -> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_module_from_constant_in_expression() {\n    let src = r#\"\nimport maths\n\npub fn main() {\n  echo maths  .    pi\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"maths\", \"pub const pi = 3.14\"),\n        \"m\",\n        find_position_of(\"maths\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_variant_in_const() {\n    let src = r#\"\nimport option\n\nconst x = option   .None\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_constant_in_const() {\n    let src = r#\"\nimport maths\n\nconst x = maths   .  pi\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"maths\", \"pub const pi = 3.14\"),\n        \"m\",\n        find_position_of(\"maths\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_variant_in_pattern() {\n    let src = r#\"\nimport option\n\npub fn is_some(option) {\n  case option {\n    option.  Some(_) -> True\n    option  .None -> False\n  }\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(4),\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_in_case_triggered_from_usage() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" <> rest -> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_module_from_variant_in_clause_guard() {\n    let src = r#\"\nimport option\n\npub fn count_none(list) {\n  case list {\n    [option, ..rest] if option == option  . None -> 1 + count_none(rest)\n    [_, ..rest] -> count_none(rest)\n    [] -> 0\n  }\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(4),\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_with_alternative_definition_in_case() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(1),\n    );\n}\n\n#[test]\nfn rename_module_from_constant_in_clause_guard() {\n    let src = r#\"\nimport maths\n\npub fn count_pi(list) {\n  case list {\n    [number, ..rest] if number == maths  . pi -> 1 + count_pi(rest)\n    [_, ..rest] -> count_pi(rest)\n    [] -> 0\n  }\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"maths\", \"pub const pi = 3.14\"),\n        \"m\",\n        find_position_of(\"maths\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_with_alternative_definition_triggered_from_second_pattern()\n{\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_type_in_custom_type() {\n    let src = r#\"\nimport option\n\ntype Value(a) {\n  Value(option.Option(a))\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_type_in_type_alias() {\n    let src = r#\"\nimport option\n\ntype Option(a) =\n  option.Option(a)\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_type_in_annotation() {\n    let src = r#\"\nimport option\n\nconst x: option.Option(Int) = option.Some(1)\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", \"pub type Option(a) { Some(a) None }\"),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_module_from_function_call() {\n    let src = r#\"\nimport option\n\npub fn main() {\n  option.is_some(option.Some(1))\n}\n\"#;\n\n    let option_module = r#\"\npub type Option(a) {\n  Some(a)\n  None\n}\n\npub fn is_some(option: Option(a)) -> Bool {\n  case option {\n    Some(_) -> True\n    None -> False\n  }\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"option\", option_module),\n        \"opt\",\n        find_position_of(\"option\").nth_occurrence(2),\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_in_let_assert() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\n  rest\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_in_let_assert_triggered_from_usage() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\n  rest\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_in_case() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" as digit <> rest -> digit <> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_in_case_triggered_from_usage() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" as digit <> rest -> digit <> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_with_alternative_definitions_in_case() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" as digit <> rest | \\\"2\\\" as digit <> rest -> digit <> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_with_alternative_definitions_triggered_from_second_pattern() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let wibble = \\\"1-wibble\\\"\n  case wibble {\n    \\\"1\\\" as digit <> rest | \\\"2\\\" as digit <> rest -> digit <> rest\n    other -> other\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_in_let_assert() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let assert \\\"1\\\" as digit <> rest = \\\"1-wibble\\\"\n  digit\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_in_let_assert_triggered_from_usage() {\n    assert_rename!(\n        \"\nfn main() -> String {\n  let assert \\\"1\\\" as digit <> rest = \\\"1-wibble\\\"\n  digit\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_variable_nested_in_tuple() {\n    assert_rename!(\n        \"\nfn main() {\n  case #(\\\"1-wibble\\\", 0) {\n    #(\\\"1\\\" <> rest, _) -> rest\n    _ -> \\\"\\\"\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_used_in_guard() {\n    assert_rename!(\n        \"\nfn main() {\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" as digit <> _rest if digit == \\\"1\\\" -> digit\n    _ -> \\\"\\\"\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_used_in_guard() {\n    assert_rename!(\n        \"\nfn main() {\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" <> rest if rest == \\\"-wibble\\\" -> rest\n    _ -> \\\"\\\"\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_prefix_string_suffix_shadowing_outer_variable() {\n    assert_rename!(\n        \"\nfn main() {\n  let rest = \\\"outer\\\"\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" <> rest -> rest\n    _ -> rest\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"rest\").nth_occurrence(2)\n    );\n}\n\n#[test]\nfn rename_prefix_string_alias_and_suffix_complex_guard() {\n    assert_rename!(\n        \"\nfn main() {\n  case \\\"1-wibble\\\" {\n    \\\"1\\\" as digit <> rest if digit == \\\"1\\\" && rest == \\\"-wibble\\\" -> #(digit, rest)\n    _ -> #(\\\"\\\", \\\"\\\")\n  }\n}\n\",\n        \"new_name\",\n        find_position_of(\"digit\").nth_occurrence(1)\n    );\n}\n\n#[test]\nfn rename_module_from_alias_use() {\n    let src = r#\"\nimport maths  as     m\n\npub fn main() {\n  echo m      .pi\n}\n\"#;\n\n    assert_rename!(\n        TestProject::for_source(src).add_module(\"maths\", \"pub const pi = 3.14\"),\n        \"mth\",\n        find_position_of(\"m\").nth_occurrence(5)\n    );\n}\n\n#[test]\nfn rename_local_variable_from_guard() {\n    assert_rename!(\n        \"\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\",\n        \"something_else\",\n        find_position_of(\"wobble\").nth_occurrence(2).under_char('o')\n    );\n}\n\n#[test]\nfn alias_imported_module_from_guard() {\n    assert_rename!(\n        (\"mod\", \"pub const wibble = 10\"),\n        \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\",\n        \"module\",\n        find_position_of(\"mod.wibble\").under_char('m')\n    );\n}\n\n#[test]\nfn rename_module_select_from_guard() {\n    assert_rename!(\n        (\"mod\", \"pub const wibble = 10\"),\n        \"\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\",\n        \"ten\",\n        find_position_of(\"mod.wibble\").under_char('w')\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/router.rs",
    "content": "use std::time::SystemTime;\n\nuse gleam_core::{Error, io::FileSystemWriter, paths::ProjectPaths};\n\nuse crate::{files::FileSystemProxy, tests::Action};\n\nuse super::LanguageServerTestIO;\n\ntype Router = crate::router::Router<LanguageServerTestIO, LanguageServerTestIO>;\n\n#[test]\nfn recompile_after_no_changes_does_not_redownload_dependencies() {\n    let paths = ProjectPaths::new(\"/app\".into());\n    let (io, mut router) = set_up_minimal_router(&paths);\n\n    assert_eq!(\n        compile(&mut router, &paths),\n        Ok(()),\n        \"Pre-condition: Initial compile should succeed\"\n    );\n\n    {\n        let mut actions = io.actions.lock().unwrap();\n        assert!(\n            actions.contains(&Action::DownloadDependencies),\n            \"Expectation: Initial compile should download dependencies\"\n        );\n        actions.clear();\n    }\n\n    assert_eq!(\n        compile(&mut router, &paths),\n        Ok(()),\n        \"Recompile should succeed\"\n    );\n\n    {\n        let actions = io.actions.lock().unwrap();\n        assert!(\n            !actions.contains(&Action::DownloadDependencies),\n            \"Recompile should not re-download dependencies\"\n        );\n    }\n}\n\n#[test]\nfn deleting_build_dir_redownloads_dependencies() {\n    let paths = ProjectPaths::new(\"/app\".into());\n    let (io, mut router) = set_up_minimal_router(&paths);\n\n    _ = compile(&mut router, &paths);\n    io.actions.lock().unwrap().clear();\n\n    io.delete_directory(&paths.build_directory()).unwrap();\n    assert_eq!(\n        compile(&mut router, &paths),\n        Ok(()),\n        \"Compile after deleting build directory should succeed\"\n    );\n\n    {\n        let actions = io.actions.lock().unwrap();\n        assert!(\n            actions.contains(&Action::DownloadDependencies),\n            \"Compile after deleting build directory should re-download dependencies\"\n        );\n    }\n}\n\n#[test]\nfn changing_config_redownloads_dependencies() {\n    let paths = ProjectPaths::new(\"/app\".into());\n    let (io, mut router) = set_up_minimal_router(&paths);\n\n    _ = compile(&mut router, &paths);\n    io.actions.lock().unwrap().clear();\n\n    let toml = r#\"name = \"wobble\"\n    version = \"1.0.0\"\"#;\n    io.write(&paths.root_config(), toml).unwrap();\n    io.io\n        .try_set_modification_time(&paths.root_config(), SystemTime::now())\n        .unwrap();\n\n    assert_eq!(\n        compile(&mut router, &paths),\n        Ok(()),\n        \"Compile after changing gleam.toml should succeed\"\n    );\n\n    {\n        let actions = io.actions.lock().unwrap();\n        assert!(\n            actions.contains(&Action::DownloadDependencies),\n            \"Compile after changing gleam.toml should re-download dependencies\"\n        );\n    }\n}\n\nfn compile(router: &mut Router, paths: &ProjectPaths) -> Result<(), Error> {\n    router\n        .project_for_path(paths.root().into())\n        .unwrap()\n        .unwrap()\n        .engine\n        .compile_please()\n        .result\n}\n\nfn set_up_minimal_router(paths: &ProjectPaths) -> (LanguageServerTestIO, Router) {\n    let io = LanguageServerTestIO::new();\n    let router = Router::new(io.clone(), FileSystemProxy::new(io.clone()));\n\n    let toml = r#\"name = \"wibble\"\n    version = \"1.0.0\"\"#;\n\n    io.write(&paths.root_config(), toml).unwrap();\n    (io, router)\n}\n"
  },
  {
    "path": "language-server/src/tests/signature_help.rs",
    "content": "use super::*;\nuse lsp_types::{\n    ParameterInformation, ParameterLabel, SignatureHelp, SignatureHelpParams, SignatureInformation,\n};\n\nfn signature_help(tester: TestProject<'_>, position: Position) -> Option<SignatureHelp> {\n    tester.at(position, |engine, param, _| {\n        let params = SignatureHelpParams {\n            context: None,\n            text_document_position_params: param,\n            work_done_progress_params: Default::default(),\n        };\n        let response = engine.signature_help(params);\n\n        response.result.unwrap()\n    })\n}\n\nfn pretty_signature_help(signature_help: SignatureHelp) -> String {\n    let SignatureHelp {\n        signatures,\n        active_signature,\n        active_parameter,\n    } = signature_help;\n\n    let SignatureInformation {\n        label,\n        documentation,\n        parameters,\n        active_parameter: _,\n    } = signatures\n        .get(active_signature.expect(\"an active signature\") as usize)\n        .expect(\"an active signature\");\n\n    let parameters = parameters\n        .as_ref()\n        .expect(\"no signature help for function with no parameters\");\n\n    let documentation = match documentation {\n        Some(d) => format!(\"Documentation:\\n{d:#?}\"),\n        None => \"No documentation\".to_string(),\n    };\n\n    let label = match active_parameter {\n        None => label.to_string(),\n        Some(i) => match parameters.get(i as usize) {\n            None => label.to_string(),\n            Some(ParameterInformation {\n                label: ParameterLabel::LabelOffsets([start, end]),\n                ..\n            }) => {\n                let spaces = \" \".repeat(*start as usize);\n                let underlined = \"▔\".repeat((end - start) as usize);\n                format!(\"{label}\\n{spaces}{underlined}\")\n            }\n            Some(_) => panic!(\"unexpected response\"),\n        },\n    };\n\n    format!(\"{label}\\n\\n{documentation}\")\n}\n\n#[macro_export]\nmacro_rules! assert_signature_help {\n    ($code:literal, $position:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_signature_help!(project, $position);\n    };\n\n    ($project:expr, $position:expr $(,)?) => {\n        let src = $project.src;\n        let position = $position.find_position(src);\n        let result = signature_help($project, position).expect(\"no signature help produced\");\n        let pretty_hover = hover::show_hover(\n            src,\n            lsp_types::Range {\n                start: Position {\n                    character: 1,\n                    line: 1,\n                },\n                end: Position {\n                    character: 0,\n                    line: 0,\n                },\n            },\n            position,\n        );\n        let output = format!(\n            \"{}\\n\\n----- Signature help -----\\n{}\",\n            pretty_hover,\n            pretty_signature_help(result)\n        );\n        insta::assert_snapshot!(insta::internals::AutoName, output, src);\n    };\n}\n\n#[macro_export]\nmacro_rules! assert_no_signature_help {\n    ($code:literal, $position:expr $(,)?) => {\n        let project = TestProject::for_source($code);\n        assert_no_signature_help!(project, $position);\n    };\n\n    ($project:expr, $position:expr $(,)?) => {\n        let src = $project.src;\n        let position = $position.find_position(src);\n        let result = signature_help($project, position);\n        match result {\n            Some(_) => panic!(\"Expected no signature help\"),\n            None => (),\n        }\n    };\n}\n\n#[test]\npub fn help_for_calling_local_variable_first_arg() {\n    assert_signature_help!(\n        r#\"\npub fn main() {\n  let wibble = fn(a: Int, b: String) { 1.0 }\n  wibble()\n}\n\"#,\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_calling_local_variable_last_arg() {\n    assert_signature_help!(\n        r#\"\npub fn main() {\n  let wibble = fn(a: Int, b: String) { 1.0 }\n  wibble(1,)\n}\n\"#,\n        find_position_of(\"wibble(1,)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_calling_local_variable_with_module_function() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  let wobble = fn(a: Int, b: String) { 1.0 }\n  wobble(1,)\n}\n\"#,\n        find_position_of(\"wobble(1,)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_calling_module_function() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  wibble()\n}\n\"#,\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_calling_module_constant_referencing_function() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b: String) { 1.0 }\nconst wobble = wibble\n\npub fn main() {\n  wobble()\n}\n\"#,\n        find_position_of(\"wobble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_calling_local_variable_referencing_constant_referencing_function() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b: String) { 1.0 }\nconst wobble = wibble\n\npub fn main() {\n  let woo = wobble\n  woo()\n}\n\"#,\n        find_position_of(\"woo()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_still_shows_up_even_if_an_argument_has_the_wrong_type() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  wibble(\"wrong\",)\n}\n\"#,\n        find_position_of(\"wibble(\\\"wrong\\\",)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_shows_documentation_for_local_function() {\n    assert_signature_help!(\n        r#\"\n/// Some doc!\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  wibble()\n}\n\"#,\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_shows_documentation_for_imported_function() {\n    let code = r#\"\nimport example\npub fn main() {\n  example.example_fn()\n}\n\"#;\n    assert_signature_help!(\n        TestProject::for_source(code).add_module(\n            \"example\",\n            \"/// Some doc!\npub fn example_fn(a: Int, b: String) { Nil }\"\n        ),\n        find_position_of(\"example_fn()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_unqualified_call() {\n    let code = r#\"\nimport example.{example_fn}\npub fn main() {\n  example_fn()\n}\n\"#;\n\n    assert_signature_help!(\n        TestProject::for_source(code)\n            .add_module(\"example\", \"pub fn example_fn(a: Int, b: String) { Nil }\"),\n        find_position_of(\"example_fn()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_aliased_unqualified_call() {\n    let code = r#\"\nimport example.{example_fn as wibble}\npub fn main() {\n  wibble()\n}\n\"#;\n\n    assert_signature_help!(\n        TestProject::for_source(code)\n            .add_module(\"example\", \"pub fn example_fn(a: Int, b: String) { Nil }\"),\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_qualified_call() {\n    let code = r#\"\nimport example\npub fn main() {\n  example.example_fn()\n}\n\"#;\n\n    assert_signature_help!(\n        TestProject::for_source(code)\n            .add_module(\"example\", \"pub fn example_fn(a: Int, b: String) { Nil }\"),\n        find_position_of(\"example_fn()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_aliased_qualified_call() {\n    let code = r#\"\nimport example as wibble\npub fn main() {\n  wibble.example_fn()\n}\n\"#;\n\n    assert_signature_help!(\n        TestProject::for_source(code)\n            .add_module(\"example\", \"pub fn example_fn(a: Int, b: String) { Nil }\"),\n        find_position_of(\"example_fn()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_shows_labels() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    wibble()\n}\n    \"#,\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_shows_labelled_argument_after_all_unlabelled() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    wibble(1,)\n}\n    \"#,\n        find_position_of(\"wibble(1,)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_shows_first_missing_labelled_argument_if_out_of_order() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    wibble(c: \"c\",)\n}\n    \"#,\n        find_position_of(\"wibble(c: \\\"c\\\",)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_piped_imported_function_starts_from_second_argument() {\n    let code = r#\"\nimport example\npub fn main() {\n    1 |> example.example_fn()\n}\n    \"#;\n\n    assert_signature_help!(\n        TestProject::for_source(code)\n            .add_module(\"example\", \"pub fn example_fn(a: Int, b: String) { Nil }\"),\n        find_position_of(\"example_fn()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_piped_function_starts_from_second_argument() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    1 |> wibble()\n}\n    \"#,\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_use_function_call_starts_from_first_argument() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(a: Int, b: Int, c: fn() -> Int) { 1.0 }\n\npub fn main() {\n    use <- wibble()\n}\n    \"#,\n        find_position_of(\"wibble()\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_use_function_call_uses_precise_types_when_missing_some_arguments() {\n    assert_signature_help!(\n        r#\"\npub fn guard(a: Bool, b: a, c: fn() -> a) { 1.0 }\n\npub fn main() {\n    use <- guard(True,)\n}\n    \"#,\n        find_position_of(\"guard(True,)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_use_function_shows_next_unlabelled_argument() {\n    assert_signature_help!(\n        r#\"\npub fn guard(a a: Bool, b b: a, c c: fn() -> a) { 1.0 }\n\npub fn main() {\n    use <- guard(b: 1,)\n}\n    \"#,\n        find_position_of(\"guard(b: 1,)\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_does_not_come_up_for_function_that_does_not_exist() {\n    assert_no_signature_help!(\n        r#\"\npub fn main() {\n    use <- to_be_or_not_to_be()\n}\n    \"#,\n        find_position_of(\"to_be_or_not_to_be()\").under_last_char()\n    );\n}\n\n#[test]\n// Regression introduced by 4112682cdb5d5b0bb6d1defc6cde849b6a6f65ab.\npub fn help_with_labelled_constructor() {\n    assert_signature_help!(\n        r#\"\npub type Pokemon {\n    Pokemon(name: String, types: List(String), moves: List(String))\n}\n\npub fn main() {\n    Pokemon(name: \"Jirachi\",)\n}\n    \"#,\n        find_position_of(r#\"Pokemon(name: \"Jirachi\",)\"#).under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_use_function_call_uses_generic_names_when_missing_all_arguments() {\n    assert_signature_help!(\n        r#\"\npub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\npub fn main() {\n    wibble( )\n}\n\"#,\n        find_position_of(\"wibble( \").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_use_function_call_uses_concrete_types_when_possible_or_generic_names_when_unbound()\n{\n    assert_signature_help!(\n        r#\"\npub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\npub fn main() {\n    wibble(1, )\n}\n\"#,\n        find_position_of(\"wibble(1, )\").under_last_char()\n    );\n}\n\n#[test]\npub fn help_for_use_function_call_uses_concrete_types_when_late_ubound() {\n    assert_signature_help!(\n        r#\"\nfn identity(x: a) -> a { x }\n\nfn main() {\n  let a = Ok(10)\n  identity( a)\n}\n\"#,\n        find_position_of(\"identity( \").under_last_char()\n    );\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_annotation_triggers_on_empty_space_before_function_curly_brace.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() { 1 }\"\n---\n----- BEFORE ACTION\npub fn main() { 1 }\n             ↑     \n\n\n----- AFTER ACTION\npub fn main() -> Int { 1 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_annotation_triggers_on_function_curly_brace.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() { 1 }\"\n---\n----- BEFORE ACTION\npub fn main() { 1 }\n              ↑    \n\n\n----- AFTER ACTION\npub fn main() -> Int { 1 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_correct_type_annotation_for_non_variable_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn usable(f) {\\n  f(#(1, 2))\\n}\\n\\npub fn main() {\\n  use #(a, b) <- usable\\n  a + b\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn usable(f) {\n  f(#(1, 2))\n}\n\npub fn main() {\n  use #(a, b) <- usable\n  ▔▔▔▔▔▔▔▔▔↑           \n  a + b\n}\n\n\n----- AFTER ACTION\n\nfn usable(f) {\n  f(#(1, 2))\n}\n\npub fn main() {\n  use #(a, b): #(Int, Int) <- usable\n  a + b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_adds_a_discard_for_opaque_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main(w: wibble.Wibble) {\\n  case w {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main(w: wibble.Wibble) {\n  case w {}\n         ↑ \n}\n\n\n----- AFTER ACTION\n\nimport wibble\n\npub fn main(w: wibble.Wibble) {\n  case w {\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_adds_a_discard_for_opaque_type_1.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub type Type {\\n  Type(wibble: wibble.Wibble, list: List(Int))\\n}\\n\\npub fn main(thing: Type) {\\n  case thing {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub type Type {\n  Type(wibble: wibble.Wibble, list: List(Int))\n}\n\npub fn main(thing: Type) {\n  case thing {}\n             ↑ \n}\n\n\n----- AFTER ACTION\n\nimport wibble\n\npub type Type {\n  Type(wibble: wibble.Wibble, list: List(Int))\n}\n\npub fn main(thing: Type) {\n  case thing {\n    Type(wibble:, list:) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_adds_a_discard_for_opaque_type_2.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub type Type {\\n  Type(wibble.Wibble)\\n}\\n\\npub fn main(thing: Type) {\\n  case thing {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub type Type {\n  Type(wibble.Wibble)\n}\n\npub fn main(thing: Type) {\n  case thing {}\n             ↑ \n}\n\n\n----- AFTER ACTION\n\nimport wibble\n\npub type Type {\n  Type(wibble.Wibble)\n}\n\npub fn main(thing: Type) {\n  case thing {\n    Type(_) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_adds_patterns_for_internal_type_inside_same_module_where_it_is_defined.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\n@internal\\npub type Wibble {\\n  Wibble(Int)\\n  Wobble(String)\\n}\\n\\npub fn main(thing: Wibble) {\\n  case thing {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\n@internal\npub type Wibble {\n  Wibble(Int)\n  Wobble(String)\n}\n\npub fn main(thing: Wibble) {\n  case thing {}\n       ↑       \n}\n\n\n----- AFTER ACTION\n\n@internal\npub type Wibble {\n  Wibble(Int)\n  Wobble(String)\n}\n\npub fn main(thing: Wibble) {\n  case thing {\n    Wibble(_) -> todo\n    Wobble(_) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_bool.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(bool: Bool) {\\n  case bool {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(bool: Bool) {\n  case bool {}\n  ▔▔▔▔▔↑      \n}\n\n\n----- AFTER ACTION\n\npub fn main(bool: Bool) {\n  case bool {\n    True -> todo\n    False -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_custom_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Wibble {\\n  Wibble\\n  Wobble\\n  Wubble\\n}\\n\\npub fn main(wibble: Wibble) {\\n  case wibble {\\n    Wobble -> Nil\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble {\n  Wibble\n  Wobble\n  Wubble\n}\n\npub fn main(wibble: Wibble) {\n  case wibble {\n  ▔▔▔▔▔↑       \n    Wobble -> Nil\n  }\n}\n\n\n----- AFTER ACTION\n\ntype Wibble {\n  Wibble\n  Wobble\n  Wubble\n}\n\npub fn main(wibble: Wibble) {\n  case wibble {\n    Wobble -> Nil\n    Wibble -> todo\n    Wubble -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_infinite.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let value = 3\\n  case value {\\n    1 -> \\\"one\\\"\\n    2 -> \\\"two\\\"\\n    3 -> \\\"three\\\"\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let value = 3\n  case value {\n  ▔▔▔▔▔↑      \n    1 -> \"one\"\n    2 -> \"two\"\n    3 -> \"three\"\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let value = 3\n  case value {\n    1 -> \"one\"\n    2 -> \"two\"\n    3 -> \"three\"\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_inline.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(a: Bool) {\\n  let value = case a {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(a: Bool) {\n  let value = case a {}\n              ▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\n\npub fn main(a: Bool) {\n  let value = case a {\n    True -> todo\n    False -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let list = [1, 2, 3]\\n  case list {\\n    [a, b, c, 4 as d] -> d\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let list = [1, 2, 3]\n  case list {\n  ▔▔▔▔▔↑     \n    [a, b, c, 4 as d] -> d\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let list = [1, 2, 3]\n  case list {\n    [a, b, c, 4 as d] -> d\n    [] -> todo\n    [_] -> todo\n    [_, _] -> todo\n    [_, _, _] -> todo\n    [_, _, _, _] -> todo\n    [_, _, _, _, _, ..] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_multi.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(a: Bool) {\\n  let b = 1\\n  case a, b {\\n\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(a: Bool) {\n  let b = 1\n  case a, b {\n  ▔▔▔▔▔▔▔▔↑  \n\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main(a: Bool) {\n  let b = 1\n  case a, b {\n    True, _ -> todo\n    False, _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_multibyte_grapheme.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// ä\\nfn wibble() {\\n  case True {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// ä\nfn wibble() {\n  case True {}\n  ▔▔▔▔▔↑      \n}\n\n\n----- AFTER ACTION\n\n// ä\nfn wibble() {\n  case True {\n    True -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_opaque_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport mod\\n\\npub fn main(w: mod.Wibble) {\\n  case w {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport mod\n\npub fn main(w: mod.Wibble) {\n  case w {}\n         ↑ \n}\n\n\n----- AFTER ACTION\n\nimport mod\n\npub fn main(w: mod.Wibble) {\n  case w {\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(two_at_once: #(Bool, Result(Int, Nil))) {\\n  case two_at_once {\\n    #(False, Error(_)) -> Nil\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(two_at_once: #(Bool, Result(Int, Nil))) {\n  case two_at_once {\n  ▔▔▔▔▔↑            \n    #(False, Error(_)) -> Nil\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main(two_at_once: #(Bool, Result(Int, Nil))) {\n  case two_at_once {\n    #(False, Error(_)) -> Nil\n    #(False, Ok(_)) -> todo\n    #(True, _) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_patterns_with_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(integer: Int, float: Float)\\n  Wobble(string: String, bool: Bool)\\n}\\n\\npub fn main(w: Wibble) {\\n  case w {}\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(integer: Int, float: Float)\n  Wobble(string: String, bool: Bool)\n}\n\npub fn main(w: Wibble) {\n  case w {}\n  ▔▔▔▔▔▔▔↑ \n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(integer: Int, float: Float)\n  Wobble(string: String, bool: Bool)\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wibble(integer:, float:) -> todo\n    Wobble(string:, bool:) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_type_parameter_for_single_constructor.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(field: t)\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble {\n  Wibble(field: t)\n                ↑ \n}\n\n\n----- AFTER ACTION\n\ntype Wibble(t) {\n  Wibble(field: t)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_type_parameter_preserves_comments.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\ntype Wibble(\\n  // Comment 1\\n  b,\\n  // Comment 2\\n) {\\n  Wibble(a, b, c)\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble(\n  // Comment 1\n  b,\n  // Comment 2\n) {\n  Wibble(a, b, c)\n               ↑ \n}\n\n\n----- AFTER ACTION\n\ntype Wibble(\n  // Comment 1\n  b,\n  // Comment 2\na, c) {\n  Wibble(a, b, c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_type_parameter_sorted_alphabetically.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\ntype Wibble(b) {\\n  Wibble(c, b, a)\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble(b) {\n  Wibble(c, b, a)\n               ↑ \n}\n\n\n----- AFTER ACTION\n\ntype Wibble(b, a, c) {\n  Wibble(c, b, a)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_missing_type_parameter_to_exising_parameter.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\ntype Wibble(t) {\\n  Wibble(field: t)\\n  Wobble(field: u)\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble(t) {\n  Wibble(field: t)\n  Wobble(field: u)\n                ↑ \n}\n\n\n----- AFTER ACTION\n\ntype Wibble(t, u) {\n  Wibble(field: t)\n  Wobble(field: u)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_multiple_annotations.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub const my_constant = 20\\n\\npub fn add_my_constant(value) {\\n  let result = value + my_constant\\n  result\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub const my_constant = 20\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn add_my_constant(value) {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let result = value + my_constant\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  result\n▔▔▔▔▔▔▔▔\n}\n↑\n\n\n----- AFTER ACTION\n\npub const my_constant: Int = 20\n\npub fn add_my_constant(value: Int) -> Int {\n  let result: Int = value + my_constant\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_does_not_label_piped_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 |> labelled(2)\\n}\\n\\npub fn labelled(a a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 |> labelled(2)\n       ↑          \n}\n\npub fn labelled(a a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 |> labelled(b: 2)\n}\n\npub fn labelled(a a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_does_not_label_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- labelled(1)\\n  todo\\n}\\n\\npub fn labelled(a a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- labelled(1)\n         ↑          \n  todo\n}\n\npub fn labelled(a a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- labelled(a: 1)\n  todo\n}\n\npub fn labelled(a a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_in_function_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  labelled(1, 2)\\n}\\n\\npub fn labelled(a a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  labelled(1, 2)\n  ↑             \n}\n\npub fn labelled(a a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  labelled(a: 1, b: 2)\n}\n\npub fn labelled(a a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_in_function_call_uses_shorthand_syntax.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n  labelled(a, 2)\\n}\\n\\npub fn labelled(a a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let a = 1\n  labelled(a, 2)\n  ↑             \n}\n\npub fn labelled(a a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let a = 1\n  labelled(a:, b: 2)\n}\n\npub fn labelled(a a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_in_function_call_with_some_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  labelled(1, 2)\\n}\\n\\npub fn labelled(a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  labelled(1, 2)\n  ↑             \n}\n\npub fn labelled(a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  labelled(1, b: 2)\n}\n\npub fn labelled(a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_works_on_call_with_wrongly_placed_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  labelled(3, b: 2, 1)\\n}\\n\\npub fn labelled(a a, b b, c c) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  labelled(3, b: 2, 1)\n  ↑                   \n}\n\npub fn labelled(a a, b b, c c) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  labelled(a: 3, b: 2, c: 1)\n}\n\npub fn labelled(a a, b b, c c) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_works_with_constructors_calls.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  Labelled(1, 2)\\n}\\n\\npub type Labelled {\\n  Labelled(Int, b: Int)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  Labelled(1, 2)\n  ↑             \n}\n\npub type Labelled {\n  Labelled(Int, b: Int)\n}\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  Labelled(1, b: 2)\n}\n\npub type Labelled {\n  Labelled(Int, b: Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_works_with_constructors_calls_with_some_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n  labelled(a, b: 2)\\n}\\n\\npub fn labelled(a a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let a = 1\n  labelled(a, b: 2)\n  ↑                \n}\n\npub fn labelled(a a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let a = 1\n  labelled(a:, b: 2)\n}\n\npub fn labelled(a a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_works_with_constructors_calls_with_some_labels_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  labelled(3, 1, b: 2)\\n}\\n\\npub fn labelled(a a, b b, c c) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  labelled(3, 1, b: 2)\n  ↑                   \n}\n\npub fn labelled(a a, b b, c c) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  labelled(a: 3, c: 1, b: 2)\n}\n\npub fn labelled(a a, b b, c c) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_omitted_labels_works_with_innermost_function_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n  labelled(a, labelled(1, 2))\\n}\\n\\npub fn labelled(a a, b b) { todo }\\n    \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let a = 1\n  labelled(a, labelled(1, 2))\n              ↑              \n}\n\npub fn labelled(a a, b b) { todo }\n    \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let a = 1\n  labelled(a, labelled(a: 1, b: 2))\n}\n\npub fn labelled(a a, b b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_type_annotations_public_alias_to_internal_generic_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport package\\n\\npub fn main() {\\n  package.make_wibble(10)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport package\n\npub fn main() {\n       ↑       \n  package.make_wibble(10)\n}\n\n\n----- AFTER ACTION\n\nimport package\n\npub fn main() -> package.Wibble(Int, a) {\n  package.make_wibble(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_type_annotations_public_alias_to_internal_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport package\\n\\npub fn main() {\\n  package.make_wibble()\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport package\n\npub fn main() {\n       ↑       \n  package.make_wibble()\n}\n\n\n----- AFTER ACTION\n\nimport package\n\npub fn main() -> package.Wibble {\n  package.make_wibble()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_type_annotations_public_alias_to_internal_type_aliased_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport package as pkg\\n\\npub fn main() {\\n  pkg.make_wibble()\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport package as pkg\n\npub fn main() {\n       ↑       \n  pkg.make_wibble()\n}\n\n\n----- AFTER ACTION\n\nimport package as pkg\n\npub fn main() -> pkg.Wibble {\n  pkg.make_wibble()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__add_type_annotations_uses_internal_name_for_same_package.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport thepackage/internal\\n\\npub fn main() {\\n  internal.Constructor\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport thepackage/internal\n\npub fn main() {\n       ↑       \n  internal.Constructor\n}\n\n\n----- AFTER ACTION\n\nimport thepackage/internal\n\npub fn main() -> internal.Internal {\n  internal.Constructor\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_correctly_prints_type_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn map_result(input, function) {\\n  case input {\\n    Ok(value) -> Ok(function(value))\\n    Error(error) -> Error(error)\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn map_result(input, function) {\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔↑                  \n  case input {\n    Ok(value) -> Ok(function(value))\n    Error(error) -> Error(error)\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn map_result(input: Result(a, b), function: fn(a) -> c) -> Result(c, b) {\n  case input {\n    Ok(value) -> Ok(function(value))\n    Error(error) -> Error(error)\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_prints_contextual_types.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type IntAlias = Int\\n\\npub fn main() {\\n  let value = 20\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type IntAlias = Int\n\npub fn main() {\n  let value = 20\n  ▔▔▔▔↑         \n}\n\n\n----- AFTER ACTION\n\npub type IntAlias = Int\n\npub fn main() {\n  let value: IntAlias = 20\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_prints_contextual_types2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Result\\n\\npub fn main() {\\n  let value = Ok(12)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Result\n\npub fn main() {\n  let value = Ok(12)\n  ▔▔▔▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\n\npub type Result\n\npub fn main() {\n  let value: gleam.Result(Int, a) = Ok(12)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_prints_contextual_types3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  let value = wibble.Wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main() {\n  let value = wibble.Wibble\n  ▔▔▔▔▔▔▔▔▔▔↑              \n}\n\n\n----- AFTER ACTION\n\nimport wibble\n\npub fn main() {\n  let value: wibble.Wibble = wibble.Wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_prints_contextual_types4.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble as wobble\\n\\npub fn main() {\\n  let value = wobble.Wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble as wobble\n\npub fn main() {\n  let value = wobble.Wibble\n  ▔▔▔▔▔▔▔▔▔▔↑              \n}\n\n\n----- AFTER ACTION\n\nimport wibble as wobble\n\npub fn main() {\n  let value: wobble.Wibble = wobble.Wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_prints_contextual_types5.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble.{type Wibble as Wobble}\\n\\npub fn main() {\\n  let value = wibble.Wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble.{type Wibble as Wobble}\n\npub fn main() {\n  let value = wibble.Wibble\n  ▔▔▔▔▔▔▔▔▔▔↑              \n}\n\n\n----- AFTER ACTION\n\nimport wibble.{type Wibble as Wobble}\n\npub fn main() {\n  let value: Wobble = wibble.Wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__adding_annotations_prints_type_variable_names.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_generic_things(a: type_a, b: type_b) {\\n  let a_value = a\\n  let b_value = b\\n  let other_value = a_value\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_generic_things(a: type_a, b: type_b) {\n  let a_value = a\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let b_value = b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let other_value = a_value\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n\n\n----- AFTER ACTION\n\npub fn do_generic_things(a: type_a, b: type_b) {\n  let a_value: type_a = a\n  let b_value: type_b = b\n  let other_value: type_a = a_value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__allow_further_pattern_matching_on_asserted_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  let assert [first, ..] = [Ok(Nil), ..todo]\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  let assert [first, ..] = [Ok(Nil), ..todo]\n              ↑                             \n  todo\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  let assert [first, ..] = [Ok(Nil), ..todo]\n  case first {\n    Ok(value) -> todo\n    Error(value) -> todo\n  }\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__allow_further_pattern_matching_on_asserted_result.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  let assert Ok(one) = Ok(Error(Nil))\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  let assert Ok(one) = Ok(Error(Nil))\n                ↑                    \n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  let assert Ok(one) = Ok(Error(Nil))\n  case one {\n    Ok(value) -> todo\n    Error(value) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__allow_further_pattern_matching_on_let_record_destructuring.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  let Wibble(field:) = Wibble(Ok(Nil))\\n}\\n\\npub type Wibble { Wibble(field: Result(Nil, String)) }\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  let Wibble(field:) = Wibble(Ok(Nil))\n             ↑                        \n}\n\npub type Wibble { Wibble(field: Result(Nil, String)) }\n\n\n----- AFTER ACTION\npub fn main(x) {\n  let Wibble(field:) = Wibble(Ok(Nil))\n  case field {\n    Ok(value) -> todo\n    Error(value) -> todo\n  }\n}\n\npub type Wibble { Wibble(field: Result(Nil, String)) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__allow_further_pattern_matching_on_let_tuple_destructuring.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  let #(one, other) = #(Ok(1), Error(Nil))\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  let #(one, other) = #(Ok(1), Error(Nil))\n        ↑                                 \n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  let #(one, other) = #(Ok(1), Error(Nil))\n  case one {\n    Ok(value) -> todo\n    Error(value) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub const answer = 42\\n\\npub fn add_two(thing) {\\n  thing + 2\\n}\\n\\npub fn add_one(thing) {\\n  thing + 1\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub const answer = 42\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n\npub fn add_two(thing) {\n  thing + 2\n}\n\npub fn add_one(thing) {\n  thing + 1\n}\n\n\n----- AFTER ACTION\n\npub const answer: Int = 42\n\npub fn add_two(thing: Int) -> Int {\n  thing + 2\n}\n\npub fn add_one(thing: Int) -> Int {\n  thing + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_dont_affect_local_vars.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nassertion_line: 11175\nexpression: \"\\npub const answer = 42\\n\\npub fn add_two(thing) {\\n  thing + 2\\n}\\n\\npub fn add_one(thing) {\\n  let result = thing + 1\\n  result\\n}\\n\"\nsnapshot_kind: text\n---\n----- BEFORE ACTION\n\npub const answer = 42\n\npub fn add_two(thing) {\n    ▔▔▔▔▔▔▔▔▔▔↑        \n  thing + 2\n}\n\npub fn add_one(thing) {\n  let result = thing + 1\n  result\n}\n\n\n----- AFTER ACTION\n\npub const answer: Int = 42\n\npub fn add_two(thing: Int) -> Int {\n  thing + 2\n}\n\npub fn add_one(thing: Int) -> Int {\n  let result = thing + 1\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn add_two(thing) {\\n  thing + 2\\n}\\n\\npub fn add_one(thing) {\\n  thing + 1\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn add_two(thing) {\n    ▔▔▔▔▔▔▔▔▔▔↑        \n  thing + 2\n}\n\npub fn add_one(thing) {\n  thing + 1\n}\n\n\n----- AFTER ACTION\n\npub fn add_two(thing: Int) -> Int {\n  thing + 2\n}\n\npub fn add_one(thing: Int) -> Int {\n  thing + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_partially_annotated.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub const answer: Int = 42\\npub const another_answer = 43\\n\\npub fn add_two(thing) -> Int {\\n  thing + 2\\n}\\n\\npub fn add_one(thing: Int) {\\n  thing + 1\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub const answer: Int = 42\npub const another_answer = 43\n\npub fn add_two(thing) -> Int {\n    ▔▔▔▔▔▔▔▔▔▔↑               \n  thing + 2\n}\n\npub fn add_one(thing: Int) {\n  thing + 1\n}\n\n\n----- AFTER ACTION\n\npub const answer: Int = 42\npub const another_answer: Int = 43\n\npub fn add_two(thing: Int) -> Int {\n  thing + 2\n}\n\npub fn add_one(thing: Int) -> Int {\n  thing + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_with_constant_and_generic_functions.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nconst answer = 42\\n\\nfn wibble(one) { todo }\\n\\nfn wobble(other) { todo }\\n\"\n---\n----- BEFORE ACTION\n\nconst answer = 42\n\nfn wibble(one) { todo }\n\nfn wobble(other) { todo }\n   ↑                     \n\n\n----- AFTER ACTION\n\nconst answer: Int = 42\n\nfn wibble(one: a) -> b { todo }\n\nfn wobble(other: a) -> b { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_with_partially_annotated_generic_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn wibble(a: a, b, c: c, d) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn wibble(a: a, b, c: c, d) {\n       ↑                         \n  todo\n}\n\n\n----- AFTER ACTION\n\npub fn wibble(a: a, b: b, c: c, d: d) -> e {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_all_top_level_definitions_with_two_generic_functions.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn wibble(one) { todo }\\n\\nfn wobble(other) { todo }\\n\"\n---\n----- BEFORE ACTION\n\nfn wibble(one) { todo }\n\nfn wobble(other) { todo }\n   ↑                     \n\n\n----- AFTER ACTION\n\nfn wibble(one: a) -> b { todo }\n\nfn wobble(other: a) -> b { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_anonymous_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn add_curry(a) {\\n  fn(b) { a + b }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn add_curry(a) {\n  fn(b) { a + b }\n  ▔▔▔↑           \n}\n\n\n----- AFTER ACTION\n\npub fn add_curry(a) {\n  fn(b: Int) -> Int { a + b }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_anonymous_function_with_annotated_return_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn add_curry(a) {\\n  fn(b) -> Int { a + b }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn add_curry(a) {\n  fn(b) -> Int { a + b }\n  ▔▔▔↑                  \n}\n\n\n----- AFTER ACTION\n\npub fn add_curry(a) {\n  fn(b: Int) -> Int { a + b }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_anonymous_function_with_partially_annotated_parameters.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  fn(a, b: Int, c) { a + b + c }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  fn(a, b: Int, c) { a + b + c }\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑               \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  fn(a: Int, b: Int, c: Int) -> Int { a + b + c }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub const my_constant = 20\\n\"\n---\n----- BEFORE ACTION\n\npub const my_constant = 20\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n\n\n----- AFTER ACTION\n\npub const my_constant: Int = 20\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn add_one(thing) {\\n  thing + 1\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn add_one(thing) {\n    ▔▔▔▔▔▔▔▔▔▔↑        \n  thing + 1\n}\n\n\n----- AFTER ACTION\n\npub fn add_one(thing: Int) -> Int {\n  thing + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_function_with_annotated_return_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn add_one(thing) -> Int {\\n  thing + 1\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn add_one(thing) -> Int {\n    ▔▔▔▔▔▔▔▔▔▔↑               \n  thing + 1\n}\n\n\n----- AFTER ACTION\n\npub fn add_one(thing: Int) -> Int {\n  thing + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_function_with_partially_annotated_parameters.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn add(a: Float, b) -> Float {\\n  a +. b\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn add(a: Float, b) -> Float {\n    ▔▔▔▔▔▔↑                       \n  a +. b\n}\n\n\n----- AFTER ACTION\n\npub fn add(a: Float, b: Float) -> Float {\n  a +. b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let my_value = 10\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let my_value = 10\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let my_value: Int = 10\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_local_variable_let_assert.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn fallible() -> Result(Int, Nil) {\\n  todo\\n}\\n\\npub fn main() {\\n  let assert Ok(value) = fallible()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn fallible() -> Result(Int, Nil) {\n  todo\n}\n\npub fn main() {\n  let assert Ok(value) = fallible()\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑           \n}\n\n\n----- AFTER ACTION\n\npub fn fallible() -> Result(Int, Nil) {\n  todo\n}\n\npub fn main() {\n  let assert Ok(value): Result(Int, Nil) = fallible()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_local_variable_with_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Int, c: Int)\\n}\\n\\npub fn main() {\\n  let Wibble(a, b, c) = Wibble(1, 2, 3)\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let Wibble(a, b, c) = Wibble(1, 2, 3)\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑                \n}\n\n\n----- AFTER ACTION\n\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int)\n}\n\npub fn main() {\n  let Wibble(a, b, c): Wibble = Wibble(1, 2, 3)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_local_variable_with_pattern2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(values) {\\n  let #(left, right) = values\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(values) {\n  let #(left, right) = values\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\n\npub fn main(values) {\n  let #(left, right): #(a, b) = values\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_nested_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let a = {\\n    let b = 10\\n    b + 1\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let a = {\n    let b = 10\n    ▔▔▔▔↑     \n    b + 1\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let a = {\n    let b: Int = 10\n    b + 1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn wibble(wobble: fn(Int, Int) -> Int) {\\n  wobble(1, 2)\\n}\\n\\npub fn main() {\\n  use a, b <- wibble\\n  a + b\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a, b <- wibble\n  ▔▔▔▔▔▔▔▔▔↑        \n  a + b\n}\n\n\n----- AFTER ACTION\n\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a: Int, b: Int <- wibble\n  a + b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__annotate_use_with_partially_annotated_parameters.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn wibble(wobble: fn(Int, Int) -> Int) {\\n  wobble(1, 2)\\n}\\n\\npub fn main() {\\n  use a: Int, b <- wibble\\n  a + b\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a: Int, b <- wibble\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑        \n  a + b\n}\n\n\n----- AFTER ACTION\n\npub fn wibble(wobble: fn(Int, Int) -> Int) {\n  wobble(1, 2)\n}\n\npub fn main() {\n  use a: Int, b: Int <- wibble\n  a + b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__assign_unused_result.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let x = 1\\n    Ok(x)\\n    Nil\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let x = 1\n    Ok(x)\n    ▔▔↑  \n    Nil\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let x = 1\n    let _ = Ok(x)\n    Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__assign_unused_result_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    {\\n        let x = 1\\n        Ok(x)\\n        Nil\\n    }\\n    Nil\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    {\n        let x = 1\n        Ok(x)\n        ▔▔↑  \n        Nil\n    }\n    Nil\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n    {\n        let x = 1\n        let _ = Ok(x)\n        Nil\n    }\n    Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__assign_unused_result_on_block_end.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    {\\n        let x = 1\\n        Ok(x)\\n        Ok(x)\\n    }\\n    Nil\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    {\n        let x = 1\n        Ok(x)\n        Ok(x)\n    }\n    ↑\n    Nil\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let _ = {\n        let x = 1\n        Ok(x)\n        Ok(x)\n    }\n    Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__assign_unused_result_on_block_start.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    {\\n        let x = 1\\n        Ok(x)\\n        Ok(x)\\n    }\\n    Nil\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    {\n    ↑\n        let x = 1\n        Ok(x)\n        Ok(x)\n    }\n    Nil\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let _ = {\n        let x = 1\n        Ok(x)\n        Ok(x)\n    }\n    Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__assign_unused_result_only_first_action.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let x = 1\\n    Ok(x)\\n    Ok(x)\\n    Nil\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let x = 1\n    Ok(x)\n    ▔▔↑  \n    Ok(x)\n    Nil\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let x = 1\n    let _ = Ok(x)\n    Ok(x)\n    Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    Ok(var) -> case var {\\n      1 -> 2\\n      2 -> 4\\n      _ -> -1\\n    }\\n    _ -> todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    Ok(var) -> case var {\n       ↑                 \n      1 -> 2\n      2 -> 4\n      _ -> -1\n    }\n    _ -> todo\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    Ok(1) -> 2\n    Ok(2) -> 4\n    Ok(_) -> -1\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_aliases_variable_if_it_is_used.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    [first, ..rest] ->\\n      case first {\\n        1 | 2 -> first\\n        3 | 4 | 5 -> 5\\n        _ -> 0\\n      }\\n\\n    [] -> -1\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    [first, ..rest] ->\n     ↑                \n      case first {\n        1 | 2 -> first\n        3 | 4 | 5 -> 5\n        _ -> 0\n      }\n\n    [] -> -1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    [1 as first, ..rest] | [2 as first, ..rest] -> first\n    [3, ..rest] | [4, ..rest] | [5, ..rest] -> 5\n    [_, ..rest] -> 0\n\n    [] -> -1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_combines_inner_and_outer_guards.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    [first, ..rest] if False ->\\n      case first {\\n        1 if False -> 1.1\\n        _ if True -> 0.0 *. 10.0\\n        _ -> 0.0\\n      }\\n\\n    [] -> 1.1\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    [first, ..rest] if False ->\n     ↑                         \n      case first {\n        1 if False -> 1.1\n        _ if True -> 0.0 *. 10.0\n        _ -> 0.0\n      }\n\n    [] -> 1.1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    [1, ..rest] if False && False -> 1.1\n    [_, ..rest] if False && True -> 0.0 *. 10.0\n    [_, ..rest] if False -> 0.0\n\n    [] -> 1.1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_combines_inner_and_outer_guards_and_adds_parentheses_when_needed.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    [first, ..rest] if False || True ->\\n      case first {\\n        1 if False && True -> 1.1\\n        _ if True || False -> 0.0 *. 10.0\\n        _ -> 0.0\\n      }\\n\\n    [] -> 1.1\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    [first, ..rest] if False || True ->\n     ↑                                 \n      case first {\n        1 if False && True -> 1.1\n        _ if True || False -> 0.0 *. 10.0\n        _ -> 0.0\n      }\n\n    [] -> 1.1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    [1, ..rest] if { False || True } && False && True -> 1.1\n    [_, ..rest] if { False || True } && { True || False } -> 0.0 *. 10.0\n    [_, ..rest] if False || True -> 0.0\n\n    [] -> 1.1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_combines_list_with_tail.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(elems: List(List(Int))) {\\n  case elems {\\n    [] -> 0\\n    [_, ..tail] ->\\n      case tail {\\n        [] -> -1\\n        [[1]] -> 1\\n        [_, [3, 4]] -> 3\\n        [_, _, [5, 6, 7], _] -> 5\\n        tail_list -> {\\n            echo tail_list\\n            -1\\n        }\\n      }\\n    _ -> -1\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(elems: List(List(Int))) {\n  case elems {\n    [] -> 0\n    [_, ..tail] ->\n          ↑       \n      case tail {\n        [] -> -1\n        [[1]] -> 1\n        [_, [3, 4]] -> 3\n        [_, _, [5, 6, 7], _] -> 5\n        tail_list -> {\n            echo tail_list\n            -1\n        }\n      }\n    _ -> -1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(elems: List(List(Int))) {\n  case elems {\n    [] -> 0\n    [_, ] -> -1\n    [_, [1]] -> 1\n    [_, _, [3, 4]] -> 3\n    [_, _, _, [5, 6, 7], _] -> 5\n    [_, ..tail_list] -> {\n            echo tail_list\n            -1\n        }\n    _ -> -1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_combines_list_with_unformatted_tail.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(elems: List(String)) {\\n  case elems {\\n    [first, .. rest_of_list] ->\\n      case rest_of_list {\\n        [] -> 0\\n        [\\\"first\\\"] -> 1\\n        [_, \\\"second\\\"] -> 2\\n        [_, \\\"second\\\", \\\"third\\\", _] -> 4\\n        _ -> -1\\n      }\\n    _ -> -1\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(elems: List(String)) {\n  case elems {\n    [first, .. rest_of_list] ->\n               ↑               \n      case rest_of_list {\n        [] -> 0\n        [\"first\"] -> 1\n        [_, \"second\"] -> 2\n        [_, \"second\", \"third\", _] -> 4\n        _ -> -1\n      }\n    _ -> -1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(elems: List(String)) {\n  case elems {\n    [first, ] -> 0\n    [first, \"first\"] -> 1\n    [first, _, \"second\"] -> 2\n    [first, _, \"second\", \"third\", _] -> 4\n    [first, _] -> -1\n    _ -> -1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_does_not_ignore_inner_guards.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    [first, ..rest] ->\\n      case first {\\n        1 -> 1.1\\n        _ if True -> 0.0 *. 10.0\\n        _ -> 0.0\\n      }\\n\\n    [] -> 1.1\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    [first, ..rest] ->\n     ↑                \n      case first {\n        1 -> 1.1\n        _ if True -> 0.0 *. 10.0\n        _ -> 0.0\n      }\n\n    [] -> 1.1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    [1, ..rest] -> 1.1\n    [_, ..rest] if True -> 0.0 *. 10.0\n    [_, ..rest] -> 0.0\n\n    [] -> 1.1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_does_not_ignore_outer_guards.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    [first, ..rest] if True ->\\n      case first {\\n        1 -> 1.1\\n        _ -> 0.0 *. 10.0\\n      }\\n\\n    [] -> 1.1\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    [first, ..rest] if True ->\n     ↑                        \n      case first {\n        1 -> 1.1\n        _ -> 0.0 *. 10.0\n      }\n\n    [] -> 1.1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    [1, ..rest] if True -> 1.1\n    [_, ..rest] if True -> 0.0 *. 10.0\n\n    [] -> 1.1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_does_not_remove_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    Wibble(field2:, field: wibble) ->\\n      case wibble {\\n        1 -> 2\\n        2 -> 4\\n        _ -> -1\\n      }\\n\\n    Wobble -> todo\\n  }\\n}\\n\\npub type Wibble {\\n  Wibble(field: Int, field2: String)\\n  Wobble\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    Wibble(field2:, field: wibble) ->\n           ↑                         \n      case wibble {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(field: Int, field2: String)\n  Wobble\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    Wibble(field2:, field: 1) -> 2\n    Wibble(field2:, field: 2) -> 4\n    Wibble(field2:, field: _) -> -1\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(field: Int, field2: String)\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_does_not_remove_labels_with_shorthand_syntax.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    Wibble(field2:, field:) ->\\n      case field {\\n        1 -> 2\\n        2 -> 4\\n        _ -> -1\\n      }\\n\\n    Wobble -> todo\\n  }\\n}\\n\\npub type Wibble {\\n  Wibble(field: Int, field2: String)\\n  Wobble\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    Wibble(field2:, field:) ->\n           ↑                  \n      case field {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(field: Int, field2: String)\n  Wobble\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    Wibble(field2:, field: 1) -> 2\n    Wibble(field2:, field: 2) -> 4\n    Wibble(field2:, field: _) -> -1\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(field: Int, field2: String)\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_works_with_alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    [first, ..rest] ->\\n      case first {\\n        1 | 2 -> True\\n        3 | 4 | 5 -> False\\n        _ -> False\\n      }\\n\\n    [] -> True\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    [first, ..rest] ->\n     ↑                \n      case first {\n        1 | 2 -> True\n        3 | 4 | 5 -> False\n        _ -> False\n      }\n\n    [] -> True\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    [1, ..rest] | [2, ..rest] -> True\n    [3, ..rest] | [4, ..rest] | [5, ..rest] -> False\n    [_, ..rest] -> False\n\n    [] -> True\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_works_with_blocks.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    Ok(var) -> {\\n      case var {\\n        1 -> 2\\n        2 -> 4\\n        _ -> -1\\n      }\\n    }\\n    _ -> todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    Ok(var) -> {\n       ↑        \n      case var {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n    }\n    _ -> todo\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    Ok(1) -> 2\n    Ok(2) -> 4\n    Ok(_) -> -1\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__collapse_nested_case_works_with_patterns_defining_multiple_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    Wibble(var, var2) ->\\n      case var {\\n        1 -> 2\\n        2 -> 4\\n        _ -> -1\\n      }\\n\\n    Wobble -> todo\\n  }\\n}\\n\\npub type Wibble {\\n  Wibble(Int, String)\\n  Wobble\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    Wibble(var, var2) ->\n           ↑            \n      case var {\n        1 -> 2\n        2 -> 4\n        _ -> -1\n      }\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(Int, String)\n  Wobble\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    Wibble(1, var2) -> 2\n    Wibble(2, var2) -> 4\n    Wibble(_, var2) -> -1\n\n    Wobble -> todo\n  }\n}\n\npub type Wibble {\n  Wibble(Int, String)\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_assert_custom_type_with_label_shorthands_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(arg: Int, arg2: Float) }\\npub fn main() {\\n  let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: Float) }\npub fn main() {\n  let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0)\n                    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: Float) }\npub fn main() {\n  let arg2 = case Wibble(arg: 1, arg2: 1.0) {\n    Wibble(arg2:, ..) -> arg2\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_assert_result_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert Ok(value) = Ok(1)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert Ok(value) = Ok(1)\n      ▔▔▔▔↑                   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let value = case Ok(1) {\n    Ok(value) -> value\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_expression_with_empty_parens.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble()\\n  todo\\n  todo\\n}\\n\\nfn wibble(f) {\\n    f()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble()\n  ↑              \n  todo\n  todo\n}\n\nfn wibble(f) {\n    f()\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(fn() {\n    todo\n    todo\n  })\n}\n\nfn wibble(f) {\n    f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_expression_with_multiple_patterns.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(1, 2)\\n  todo\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(1, 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(1, 2)\n              ↑           \n  todo\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a, b) {\n    todo\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_expression_with_no_parens.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble\\n  todo\\n  todo\\n}\\n\\nfn wibble(f) {\\n    f()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble\n  ▔▔▔▔▔▔▔↑     \n  todo\n  todo\n}\n\nfn wibble(f) {\n    f()\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(fn() {\n    todo\n    todo\n  })\n}\n\nfn wibble(f) {\n    f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_expression_with_parens_and_other_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble(1, 2)\\n  todo\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble(1, 2)\n         ▔▔▔▔▔▔▔↑    \n  todo\n  todo\n}\n\nfn wibble(n, m, f) {\n    f()\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, 2, fn() {\n    todo\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_expression_with_single_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a <- wibble(1, 2)\\n  todo\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a <- wibble(1, 2)\n      ↑                \n  todo\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a) {\n    todo\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_expression_with_type_annotations.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a: Int, b: Int <- wibble(1, 2)\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(1, 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a: Int, b: Int <- wibble(1, 2)\n                     ▔▔▔↑           \n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a: Int, b: Int) {\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_multiline_with_no_trailing_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(\\n    1,\\n    2\\n  )\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(todo, todo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(\n           ▔▔▔↑      \n    1,\n    2\n  )\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(\n    1,\n    2\n  , fn(a, b) {\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a <- wibble(one: 1, two: 2)\\n  todo\\n}\\n\\nfn wibble(one _, two _, three f) {\\n    f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a <- wibble(one: 1, two: 2)\n  ↑                              \n  todo\n}\n\nfn wibble(one _, two _, three f) {\n    f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(one: 1, two: 2, three: fn(a) {\n    todo\n  })\n}\n\nfn wibble(one _, two _, three f) {\n    f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_labels_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a <- wibble(1, two: 2)\\n  todo\\n}\\n\\nfn wibble(one _, two _, three f) {\\n    f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a <- wibble(1, two: 2)\n  ↑                         \n  todo\n}\n\nfn wibble(one _, two _, three f) {\n    f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, two: 2, three: fn(a) {\n    todo\n  })\n}\n\nfn wibble(one _, two _, three f) {\n    f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_labels_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a <- wibble(1, three: 3)\\n  todo\\n}\\n\\nfn wibble(one _, two f, three _) {\\n    f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a <- wibble(1, three: 3)\n  ↑                           \n  todo\n}\n\nfn wibble(one _, two f, three _) {\n    f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, three: 3, two: fn(a) {\n    todo\n  })\n}\n\nfn wibble(one _, two f, three _) {\n    f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_labels_4.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a <- wibble(two: 2, three: 3)\\n  todo\\n}\\n\\nfn wibble(one f, two _, three _) {\\n    f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a <- wibble(two: 2, three: 3)\n  ↑                                \n  todo\n}\n\nfn wibble(one f, two _, three _) {\n    f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(two: 2, three: 3, one: fn(a) {\n    todo\n  })\n}\n\nfn wibble(one f, two _, three _) {\n    f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_trailing_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(1, 2,)\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(todo, todo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(1, 2,)\n           ▔▔▔↑            \n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a, b) {\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_trailing_comma_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(\\n    1,\\n    2,\\n  )\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(todo, todo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(\n           ▔▔▔↑      \n    1,\n    2,\n  )\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(\n    1,\n    2,\n  fn(a, b) {\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_from_use_with_trailing_comma_and_label.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(\\n    1,\\n    wibble: 2,\\n  )\\n  todo\\n}\\n\\nfn wibble(n, wibble m, wobble f) {\\n    f(todo, todo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(\n           ▔▔▔↑      \n    1,\n    wibble: 2,\n  )\n  todo\n}\n\nfn wibble(n, wibble m, wobble f) {\n    f(todo, todo)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(\n    1,\n    wibble: 2,\n  wobble: fn(a, b) {\n    todo\n  })\n}\n\nfn wibble(n, wibble m, wobble f) {\n    f(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_inner_let_assert_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert [wibble] = {\\n        let assert Ok(wobble) = {\\n            Ok(1)\\n        }\\n        [wobble]\\n    }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert [wibble] = {\n        let assert Ok(wobble) = {\n                          ↑      \n            Ok(1)\n        }\n        [wobble]\n    }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert [wibble] = {\n        let wobble = case {\n            Ok(1)\n        } {\n          Ok(wobble) -> wobble\n          _ -> panic\n        }\n        [wobble]\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_alias_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert 10 as ten = 10\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert 10 as ten = 10\n      ▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let ten = case 10 {\n    10 as ten -> ten\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_bit_array_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert <<bits1, bits2>> = <<73, 98>>\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert <<bits1, bits2>> = <<73, 98>>\n               ▔▔▔▔▔▔▔▔▔▔▔↑               \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let #(bits1, bits2) = case <<73, 98>> {\n    <<bits1, bits2>> -> #(bits1, bits2)\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_string_prefix_pattern_alias_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert \\\"123\\\" as one_two_three <> rest = \\\"123456\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert \"123\" as one_two_three <> rest = \"123456\"\n                ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑      \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let #(one_two_three, rest) = case \"123456\" {\n      \"123\" as one_two_three <> rest -> #(one_two_three, rest)\n      _ -> panic\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_string_prefix_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert \\\"_\\\" <> thing = \\\"_Hello\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert \"_\" <> thing = \"_Hello\"\n              ↑                     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let thing = case \"_Hello\" {\n    \"_\" <> thing -> thing\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_to_case_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert [_elem] = [6]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert [_elem] = [6]\n      ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let _ = case [6] {\n    [_elem] -> Nil\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_to_case_indented.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  {\\n    let assert Ok(value) = Ok(1)\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  {\n    let assert Ok(value) = Ok(1)\n               ↑                \n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  {\n    let value = case Ok(1) {\n      Ok(value) -> value\n      _ -> panic\n    }\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_to_case_multi_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert [var1, var2, _var3, var4] = [1, 2, 3, 4]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert [var1, var2, _var3, var4] = [1, 2, 3, 4]\n              ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑                       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let #(var1, var2, var4) = case [1, 2, 3, 4] {\n    [var1, var2, _var3, var4] -> #(var1, var2, var4)\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_to_case_no_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let assert [] = []\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let assert [] = []\n             ↑      \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let _ = case [] {\n    [] -> Nil\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_tuple_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n   let assert #(first, 10, third) = #(5, 10, 15)\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n   let assert #(first, 10, third) = #(5, 10, 15)\n   ↑                                            \n}\n\n\n----- AFTER ACTION\npub fn main() {\n   let #(first, third) = case #(5, 10, 15) {\n     #(first, 10, third) -> #(first, third)\n     _ -> panic\n   }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_let_assert_with_message_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn expect(value, message) {\\n  let assert Ok(inner) = value as message\\n  inner\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn expect(value, message) {\n  let assert Ok(inner) = value as message\n      ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑                 \n  inner\n}\n\n\n----- AFTER ACTION\n\npub fn expect(value, message) {\n  let inner = case value {\n    Ok(inner) -> inner\n    _ -> panic as message\n  }\n  inner\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_outer_let_assert_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert [wibble] = {\\n        let assert Ok(wobble) = {\\n            Ok(1)\\n        }\\n        [wobble]\\n    }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert [wibble] = {\n                 ▔▔▔▔▔▔▔↑  \n        let assert Ok(wobble) = {\n            Ok(1)\n        }\n        [wobble]\n    }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let wibble = case {\n        let assert Ok(wobble) = {\n            Ok(1)\n        }\n        [wobble]\n    } {\n      [wibble] -> wibble\n      _ -> panic\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_always_inlines_the_first_step.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(todo)\\n  |> filter(todo)\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3]\n  ▔▔▔▔▔▔▔▔▔\n  |> map(todo)\n▔▔▔▔▔↑        \n  |> filter(todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  map([1, 2, 3], todo)\n  |> filter(todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_when_piping_a_module_select.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.wobble |> woo(_)\\n}\\n\\nfn woo(n) { todo }\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main() {\n  wibble.wobble |> woo(_)\n                   ↑     \n}\n\nfn woo(n) { todo }\n\n\n----- AFTER ACTION\n\nimport wibble\n\npub fn main() {\n  woo(wibble.wobble)\n}\n\nfn woo(n) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_when_piping_an_invalid_module_select.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble.wobble |> woo(_)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble.wobble |> woo(_)\n                   ↑     \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  woo(wibble.wobble)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_argument_in_first_position.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(todo)\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3]\n  |> map(todo)\n     ↑        \n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  map([1, 2, 3], todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_argument_in_first_position_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3] |> wibble\\n}\\n\\nfn wibble(a) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3] |> wibble\n               ↑     \n}\n\nfn wibble(a) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble([1, 2, 3])\n}\n\nfn wibble(a) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_argument_in_first_position_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3] |> wibble()\\n}\\n\\nfn wibble(a) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3] |> wibble()\n               ↑       \n}\n\nfn wibble(a) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble([1, 2, 3])\n}\n\nfn wibble(a) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_argument_in_first_position_4.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3] |> wibble.wobble\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3] |> wibble.wobble\n               ↑            \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble.wobble([1, 2, 3])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_echo.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble.wobble |> echo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble.wobble |> echo\n                   ↑   \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  echo wibble.wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_function_producing_another_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 |> wibble(2)\\n}\\n\\nfn wibble(c) -> fn(a) -> Nil {\\n  fn(_) { Nil }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 |> wibble(2)\n       ↑        \n}\n\nfn wibble(c) -> fn(a) -> Nil {\n  fn(_) { Nil }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(2)(1)\n}\n\nfn wibble(c) -> fn(a) -> Nil {\n  fn(_) { Nil }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_hole_in_first_position.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(_, todo)\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3]\n  ↑        \n  |> map(_, todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  map([1, 2, 3], todo)\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_hole_not_in_first_position.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  fn(a) { todo }\\n  |> map([1, 2, 3], _)\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  fn(a) { todo }\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  |> map([1, 2, 3], _)\n▔▔▔▔▔↑                \n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  map([1, 2, 3], fn(a) { todo })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_labelled_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3] |> wibble(wobble: _, woo:)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3] |> wibble(wobble: _, woo:)\n               ↑                      \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(wobble: [1, 2, 3], woo:)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_function_call_works_with_labelled_argument_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3] |> wibble(wobble:, woo: _)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3] |> wibble(wobble:, woo: _)\n               ↑                      \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(wobble:, woo: [1, 2, 3])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_on_first_step_of_pipeline.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble, woo) |> wobble\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble, woo) |> wobble\n  ↑                            \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wobble |> wibble(woo) |> wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_pipes_the_outermost_argument.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble(woo))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble(woo))\n         ↑           \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(woo |> wobble)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_when_first_arg_is_a_pipe_itself.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble |> woo, waa)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble |> woo, waa)\n  ↑                         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wobble |> woo |> wibble(waa)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_bool_operator_adds_braces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble != woo, waa)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble != woo, waa)\n  ↑                         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  { wobble != woo } |> wibble(waa)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_comparison_adds_braces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1.0 >=. 0.0, waa)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1.0 >=. 0.0, waa)\n  ↑                       \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  { 1.0 >=. 0.0 } |> wibble(waa)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_complex_binop_adds_braces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn bug() {\\n    bool.guard(1 == 2 || 2 == 3, Nil, fn() { Nil })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn bug() {\n    bool.guard(1 == 2 || 2 == 3, Nil, fn() { Nil })\n                      ↑                            \n}\n\n\n----- AFTER ACTION\n\nfn bug() {\n    { 1 == 2 || 2 == 3 } |> bool.guard(Nil, fn() { Nil })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_on_first_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble, woo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble, woo)\n         ↑           \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wobble |> wibble(woo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_on_function_name_extracts_first_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble, woo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble, woo)\n  ↑                  \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wobble |> wibble(woo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_on_second_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble, woo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble, woo)\n                 ↑   \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  woo |> wibble(wobble, _)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble: 1, woo: 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble: 1, woo: 2)\n         ↑                 \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 |> wibble(wobble: _, woo: 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble: 1, woo: 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble: 1, woo: 2)\n                    ↑      \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  2 |> wibble(wobble: 1, woo: _)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble:, woo:)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble:, woo:)\n         ↑             \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wobble |> wibble(wobble: _, woo:)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble:, woo:)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble:, woo:)\n                  ↑    \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  woo |> wibble(wobble:, woo: _)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_function_returning_other_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble)(woo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble)(woo)\n                 ↑   \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  woo |> wibble(wobble)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_nested_calls_picks_the_innermost_one.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nfn bug() {\\n    wibble(Wobble(\\n      field: woo(other_call(last))\\n    ))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn bug() {\n    wibble(Wobble(\n      field: woo(other_call(last))\n             ↑                    \n    ))\n}\n\n\n----- AFTER ACTION\n\nfn bug() {\n    wibble(Wobble(\n      field: other_call(last) |> woo\n    ))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_string_concat_adds_braces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(wobble <> woo, waa)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(wobble <> woo, waa)\n  ↑                         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  { wobble <> woo } |> wibble(waa)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_with_sum_adds_no_braces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1 + 1, waa)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1 + 1, waa)\n  ↑                 \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 + 1 |> wibble(waa)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_works_in_anonymous_function_inside_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble |> wobble(fn() { woo(1) })\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble |> wobble(fn() { woo(1) })\n                          ↑        \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble |> wobble(fn() { 1 |> woo })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_works_in_final_step_of_a_pipeline.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble |> wobble(woo(1))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble |> wobble(woo(1))\n                   ↑      \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble |> wobble(1 |> woo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__convert_to_pipe_works_inside_body_of_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble(wobble)\\n  woo(123)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble(wobble)\n  woo(123)\n  ↑       \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- wibble(wobble)\n  123 |> woo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__desugar_nested_use_expressions_picks_inner_under_cursor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(1, 2)\\n  use a, b <- wibble(a, b)\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(1, 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(1, 2)\n  use a, b <- wibble(a, b)\n  ↑                       \n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a, b <- wibble(1, 2)\n  wibble(a, b, fn(a, b) {\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__desugar_nested_use_expressions_picks_inner_under_cursor_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use a, b <- wibble(1, 2)\\n  use a, b <- wibble(a, b)\\n  todo\\n}\\n\\nfn wibble(n, m, f) {\\n    f(1, 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use a, b <- wibble(1, 2)\n           ▔▔▔↑           \n  use a, b <- wibble(a, b)\n  todo\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a, b) {\n    use a, b <- wibble(a, b)\n    todo\n  })\n}\n\nfn wibble(n, m, f) {\n    f(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__different_annotations_create_compatible_type_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_generic_things(a, b) {\\n  let a_value = a\\n  let b_value = b\\n  let other_value = a_value\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_generic_things(a, b) {\n  let a_value = a\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let b_value = b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let other_value = a_value\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n\n\n----- AFTER ACTION\n\npub fn do_generic_things(a, b) {\n  let a_value: a = a\n  let b_value: b = b\n  let other_value: a = a_value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__expand_function_capture.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  wibble(_, 1)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  wibble(_, 1)\n         ↑    \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  fn(value) { wibble(value, 1) }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__expand_function_capture_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  wibble(1, _)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  wibble(1, _)\n  ↑           \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  fn(value) { wibble(1, value) }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__expand_function_capture_does_not_shadow_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let value = 1\\n  let value_2 = 2\\n  wibble(value, _, value_2)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let value = 1\n  let value_2 = 2\n  wibble(value, _, value_2)\n  ↑                        \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let value = 1\n  let value_2 = 2\n  fn(value_3) { wibble(value, value_3, value_2) }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__expand_function_capture_picks_a_name_based_on_the_type_of_the_hole.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> map(add(_, 1))\\n}\\n\\npub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo }\\npub fn add(n, m) { n + m }\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> map(add(_, 1))\n         ↑         \n}\n\npub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo }\npub fn add(n, m) { n + m }\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n  |> map(fn(int) { add(int, 1) })\n}\n\npub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo }\npub fn add(n, m) { n + m }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_anonymous_function_with_variable_capture_1.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let outer_scope = 3\\n  let wibble = fn(a, b) {\\n    a + b + outer_scope\\n  }\\n}\\n        \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let outer_scope = 3\n  let wibble = fn(a, b) {\n               ▔▔▔▔▔▔▔▔▔▔\n    a + b + outer_scope\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n}\n        \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let outer_scope = 3\n  let wibble = fn(a, b) {\n    function(a, b, outer_scope)\n  }\n}\n\nfn function(a: Int, b: Int, outer_scope: Int) -> Int {\n  a + b + outer_scope\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_anonymous_function_with_variable_capture_2.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/list\\n\\npub fn main() {\\n  let shorter = [1, 2, 3]\\n  let longer = [4, 5, 6, 7, 8]\\n  let offset = 5\\n  list.map2(shorter, longer, fn(_left, right) { right + offset })\\n}\\n        \"\n---\n----- BEFORE ACTION\n\nimport gleam/list\n\npub fn main() {\n  let shorter = [1, 2, 3]\n  let longer = [4, 5, 6, 7, 8]\n  let offset = 5\n  list.map2(shorter, longer, fn(_left, right) { right + offset })\n                             ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n}\n        \n\n\n----- AFTER ACTION\n\nimport gleam/list\n\npub fn main() {\n  let shorter = [1, 2, 3]\n  let longer = [4, 5, 6, 7, 8]\n  let offset = 5\n  list.map2(shorter, longer, fn(_left, right) { function(right, offset) })\n}\n\nfn function(right: Int, offset: Int) -> Int {\n  right + offset\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_anonymous_function_without_variable_capture_1.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let int_pow = fn(base, exp) {\\n    case exp {\\n      exp if exp < 0 -> 0\\n      0 -> base\\n      exp -> int_pow(base * exp, exp - 1)\\n    }\\n  }\\n}\\n        \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let int_pow = fn(base, exp) {\n                ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    case exp {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      exp if exp < 0 -> 0\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      0 -> base\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      exp -> int_pow(base * exp, exp - 1)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    }\n▔▔▔▔▔\n  }\n▔▔↑\n}\n        \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let int_pow = function\n}\n\nfn function(base: Int, exp: Int) -> Int {\n  case exp {\n      exp if exp < 0 -> 0\n      0 -> base\n      exp -> int_pow(base * exp, exp - 1)\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_anonymous_function_without_variable_capture_2.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/io\\nimport gleam/list\\n\\npub fn main() {\\n  list.each(list.range(0, 10), fn(_) { io.println(\\\"wibble wobble\\\") })\\n}\\n        \"\n---\n----- BEFORE ACTION\n\nimport gleam/io\nimport gleam/list\n\npub fn main() {\n  list.each(list.range(0, 10), fn(_) { io.println(\"wibble wobble\") })\n                               ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n}\n        \n\n\n----- AFTER ACTION\n\nimport gleam/io\nimport gleam/list\n\npub fn main() {\n  list.each(list.range(0, 10), function)\n}\n\nfn function(_int: Int) -> Nil {\n  io.println(\"wibble wobble\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_block_tail_position_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case 1 {\\n    _ -> {\\n      use <- wibble\\n      123\\n    }\\n    _ -> todo\\n  }\\n}\\n\\nfn wibble(f: fn() -> Float) -> Float { f() }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case 1 {\n    _ -> {\n         ▔\n      use <- wibble\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      123\n▔▔▔▔▔▔▔▔▔\n    }\n▔▔▔▔↑\n    _ -> todo\n  }\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case 1 {\n    _ -> function()\n    _ -> todo\n  }\n}\n\nfn function() -> Float {\n  use <- wibble\n      123\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_block_tail_position_4.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case 1 {\\n    _ -> {\\n      use <- wibble\\n      use <- wibble\\n      123\\n    }\\n    _ -> todo\\n  }\\n}\\n\\nfn wibble(f: fn() -> Float) -> Float { f() }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case 1 {\n    _ -> {\n         ▔\n      use <- wibble\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      use <- wibble\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      123\n▔▔▔▔▔▔▔▔▔\n    }\n▔▔▔▔↑\n    _ -> todo\n  }\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case 1 {\n    _ -> function()\n    _ -> todo\n  }\n}\n\nfn function() -> Float {\n  use <- wibble\n      use <- wibble\n      123\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_declaration_with_proper_indentation.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let fahrenheit = {\\n    let degrees = 64\\n    degrees\\n  }\\n  fahrenheit\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let fahrenheit = {\n    let degrees = 64\n    ▔▔▔▔▔▔▔▔▔▔↑     \n    degrees\n  }\n  fahrenheit\n}\n\n\n----- AFTER ACTION\n\nconst degrees = 64\n\npub fn main() {\n  let fahrenheit = {\n    degrees\n  }\n  fahrenheit\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_doesnt_place_constant_below_documentation.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\n/// Wibble does some wobbling\\npub fn wibble() {\\n    let x = \\\"wobble\\\"\\n    x\\n}\\n\"\n---\n----- BEFORE ACTION\n\n/// Wibble does some wobbling\npub fn wibble() {\n    let x = \"wobble\"\n        ↑           \n    x\n}\n\n\n----- AFTER ACTION\n\nconst x = \"wobble\"\n\n/// Wibble does some wobbling\npub fn wibble() {\n    x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_doesnt_place_constant_below_large_documentation.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\n/// Wibble does some wobbling\\n/// Note that it doesn't perform wibbling\\npub fn wibble() {\\n    let x = \\\"wobble\\\"\\n    x\\n}\\n\"\n---\n----- BEFORE ACTION\n\n/// Wibble does some wobbling\n/// Note that it doesn't perform wibbling\npub fn wibble() {\n    let x = \"wobble\"\n        ↑           \n    x\n}\n\n\n----- AFTER ACTION\n\nconst x = \"wobble\"\n\n/// Wibble does some wobbling\n/// Note that it doesn't perform wibbling\npub fn wibble() {\n    x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_bit_array.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  io.debug(<<3:size(8)>>)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  io.debug(<<3:size(8)>>)\n           ▔↑            \n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst bit_array = <<3:size(8)>>\n\npub fn main() {\n  io.debug(bit_array)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_float.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/float\\n\\npub fn main() {\\n  float.ceiling(1.9998)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/float\n\npub fn main() {\n  float.ceiling(1.9998)\n                ▔▔▔▔▔↑ \n}\n\n\n----- AFTER ACTION\nimport gleam/float\n\nconst float = 1.9998\n\npub fn main() {\n  float.ceiling(float)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_int.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/list\\n\\npub fn main() {\\n  list.sample([4, 5, 6], 2)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/list\n\npub fn main() {\n  list.sample([4, 5, 6], 2)\n                         ↑ \n}\n\n\n----- AFTER ACTION\nimport gleam/list\n\nconst int = 2\n\npub fn main() {\n  list.sample([4, 5, 6], int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  io.debug([\\\"constant\\\", \\\"another constant\\\"])\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  io.debug([\"constant\", \"another constant\"])\n           ↑                                \n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst strings = [\"constant\", \"another constant\"]\n\npub fn main() {\n  io.debug(strings)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_nested_inside.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/list\\n\\npub fn main() {\\n  list.unzip([#(1, 2), #(3, 4)])\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/list\n\npub fn main() {\n  list.unzip([#(1, 2), #(3, 4)])\n              ▔↑                \n}\n\n\n----- AFTER ACTION\nimport gleam/list\n\nconst value = #(1, 2)\n\npub fn main() {\n  list.unzip([value, #(3, 4)])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_nested_outside.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/list\\n\\npub fn main() {\\n  list.unzip([#(1, 2), #(3, 4)])\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/list\n\npub fn main() {\n  list.unzip([#(1, 2), #(3, 4)])\n             ↑                  \n}\n\n\n----- AFTER ACTION\nimport gleam/list\n\nconst values = [#(1, 2), #(3, 4)]\n\npub fn main() {\n  list.unzip(values)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_string.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  io.print(\\\"constant\\\")\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  io.print(\"constant\")\n           ↑          \n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst string = \"constant\"\n\npub fn main() {\n  io.print(string)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_call_argument_with_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  io.debug(#(1, 2, 3))\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  io.debug(#(1, 2, 3))\n           ▔↑         \n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst value = #(1, 2, 3)\n\npub fn main() {\n  io.debug(value)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_bin_op.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let twelve = \\\"1\\\" <> \\\"2\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let twelve = \"1\" <> \"2\"\n                   ↑     \n}\n\n\n----- AFTER ACTION\nconst string = \"1\" <> \"2\"\n\npub fn main() {\n  let twelve = string\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_bit_array.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let b = <<\\\"arr\\\":utf32>>\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let b = <<\"arr\":utf32>>\n                  ▔▔▔▔▔▔↑\n}\n\n\n----- AFTER ACTION\nconst bit_array = <<\"arr\":utf32>>\n\npub fn main() {\n  let b = bit_array\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_float.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = 3.1415\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = 3.1415\n          ▔▔▔▔▔↑\n}\n\n\n----- AFTER ACTION\nconst float = 3.1415\n\npub fn main() {\n  let c = float\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_int.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = 125\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = 125\n          ▔▔↑\n}\n\n\n----- AFTER ACTION\nconst int = 125\n\npub fn main() {\n  let c = int\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = [3.1415, 0.33333333]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = [3.1415, 0.33333333]\n          ↑                   \n}\n\n\n----- AFTER ACTION\nconst floats = [3.1415, 0.33333333]\n\npub fn main() {\n  let c = floats\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_nested_inside.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = #([1, 2, 3], [3, 2, 1])\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = #([1, 2, 3], [3, 2, 1])\n            ↑                    \n}\n\n\n----- AFTER ACTION\nconst ints = [1, 2, 3]\n\npub fn main() {\n  let c = #(ints, [3, 2, 1])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_nested_outside.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = #([1, 2, 3], [3, 2, 1])\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = #([1, 2, 3], [3, 2, 1])\n          ▔↑                     \n}\n\n\n----- AFTER ACTION\nconst value = #([1, 2, 3], [3, 2, 1])\n\npub fn main() {\n  let c = value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_string.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = \\\"constant\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = \"constant\"\n          ↑         \n}\n\n\n----- AFTER ACTION\nconst string = \"constant\"\n\npub fn main() {\n  let c = string\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_declaration_of_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let #(one, two, three) = #(\\\"one\\\", \\\"two\\\", \\\"three\\\")\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let #(one, two, three) = #(\"one\", \"two\", \"three\")\n                           ▔↑                      \n}\n\n\n----- AFTER ACTION\nconst value = #(\"one\", \"two\", \"three\")\n\npub fn main() {\n  let #(one, two, three) = value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_inside_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let fahrenheit = {\\n    let degrees = 64 + 32\\n    degrees\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let fahrenheit = {\n    let degrees = 64 + 32\n                       ↑ \n    degrees\n  }\n}\n\n\n----- AFTER ACTION\nconst int = 32\n\npub fn main() {\n  let fahrenheit = {\n    let degrees = 64 + int\n    degrees\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_inside_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(result) {\\n  case result {\\n    Ok(value) -> value + 1\\n    Error(_) -> panic\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(result) {\n  case result {\n    Ok(value) -> value + 1\n                         ↑\n    Error(_) -> panic\n  }\n}\n\n\n----- AFTER ACTION\nconst int = 1\n\npub fn main(result) {\n  case result {\n    Ok(value) -> value + int\n    Error(_) -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_inside_use_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  use x <- result.try(todo)\\n  Ok(123)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  use x <- result.try(todo)\n  Ok(123)\n  ↑      \n}\n\n\n----- AFTER ACTION\nconst result = Ok(123)\n\npub fn main() {\n  use x <- result.try(todo)\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_inside_use_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"const number = 123\\n\\npub fn main() {\\n  use x <- result.try(todo)\\n  Ok(number)\\n}\"\n---\n----- BEFORE ACTION\nconst number = 123\n\npub fn main() {\n  use x <- result.try(todo)\n  Ok(number)\n  ↑         \n}\n\n\n----- AFTER ACTION\nconst number = 123\n\nconst result = Ok(number)\n\npub fn main() {\n  use x <- result.try(todo)\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_list_containing_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"const something = \\\"something\\\"\\n\\npub fn main() {\\n  let c = [\\\"constant\\\", something]\\n}\"\n---\n----- BEFORE ACTION\nconst something = \"something\"\n\npub fn main() {\n  let c = [\"constant\", something]\n          ↑                      \n}\n\n\n----- AFTER ACTION\nconst something = \"something\"\n\nconst strings = [\"constant\", something]\n\npub fn main() {\n  let c = strings\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_literal_within_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = [\\\"constant\\\", todo]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = [\"constant\", todo]\n           ↑                \n}\n\n\n----- AFTER ACTION\nconst string = \"constant\"\n\npub fn main() {\n  let c = [string, todo]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_literal_within_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let c = #(0.333334, todo)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let c = #(0.333334, todo)\n            ▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\nconst float = 0.333334\n\npub fn main() {\n  let c = #(float, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_nested_inside_in_expr.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [#(\\\"a\\\", 0), #(\\\"b\\\", 1), #(\\\"a\\\", 2)]\\n  |> key_filter(\\\"a\\\")\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n   ▔↑                              \n  |> key_filter(\"a\")\n}\n\n\n----- AFTER ACTION\nconst value = #(\"a\", 0)\n\npub fn main() {\n  [value, #(\"b\", 1), #(\"a\", 2)]\n  |> key_filter(\"a\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_nested_outside_in_expr.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [#(\\\"a\\\", 0), #(\\\"b\\\", 1), #(\\\"a\\\", 2)]\\n  |> key_filter(\\\"a\\\")\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n  ↑                                \n  |> key_filter(\"a\")\n}\n\n\n----- AFTER ACTION\nconst values = [#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)]\n\npub fn main() {\n  values\n  |> key_filter(\"a\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_nil.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let x = Nil\\n  x\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let x = Nil\n  ▔▔▔▔↑      \n  x\n}\n\n\n----- AFTER ACTION\nconst x = Nil\n\npub fn main() {\n  x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_non_record_variant_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type Auth {\\n  Verified\\n  Unverified\\n}\\n\\npub fn main() {\\n  let a = Unverified\\n  let a = verify(something, a)\\n\\n  a\\n}\\n\"\n---\n----- BEFORE ACTION\npub type Auth {\n  Verified\n  Unverified\n}\n\npub fn main() {\n  let a = Unverified\n          ▔▔▔▔▔▔▔▔▔↑\n  let a = verify(something, a)\n\n  a\n}\n\n\n----- AFTER ACTION\npub type Auth {\n  Verified\n  Unverified\n}\n\nconst auth = Unverified\n\npub fn main() {\n  let a = auth\n  let a = verify(something, a)\n\n  a\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_non_record_variant_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type Auth {\\n  Verified\\n  Unverified\\n}\\n\\npub fn main() {\\n  let a = verify(something, Unverified)\\n\\n  a\\n}\\n\"\n---\n----- BEFORE ACTION\npub type Auth {\n  Verified\n  Unverified\n}\n\npub fn main() {\n  let a = verify(something, Unverified)\n                            ▔▔▔▔▔▔▔▔▔↑ \n\n  a\n}\n\n\n----- AFTER ACTION\npub type Auth {\n  Verified\n  Unverified\n}\n\nconst auth = Unverified\n\npub fn main() {\n  let a = verify(something, auth)\n\n  a\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_record_variant_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type Auth {\\n  Verified(String)\\n  Unverified\\n}\\n\\npub fn main() {\\n  let u = Verified(\\\"User\\\")\\n  let v = verify(something, u)\\n\\n  v\\n}\"\n---\n----- BEFORE ACTION\npub type Auth {\n  Verified(String)\n  Unverified\n}\n\npub fn main() {\n  let u = Verified(\"User\")\n  ▔▔▔▔↑                   \n  let v = verify(something, u)\n\n  v\n}\n\n\n----- AFTER ACTION\npub type Auth {\n  Verified(String)\n  Unverified\n}\n\nconst u = Verified(\"User\")\n\npub fn main() {\n  let v = verify(something, u)\n\n  v\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_record_variant_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type Auth {\\n  Verified(Int)\\n  Unverified\\n}\\n\\nconst auth = True\\n\\nconst id = 1234\\n\\npub fn main() {\\n  let v = verify(auth, Verified(id))\\n\\n  v\\n}\"\n---\n----- BEFORE ACTION\npub type Auth {\n  Verified(Int)\n  Unverified\n}\n\nconst auth = True\n\nconst id = 1234\n\npub fn main() {\n  let v = verify(auth, Verified(id))\n                       ▔▔▔▔▔▔▔▔↑    \n\n  v\n}\n\n\n----- AFTER ACTION\npub type Auth {\n  Verified(Int)\n  Unverified\n}\n\nconst auth = True\n\nconst id = 1234\n\nconst auth_2 = Verified(id)\n\npub fn main() {\n  let v = verify(auth, auth_2)\n\n  v\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_return_of_float.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  0.25\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  0.25\n  ▔▔▔↑\n}\n\n\n----- AFTER ACTION\nconst float = 0.25\n\npub fn main() {\n  float\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_return_of_int.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  100\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  100\n  ▔▔↑\n}\n\n\n----- AFTER ACTION\nconst int = 100\n\npub fn main() {\n  int\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_return_of_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3, 4]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3, 4]\n  ↑           \n}\n\n\n----- AFTER ACTION\nconst ints = [1, 2, 3, 4]\n\npub fn main() {\n  ints\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_return_of_nested_outside.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [#(0.25, 0.75), #(0.5, 1.5)]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [#(0.25, 0.75), #(0.5, 1.5)]\n   ▔↑                         \n}\n\n\n----- AFTER ACTION\nconst value = #(0.25, 0.75)\n\npub fn main() {\n  [value, #(0.5, 1.5)]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_return_of_string.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"constant\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"constant\"\n  ↑         \n}\n\n\n----- AFTER ACTION\nconst string = \"constant\"\n\npub fn main() {\n  string\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_return_of_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  #(0.25, 0.75)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  #(0.25, 0.75)\n  ▔↑           \n}\n\n\n----- AFTER ACTION\nconst value = #(0.25, 0.75)\n\npub fn main() {\n  value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_taken_name_by_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"const ints = [1, 2]\\n\\npub fn main() {\\n  [5, 50]\\n}\"\n---\n----- BEFORE ACTION\nconst ints = [1, 2]\n\npub fn main() {\n  [5, 50]\n  ↑      \n}\n\n\n----- AFTER ACTION\nconst ints = [1, 2]\n\nconst ints_2 = [5, 50]\n\npub fn main() {\n  ints_2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_taken_name_by_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn floats() {\\n    [1.0, 2.0]\\n}\\n\\npub fn main() {\\n  [0.25, 0.75]\\n}\"\n---\n----- BEFORE ACTION\nfn floats() {\n    [1.0, 2.0]\n}\n\npub fn main() {\n  [0.25, 0.75]\n  ↑           \n}\n\n\n----- AFTER ACTION\nfn floats() {\n    [1.0, 2.0]\n}\n\nconst floats_2 = [0.25, 0.75]\n\npub fn main() {\n  floats_2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_tuple_containing_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"const something = \\\"something\\\"\\n\\npub fn main() {\\n  let c = #(0.333334, something)\\n}\"\n---\n----- BEFORE ACTION\nconst something = \"something\"\n\npub fn main() {\n  let c = #(0.333334, something)\n          ▔↑                    \n}\n\n\n----- AFTER ACTION\nconst something = \"something\"\n\nconst value = #(0.333334, something)\n\npub fn main() {\n  let c = value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_bin_op.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let twelve = \\\"1\\\" <> \\\"2\\\"\\n  io.print(twelve)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let twelve = \"1\" <> \"2\"\n  ▔▔▔▔▔▔▔▔▔↑             \n  io.print(twelve)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst twelve = \"1\" <> \"2\"\n\npub fn main() {\n  io.print(twelve)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_bit_array.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\nconst n = 24\\n\\npub fn main() {\\n  let bits = <<8080:size(n)>>\\n  bits\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\nconst n = 24\n\npub fn main() {\n  let bits = <<8080:size(n)>>\n  ▔▔▔▔▔▔▔↑                   \n  bits\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst n = 24\n\nconst bits = <<8080:size(n)>>\n\npub fn main() {\n  bits\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_float.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let c = 3.1415\\n  io.debug(c)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let c = 3.1415\n  ▔▔▔▔↑         \n  io.debug(c)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst c = 3.1415\n\npub fn main() {\n  io.debug(c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_int.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let c = 125\\n  io.debug(c)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let c = 125\n  ▔▔▔▔↑      \n  io.debug(c)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst c = 125\n\npub fn main() {\n  io.debug(c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_list.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let c = [3.1415, 0.33333333]\\n  io.debug(c)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let c = [3.1415, 0.33333333]\n  ▔▔▔▔↑                       \n  io.debug(c)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst c = [3.1415, 0.33333333]\n\npub fn main() {\n  io.debug(c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_nested.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let c = #([1, 2, 3], [3, 2, 1])\\n  io.debug(c)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let c = #([1, 2, 3], [3, 2, 1])\n  ▔▔▔▔↑                          \n  io.debug(c)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst c = #([1, 2, 3], [3, 2, 1])\n\npub fn main() {\n  io.debug(c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_string.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let c = \\\"constant\\\"\\n  io.debug(c)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let c = \"constant\"\n  ▔▔▔▔↑             \n  io.debug(c)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst c = \"constant\"\n\npub fn main() {\n  io.debug(c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_from_whole_declaration_of_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/io\\n\\npub fn main() {\\n  let c = #(\\\"one\\\", \\\"two\\\", \\\"three\\\")\\n  io.debug(c)\\n}\"\n---\n----- BEFORE ACTION\nimport gleam/io\n\npub fn main() {\n  let c = #(\"one\", \"two\", \"three\")\n  ▔▔▔▔↑                           \n  io.debug(c)\n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\nconst c = #(\"one\", \"two\", \"three\")\n\npub fn main() {\n  io.debug(c)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_in_correct_position_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn first() {\\n    1\\n}\\n\\nfn second() {\\n    2\\n}\\n\\nfn third() {\\n    3\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn first() {\n    1\n    ↑\n}\n\nfn second() {\n    2\n}\n\nfn third() {\n    3\n}\n\n\n----- AFTER ACTION\n\nconst int = 1\n\nfn first() {\n    int\n}\n\nfn second() {\n    2\n}\n\nfn third() {\n    3\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_in_correct_position_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn first() {\\n    1\\n}\\n\\nfn second() {\\n    2\\n}\\n\\nfn third() {\\n    3\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn first() {\n    1\n}\n\nfn second() {\n    2\n    ↑\n}\n\nfn third() {\n    3\n}\n\n\n----- AFTER ACTION\n\nfn first() {\n    1\n}\n\nconst int = 2\n\nfn second() {\n    int\n}\n\nfn third() {\n    3\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_constant_in_correct_position_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn first() {\\n    1\\n}\\n\\nfn second() {\\n    2\\n}\\n\\nfn third() {\\n    3\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn first() {\n    1\n}\n\nfn second() {\n    2\n}\n\nfn third() {\n    3\n    ↑\n}\n\n\n----- AFTER ACTION\n\nfn first() {\n    1\n}\n\nfn second() {\n    2\n}\n\nconst int = 3\n\nfn third() {\n    int\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let result = {\\n    let a = 10 + a\\n    let b = 10 + b\\n    a * b\\n  }\\n  result + 3\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let result = {\n               ▔\n    let a = 10 + a\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    let b = 10 + b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    a * b\n▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n  result + 3\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  let result = function(a, b)\n  result + 3\n}\n\nfn function(a: Int, b: Int) -> Int {\n  let a = 10 + a\n    let b = 10 + b\n    a * b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_from_statements.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let a = 10 + a\\n  let b = 10 + b\\n  let result = a * b\\n  result + 3\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let a = 10 + a\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let b = 10 + b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let result = a * b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑  \n  result + 3\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  let result = function(a, b)\n  result + 3\n}\n\nfn function(a: Int, b: Int) -> Int {\n  let a = 10 + a\n  let b = 10 + b\n  let result = a * b\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_partially_selected.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let a = 10\\n  let b = 20\\n  let c = a + b\\n\\n  echo c\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let a = 10\n      ▔▔▔▔▔▔\n  let b = 20\n▔▔▔▔▔▔▔▔▔▔▔▔\n  let c = a + b\n▔▔▔▔▔▔↑        \n\n  echo c\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let c = function()\n\n  echo c\n}\n\nfn function() -> Int {\n  let a = 10\n  let b = 20\n  let c = a + b\n  c\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_when_multiple_names_already_in_scope.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn function() { todo }\\nfn function_2() { todo }\\nfn function_3() { todo }\\nfn function_4() { todo }\\n\\npub fn do_things(a, b) {\\n  let result = {\\n    let a = 10 + a\\n    let b = 10 + b\\n    a * b\\n  }\\n  result + 3\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn function() { todo }\nfn function_2() { todo }\nfn function_3() { todo }\nfn function_4() { todo }\n\npub fn do_things(a, b) {\n  let result = {\n             ▔▔▔\n    let a = 10 + a\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    let b = 10 + b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    a * b\n▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n  result + 3\n}\n\n\n----- AFTER ACTION\n\nfn function() { todo }\nfn function_2() { todo }\nfn function_3() { todo }\nfn function_4() { todo }\n\npub fn do_things(a, b) {\n  let result = function_5(a, b)\n  result + 3\n}\n\nfn function_5(a: Int, b: Int) -> Int {\n  let a = 10 + a\n    let b = 10 + b\n    a * b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_when_name_already_in_scope.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn function() { todo }\\n\\npub fn do_things(a, b) {\\n  let result = {\\n    let a = 10 + a\\n    let b = 10 + b\\n    a * b\\n  }\\n  result + 3\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn function() { todo }\n\npub fn do_things(a, b) {\n  let result = {\n             ▔▔▔\n    let a = 10 + a\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    let b = 10 + b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    a * b\n▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n  result + 3\n}\n\n\n----- AFTER ACTION\n\nfn function() { todo }\n\npub fn do_things(a, b) {\n  let result = function_2(a, b)\n  result + 3\n}\n\nfn function_2(a: Int, b: Int) -> Int {\n  let a = 10 + a\n    let b = 10 + b\n    a * b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_use_variables_defined_in_the_extracted_span.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let new_a = 10 + a\\n  let new_b = 10 + b\\n  let result = new_a * new_b\\n  result + 3\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let new_a = 10 + a\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let new_b = 10 + b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let result = new_a * new_b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑      \n  result + 3\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  let result = function(a, b)\n  result + 3\n}\n\nfn function(a: Int, b: Int) -> Int {\n  let new_a = 10 + a\n  let new_b = 10 + b\n  let result = new_a * new_b\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_use_variables_shadowed_in_an_inner_scope.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let first_part = {\\n    let a = a + 10\\n    let b = b + 10\\n    a * b\\n  }\\n  let result = first_part + a * b\\n  result + 3\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let first_part = {\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    let a = a + 10\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    let b = b + 10\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    a * b\n▔▔▔▔▔▔▔▔▔\n  }\n▔▔▔\n  let result = first_part + a * b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑      \n  result + 3\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  let result = function(a, b)\n  result + 3\n}\n\nfn function(a: Int, b: Int) -> Int {\n  let first_part = {\n    let a = a + 10\n    let b = b + 10\n    a * b\n  }\n  let result = first_part + a * b\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_uses_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nconst pi = 3.14\\n\\npub fn main() {\\n  let radius = 4.5\\n\\n  let circumference = radius *. pi *. 2.0\\n\\n  echo circumference\\n}\\n\"\n---\n----- BEFORE ACTION\n\nconst pi = 3.14\n\npub fn main() {\n  let radius = 4.5\n\n  let circumference = radius *. pi *. 2.0\n                      ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑  \n\n  echo circumference\n}\n\n\n----- AFTER ACTION\n\nconst pi = 3.14\n\npub fn main() {\n  let radius = 4.5\n\n  let circumference = function(radius)\n\n  echo circumference\n}\n\nfn function(radius: Float) -> Float {\n  radius *. pi *. 2.0\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_uses_constant_in_guard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nconst pi = 3.14\\n\\npub fn main() {\\n  let value = 3.15\\n\\n  let string = case value {\\n    0.0 -> \\\"Zero\\\"\\n    1.0 -> \\\"One\\\"\\n    _ if value == pi -> \\\"PI\\\"\\n    _ -> \\\"Something else\\\"\\n  }\\n\\n  echo string\\n}\\n\"\n---\n----- BEFORE ACTION\n\nconst pi = 3.14\n\npub fn main() {\n  let value = 3.15\n\n  let string = case value {\n               ▔▔▔▔▔▔▔▔▔▔▔▔\n    0.0 -> \"Zero\"\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    1.0 -> \"One\"\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    _ if value == pi -> \"PI\"\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    _ -> \"Something else\"\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n\n  echo string\n}\n\n\n----- AFTER ACTION\n\nconst pi = 3.14\n\npub fn main() {\n  let value = 3.15\n\n  let string = function(value)\n\n  echo string\n}\n\nfn function(value: Float) -> String {\n  case value {\n    0.0 -> \"Zero\"\n    1.0 -> \"One\"\n    _ if value == pi -> \"PI\"\n    _ -> \"Something else\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_uses_multiple_extracted_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let wibble = a + b\\n  let wobble = a * b\\n  wobble / wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let wibble = a + b\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  let wobble = a * b\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑  \n  wobble / wibble\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  let #(wobble, wibble) = function(a, b)\n  wobble / wibble\n}\n\nfn function(a: Int, b: Int) -> #(Int, Int) {\n  let wibble = a + b\n  let wobble = a * b\n  #(wobble, wibble)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_uses_no_extracted_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let x = a + b\\n  echo x\\n  a\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let x = a + b\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔\n  echo x\n▔▔↑     \n  a\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  function(a, b)\n  a\n}\n\nfn function(a: Int, b: Int) -> Nil {\n  let x = a + b\n  echo x\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_uses_variable_in_bit_array_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let bits = todo\\n  let size = todo\\n\\n  let segment = case bits {\\n    <<x:size(size), _:bits>> -> Ok(x)\\n    _ -> Error(Nil)\\n  }\\n\\n  case segment {\\n    Ok(value) -> echo value\\n    Error(_) -> panic\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let bits = todo\n  let size = todo\n\n  let segment = case bits {\n                ▔▔▔▔▔▔▔▔▔▔▔\n    <<x:size(size), _:bits>> -> Ok(x)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    _ -> Error(Nil)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n\n  case segment {\n    Ok(value) -> echo value\n    Error(_) -> panic\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let bits = todo\n  let size = todo\n\n  let segment = function(bits, size)\n\n  case segment {\n    Ok(value) -> echo value\n    Error(_) -> panic\n  }\n}\n\nfn function(bits: BitArray, size: Int) -> Result(Int, Nil) {\n  case bits {\n    <<x:size(size), _:bits>> -> Ok(x)\n    _ -> Error(Nil)\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_function_which_uses_variable_in_guard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn do_things(a, b) {\\n  let result = case Nil {\\n    _ if a > b -> 17\\n    _ if a < b -> 12\\n    _ -> panic\\n  }\\n\\n  result % 4\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn do_things(a, b) {\n  let result = case Nil {\n               ▔▔▔▔▔▔▔▔▔▔\n    _ if a > b -> 17\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    _ if a < b -> 12\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    _ -> panic\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  }\n▔▔↑\n\n  result % 4\n}\n\n\n----- AFTER ACTION\n\npub fn do_things(a, b) {\n  let result = function(a, b)\n\n  result % 4\n}\n\nfn function(a: Int, b: Int) -> Int {\n  case Nil {\n    _ if a > b -> 17\n    _ if a < b -> 12\n    _ -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_statements_in_tail_position.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let a = 1\\n  let b = 2\\n  let c = 3\\n  let d = 4\\n  a * b + c * d\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let a = 1\n  let b = 2\n  let c = 3\n  ▔▔▔▔▔▔▔▔▔\n  let d = 4\n▔▔▔▔▔▔▔▔▔▔▔\n  a * b + c * d\n▔▔▔▔▔▔▔▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let a = 1\n  let b = 2\n  function(a, b)\n}\n\nfn function(a: Int, b: Int) -> Int {\n  let c = 3\n  let d = 4\n  a * b + c * d\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_unary_anonymous_function_with_variable_capture_1.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/list\\n\\npub fn main() {\\n  let needle = 42\\n  let haystack = [25, 81, 74, 42, 33]\\n  list.filter(haystack, fn(x) { x == needle })\\n}\\n        \"\n---\n----- BEFORE ACTION\n\nimport gleam/list\n\npub fn main() {\n  let needle = 42\n  let haystack = [25, 81, 74, 42, 33]\n  list.filter(haystack, fn(x) { x == needle })\n                        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n}\n        \n\n\n----- AFTER ACTION\n\nimport gleam/list\n\npub fn main() {\n  let needle = 42\n  let haystack = [25, 81, 74, 42, 33]\n  list.filter(haystack, function(_, needle))\n}\n\nfn function(x: Int, needle: Int) -> Bool {\n  x == needle\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_unary_anonymous_function_with_variable_capture_2.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/list\\n\\npub fn main() {\\n  let needle = 42\\n  let haystack = [25, 81, 74, 42, 33]\\n  list.filter(haystack, fn(_) { needle == 42 })\\n}\\n        \"\n---\n----- BEFORE ACTION\n\nimport gleam/list\n\npub fn main() {\n  let needle = 42\n  let haystack = [25, 81, 74, 42, 33]\n  list.filter(haystack, fn(_) { needle == 42 })\n                        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n}\n        \n\n\n----- AFTER ACTION\n\nimport gleam/list\n\npub fn main() {\n  let needle = 42\n  let haystack = [25, 81, 74, 42, 33]\n  list.filter(haystack, function(_, needle))\n}\n\nfn function(_int: Int, needle: Int) -> Bool {\n  needle == 42\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_use_in_tail_position.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble\\n  123\\n}\\n\\nfn wibble(f: fn() -> Int) -> Int { f() }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble\n  ▔▔▔▔▔▔▔↑     \n  123\n}\n\nfn wibble(f: fn() -> Int) -> Int { f() }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  function()\n}\n\nfn function() -> Int {\n  use <- wibble\n  123\n}\n\nfn wibble(f: fn() -> Int) -> Int { f() }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_use_in_tail_position_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble\\n  use <- wobble\\n  123\\n}\\n\\nfn wibble(f: fn() -> Float) -> Float { f() }\\nfn wobble(f: fn() -> Int) -> Float { 1.1 }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble\n  use <- wobble\n  ▔▔▔▔▔▔▔↑     \n  123\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\nfn wobble(f: fn() -> Int) -> Float { 1.1 }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- wibble\n  function()\n}\n\nfn function() -> Float {\n  use <- wobble\n  123\n}\n\nfn wibble(f: fn() -> Float) -> Float { f() }\nfn wobble(f: fn() -> Int) -> Float { 1.1 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  list.map([1, 2, 3], int.add(1, _))\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  list.map([1, 2, 3], int.add(1, _))\n           ▔▔▔▔↑                    \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let ints = [1, 2, 3]\n  list.map(ints, int.add(1, _))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  map([1, 2, 3], add(1, _))\\n}\\npub fn add(n, m) { todo }\\npub fn map(l, f) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  map([1, 2, 3], add(1, _))\n                 ↑         \n}\npub fn add(n, m) { todo }\npub fn map(l, f) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let value = add(1, _)\n  map([1, 2, 3], value)\n}\npub fn add(n, m) { todo }\npub fn map(l, f) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  list.map([1, 2, 3], todo, todo)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  list.map([1, 2, 3], todo, todo)\n                            ▔▔▔▔↑\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let value = todo\n  list.map([1, 2, 3], todo, value)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_after_nested_anonymous_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let f = fn() {\\n        let x = 1 + 2\\n        let ff = fn() {\\n            let y = x + 3\\n            let z = y + x\\n            z\\n        }\\n        let z = x * 4\\n        z\\n    }\\n    let y = 5 + 6\\n    f()\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let y = 5 + 6\n                ↑\n    f()\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let int = 6\n    let y = 5 + int\n    f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_and_dont_shadow_existing_variable_in_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn wibble(a, b) {\\n  a + b\\n}\\n\\nfn main() {\\n  let int = 1\\n  wibble(int, 2)\\n}\"\n---\n----- BEFORE ACTION\nfn wibble(a, b) {\n  a + b\n}\n\nfn main() {\n  let int = 1\n  wibble(int, 2)\n              ↑ \n}\n\n\n----- AFTER ACTION\nfn wibble(a, b) {\n  a + b\n}\n\nfn main() {\n  let int = 1\n  let int_2 = 2\n  wibble(int, int_2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_and_dont_shadow_existing_variable_in_operator.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import gleam/int\\nimport random_import as int_2\\n\\nconst int_3 = 3\\n\\nfn int_4() { 4 }\\n\\nfn isolated_scope() {\\n    let int_6 = 6\\n    int_6 + 1\\n}\\n\\npub fn main() {\\n  let int_5 = 5\\n  let result = int_5 + 6\\n  result\\n}\\n\"\n---\n----- BEFORE ACTION\nimport gleam/int\nimport random_import as int_2\n\nconst int_3 = 3\n\nfn int_4() { 4 }\n\nfn isolated_scope() {\n    let int_6 = 6\n    int_6 + 1\n}\n\npub fn main() {\n  let int_5 = 5\n  let result = int_5 + 6\n                       ↑\n  result\n}\n\n\n----- AFTER ACTION\nimport gleam/int\nimport random_import as int_2\n\nconst int_3 = 3\n\nfn int_4() { 4 }\n\nfn isolated_scope() {\n    let int_6 = 6\n    int_6 + 1\n}\n\npub fn main() {\n  let int_5 = 5\n  let int_6 = 6\n  let result = int_5 + int_6\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_does_not_shadow_name_in_same_block.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let result = {\\n    let int = 1\\n    wibble(11)\\n  }\\n  result\\n}\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let result = {\n    let int = 1\n    wibble(11)\n           ↑  \n  }\n  result\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let result = {\n    let int = 1\n    let int_2 = 11\n    wibble(int_2)\n  }\n  result\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_does_not_shadow_name_in_same_branch.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main(x: Result(_, _)) {\\n  case x {\\n    Ok(_) -> {\\n        let int = 1\\n        wibble(11)\\n    }\\n    Error(_) -> {\\n        panic\\n    }\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n        let int = 1\n        wibble(11)\n               ↑  \n    }\n    Error(_) -> {\n        panic\n    }\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n        let int = 1\n        let int_2 = 11\n        wibble(int_2)\n    }\n    Error(_) -> {\n        panic\n    }\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_does_not_shadow_names_in_anonymous_function.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let fun = fn() {\\n    let int = 1\\n    wibble(11)\\n  }\\n  fun()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let fun = fn() {\n    let int = 1\n    wibble(11)\n           ↑  \n  }\n  fun()\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let fun = fn() {\n    let int = 1\n    let int_2 = 11\n    wibble(int_2)\n  }\n  fun()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_from_arg_in_nested_function_called_in_pipeline.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let result =\\n    [1, 2, 3]\\n    |> map(add(_, 1))\\n    |> map(subtract(_, 9))\\n\\n  result\\n}\\npub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\\npub fn add(a: Int, b: Int) -> Int { todo }\\npub fn subtract(a: Int, b: Int) -> Int { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let result =\n    [1, 2, 3]\n    |> map(add(_, 1))\n    |> map(subtract(_, 9))\n                       ↑  \n\n  result\n}\npub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\npub fn subtract(a: Int, b: Int) -> Int { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let int = 9\n  let result =\n    [1, 2, 3]\n    |> map(add(_, 1))\n    |> map(subtract(_, int))\n\n  result\n}\npub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\npub fn subtract(a: Int, b: Int) -> Int { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_from_arg_in_pipelined_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let adder = add\\n  let x = [4, 5, 6] |> map2([1, 2, 3], adder)\\n  x\\n}\\npub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo }\\npub fn add(a: Int, b: Int) -> Int { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let adder = add\n  let x = [4, 5, 6] |> map2([1, 2, 3], adder)\n                            ↑                \n  x\n}\npub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let adder = add\n  let ints = [1, 2, 3]\n  let x = [4, 5, 6] |> map2(ints, adder)\n  x\n}\npub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_from_arg_in_pipelined_call_of_function_to_capture.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  fn(total, item) { total + item }\\n  |> fold(with: _, from: 0, over: [1, 2, 3])\\n}\\npub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  fn(total, item) { total + item }\n  |> fold(with: _, from: 0, over: [1, 2, 3])\n     ↑                                      \n}\npub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let value = fold(with: _, from: 0, over: [1, 2, 3])\n  fn(total, item) { total + item }\n  |> value\n}\npub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_from_arg_in_pipelined_call_to_capture.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let adder = add\\n  let x = adder |> reduce([1, 2, 3], _)\\n  x\\n}\\npub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo }\\npub fn add(a: Int, b: Int) -> Int { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let adder = add\n  let x = adder |> reduce([1, 2, 3], _)\n                          ↑            \n  x\n}\npub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let adder = add\n  let ints = [1, 2, 3]\n  let x = adder |> reduce(ints, _)\n  x\n}\npub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo }\npub fn add(a: Int, b: Int) -> Int { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_from_capture_arguments_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  int.add(11, _)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  int.add(11, _)\n          ↑     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let int = 11\n  int.add(int, _)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_ignores_names_in_anonymous_functions.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let fun = fn() {\\n    let int = 1\\n    int + 2\\n  }\\n\\n  wibble(11)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let fun = fn() {\n    let int = 1\n    int + 2\n  }\n\n  wibble(11)\n         ↑  \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let fun = fn() {\n    let int = 1\n    int + 2\n  }\n\n  let int = 11\n  wibble(int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_ignores_names_in_other_blocks.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main() {\\n  {\\n    let int = 1\\n    int + 2\\n  }\\n  wibble(11)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  {\n    let int = 1\n    int + 2\n  }\n  wibble(11)\n         ↑  \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  {\n    let int = 1\n    int + 2\n  }\n  let int = 11\n  wibble(int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_ignores_names_in_other_branches.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"pub fn main(x: Result(_, _)) {\\n  case x {\\n    Ok(_) -> {\\n      let int = 1\\n      int + 2\\n    }\\n    Error(_) -> wibble(11)\\n  }\\n\\n}\"\n---\n----- BEFORE ACTION\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n      let int = 1\n      int + 2\n    }\n    Error(_) -> wibble(11)\n                       ↑  \n  }\n\n}\n\n\n----- AFTER ACTION\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n      let int = 1\n      int + 2\n    }\n    Error(_) -> {\n      let int = 11\n      wibble(int)\n    }\n  }\n\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_ignores_names_in_other_branches_2.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn main(x: Result(_, _)) {\\n  case x {\\n    Ok(_) -> {\\n      let int = 1\\n      int + 2\\n    }\\n    Error(_) -> {\\n        wibble(11)\\n    }\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n      let int = 1\n      int + 2\n    }\n    Error(_) -> {\n        wibble(11)\n               ↑  \n    }\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main(x: Result(_, _)) {\n  case x {\n    Ok(_) -> {\n      let int = 1\n      int + 2\n    }\n    Error(_) -> {\n        let int = 11\n        wibble(int)\n    }\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_anonymous_fn_in_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn map(value, fn_over_value) { todo }\\n\\npub fn main() {\\n  1\\n  |> Ok\\n  |> map(fn(value) { value + 2 })\\n}\"\n---\n----- BEFORE ACTION\nfn map(value, fn_over_value) { todo }\n\npub fn main() {\n  1\n  |> Ok\n  |> map(fn(value) { value + 2 })\n                             ↑   \n}\n\n\n----- AFTER ACTION\nfn map(value, fn_over_value) { todo }\n\npub fn main() {\n  1\n  |> Ok\n  |> map(fn(value) { let int = 2\n  value + int })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  {\\n    todo\\n    wibble([1, 2, 3])\\n    todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  {\n    todo\n    wibble([1, 2, 3])\n               ▔▔▔↑  \n    todo\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  {\n    todo\n    let ints = [1, 2, 3]\n    wibble(ints)\n    todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_case_branch.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    case wibble {\\n      _ -> [1, 2, 3]\\n    }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    case wibble {\n      _ -> [1, 2, 3]\n           ↑        \n    }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    case wibble {\n      _ -> {\n        let ints = [1, 2, 3]\n        ints\n      }\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_case_branch_from_second_arg.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  case todo {\\n    Ok(_) -> #(Ok(1), Error(\\\"s\\\"))\\n    Error(_) -> panic\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  case todo {\n    Ok(_) -> #(Ok(1), Error(\"s\"))\n                      ↑          \n    Error(_) -> panic\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  case todo {\n    Ok(_) -> {\n      let result = Error(\"s\")\n      #(Ok(1), result)\n    }\n    Error(_) -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_case_branch_using_var.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  case todo {\\n    Ok(value) -> 2 * value + 1\\n    Error(_) -> panic\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  case todo {\n    Ok(value) -> 2 * value + 1\n                 ▔▔▔▔↑        \n    Error(_) -> panic\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  case todo {\n    Ok(value) -> {\n      let int = 2 * value\n      int + 1\n    }\n    Error(_) -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_double_nested_anonymous_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let f = fn() {\\n        let x = 1 + 2\\n        let ff = fn() {\\n            let y = x + 3\\n            let z = y + x\\n            z\\n        }\\n        let z = x * 4\\n        z\\n    }\\n    let y = 5 + 6\\n    f()\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n                        ↑\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let y = 5 + 6\n    f()\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let int = 3\n            let y = x + int\n            let z = y + x\n            z\n        }\n        let z = x * 4\n        z\n    }\n    let y = 5 + 6\n    f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_multiline_case_subject_branch.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    case\\n        list.map(\\n          [1, 2, 3],\\n          int.add(1, _)\\n        )\\n    {\\n      _ -> todo\\n    }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    case\n        list.map(\n          [1, 2, 3],\n          ↑         \n          int.add(1, _)\n        )\n    {\n      _ -> todo\n    }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let ints = [1, 2, 3]\n    case\n        list.map(\n          ints,\n          int.add(1, _)\n        )\n    {\n      _ -> todo\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_multiline_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    use <- wibble(\\n        [1, 2, 3]\\n    )\\n    todo\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    use <- wibble(\n        [1, 2, 3]\n        ↑        \n    )\n    todo\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let ints = [1, 2, 3]\n    use <- wibble(\n        ints\n    )\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_nested_anonymous_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let f = fn() {\\n        let x = 1 + 2\\n        let ff = fn() {\\n            let y = x + 3\\n            let z = y + x\\n            z\\n        }\\n        let z = x * 4\\n        z\\n    }\\n    let y = 5 + 6\\n    f()\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let z = x * 4\n                    ↑\n        z\n    }\n    let y = 5 + 6\n    f()\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let f = fn() {\n        let x = 1 + 2\n        let ff = fn() {\n            let y = x + 3\n            let z = y + x\n            z\n        }\n        let int = 4\n        let z = x * int\n        z\n    }\n    let y = 5 + 6\n    f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_in_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    use <- wibble([1, 2, 3])\\n    todo\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    use <- wibble([1, 2, 3])\n                  ↑         \n    todo\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let ints = [1, 2, 3]\n    use <- wibble(ints)\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_inside_multiline_function_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  list.map(\\n    [1, 2, 3],\\n    int.add(1, _),\\n  )\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  list.map(\n    [1, 2, 3],\n    ↑         \n    int.add(1, _),\n  )\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let ints = [1, 2, 3]\n  list.map(\n    ints,\n    int.add(1, _),\n  )\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_inside_use_body.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    use <- wibble(todo)\\n    list.map([1, 2, 3], int.add(1, _))\\n    todo\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    use <- wibble(todo)\n    list.map([1, 2, 3], int.add(1, _))\n             ↑                        \n    todo\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    use <- wibble(todo)\n    let ints = [1, 2, 3]\n    list.map(ints, int.add(1, _))\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_starting_pipeline_steps.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nassertion_line: 9619\nexpression: \"fn map(value, fn_over_value) { todo }\\n\\npub fn main() {\\n  1\\n  |> Ok\\n  |> map(fn(value) { value + 2 })\\n}\"\nsnapshot_kind: text\n---\n----- BEFORE ACTION\nfn map(value, fn_over_value) { todo }\n\npub fn main() {\n  1\n  ▔\n  |> Ok\n▔▔▔▔▔↑ \n  |> map(fn(value) { value + 2 })\n}\n\n\n----- AFTER ACTION\nfn map(value, fn_over_value) { todo }\n\npub fn main() {\n  let result =\n    1\n  |> Ok\n\n  result\n  |> map(fn(value) { value + 2 })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_variable_with_list_with_plural_name_does_not_add_another_s.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble([Names, Names])\\n}\\n\\npub type Names {\\n  Names\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble([Names, Names])\n         ↑              \n}\n\npub type Names {\n  Names\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let names = [Names, Names]\n  wibble(names)\n}\n\npub type Names {\n  Names\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_selects_innermost_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(\\n    wibble()\\n  )\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(\n    wibble()\n           ↑\n  )\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(\n    wibble(arg1: todo, arg2: todo)\n  )\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_with_some_arguments_already_supplied.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1,)\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1,)\n    ↑       \n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1,arg2: todo)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_with_some_arguments_already_supplied_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(arg2: 1)\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(arg2: 1)\n  ↑              \n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(arg2: 1, arg1: todo)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_with_some_arguments_already_supplied_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1, arg3: 2)\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1, arg3: 2)\n  ↑                 \n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(1, arg3: 2, arg2: todo)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_pattern_and_no_parentheses.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let assert Ok(Wibble) = Wibble(1, \\\"2\\\")\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: String) }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let assert Ok(Wibble) = Wibble(1, \"2\")\n                ▔▔▔▔▔↑                  \n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let assert Ok(Wibble(arg1:, arg2:)) = Wibble(1, \"2\")\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_pattern_and_parentheses.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let assert Ok(Wibble()) = Wibble(1, \\\"2\\\")\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: String) }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let assert Ok(Wibble()) = Wibble(1, \"2\")\n                ▔▔▔▔▔↑                    \n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let assert Ok(Wibble(arg1:, arg2:)) = Wibble(1, \"2\")\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_pattern_and_parentheses_with_spaces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let assert Ok(Wibble   ()) = Wibble(1, \\\"2\\\")\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: String) }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let assert Ok(Wibble   ()) = Wibble(1, \"2\")\n                ▔▔▔▔▔↑                       \n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  let assert Ok(Wibble   (arg1:, arg2:)) = Wibble(1, \"2\")\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_pipes.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 |> wibble()\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 |> wibble()\n              ↑\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 |> wibble(arg2: todo)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_pipes_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 |> wibble()\\n}\\n\\npub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 |> wibble()\n              ↑\n}\n\npub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 |> wibble(arg1: todo, arg2: todo)\n}\n\npub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_record_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  Wibble()\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: String) }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  Wibble()\n  ▔▔▔▔▔▔▔↑\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  Wibble(arg1: todo, arg2: todo)\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: String) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_regular_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble()\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble()\n  ↑       \n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(arg1: todo, arg2: todo)\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble()\\n  todo\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble()\n         ▔▔▔▔▔▔▔↑\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- wibble(arg1: todo)\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_use_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble(arg1: 1)\\n  todo\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble(arg1: 1)\n         ▔▔▔▔▔▔▔▔▔▔↑    \n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- wibble(arg1: 1, arg2: todo)\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_in_labelled_args_works_with_use_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use <- wibble(arg2: 2)\\n  todo\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\\n \"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use <- wibble(arg2: 2)\n         ▔▔▔▔▔▔▔▔▔▔↑    \n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n \n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- wibble(arg2: 2, arg1: todo)\n  todo\n}\n\npub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_all_fields_have_matching_variables.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, age: Int, team: String)\\n}\\n\\npub fn main() {\\n    let name = \\\"Priya\\\"\\n    let age = 25\\n    let team = \\\"BLU\\\"\\n    Player()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, age: Int, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    let age = 25\n    let team = \"BLU\"\n    Player()\n    ↑       \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, age: Int, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    let age = 25\n    let team = \"BLU\"\n    Player(name:, age:, team:)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_falls_back_to_todo_when_type_does_not_match.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    let name = 1\\n    Player(team: \\\"BLU\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = 1\n    Player(team: \"BLU\")\n    ↑                  \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = 1\n    Player(team: \"BLU\", name: todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_generic_type_matching.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Container(a) {\\n    Container(value: a, label: String)\\n}\\n\\npub fn main() {\\n    let value = 42\\n    let label = \\\"test\\\"\\n    Container()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Container(a) {\n    Container(value: a, label: String)\n}\n\npub fn main() {\n    let value = 42\n    let label = \"test\"\n    Container()\n    ↑          \n}\n\n\n----- AFTER ACTION\n\npub type Container(a) {\n    Container(value: a, label: String)\n}\n\npub fn main() {\n    let value = 42\n    let label = \"test\"\n    Container(value:, label:)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_ignores_underscore_prefixed_variables.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    let _name = \\\"Priya\\\"\\n    Player(team: \\\"BLU\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let _name = \"Priya\"\n    Player(team: \"BLU\")\n    ↑                  \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let _name = \"Priya\"\n    Player(team: \"BLU\", name: todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_ignores_variable_defined_after_call.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    Player(team: \\\"BLU\\\")\\n    let name = \\\"Priya\\\"\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    Player(team: \"BLU\")\n    ↑                  \n    let name = \"Priya\"\n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    Player(team: \"BLU\", name: todo)\n    let name = \"Priya\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_inside_anonymous_function.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    let name = \\\"Outer\\\"\\n    let callback = fn() {\\n        let name = \\\"Inner\\\"\\n        Player(team: \\\"BLU\\\")\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Outer\"\n    let callback = fn() {\n        let name = \"Inner\"\n        Player(team: \"BLU\")\n        ↑                  \n    }\n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Outer\"\n    let callback = fn() {\n        let name = \"Inner\"\n        Player(team: \"BLU\", name:)\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_inside_assignment_with_same_name_as_field.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    let name = Player(team: \\\"BLU\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = Player(team: \"BLU\")\n               ↑                  \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = Player(team: \"BLU\", name: todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_multiple_fields_some_matching.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, age: Int, team: String)\\n}\\n\\npub fn main() {\\n    let name = \\\"Priya\\\"\\n    let age = \\\"not an int\\\"\\n    Player()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, age: Int, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    let age = \"not an int\"\n    Player()\n    ↑       \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, age: Int, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    let age = \"not an int\"\n    Player(name:, age: todo, team: todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_nested_pattern_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Float, c: String)\\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\\n}\\n\\npub fn main() {\\n  case todo {\\n    #([Wobble()], 2, 3) -> todo\\n    _ -> todo\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main() {\n  case todo {\n    #([Wobble()], 2, 3) -> todo\n       ↑                       \n    _ -> todo\n  }\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main() {\n  case todo {\n    #([Wobble(d:, e:, f:)], 2, 3) -> todo\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_pattern_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Float, c: String)\\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\\n}\\n\\npub fn main(w: Wibble) {\\n  case w {\\n    Wibble(..) -> todo\\n    Wobble() -> todo\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wibble(..) -> todo\n    Wobble() -> todo\n    ↑               \n  }\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wibble(..) -> todo\n    Wobble(d:, e:, f:) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_pattern_constructor_let_assignment.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Float, c: String)\\n}\\n\\npub fn main() {\\n  let Wibble() = todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\npub fn main() {\n  let Wibble() = todo\n      ↑              \n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\npub fn main() {\n  let Wibble(a:, b:, c:) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_pattern_constructor_with_some_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(a: Int, b: Float, c: String)\\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\\n}\\n\\npub fn main(w: Wibble) {\\n  case w {\\n    Wobble(e: <<>>) -> todo\\n    _ -> todo\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wobble(e: <<>>) -> todo\n    ↑                      \n    _ -> todo\n  }\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n  Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))\n}\n\npub fn main(w: Wibble) {\n  case w {\n    Wobble(e: <<>>, d:, f:) -> todo\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_uses_function_argument_in_scope.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn create_player(name: String) {\\n    Player(team: \\\"BLU\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn create_player(name: String) {\n    Player(team: \"BLU\")\n    ↑                  \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn create_player(name: String) {\n    Player(team: \"BLU\", name:)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_uses_variable_in_scope_with_matching_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    let name = \\\"Priya\\\"\\n    Player(team: \\\"BLU\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    Player(team: \"BLU\")\n    ↑                  \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Priya\"\n    Player(team: \"BLU\", name:)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_variable_from_outer_scope_not_shadowed.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    let name = \\\"Outer\\\"\\n    let callback = fn() {\\n        Player(team: \\\"BLU\\\")\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Outer\"\n    let callback = fn() {\n        Player(team: \"BLU\")\n        ↑                  \n    }\n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    let name = \"Outer\"\n    let callback = fn() {\n        Player(team: \"BLU\", name:)\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_variable_in_scope_from_case_pattern.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main(result: Result(String, Nil)) {\\n    case result {\\n        Ok(name) -> Player(team: \\\"BLU\\\")\\n        Error(_) -> Player(team: \\\"RED\\\", name: \\\"Unknown\\\")\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main(result: Result(String, Nil)) {\n    case result {\n        Ok(name) -> Player(team: \"BLU\")\n                    ↑                  \n        Error(_) -> Player(team: \"RED\", name: \"Unknown\")\n    }\n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main(result: Result(String, Nil)) {\n    case result {\n        Ok(name) -> Player(team: \"BLU\", name:)\n        Error(_) -> Player(team: \"RED\", name: \"Unknown\")\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_labels_variable_out_of_scope_in_block.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Player {\\n    Player(name: String, team: String)\\n}\\n\\npub fn main() {\\n    {\\n        let name = \\\"Priya\\\"\\n    }\\n    Player(team: \\\"BLU\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    {\n        let name = \"Priya\"\n    }\n    Player(team: \"BLU\")\n    ↑                  \n}\n\n\n----- AFTER ACTION\n\npub type Player {\n    Player(name: String, team: String)\n}\n\npub fn main() {\n    {\n        let name = \"Priya\"\n    }\n    Player(team: \"BLU\", name: todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_unused_fields_with_all_ignored_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\\n\\npub fn main() {\\n  let Wibble(..) = todo\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(..) = todo\n             ↑         \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(int, label1:, label2:) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_unused_fields_with_all_positional_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(Int, String) }\\n\\npub fn main() {\\n  let Wibble(..) = todo\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(Int, String) }\n\npub fn main() {\n  let Wibble(..) = todo\n             ↑         \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(Int, String) }\n\npub fn main() {\n  let Wibble(int, string) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_unused_fields_with_ignored_fields_never_calls_a_positional_arg_as_a_labelled_one.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(Int, int: Int) }\\n\\npub fn main() {\\n  let Wibble(..) = todo\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(Int, int: Int) }\n\npub fn main() {\n  let Wibble(..) = todo\n             ↑         \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(Int, int: Int) }\n\npub fn main() {\n  let Wibble(int_2, int:) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_unused_fields_with_ignored_labelled_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\\n\\npub fn main() {\\n  let Wibble(_, ..) = todo\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(_, ..) = todo\n                ↑         \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(_, label1:, label2:) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_unused_fields_with_ignored_mixed_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(Int, String, label1: String, label2: Int) }\\n\\npub fn main() {\\n  let Wibble(_, label2:, ..) = todo\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(Int, String, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(_, label2:, ..) = todo\n                         ↑         \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(Int, String, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(_, string, label2:, label1:) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fill_unused_fields_with_ignored_positional_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\\n\\npub fn main() {\\n  let Wibble(label1:, label2:, ..) = todo\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(label1:, label2:, ..) = todo\n                               ↑         \n}\n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(Int, label1: String, label2: Int) }\n\npub fn main() {\n  let Wibble(int, label1:, label2:) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_float_operator_on_ints.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 >=. 2\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 >=. 2\n  ↑      \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 >= 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_float_operator_on_ints_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 -. 2\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 -. 2\n  ▔▔▔▔▔↑\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 - 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_float_operator_on_ints_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1 *. wobble()\\n}\\n\\nfn wobble() { 3 }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1 *. wobble()\n    ↑          \n}\n\nfn wobble() { 3 }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1 * wobble()\n}\n\nfn wobble() { 3 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_int_operator_on_floats.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1.0 >= 2.3\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1.0 >= 2.3\n  ↑         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1.0 >=. 2.3\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_int_operator_on_floats_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1.12 - 2.0\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1.12 - 2.0\n  ▔▔▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1.12 -. 2.0\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_int_operator_on_floats_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  1.3 * wobble()\\n}\\n\\nfn wobble() { 3.2 }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  1.3 * wobble()\n      ↑         \n}\n\nfn wobble() { 3.2 }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  1.3 *. wobble()\n}\n\nfn wobble() { 3.2 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_plus_operator_on_strings.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  \\\"hello, \\\" + name()\\n}\\n\\nfn name() { \\\"Jak\\\" }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  \"hello, \" + name()\n   ▔▔▔▔▔▔▔▔▔▔▔↑     \n}\n\nfn name() { \"Jak\" }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  \"hello, \" <> name()\n}\n\nfn name() { \"Jak\" }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_truncated_segment_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  <<1, 257, 259:size(1)>>\\n}\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  <<1, 257, 259:size(1)>>\n       ↑                 \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  <<1, 1, 259:size(1)>>\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__fix_truncated_segment_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  <<1, 1024:size(10)>>\\n}\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  <<1, 1024:size(10)>>\n            ↑         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  <<1, 0:size(10)>>\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Person {\\n  Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Person {\n    ↑            \n  Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray)\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Person {\n  Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray)\n}\n\nfn person_decoder() -> decode.Decoder(Person) {\n  use name <- decode.field(\"name\", decode.string)\n  use age <- decode.field(\"age\", decode.int)\n  use height <- decode.field(\"height\", decode.float)\n  use is_cool <- decode.field(\"is_cool\", decode.bool)\n  use brain <- decode.field(\"brain\", decode.bit_array)\n  decode.success(Person(name:, age:, height:, is_cool:, brain:))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_already_imported_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/dynamic/decode as dyn_dec\\n\\npub type Wibble {\\n  Wibble(a: Int, b: Float, c: String)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/dynamic/decode as dyn_dec\n\npub type Wibble {\n    ↑            \n  Wibble(a: Int, b: Float, c: String)\n}\n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode as dyn_dec\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\nfn wibble_decoder() -> dyn_dec.Decoder(Wibble) {\n  use a <- dyn_dec.field(\"a\", dyn_dec.int)\n  use b <- dyn_dec.field(\"b\", dyn_dec.float)\n  use c <- dyn_dec.field(\"c\", dyn_dec.string)\n  dyn_dec.success(Wibble(a:, b:, c:))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_complex_types.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/option\\nimport gleam/dynamic\\nimport gleam/dict\\n\\npub type Something\\n\\npub type Wibble(value) {\\n  Wibble(\\n    maybe: option.Option(Something),\\n    map: dict.Dict(String, List(value)),\\n    unknown: List(dynamic.Dynamic),\\n  )\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/option\nimport gleam/dynamic\nimport gleam/dict\n\npub type Something\n\npub type Wibble(value) {\n    ↑                   \n  Wibble(\n    maybe: option.Option(Something),\n    map: dict.Dict(String, List(value)),\n    unknown: List(dynamic.Dynamic),\n  )\n}\n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode\nimport gleam/option\nimport gleam/dynamic\nimport gleam/dict\n\npub type Something\n\npub type Wibble(value) {\n  Wibble(\n    maybe: option.Option(Something),\n    map: dict.Dict(String, List(value)),\n    unknown: List(dynamic.Dynamic),\n  )\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble(value)) {\n  use maybe <- decode.field(\"maybe\", decode.optional(todo as \"Decoder for Something\"))\n  use map <- decode.field(\"map\", decode.dict(decode.string, decode.list(todo as \"Decoder for value\")))\n  use unknown <- decode.field(\"unknown\", decode.list(decode.dynamic))\n  decode.success(Wibble(maybe:, map:, unknown:))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_does_not_produce_zero_values_for_types_from_other_packages.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble.{type Wibble}\\n\\npub type Wobble {\\n  Wobble(value: Wibble)\\n  Dummy(a: Int, b: Wibble)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\nimport wibble.{type Wibble}\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(value: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Dummy(a: Int, b: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Wibble)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use value <- decode.field(\"value\", todo as \"Decoder for Wibble\")\n      decode.success(Wobble(value:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", todo as \"Decoder for Wibble\")\n      decode.success(Dummy(a:, b:))\n    }\n    _ -> decode.failure(todo as \"Zero value for Wobble\", \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_for_multi_variant_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, next: Wibble)\\n  Wobble(wobble: Float, text: String, values: List(Bool))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble(wibble: Int, next: Wibble)\n  Wobble(wobble: Float, text: String, values: List(Bool))\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wibble {\n  Wibble(wibble: Int, next: Wibble)\n  Wobble(wobble: Float, text: String, values: List(Bool))\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wibble\" -> {\n      use wibble <- decode.field(\"wibble\", decode.int)\n      use next <- decode.field(\"next\", wibble_decoder())\n      decode.success(Wibble(wibble:, next:))\n    }\n    \"wobble\" -> {\n      use wobble <- decode.field(\"wobble\", decode.float)\n      use text <- decode.field(\"text\", decode.string)\n      use values <- decode.field(\"values\", decode.list(decode.bool))\n      decode.success(Wobble(wobble:, text:, values:))\n    }\n    _ -> decode.failure(Wobble(wobble: 0.0, text: \"\", values: []), \"Wibble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_for_multi_variant_type_multi_word_name.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  OneTwo(wibble: Int, next: Wibble)\\n  ThreeFour(wobble: Float, text: String, values: List(Bool))\\n  FiveSixSeven(one_two: Int)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  OneTwo(wibble: Int, next: Wibble)\n  ThreeFour(wobble: Float, text: String, values: List(Bool))\n  FiveSixSeven(one_two: Int)\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wibble {\n  OneTwo(wibble: Int, next: Wibble)\n  ThreeFour(wobble: Float, text: String, values: List(Bool))\n  FiveSixSeven(one_two: Int)\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"one_two\" -> {\n      use wibble <- decode.field(\"wibble\", decode.int)\n      use next <- decode.field(\"next\", wibble_decoder())\n      decode.success(OneTwo(wibble:, next:))\n    }\n    \"three_four\" -> {\n      use wobble <- decode.field(\"wobble\", decode.float)\n      use text <- decode.field(\"text\", decode.string)\n      use values <- decode.field(\"values\", decode.list(decode.bool))\n      decode.success(ThreeFour(wobble:, text:, values:))\n    }\n    \"five_six_seven\" -> {\n      use one_two <- decode.field(\"one_two\", decode.int)\n      decode.success(FiveSixSeven(one_two:))\n    }\n    _ -> decode.failure(FiveSixSeven(one_two: 0), \"Wibble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_for_variant_with_no_fields.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wibble {\n  Wibble\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble) {\n  use variant <- decode.then(decode.string)\n  case variant {\n    \"wibble\" -> decode.success(Wibble)\n    _ -> decode.failure(Wibble, \"Wibble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_for_variants_with_mixed_fields.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble(field: String, field2: Int)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble\n  Wobble(field: String, field2: Int)\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wibble {\n  Wibble\n  Wobble(field: String, field2: Int)\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wibble\" -> decode.success(Wibble)\n    \"wobble\" -> {\n      use field <- decode.field(\"field\", decode.string)\n      use field2 <- decode.field(\"field2\", decode.int)\n      decode.success(Wobble(field:, field2:))\n    }\n    _ -> decode.failure(Wibble, \"Wibble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_for_variants_with_no_fields.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n  Woo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble\n  Wobble\n  Woo\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wibble {\n  Wibble\n  Wobble\n  Woo\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble) {\n  use variant <- decode.then(decode.string)\n  case variant {\n    \"wibble\" -> decode.success(Wibble)\n    \"wobble\" -> decode.success(Wobble)\n    \"woo\" -> decode.success(Woo)\n    _ -> decode.failure(Wibble, \"Wibble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_generates_todo_for_zero_value_when_all_constructors_fail.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wobble {\\n  Wobble(nope: Wobble)\\n  Wibble(not: Int, again: Wobble)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(nope: Wobble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wibble(not: Int, again: Wobble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wobble {\n  Wobble(nope: Wobble)\n  Wibble(not: Int, again: Wobble)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use nope <- decode.field(\"nope\", wobble_decoder())\n      decode.success(Wobble(nope:))\n    }\n    \"wibble\" -> {\n      use not <- decode.field(\"not\", decode.int)\n      use again <- decode.field(\"again\", wobble_decoder())\n      decode.success(Wibble(not:, again:))\n    }\n    _ -> decode.failure(todo as \"Zero value for Wobble\", \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_produces_zero_values_for_prelude_and_stdlib_types.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/option\\nimport gleam/dict\\n\\npub type Wobble {\\n  Wobble(\\n    bit_array: BitArray,\\n    int: Int,\\n    float: Float,\\n    bool: Bool,\\n    list: List(Int),\\n    string: String,\\n    nil: Nil,\\n    option: option.Option(String),\\n    dict: dict.Dict(Int, Bool),\\n  )\\n  Dummy(\\n    a: Int,\\n    b: Int,\\n    c: Int,\\n    d: Int,\\n    e: Int,\\n    f: Int,\\n    g: Int,\\n    h: Int,\\n    i: Int,\\n    j: Int,\\n  )\\n}\\n    \"\n---\n----- BEFORE ACTION\n\nimport gleam/option\nimport gleam/dict\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(\n▔▔▔▔▔▔▔▔▔\n    bit_array: BitArray,\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    int: Int,\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n    float: Float,\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    bool: Bool,\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    list: List(Int),\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    string: String,\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    nil: Nil,\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n    option: option.Option(String),\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    dict: dict.Dict(Int, Bool),\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  )\n▔▔▔\n  Dummy(\n▔▔▔▔▔▔▔▔\n    a: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    b: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    c: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    d: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    e: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    f: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    g: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    h: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    i: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n    j: Int,\n▔▔▔▔▔▔▔▔▔▔▔\n  )\n▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode\nimport gleam/option\nimport gleam/dict\n\npub type Wobble {\n  Wobble(\n    bit_array: BitArray,\n    int: Int,\n    float: Float,\n    bool: Bool,\n    list: List(Int),\n    string: String,\n    nil: Nil,\n    option: option.Option(String),\n    dict: dict.Dict(Int, Bool),\n  )\n  Dummy(\n    a: Int,\n    b: Int,\n    c: Int,\n    d: Int,\n    e: Int,\n    f: Int,\n    g: Int,\n    h: Int,\n    i: Int,\n    j: Int,\n  )\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use bit_array <- decode.field(\"bit_array\", decode.bit_array)\n      use int <- decode.field(\"int\", decode.int)\n      use float <- decode.field(\"float\", decode.float)\n      use bool <- decode.field(\"bool\", decode.bool)\n      use list <- decode.field(\"list\", decode.list(decode.int))\n      use string <- decode.field(\"string\", decode.string)\n      use nil <- decode.field(\"nil\", decode.success(Nil))\n      use option <- decode.field(\"option\", decode.optional(decode.string))\n      use dict <- decode.field(\"dict\", decode.dict(decode.int, decode.bool))\n      decode.success(Wobble(bit_array:, int:, float:, bool:, list:, string:, nil:, option:, dict:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", decode.int)\n      use c <- decode.field(\"c\", decode.int)\n      use d <- decode.field(\"d\", decode.int)\n      use e <- decode.field(\"e\", decode.int)\n      use f <- decode.field(\"f\", decode.int)\n      use g <- decode.field(\"g\", decode.int)\n      use h <- decode.field(\"h\", decode.int)\n      use i <- decode.field(\"i\", decode.int)\n      use j <- decode.field(\"j\", decode.int)\n      decode.success(Dummy(a:, b:, c:, d:, e:, f:, g:, h:, i:, j:))\n    }\n    _ -> decode.failure(Wobble(bit_array: <<>>, int: 0, float: 0.0, bool: False, list: [], string: \"\", nil: Nil, option: option.None, dict: dict.new()), \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_1.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble.{type Wibble}\\n\\npub type Wobble {\\n  Wobble(value: Wibble)\\n  Dummy(a: Int, b: Int)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\nimport wibble.{type Wibble}\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(value: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Dummy(a: Int, b: Int)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Int)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use value <- decode.field(\"value\", todo as \"Decoder for Wibble\")\n      decode.success(Wobble(value:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", decode.int)\n      decode.success(Dummy(a:, b:))\n    }\n    _ -> decode.failure(Wobble(value: wibble.Wibble), \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_2.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport internal/wibble.{type Wibble}\\n\\npub type Wobble {\\n  Wobble(value: Wibble)\\n  Dummy(a: Int, b: Int)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\nimport internal/wibble.{type Wibble}\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(value: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Dummy(a: Int, b: Int)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\n\nimport internal/nested_wibble\nimport gleam/dynamic/decode\nimport internal/wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Int)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use value <- decode.field(\"value\", todo as \"Decoder for Wibble\")\n      decode.success(Wobble(value:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", decode.int)\n      decode.success(Dummy(a:, b:))\n    }\n    _ -> decode.failure(Wobble(value: wibble.Wibble(value: nested_wibble.NestedWibble)), \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_3.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble.{type Wibble}\\n\\npub type Wobble {\\n  Wobble(value: Wibble)\\n  Dummy(a: Int, b: Int)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\nimport wibble.{type Wibble}\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(value: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Dummy(a: Int, b: Int)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\n\nimport gleam/dict\nimport gleam/dynamic/decode\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(value: Wibble)\n  Dummy(a: Int, b: Int)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use value <- decode.field(\"value\", todo as \"Decoder for Wibble\")\n      decode.success(Wobble(value:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", decode.int)\n      decode.success(Dummy(a:, b:))\n    }\n    _ -> decode.failure(Wobble(value: wibble.Wibble(map: dict.new())), \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_recursive_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/option\\n\\npub type LinkedList {\\n  LinkedList(value: Int, next: option.Option(LinkedList))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/option\n\npub type LinkedList {\n    ↑                \n  LinkedList(value: Int, next: option.Option(LinkedList))\n}\n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode\nimport gleam/option\n\npub type LinkedList {\n  LinkedList(value: Int, next: option.Option(LinkedList))\n}\n\nfn linked_list_decoder() -> decode.Decoder(LinkedList) {\n  use value <- decode.field(\"value\", decode.int)\n  use next <- decode.field(\"next\", decode.optional(linked_list_decoder()))\n  decode.success(LinkedList(value:, next:))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_skips_over_mutually_recursive_constructors_when_generating_zero_values.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wobble {\\n  Wobble(inside: Wibble)\\n  DummyWobble(a: Int, b: Int)\\n}\\n\\npub type Wibble {\\n  Wibble(inside: Wobble)\\n  DummyWibble(a: Int, b: Int)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(inside: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  DummyWobble(a: Int, b: Int)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n\npub type Wibble {\n  Wibble(inside: Wobble)\n  DummyWibble(a: Int, b: Int)\n}\n    \n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wobble {\n  Wobble(inside: Wibble)\n  DummyWobble(a: Int, b: Int)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use inside <- decode.field(\"inside\", todo as \"Decoder for Wibble\")\n      decode.success(Wobble(inside:))\n    }\n    \"dummy_wobble\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", decode.int)\n      decode.success(DummyWobble(a:, b:))\n    }\n    _ -> decode.failure(Wobble(inside: DummyWibble(a: 0, b: 0)), \"Wobble\")\n  }\n}\n\npub type Wibble {\n  Wibble(inside: Wobble)\n  DummyWibble(a: Int, b: Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_skips_over_recursive_constructors_when_generating_zero_values.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Wobble {\\n  Wobble(inside: Wobble)\\n  Dummy(a: Int, b: Int)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(inside: Wobble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Dummy(a: Int, b: Int)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wobble {\n  Wobble(inside: Wobble)\n  Dummy(a: Int, b: Int)\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use inside <- decode.field(\"inside\", wobble_decoder())\n      decode.success(Wobble(inside:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", decode.int)\n      decode.success(Dummy(a:, b:))\n    }\n    _ -> decode.failure(Dummy(a: 0, b: 0), \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(tuple: #(Int, Float, #(String, Bool)))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble(tuple: #(Int, Float, #(String, Bool)))\n}\n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Wibble {\n  Wibble(tuple: #(Int, Float, #(String, Bool)))\n}\n\nfn wibble_decoder() -> decode.Decoder(Wibble) {\n  use tuple <- decode.field(\"tuple\", {\n    use a <- decode.field(0, decode.int)\n    use b <- decode.field(1, decode.float)\n    use c <- decode.field(2, {\n      use a <- decode.field(0, decode.string)\n      use b <- decode.field(1, decode.bool)\n\n      decode.success(#(a, b))\n    })\n\n    decode.success(#(a, b, c))\n  })\n  decode.success(Wibble(tuple:))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_uses_decode_success_for_nil.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub type Nothing {\\n  No(val: Nil)\\n  Nope(val: #(Nil, Nil))\\n  Nothing(val: List(Nil))\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub type Nothing {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  No(val: Nil)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Nope(val: #(Nil, Nil))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Nothing(val: List(Nil))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\nimport gleam/dynamic/decode\n\npub type Nothing {\n  No(val: Nil)\n  Nope(val: #(Nil, Nil))\n  Nothing(val: List(Nil))\n}\n\nfn nothing_decoder() -> decode.Decoder(Nothing) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"no\" -> {\n      use val <- decode.field(\"val\", decode.success(Nil))\n      decode.success(No(val:))\n    }\n    \"nope\" -> {\n      use val <- decode.field(\"val\", {\n        use a <- decode.field(0, decode.success(Nil))\n        use b <- decode.field(1, decode.success(Nil))\n\n        decode.success(#(a, b))\n      })\n      decode.success(Nope(val:))\n    }\n    \"nothing\" -> {\n      use val <- decode.field(\"val\", decode.list(decode.success(Nil)))\n      decode.success(Nothing(val:))\n    }\n    _ -> decode.failure(No(val: Nil), \"Nothing\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_dynamic_decoder_uses_smallest_possible_constructor_for_zero_value.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport wibble.{type Wibble}\\n\\npub type Wobble {\\n  Wobble(impossible: Wobble)\\n  WibbleWobble(nope: Wibble)\\n  Dummy(a: Int, b: #(Float, Float))\\n}\\n    \"\n---\n----- BEFORE ACTION\n\nimport wibble.{type Wibble}\n\npub type Wobble {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(impossible: Wobble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  WibbleWobble(nope: Wibble)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Dummy(a: Int, b: #(Float, Float))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n    \n\n\n----- AFTER ACTION\n\nimport gleam/dynamic/decode\nimport wibble.{type Wibble}\n\npub type Wobble {\n  Wobble(impossible: Wobble)\n  WibbleWobble(nope: Wibble)\n  Dummy(a: Int, b: #(Float, Float))\n}\n\nfn wobble_decoder() -> decode.Decoder(Wobble) {\n  use variant <- decode.field(\"type\", decode.string)\n  case variant {\n    \"wobble\" -> {\n      use impossible <- decode.field(\"impossible\", wobble_decoder())\n      decode.success(Wobble(impossible:))\n    }\n    \"wibble_wobble\" -> {\n      use nope <- decode.field(\"nope\", todo as \"Decoder for Wibble\")\n      decode.success(WibbleWobble(nope:))\n    }\n    \"dummy\" -> {\n      use a <- decode.field(\"a\", decode.int)\n      use b <- decode.field(\"b\", {\n        use a <- decode.field(0, decode.float)\n        use b <- decode.field(1, decode.float)\n\n        decode.success(#(a, b))\n      })\n      decode.success(Dummy(a:, b:))\n    }\n    _ -> decode.failure(Dummy(a: 0, b: #(0.0, 0.0)), \"Wobble\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_arguments_with_labels_and_variables_uses_different_names.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let list = [2, 4, 5]\\n  let value = 1\\n  find(each: value, in: list)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let list = [2, 4, 5]\n  let value = 1\n  find(each: value, in: list)\n  ↑                          \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let list = [2, 4, 5]\n  let value = 1\n  find(each: value, in: list)\n}\n\nfn find(each value: Int, in list: List(Int)) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_arguments_with_same_name_get_renamed.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  wubble(wibble, wibble)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let wibble = 10\n  wubble(wibble, wibble)\n  ↑                     \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let wibble = 10\n  wubble(wibble, wibble)\n}\n\nfn wubble(wibble: Int, wibble_2: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_capture.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nfn map(list: List(a), f: fn(a) -> b) -> List(b) {\\n  todo\\n}\\n\\npub fn main() {\\n  map([1, 2, 3], add(_, 1))\\n}\\n\"\nsnapshot_kind: text\n---\n----- BEFORE ACTION\n\nfn map(list: List(a), f: fn(a) -> b) -> List(b) {\n  todo\n}\n\npub fn main() {\n  map([1, 2, 3], add(_, 1))\n                 ↑         \n}\n\n\n----- AFTER ACTION\n\nfn map(list: List(a), f: fn(a) -> b) -> List(b) {\n  todo\n}\n\npub fn main() {\n  map([1, 2, 3], add(_, 1))\n}\n\nfn add(int: Int, int_2: Int) -> b {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_generates_argument_names_from_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  add(1, addend: 10)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  add(1, addend: 10)\n  ↑                 \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  add(1, addend: 10)\n}\n\nfn add(int: Int, addend addend: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_generates_argument_names_from_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  let wobble = 20\\n\\n  wubble(wibble, wobble, 14)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let wibble = 10\n  let wobble = 20\n\n  wubble(wibble, wobble, 14)\n  ↑                         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let wibble = 10\n  let wobble = 20\n\n  wubble(wibble, wobble, 14)\n}\n\nfn wubble(wibble: Int, wobble: Int, int: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_in_other_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.wibble()\\n  wibble.wobble()\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main() {\n  wibble.wibble()\n  wibble.wobble()\n         ↑       \n}\n\n\n----- AFTER ACTION\n// --- Edits applied to module 'wibble'\npub fn wibble() {}\n\npub fn wobble() -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_in_other_module_correctly_appends.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import module_breaker/another\\n\\npub fn main() -> Nil {\\n  another.function()\\n}\\n\"\n---\n----- BEFORE ACTION\nimport module_breaker/another\n\npub fn main() -> Nil {\n  another.function()\n          ↑         \n}\n\n\n----- AFTER ACTION\n// --- Edits applied to module 'module_breaker/another'\npub fn useless() {\n  Nil\n}\n\n\npub fn function() -> Nil {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_labels_and_arguments_can_share_the_same_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  wubble(wibble, wibble: 14)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let wibble = 10\n  wubble(wibble, wibble: 14)\n  ↑                         \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let wibble = 10\n  wubble(wibble, wibble: 14)\n}\n\nfn wubble(wibble: Int, wibble wibble_2: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_picks_argument_name_based_on_record_access.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type User {\\n    User(id: Int, name: String)\\n}\\n\\npub fn go(user: User) {\\n  authenticate(user.id, user.name)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type User {\n    User(id: Int, name: String)\n}\n\npub fn go(user: User) {\n  authenticate(user.id, user.name)\n  ↑                               \n}\n\n\n----- AFTER ACTION\n\npub type User {\n    User(id: Int, name: String)\n}\n\npub fn go(user: User) {\n  authenticate(user.id, user.name)\n}\n\nfn authenticate(id: Int, name: String) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_picks_argument_name_based_on_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(\\\"Hello\\\", 1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(\"Hello\", 1)\n  ↑                 \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(\"Hello\", 1)\n}\n\nfn wibble(string: String, int: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_takes_labels_into_account.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(2, n: 1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(2, n: 1)\n  ↑              \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(2, n: 1)\n}\n\nfn wibble(int: Int, n n: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_wont_generate_two_arguments_with_the_same_name_if_they_have_the_same_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(2, 1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(2, 1)\n  ↑           \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(2, 1)\n}\n\nfn wibble(int: Int, int_2: Int) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_works_with_constants.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"const wibble: fn(Int) -> String = wobble\"\n---\n----- BEFORE ACTION\nconst wibble: fn(Int) -> String = wobble\n                                  ↑     \n\n\n----- AFTER ACTION\nconst wibble: fn(Int) -> String = wobble\n\nfn wobble(int: Int) -> String {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_works_with_constants_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Wibble(a) {\\n    Wibble(fun: fn(Int) -> a)\\n}\\n\\nconst wibble: Wibble(Int) = Wibble(missing)\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble(a) {\n    Wibble(fun: fn(Int) -> a)\n}\n\nconst wibble: Wibble(Int) = Wibble(missing)\n                                   ↑       \n\n\n----- AFTER ACTION\n\ntype Wibble(a) {\n    Wibble(fun: fn(Int) -> a)\n}\n\nconst wibble: Wibble(Int) = Wibble(missing)\n\nfn missing(int: Int) -> Int {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_works_with_invalid_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() -> Bool {\\n  wibble(1, True, 2.3)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() -> Bool {\n  wibble(1, True, 2.3)\n  ↑                   \n}\n\n\n----- AFTER ACTION\n\npub fn main() -> Bool {\n  wibble(1, True, 2.3)\n}\n\nfn wibble(int: Int, bool: Bool, float: Float) -> Bool {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_works_with_pipeline_steps.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> sum\\n  |> int_to_string\\n}\\n\\nfn int_to_string(n: Int) -> String {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3]\n  |> sum\n     ↑  \n  |> int_to_string\n}\n\nfn int_to_string(n: Int) -> String {\n  todo\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  [1, 2, 3]\n  |> sum\n  |> int_to_string\n}\n\nfn sum(ints: List(Int)) -> Int {\n  todo\n}\n\nfn int_to_string(n: Int) -> String {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_function_works_with_pipeline_steps_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(int_to_string)\\n  |> join\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {\\n  todo\\n}\\n\\nfn join(n: List(String)) -> String {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [1, 2, 3]\n  |> map(int_to_string)\n         ↑             \n  |> join\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {\n  todo\n}\n\nfn join(n: List(String)) -> String {\n  todo\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  [1, 2, 3]\n  |> map(int_to_string)\n  |> join\n}\n\nfn int_to_string(int: Int) -> String {\n  todo\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {\n  todo\n}\n\nfn join(n: List(String)) -> String {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Person {\\n  Person(name: String, age: Int, height: Float, is_cool: Bool)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Person {\n    ↑            \n  Person(name: String, age: Int, height: Float, is_cool: Bool)\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Person {\n  Person(name: String, age: Int, height: Float, is_cool: Bool)\n}\n\nfn person_to_json(person: Person) -> json.Json {\n  let Person(name:, age:, height:, is_cool:) = person\n  json.object([\n    #(\"name\", json.string(name)),\n    #(\"age\", json.int(age)),\n    #(\"height\", json.float(height)),\n    #(\"is_cool\", json.bool(is_cool)),\n  ])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_already_imported_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/json as json_encoding\\n\\npub type Wibble {\\n  Wibble(a: Int, b: Float, c: String)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/json as json_encoding\n\npub type Wibble {\n    ↑            \n  Wibble(a: Int, b: Float, c: String)\n}\n\n\n----- AFTER ACTION\n\nimport gleam/json as json_encoding\n\npub type Wibble {\n  Wibble(a: Int, b: Float, c: String)\n}\n\nfn wibble_to_json(wibble: Wibble) -> json_encoding.Json {\n  let Wibble(a:, b:, c:) = wibble\n  json_encoding.object([\n    #(\"a\", json_encoding.int(a)),\n    #(\"b\", json_encoding.float(b)),\n    #(\"c\", json_encoding.string(c)),\n  ])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_complex_types.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/option\\nimport gleam/dict\\n\\npub type Something\\n\\npub type Wibble(value) {\\n  Wibble(\\n    maybe: option.Option(Int),\\n    something: Something,\\n    map: dict.Dict(String, List(Float)),\\n    unknown: List(value),\\n  )\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/option\nimport gleam/dict\n\npub type Something\n\npub type Wibble(value) {\n    ↑                   \n  Wibble(\n    maybe: option.Option(Int),\n    something: Something,\n    map: dict.Dict(String, List(Float)),\n    unknown: List(value),\n  )\n}\n\n\n----- AFTER ACTION\n\nimport gleam/json\nimport gleam/option\nimport gleam/dict\n\npub type Something\n\npub type Wibble(value) {\n  Wibble(\n    maybe: option.Option(Int),\n    something: Something,\n    map: dict.Dict(String, List(Float)),\n    unknown: List(value),\n  )\n}\n\nfn wibble_to_json(wibble: Wibble(value)) -> json.Json {\n  let Wibble(maybe:, something:, map:, unknown:) = wibble\n  json.object([\n    #(\"maybe\", case maybe {\n      option.None -> json.null()\n      option.Some(value) -> json.int(value)\n    }),\n    #(\"something\", todo as \"Encoder for Something\"),\n    #(\"map\", json.dict(map, fn(string) { string }, json.array(_, json.float))),\n    #(\"unknown\", json.array(unknown, todo as \"Encoder for value\")),\n  ])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_for_multi_variant_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, next: Wibble)\\n  Wobble(wobble: Float, text: String, values: List(Bool))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble(wibble: Int, next: Wibble)\n  Wobble(wobble: Float, text: String, values: List(Bool))\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  Wibble(wibble: Int, next: Wibble)\n  Wobble(wobble: Float, text: String, values: List(Bool))\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  case wibble {\n    Wibble(wibble:, next:) -> json.object([\n      #(\"type\", json.string(\"wibble\")),\n      #(\"wibble\", json.int(wibble)),\n      #(\"next\", wibble_to_json(next)),\n    ])\n    Wobble(wobble:, text:, values:) -> json.object([\n      #(\"type\", json.string(\"wobble\")),\n      #(\"wobble\", json.float(wobble)),\n      #(\"text\", json.string(text)),\n      #(\"values\", json.array(values, json.bool)),\n    ])\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_for_multi_variant_type_multi_word_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  OneTwoThree(wibble: Int, next: Wibble)\\n  FourFive(wobble: Float, text: String, values: List(Bool))\\n  SixSevenEight(one_two: Float)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  OneTwoThree(wibble: Int, next: Wibble)\n  FourFive(wobble: Float, text: String, values: List(Bool))\n  SixSevenEight(one_two: Float)\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  OneTwoThree(wibble: Int, next: Wibble)\n  FourFive(wobble: Float, text: String, values: List(Bool))\n  SixSevenEight(one_two: Float)\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  case wibble {\n    OneTwoThree(wibble:, next:) -> json.object([\n      #(\"type\", json.string(\"one_two_three\")),\n      #(\"wibble\", json.int(wibble)),\n      #(\"next\", wibble_to_json(next)),\n    ])\n    FourFive(wobble:, text:, values:) -> json.object([\n      #(\"type\", json.string(\"four_five\")),\n      #(\"wobble\", json.float(wobble)),\n      #(\"text\", json.string(text)),\n      #(\"values\", json.array(values, json.bool)),\n    ])\n    SixSevenEight(one_two:) -> json.object([\n      #(\"type\", json.string(\"six_seven_eight\")),\n      #(\"one_two\", json.float(one_two)),\n    ])\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_for_type_with_multiple_variants_with_no_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble\\n  Woo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble\n  Wobble\n  Woo\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  Wibble\n  Wobble\n  Woo\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  case wibble {\n    Wibble -> json.string(\"wibble\")\n    Wobble -> json.string(\"wobble\")\n    Woo -> json.string(\"woo\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_for_variant_with_no_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  Wibble\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  json.string(\"wibble\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_for_variants_with_mixed_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n  Wobble(field: String, field1: Int)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble\n  Wobble(field: String, field1: Int)\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  Wibble\n  Wobble(field: String, field1: Int)\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  case wibble {\n    Wibble -> json.object([\n      #(\"type\", json.string(\"wibble\")),\n    ])\n    Wobble(field:, field1:) -> json.object([\n      #(\"type\", json.string(\"wobble\")),\n      #(\"field\", json.string(field)),\n      #(\"field1\", json.int(field1)),\n    ])\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_list_of_tuples.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(values: List(#(Int, String)))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble(values: List(#(Int, String)))\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  Wibble(values: List(#(Int, String)))\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  let Wibble(values:) = wibble\n  json.object([\n    #(\"values\", json.array(values, fn(value) {\n      json.preprocessed_array([\n        json.int(value.0),\n        json.string(value.1),\n      ])\n    })),\n  ])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_recursive_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/option.{Some}\\n\\npub type LinkedList {\\n  LinkedList(value: Int, next: option.Option(LinkedList))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/option.{Some}\n\npub type LinkedList {\n    ↑                \n  LinkedList(value: Int, next: option.Option(LinkedList))\n}\n\n\n----- AFTER ACTION\n\nimport gleam/json\nimport gleam/option.{Some}\n\npub type LinkedList {\n  LinkedList(value: Int, next: option.Option(LinkedList))\n}\n\nfn linked_list_to_json(linked_list: LinkedList) -> json.Json {\n  let LinkedList(value:, next:) = linked_list\n  json.object([\n    #(\"value\", json.int(value)),\n    #(\"next\", case next {\n      option.None -> json.null()\n      Some(value) -> linked_list_to_json(value)\n    }),\n  ])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_json_encoder_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(tuple: #(Int, Float, #(String, Bool)))\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    ↑            \n  Wibble(tuple: #(Int, Float, #(String, Bool)))\n}\n\n\n----- AFTER ACTION\nimport gleam/json\n\npub type Wibble {\n  Wibble(tuple: #(Int, Float, #(String, Bool)))\n}\n\nfn wibble_to_json(wibble: Wibble) -> json.Json {\n  let Wibble(tuple:) = wibble\n  json.object([\n    #(\"tuple\", json.preprocessed_array([\n      json.int(tuple.0),\n      json.float(tuple.1),\n      json.preprocessed_array([\n        json.string(tuple.2.0),\n        json.bool(tuple.2.1),\n      ]),\n    ])),\n  ])\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_qualified_variant_in_other_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport other\\n\\npub fn main() -> other.Wibble {\\n  let assert other.Wobble = new()\\n}\\n\\npub fn new() -> other.Wibble { todo }\\n\"\n---\n----- BEFORE ACTION\n\nimport other\n\npub fn main() -> other.Wibble {\n  let assert other.Wobble = new()\n                   ↑             \n}\n\npub fn new() -> other.Wibble { todo }\n\n\n----- AFTER ACTION\n// --- Edits applied to module 'other'\npub type Wibble {\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_to_json_function_ignores_nil_and_nil_tuple_fields_with_underscore.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/json\\nimport gleam/dict.{type Dict}\\n\\n\\npub type Nothing {\\n  No(val: #(Nil), another: #(Nil, #(Nil, Int)))\\n  Nope(val: List(#(Nil)))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/json\nimport gleam/dict.{type Dict}\n\n\npub type Nothing {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  No(val: #(Nil), another: #(Nil, #(Nil, Int)))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Nope(val: List(#(Nil)))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n\n\n----- AFTER ACTION\n\nimport gleam/json\nimport gleam/dict.{type Dict}\n\n\npub type Nothing {\n  No(val: #(Nil), another: #(Nil, #(Nil, Int)))\n  Nope(val: List(#(Nil)))\n}\n\nfn nothing_to_json(nothing: Nothing) -> json.Json {\n  case nothing {\n    No(val: _, another:) -> json.object([\n      #(\"type\", json.string(\"no\")),\n      #(\"val\", json.preprocessed_array([\n        json.null(),\n      ])),\n      #(\"another\", json.preprocessed_array([\n        json.null(),\n        json.preprocessed_array([\n          json.null(),\n          json.int(another.1.1),\n        ]),\n      ])),\n    ])\n    Nope(val:) -> json.object([\n      #(\"type\", json.string(\"nope\")),\n      #(\"val\", json.array(val, fn(_) {\n        json.preprocessed_array([\n          json.null(),\n        ])\n      })),\n    ])\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_to_json_function_uses_json_null_for_nil.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\nimport gleam/json\\nimport gleam/dict.{type Dict}\\n\\n\\npub type Nothing {\\n  Nope(val: Nil)\\n  Nothing(val1: List(Nil), val2: Dict(Int, Nil))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/json\nimport gleam/dict.{type Dict}\n\n\npub type Nothing {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Nope(val: Nil)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Nothing(val1: List(Nil), val2: Dict(Int, Nil))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n\n\n----- AFTER ACTION\n\nimport gleam/json\nimport gleam/dict.{type Dict}\n\n\npub type Nothing {\n  Nope(val: Nil)\n  Nothing(val1: List(Nil), val2: Dict(Int, Nil))\n}\n\nfn nothing_to_json(nothing: Nothing) -> json.Json {\n  case nothing {\n    Nope(val: _) -> json.object([\n      #(\"type\", json.string(\"nope\")),\n      #(\"val\", json.null()),\n    ])\n    Nothing(val1:, val2:) -> json.object([\n      #(\"type\", json.string(\"nothing\")),\n      #(\"val1\", json.array(val1, fn(_) { json.null() })),\n      #(\"val2\", json.dict(val2, todo as \"Function to stringify Int\", fn(_) { json.null() })),\n    ])\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_unqualified_variant_in_other_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport other\\n\\npub fn main() -> other.Wibble {\\n  let assert Wobble = new()\\n}\\n\\npub fn new() -> other.Wibble { todo }\\n\"\n---\n----- BEFORE ACTION\n\nimport other\n\npub fn main() -> other.Wibble {\n  let assert Wobble = new()\n             ↑             \n}\n\npub fn new() -> other.Wibble { todo }\n\n\n----- AFTER ACTION\n// --- Edits applied to module 'other'\npub type Wibble {\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_variant_from_pattern_with_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn new() { Wibble }\\n\\npub fn main() -> Wibble {\\n  let assert Wobble(1) = new()\\n}\\n\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble(1) = new()\n             ↑                \n}\n\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble\n  Wobble(Int)\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble(1) = new()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_variant_from_pattern_with_labelled_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn new() { Wibble }\\n\\npub fn main() -> Wibble {\\n  let assert Wobble(\\\"hello\\\", label: 1) = new()\\n}\\n\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble(\"hello\", label: 1) = new()\n             ↑                                \n}\n\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble\n  Wobble(String, label: Int)\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble(\"hello\", label: 1) = new()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_variant_from_pattern_with_no_fields.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn new() { Wibble }\\n\\npub fn main() -> Wibble {\\n  let assert Wobble = new()\\n}\\n\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble = new()\n             ↑             \n}\n\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn new() { Wibble }\n\npub fn main() -> Wibble {\n  let assert Wobble = new()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_variant_with_fields_in_same_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn main() -> Wibble {\\n  Wobble(1)\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble\n}\n\npub fn main() -> Wibble {\n  Wobble(1)\n  ↑        \n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble\n  Wobble(Int)\n}\n\npub fn main() -> Wibble {\n  Wobble(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_variant_with_labels_in_same_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn main() -> Wibble {\\n  Wobble(\\\"hello\\\", label: 1)\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble\n}\n\npub fn main() -> Wibble {\n  Wobble(\"hello\", label: 1)\n  ↑                        \n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble\n  Wobble(String, label: Int)\n}\n\npub fn main() -> Wibble {\n  Wobble(\"hello\", label: 1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generate_variant_with_no_fields_in_same_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn main() -> Wibble {\\n  Wobble\\n}\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble\n}\n\npub fn main() -> Wibble {\n  Wobble\n  ↑     \n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() -> Wibble {\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generated_function_annotations_are_not_affected_by_other_functions.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn wibble(a: a, b: b, c: c) -> d { todo }\\n\\npub fn main() {\\n  let x = todo\\n  let y = todo\\n  let #(a, b) = something(x, y)\\n  b\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\npub fn main() {\n  let x = todo\n  let y = todo\n  let #(a, b) = something(x, y)\n                ↑              \n  b\n}\n\n\n----- AFTER ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\npub fn main() {\n  let x = todo\n  let y = todo\n  let #(a, b) = something(x, y)\n  b\n}\n\nfn something(x: a, y: b) -> #(c, d) {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generating_function_in_other_module_uses_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.wibble(\\\"Unlabelled\\\", int: 1, bool: True)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main() {\n  wibble.wibble(\"Unlabelled\", int: 1, bool: True)\n         ↑                                       \n}\n\n\n----- AFTER ACTION\n// --- Edits applied to module 'wibble'\n\n\npub fn wibble(string: String, int int: Int, bool bool: Bool) -> a {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__generating_function_in_other_module_uses_local_names.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() -> List(Nil) {\\n  wibble.wibble(1, #(True, \\\"Hello\\\"))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main() -> List(Nil) {\n  wibble.wibble(1, #(True, \"Hello\"))\n         ↑                          \n}\n\n\n----- AFTER ACTION\n// --- Edits applied to module 'wibble'\nimport gleam.{type Int as Number, type Bool as Boolean, type String as Text, type Nil as Nothing}\n\npub fn wibble(int: Number, value: #(Boolean, Text)) -> List(Nothing) {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_internal_module_from_same_package.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  internal.some_internal_function()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  internal.some_internal_function()\n  ↑                                \n}\n\n\n----- AFTER ACTION\nimport app/internal\n\npub fn main() {\n  internal.some_internal_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_module_from_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let value = values.Value(10)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let value = values.Value(10)\n              ▔▔▔▔▔▔↑         \n}\n\n\n----- AFTER ACTION\nimport values\n\npub fn main() {\n  let value = values.Value(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_module_from_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  result.is_ok()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  result.is_ok()\n  ▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\nimport result\n\npub fn main() {\n  result.is_ok()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_module_from_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(res) {\\n  case res {\\n    result.Ok(_) -> Nil\\n    result.Error(_) -> Nil\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(res) {\n  case res {\n    result.Ok(_) -> Nil\n    ▔▔▔▔▔▔↑            \n    result.Error(_) -> Nil\n  }\n}\n\n\n----- AFTER ACTION\nimport result\n\npub fn main(res) {\n  case res {\n    result.Ok(_) -> Nil\n    result.Error(_) -> Nil\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_module_from_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: type Wobble = wibble.Wubble\n---\n----- BEFORE ACTION\ntype Wobble = wibble.Wubble\n              ▔▔▔▔▔▔↑      \n\n\n----- AFTER ACTION\nimport mod/wibble\n\ntype Wobble = wibble.Wubble\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_path_module_from_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  io.println(\\\"Hello, world!\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  io.println(\"Hello, world!\")\n  ▔▔↑                        \n}\n\n\n----- AFTER ACTION\nimport gleam/io\n\npub fn main() {\n  io.println(\"Hello, world!\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__import_similar_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  reult.is_ok()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  reult.is_ok()\n  ▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\nimport result\n\npub fn main() {\n  result.is_ok()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_alias_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let 10 as ten = 10\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let 10 as ten = 10\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let ten = case 10 {\n    10 as ten -> ten\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_bit_array_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let <<bits1, bits2>> = <<73, 98>>\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let <<bits1, bits2>> = <<73, 98>>\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑           \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let #(bits1, bits2) = case <<73, 98>> {\n    <<bits1, bits2>> -> #(bits1, bits2)\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_result_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(result) {\\n  let Ok(value) = result\\n}\"\n---\n----- BEFORE ACTION\npub fn main(result) {\n  let Ok(value) = result\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\npub fn main(result) {\n  let value = case result {\n    Ok(value) -> value\n    Error(_) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_string_prefix_pattern_alias_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let \\\"123\\\" as one_two_three <> rest = \\\"123456\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let \"123\" as one_two_three <> rest = \"123456\"\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑         \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let #(one_two_three, rest) = case \"123456\" {\n    \"123\" as one_two_three <> rest -> #(one_two_three, rest)\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_string_prefix_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let \\\"_\\\" <> thing = \\\"_Hello\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let \"_\" <> thing = \"_Hello\"\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑         \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let thing = case \"_Hello\" {\n    \"_\" <> thing -> thing\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_to_case_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let [_elem] = [6]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let [_elem] = [6]\n  ▔▔▔▔▔▔▔▔▔▔▔▔↑    \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let _ = case [6] {\n    [_elem] -> Nil\n    [] -> todo\n    [_, _, ..] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_to_case_indented.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(result) {\\n  {\\n    let Ok(value) = result\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(result) {\n  {\n    let Ok(value) = result\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n  }\n}\n\n\n----- AFTER ACTION\npub fn main(result) {\n  {\n    let value = case result {\n      Ok(value) -> value\n      Error(_) -> todo\n    }\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_to_case_multi_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let [var1, var2, _var3, var4] = [1, 2, 3, 4]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let [var1, var2, _var3, var4] = [1, 2, 3, 4]\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑             \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let #(var1, var2, var4) = case [1, 2, 3, 4] {\n    [var1, var2, _var3, var4] -> #(var1, var2, var4)\n    [] -> todo\n    [_] -> todo\n    [_, _] -> todo\n    [_, _, _] -> todo\n    [_, _, _, _, _, ..] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_to_case_no_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let [] = []\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let [] = []\n  ▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let _ = case [] {\n    [] -> Nil\n    [_, ..] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inexhaustive_let_tuple_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let #(first, 10, third) = #(5, 10, 15)\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let #(first, 10, third) = #(5, 10, 15)\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑             \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let #(first, third) = case #(5, 10, 15) {\n    #(first, 10, third) -> #(first, third)\n    #(_, _, _) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/io\\n\\npub fn main() {\\n  let message = \\\"Hello!\\\"\\n  io.println(message)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/io\n\npub fn main() {\n  let message = \"Hello!\"\n  io.println(message)\n             ↑       \n}\n\n\n----- AFTER ACTION\n\nimport gleam/io\n\npub fn main() {\n  io.println(\"Hello!\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/io\\n\\npub fn main() {\\n  let message = \\\"Hello!\\\"\\n  io.println(message)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/io\n\npub fn main() {\n  let message = \"Hello!\"\n      ↑                 \n  io.println(message)\n}\n\n\n----- AFTER ACTION\n\nimport gleam/io\n\npub fn main() {\n  io.println(\"Hello!\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_in_case_scope.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/io\\n\\npub fn main(x) {\\n  case x {\\n    True -> {\\n      let message = \\\"Hello!\\\"\\n      io.println(message)\\n    }\\n    False -> Nil\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/io\n\npub fn main(x) {\n  case x {\n    True -> {\n      let message = \"Hello!\"\n          ↑                 \n      io.println(message)\n    }\n    False -> Nil\n  }\n}\n\n\n----- AFTER ACTION\n\nimport gleam/io\n\npub fn main(x) {\n  case x {\n    True -> {\n      io.println(\"Hello!\")\n    }\n    False -> Nil\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_in_nested_scope.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/io\\n\\npub fn main() {\\n  let _ = {\\n    let message = \\\"Hello!\\\"\\n    io.println(message)\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/io\n\npub fn main() {\n  let _ = {\n    let message = \"Hello!\"\n        ↑                 \n    io.println(message)\n  }\n}\n\n\n----- AFTER ACTION\n\nimport gleam/io\n\npub fn main() {\n  let _ = {\n    io.println(\"Hello!\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_in_record_update.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Couple {\\n  Couple(l: Int, r: Int)\\n}\\n\\npub fn main() {\\n  let c1 = Couple(l: 1, r: 1)\\n  let c2 = Couple(..c1, r: 1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c1 = Couple(l: 1, r: 1)\n  let c2 = Couple(..c1, r: 1)\n                    ↑        \n}\n\n\n----- AFTER ACTION\n\ntype Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c2 = Couple(..Couple(l: 1, r: 1), r: 1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Example {\\n  Example(sum: Int, nil: Nil)\\n}\\n\\npub fn main() {\\n  let sum = 1 + 1\\n\\n  Example(Nil, sum:)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Example {\n  Example(sum: Int, nil: Nil)\n}\n\npub fn main() {\n  let sum = 1 + 1\n      ↑          \n\n  Example(Nil, sum:)\n}\n\n\n----- AFTER ACTION\n\npub type Example {\n  Example(sum: Int, nil: Nil)\n}\n\npub fn main() {\n  Example(Nil, sum: 1 + 1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_when_over_let_keyword.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let x = 123\\n  x + 1\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let x = 123\n  ↑          \n  x + 1\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  123 + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inline_variable_with_record_field.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Couple {\\n  Couple(l: Int, r: Int)\\n}\\n\\npub fn main() {\\n  let c1 = Couple(l: 1, r: 1)\\n  let c2 = c1.l\\n  echo c2\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c1 = Couple(l: 1, r: 1)\n  let c2 = c1.l\n  echo c2\n       ↑ \n}\n\n\n----- AFTER ACTION\n\ntype Couple {\n  Couple(l: Int, r: Int)\n}\n\npub fn main() {\n  let c1 = Couple(l: 1, r: 1)\n  echo c1.l\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__inner_inexhaustive_let_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(result) {\\n  let [wibble] = {\\n    let Ok(wobble) = {\\n      result\\n    }\\n    [wobble]\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(result) {\n  let [wibble] = {\n    let Ok(wobble) = {\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔↑    \n      result\n    }\n    [wobble]\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(result) {\n  let [wibble] = {\n    let wobble = case {\n      result\n    } {\n      Ok(wobble) -> wobble\n      Error(_) -> todo\n    }\n    [wobble]\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__interpolate_string_allows_extracting_record_access_syntax.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble wobble.some_field woo\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble wobble.some_field woo\"\n          ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑    \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  \"wibble \" <> wobble.some_field <> \" woo\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__interpolate_string_does_not_add_empty_string_right_at_the_end.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble wobble woo\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble wobble woo\"\n                 ▔▔▔↑\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  \"wibble wobble \" <> woo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__interpolate_string_does_not_add_empty_string_right_at_the_start.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble wobble woo\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble wobble woo\"\n   ▔▔▔▔▔▔↑           \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  wibble <> \" wobble woo\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__interpolate_string_inside_string.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble wobble woo\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble wobble woo\"\n          ▔▔▔▔▔▔↑    \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  \"wibble \" <> wobble <> \" woo\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__interpolating_string_as_first_pipeline_step_inserts_brackets.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble wobble woo\\\" |> io.println\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble wobble woo\" |> io.println\n          ▔▔▔▔▔▔↑                  \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  { \"wibble \" <> wobble <> \" woo\" } |> io.println\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__label_shorthand_action_only_applies_to_selected_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let arg1 = 1\\n    let arg2 = 2\\n    Wibble(arg2: arg2, arg1: arg1)\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    Wibble(arg2: arg2, arg1: arg1)\n    ▔▔▔▔▔▔▔▔▔▔▔↑                  \n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    Wibble(arg2: , arg1: arg1)\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__label_shorthand_action_works_on_labelled_call_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let arg1 = 1\\n    let arg2 = 2\\n    wibble(arg2: arg2, arg1: arg1)\\n}\\n\\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    wibble(arg2: arg2, arg1: arg1)\n     ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑          \n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    wibble(arg2: , arg1: )\n}\n\npub fn wibble(arg1 arg1, arg2 arg2) { Nil }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__label_shorthand_action_works_on_labelled_constructor_call_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let arg1 = 1\\n    let arg2 = 2\\n    Wibble(arg2: arg2, arg1: arg1)\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    Wibble(arg2: arg2, arg1: arg1)\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑      \n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let arg1 = 1\n    let arg2 = 2\n    Wibble(arg2: , arg1: )\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__label_shorthand_action_works_on_labelled_pattern_call_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let Wibble(arg1: arg1, arg2: arg2) = todo\\n    arg1 + arg2\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let Wibble(arg1: arg1, arg2: arg2) = todo\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑\n    arg1 + arg2\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let Wibble(arg1: , arg2: ) = todo\n    arg1 + arg2\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__label_shorthand_action_works_on_labelled_update_call_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n    let arg1 = 1\\n    Wibble(..todo, arg1: arg1)\\n}\\n\\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n    let arg1 = 1\n    Wibble(..todo, arg1: arg1)\n           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n\n\n----- AFTER ACTION\n\npub fn main() {\n    let arg1 = 1\n    Wibble(..todo, arg1: )\n}\n\npub type Wibble { Wibble(arg1: Int, arg2: Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> todo\\n    2 -> todo\\n    _ -> todo\\n  }\\n  }\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> todo\n    ▔▔▔▔▔▔▔▔▔\n    2 -> todo\n▔▔▔▔↑        \n    _ -> todo\n  }\n  }\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 -> todo\n    _ -> todo\n  }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_can_merge_branches_defining_the_same_variables.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(result) {\\n  case result {\\n    [Ok(value), ..] -> todo\\n    [_, Error(value)] -> todo\\n    _ -> todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn go(result) {\n  case result {\n    [Ok(value), ..] -> todo\n     ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    [_, Error(value)] -> todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n    _ -> todo\n  }\n}\n\n\n----- AFTER ACTION\npub fn go(result) {\n  case result {\n    [Ok(value), ..] | [_, Error(value)] -> todo\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_can_merge_multiple_branches.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(result) {\\n  case result {\\n    [_] -> 1\\n    [Ok(value), ..] -> todo\\n    [_, Error(value)] -> todo\\n    [_, _, Error(value)] -> todo\\n    [_, _] -> 1\\n    _ -> 2\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn go(result) {\n  case result {\n    [_] -> 1\n    [Ok(value), ..] -> todo\n                       ▔▔▔▔\n    [_, Error(value)] -> todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    [_, _, Error(value)] -> todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n    [_, _] -> 1\n    _ -> 2\n  }\n}\n\n\n----- AFTER ACTION\npub fn go(result) {\n  case result {\n    [_] -> 1\n    [Ok(value), ..] | [_, Error(value)] | [_, _, Error(value)] -> todo\n    [_, _] -> 1\n    _ -> 2\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_complex_bodies_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> Ok(\\\"one or two\\\")\\n    2 -> Ok(\\\"one or two\\\")\\n    _ -> Error(\\\"neither one or two\\\")\\n  }\\n  }\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> Ok(\"one or two\")\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    2 -> Ok(\"one or two\")\n▔▔▔▔↑                    \n    _ -> Error(\"neither one or two\")\n  }\n  }\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 -> Ok(\"one or two\")\n    _ -> Error(\"neither one or two\")\n  }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_complex_bodies_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> n\\n    2 -> n\\n    _ -> panic as \\\"neither one nor two\\\"\\n  }\\n  }\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> n\n    ▔▔▔▔▔▔\n    2 -> n\n▔▔▔▔↑     \n    _ -> panic as \"neither one nor two\"\n  }\n  }\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 -> n\n    _ -> panic as \"neither one nor two\"\n  }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_complex_bodies_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> go(n - 1)\\n    2 -> go(n - 1)\\n    _ -> 10\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> go(n - 1)\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    2 -> go(n - 1)\n▔▔▔▔↑             \n    _ -> 10\n  }\n}\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 -> go(n - 1)\n    _ -> 10\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_complex_bodies_4.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> {\\n      let a = go(n - 1)\\n      a * 10\\n    }\\n    2 -> {\\n      let a = go(n - 1)\\n      a * 10\\n    }\\n    _ -> 10\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> {\n    ▔▔▔▔▔▔\n      let a = go(n - 1)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n      a * 10\n▔▔▔▔▔▔▔▔▔▔▔▔\n    }\n▔▔▔▔▔\n    2 -> {\n▔▔▔▔↑     \n      let a = go(n - 1)\n      a * 10\n    }\n    _ -> 10\n  }\n}\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 -> {\n      let a = go(n - 1)\n      a * 10\n    }\n    _ -> 10\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_todo_keeps_the_non_todo_body.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> todo\\n    2 -> n * 2\\n    3 -> todo\\n    _ -> todo\\n  }\\n  }\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> todo\n    ▔▔▔▔▔▔▔▔▔\n    2 -> n * 2\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    3 -> todo\n▔▔▔▔↑        \n    _ -> todo\n  }\n  }\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 | 3 -> n * 2\n    _ -> todo\n  }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_todo_keeps_the_non_todo_body_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> todo\\n    2 -> todo\\n    3 -> n * 2\\n    _ -> todo\\n  }\\n  }\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> todo\n    ▔▔▔▔▔▔▔▔▔\n    2 -> todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n    3 -> n * 2\n▔▔▔▔↑         \n    _ -> todo\n  }\n  }\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 | 3 -> n * 2\n    _ -> todo\n  }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_with_todo_keeps_the_non_todo_body_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(n: Int) {\\n  case n {\\n    1 -> n * 2\\n    2 -> todo\\n    3 -> todo\\n    _ -> todo\\n  }\\n  }\"\n---\n----- BEFORE ACTION\npub fn go(n: Int) {\n  case n {\n    1 -> n * 2\n    ▔▔▔▔▔▔▔▔▔▔\n    2 -> todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n    3 -> todo\n▔▔▔▔↑        \n    _ -> todo\n  }\n  }\n\n\n----- AFTER ACTION\npub fn go(n: Int) {\n  case n {\n    1 | 2 | 3 -> n * 2\n    _ -> todo\n  }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__merge_case_branch_works_with_existing_alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn go(result) {\\n  case result {\\n    [] | [_, _, ..]-> todo\\n    [_] -> todo\\n    _ -> 2\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn go(result) {\n  case result {\n    [] | [_, _, ..]-> todo\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    [_] -> todo\n▔▔▔▔↑          \n    _ -> 2\n  }\n}\n\n\n----- AFTER ACTION\npub fn go(result) {\n  case result {\n    [] | [_, _, ..] | [_] -> todo\n    _ -> 2\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__outer_inexhaustive_let_to_case.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(result) {\\n  let [wibble] = {\\n    let Ok(wobble) = {\\n      result\\n    }\\n    [wobble]\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(result) {\n  let [wibble] = {\n  ▔▔▔▔▔▔▔▔▔▔▔↑    \n    let Ok(wobble) = {\n      result\n    }\n    [wobble]\n  }\n}\n\n\n----- AFTER ACTION\npub fn main(result) {\n  let wibble = case {\n    let Ok(wobble) = {\n      result\n    }\n    [wobble]\n  } {\n    [wibble] -> wibble\n    [] -> todo\n    [_, _, ..] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_adds_patterns_for_internal_type_inside_module_where_it_is_defined.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\n@internal\\npub type Wibble {\\n  Wibble(Int)\\n  Wobble(String)\\n}\\n\\npub fn main(thing: Wibble) {}\\n\"\n---\n----- BEFORE ACTION\n\n@internal\npub type Wibble {\n  Wibble(Int)\n  Wobble(String)\n}\n\npub fn main(thing: Wibble) {}\n            ↑                \n\n\n----- AFTER ACTION\n\n@internal\npub type Wibble {\n  Wibble(Int)\n  Wobble(String)\n}\n\npub fn main(thing: Wibble) {\n  case thing {\n    Wibble(int) -> todo\n    Wobble(string) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_available_for_internal_type_defined_in_current_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n@internal\\npub type Wibble {\\n  Wobble(label: Int)\\n}\\n\\npub fn main(arg: Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\n@internal\npub type Wibble {\n  Wobble(label: Int)\n}\n\npub fn main(arg: Wibble) {\n            ▔▔▔▔▔↑        \n  todo\n}\n\n\n----- AFTER ACTION\n\n@internal\npub type Wibble {\n  Wobble(label: Int)\n}\n\npub fn main(arg: Wibble) {\n  let Wobble(label:) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_generates_unique_names_even_with_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(String, string: String)\\n}\\n\\npub fn main(wibble: Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(String, string: String)\n}\n\npub fn main(wibble: Wibble) {\n            ↑                \n  todo\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(String, string: String)\n}\n\npub fn main(wibble: Wibble) {\n  let Wibble(string_2, string:) = wibble\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_multi_item_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(tuple: #(Int, String, Bool)) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(tuple: #(Int, String, Bool)) {\n            ▔▔▔▔▔▔▔▔▔↑                    \n  todo\n}\n\n\n----- AFTER ACTION\n\npub fn main(tuple: #(Int, String, Bool)) {\n  let #(int, string, bool) = tuple\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_nicely_formats_code_when_used_on_function_with_empty_body.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(arg: #(Int, String)) {}\"\n---\n----- BEFORE ACTION\npub fn main(arg: #(Int, String)) {}\n            ↑                      \n\n\n----- AFTER ACTION\npub fn main(arg: #(Int, String)) {\n  let #(int, string) = arg\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_preserves_indentation_of_statement_following_inserted_let.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(arg: #(Int, String)) {\\n  todo\\n//^^^^ This should still have two spaces of indentation!\\n}\"\n---\n----- BEFORE ACTION\npub fn main(arg: #(Int, String)) {\n            ↑                     \n  todo\n//^^^^ This should still have two spaces of indentation!\n}\n\n\n----- AFTER ACTION\npub fn main(arg: #(Int, String)) {\n  let #(int, string) = arg\n  todo\n//^^^^ This should still have two spaces of indentation!\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_single_item_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main(tuple: #(Int)) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main(tuple: #(Int)) {\n                 ↑          \n  todo\n}\n\n\n----- AFTER ACTION\n\npub fn main(tuple: #(Int)) {\n  let #(int) = tuple\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_single_unlabelled_field_is_not_numbered.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int)\\n}\\n\\npub fn main(arg: Wibble) {}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn main(arg: Wibble) {}\n               ↑           \n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn main(arg: Wibble) {\n  let Wibble(int) = arg\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_uses_case_with_multiple_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type CannotBeDestructured {\\n  One(one: String)\\n  Two(two: Int)\\n}\\n\\npub fn main(arg: CannotBeDestructured) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type CannotBeDestructured {\n  One(one: String)\n  Two(two: Int)\n}\n\npub fn main(arg: CannotBeDestructured) {\n            ↑                           \n  todo\n}\n\n\n----- AFTER ACTION\n\npub type CannotBeDestructured {\n  One(one: String)\n  Two(two: Int)\n}\n\npub fn main(arg: CannotBeDestructured) {\n  case arg {\n    One(one:) -> todo\n    Two(two:) -> todo\n  }\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_uses_label_shorthand_syntax_for_labelled_arguments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wobble(Int, String, i_want_to_see_this: String, and_this: Bool)\\n}\\n\\npub fn main(arg: Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wobble(Int, String, i_want_to_see_this: String, and_this: Bool)\n}\n\npub fn main(arg: Wibble) {\n            ▔▔▔▔▔↑        \n  todo\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wobble(Int, String, i_want_to_see_this: String, and_this: Bool)\n}\n\npub fn main(arg: Wibble) {\n  let Wobble(int, string, i_want_to_see_this:, and_this:) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_will_use_aliased_constructor_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble.{Wobble as IWantToSeeThisName}\\n\\npub fn main(arg: wibble.Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble.{Wobble as IWantToSeeThisName}\n\npub fn main(arg: wibble.Wibble) {\n            ↑                    \n  todo\n}\n\n\n----- AFTER ACTION\n\nimport wibble.{Wobble as IWantToSeeThisName}\n\npub fn main(arg: wibble.Wibble) {\n  let IWantToSeeThisName(label:) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_will_use_aliased_module_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble as i_want_to_see_this_name\\n\\npub fn main(arg: i_want_to_see_this_name.Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble as i_want_to_see_this_name\n\npub fn main(arg: i_want_to_see_this_name.Wibble) {\n            ↑                                     \n  todo\n}\n\n\n----- AFTER ACTION\n\nimport wibble as i_want_to_see_this_name\n\npub fn main(arg: i_want_to_see_this_name.Wibble) {\n  let i_want_to_see_this_name.Wobble(label:) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_will_use_qualified_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble\\n\\npub fn main(arg: wibble.Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble\n\npub fn main(arg: wibble.Wibble) {\n                 ↑               \n  todo\n}\n\n\n----- AFTER ACTION\n\nimport wibble\n\npub fn main(arg: wibble.Wibble) {\n  let wibble.ThisShouldBeQualified(label:) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_will_use_unqualified_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble.{ThisShouldBeUnqualified}\\n\\npub fn main(arg: wibble.Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble.{ThisShouldBeUnqualified}\n\npub fn main(arg: wibble.Wibble) {\n                        ↑        \n  todo\n}\n\n\n----- AFTER ACTION\n\nimport wibble.{ThisShouldBeUnqualified}\n\npub fn main(arg: wibble.Wibble) {\n  let ThisShouldBeUnqualified(label:) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_with_multiple_constructors_is_nicely_formatted_in_function_with_empty_body.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type CannotBeDestructured {\\n  One(one: String)\\n  Two(two: Int)\\n}\\n\\npub fn main(arg: CannotBeDestructured) {}\\n\"\n---\n----- BEFORE ACTION\n\npub type CannotBeDestructured {\n  One(one: String)\n  Two(two: Int)\n}\n\npub fn main(arg: CannotBeDestructured) {}\n            ↑                            \n\n\n----- AFTER ACTION\n\npub type CannotBeDestructured {\n  One(one: String)\n  Two(two: Int)\n}\n\npub fn main(arg: CannotBeDestructured) {\n  case arg {\n    One(one:) -> todo\n    Two(two:) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_with_private_type_from_same_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Wibble {\\n  Wobble(Int, String)\\n}\\n\\npub fn main(arg: Wibble) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble {\n  Wobble(Int, String)\n}\n\npub fn main(arg: Wibble) {\n            ▔▔▔▔▔↑        \n  todo\n}\n\n\n----- AFTER ACTION\n\ntype Wibble {\n  Wobble(Int, String)\n}\n\npub fn main(arg: Wibble) {\n  let Wobble(int, string) = arg\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_works_on_fn_arguments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  [#(1, 2)]\\n  |> map(fn(tuple) {})\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  [#(1, 2)]\n  |> map(fn(tuple) {})\n            ↑         \n}\n\nfn map(list: List(a), fun: fn(a) -> b) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  [#(1, 2)]\n  |> map(fn(tuple) {\n  let #(int, int_2) = tuple\n})\n}\n\nfn map(list: List(a), fun: fn(a) -> b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_argument_works_on_nested_fn_arguments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  map([[#(1, 2)]], fn(list) {\\n    map(list, fn(tuple) {\\n      todo\\n    })\\n  })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) { todo }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  map([[#(1, 2)]], fn(list) {\n    map(list, fn(tuple) {\n                 ↑       \n      todo\n    })\n  })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) { todo }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  map([[#(1, 2)]], fn(list) {\n    map(list, fn(tuple) {\n      let #(int, int_2) = tuple\n      todo\n    })\n  })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_clause_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case maybe_wibble() {\\n    Ok(something) -> 1\\n    Error(_) -> 2\\n  }\\n}\\n\\ntype Wibble {\\n  Wobble\\n  Woo\\n}\\n\\nfn maybe_wibble() { Ok(Wobble) }\\n\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case maybe_wibble() {\n    Ok(something) -> 1\n       ↑              \n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble\n  Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case maybe_wibble() {\n    Ok(Wobble) -> 1\n    Ok(Woo) -> 1\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble\n  Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_clause_variable_nested_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case maybe_wibble() {\\n    Ok(Wobble(something)) -> 1\\n    Error(_) -> 2\\n  }\\n}\\n\\ntype Wibble {\\n  Wobble(Wibble)\\n  Woo\\n}\\n\\nfn maybe_wibble() { Ok(Woo) }\\n\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case maybe_wibble() {\n    Ok(Wobble(something)) -> 1\n              ↑               \n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(Wibble)\n  Woo\n}\n\nfn maybe_wibble() { Ok(Woo) }\n\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case maybe_wibble() {\n    Ok(Wobble(Wobble(wibble))) -> 1\n    Ok(Wobble(Woo)) -> 1\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(Wibble)\n  Woo\n}\n\nfn maybe_wibble() { Ok(Woo) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_clause_variable_with_block_body.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case maybe_wibble() {\\n    Ok(something) -> {\\n      1\\n      2\\n    }\\n    Error(_) -> 2\\n  }\\n}\\n\\ntype Wibble {\\n  Wobble\\n  Woo\\n}\\n\\nfn maybe_wibble() { Ok(Wobble) }\\n\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case maybe_wibble() {\n    Ok(something) -> {\n       ↑              \n      1\n      2\n    }\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble\n  Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case maybe_wibble() {\n    Ok(Wobble) -> {\n      1\n      2\n    }\n    Ok(Woo) -> {\n      1\n      2\n    }\n    Error(_) -> 2\n  }\n}\n\ntype Wibble {\n  Wobble\n  Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_clause_variable_with_label.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case wibble() {\\n    Wobble(wibble: something) -> 1\\n    _ -> 2\\n  }\\n}\\n\\ntype Wibble {\\n  Wobble(wibble: Wibble)\\n  Woo\\n}\\n\\nfn new() { Wobble }\\n\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case wibble() {\n    Wobble(wibble: something) -> 1\n                   ↑              \n    _ -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(wibble: Wibble)\n  Woo\n}\n\nfn new() { Wobble }\n\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case wibble() {\n    Wobble(wibble: Wobble(wibble:)) -> 1\n    Wobble(wibble: Woo) -> 1\n    _ -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(wibble: Wibble)\n  Woo\n}\n\nfn new() { Wobble }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_clause_variable_with_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case new() {\\n    Wobble(wibble:) -> 1\\n    _ -> 2\\n  }\\n}\\n\\ntype Wibble {\\n  Wobble(wibble: Wibble)\\n  Woo\\n}\\n\\nfn new() { Wobble }\\n\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case new() {\n    Wobble(wibble:) -> 1\n           ↑            \n    _ -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(wibble: Wibble)\n  Woo\n}\n\nfn new() { Wobble }\n\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case new() {\n    Wobble(wibble: Wobble(wibble:)) -> 1\n    Wobble(wibble: Woo) -> 1\n    _ -> 2\n  }\n}\n\ntype Wibble {\n  Wobble(wibble: Wibble)\n  Woo\n}\n\nfn new() { Wobble }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_let_assignment.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let var = #(1, 2)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let var = #(1, 2)\n      ↑            \n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let var = #(1, 2)\n  let #(int, int_2) = var\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_let_assignment_with_multiple_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wobble\\n  Woo\\n}\\n\\npub fn main() {\\n  let var = Woo\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wobble\n  Woo\n}\n\npub fn main() {\n  let var = Woo\n      ↑        \n  todo\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wobble\n  Woo\n}\n\npub fn main() {\n  let var = Woo\n  case var {\n    Wobble -> todo\n    Woo -> todo\n  }\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_list_tail.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(a_list: List(a)) {\\n  case a_list {\\n    [] -> todo\\n    [first, ..rest] -> todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..rest] -> todo\n              ↑            \n  }\n}\n\n\n----- AFTER ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ] -> todo\n    [first, first_2, ..rest_2] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_list_tail_used_in_a_branch.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(a_list: List(a)) {\\n  case a_list {\\n    [] -> todo\\n    [first, ..rest] -> rest\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..rest] -> rest\n              ↑            \n  }\n}\n\n\n----- AFTER ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ] -> rest\n    [first, first_2, ..rest_2] -> rest\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_list_tail_with_shadowed_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(a_list: List(a)) {\\n  case a_list {\\n    [] -> todo\\n    [rest, ..else_] -> todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [rest, ..else_] -> todo\n             ↑             \n  }\n}\n\n\n----- AFTER ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [rest, ] -> todo\n    [rest, first, ..rest_2] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_list_tail_with_strange_whitespace.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(a_list: List(a)) {\\n  case a_list {\\n    [] -> todo\\n    [first, ..        rest] -> todo\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..        rest] -> todo\n              ↑                    \n  }\n}\n\n\n----- AFTER ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ] -> todo\n    [first, first_2, ..rest_2] -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_list_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(a_list: List(a)) {\\n  todo\\n}\"\n---\n----- BEFORE ACTION\npub fn main(a_list: List(a)) {\n            ↑                 \n  todo\n}\n\n\n----- AFTER ACTION\npub fn main(a_list: List(a)) {\n  case a_list {\n    [] -> todo\n    [first, ..rest] -> todo\n  }\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_use_assignment.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  use var <- f\\n}\\n\\nfn f(g) { g(#(1, 2)) }\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  use var <- f\n      ↑       \n}\n\nfn f(g) { g(#(1, 2)) }\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use var <- f\n  let #(int, int_2) = var\n}\n\nfn f(g) { g(#(1, 2)) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_use_assignment_with_multiple_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n  Wobble\\n  Woo\\n}\\n\\npub fn main() {\\n  use var <- f\\n}\\n\\nfn f(g) { g(Wobble) }\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n  Wobble\n  Woo\n}\n\npub fn main() {\n  use var <- f\n      ↑       \n}\n\nfn f(g) { g(Wobble) }\n\n\n----- AFTER ACTION\n\npub type Wibble {\n  Wobble\n  Woo\n}\n\npub fn main() {\n  use var <- f\n  case var {\n    Wobble -> todo\n    Woo -> todo\n  }\n}\n\nfn f(g) { g(Wobble) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_value_with_private_type_from_same_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\ntype Wibble {\\n  Wobble(Int, String)\\n}\\n\\npub fn main() {\\n  let wibble = Wobble(1, \\\"Hello\\\")\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\ntype Wibble {\n  Wobble(Int, String)\n}\n\npub fn main() {\n  let wibble = Wobble(1, \"Hello\")\n      ↑                          \n  todo\n}\n\n\n----- AFTER ACTION\n\ntype Wibble {\n  Wobble(Int, String)\n}\n\npub fn main() {\n  let wibble = Wobble(1, \"Hello\")\n  let Wobble(int, string) = wibble\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__pattern_match_on_variable_crashes.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble {\\n    Wibble(Wobble)\\n}\\n\\npub type Wobble {\\n    Wobble\\n    Wubble\\n}\\n\\npub fn main() {\\n    let Wibble(wobble) = todo\\n\\n    case todo {\\n      _ -> todo\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Wibble {\n    Wibble(Wobble)\n}\n\npub type Wobble {\n    Wobble\n    Wubble\n}\n\npub fn main() {\n    let Wibble(wobble) = todo\n               ↑             \n\n    case todo {\n      _ -> todo\n    }\n}\n\n\n----- AFTER ACTION\n\npub type Wibble {\n    Wibble(Wobble)\n}\n\npub type Wobble {\n    Wobble\n    Wubble\n}\n\npub fn main() {\n    let Wibble(wobble) = todo\n    case wobble {\n      Wobble -> todo\n      Wubble -> todo\n    }\n\n    case todo {\n      _ -> todo\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_aliased_to_unqualified_aliased_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble as wob\\n\\npub fn main(x) -> wob.Wibble(a) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble as wob\n\npub fn main(x) -> wob.Wibble(a) {\n                  ▔▔▔▔↑          \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport wobble.{type Wibble} as wob\n\npub fn main(x) -> Wibble(a) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_aliased_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble\\n\\npub fn main(x) -> wobble.Wibble(a) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble\n\npub fn main(x) -> wobble.Wibble(a) {\n                  ▔▔▔▔▔▔▔↑          \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport wobble.{type Wibble}\n\npub fn main(x) -> Wibble(a) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_aliased_type_with_multiple_imports.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport other/wobble as other\\nimport wibble/wobble\\n\\npub fn main(x) -> wobble.Wibble(a) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport other/wobble as other\nimport wibble/wobble\n\npub fn main(x) -> wobble.Wibble(a) {\n                  ▔▔▔▔▔▔▔↑          \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport other/wobble as other\nimport wibble/wobble.{type Wibble}\n\npub fn main(x) -> Wibble(a) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_basic_multiple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n  option.Some(1)\\n  option.Some(1)\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n  option.Some(1)\n  todo\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n  Some(1)\n  Some(1)\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_basic_record_without_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble\\n\\npub fn main() {\\n  wobble.Wibble\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble\n\npub fn main() {\n  wobble.Wibble\n        ▔▔↑    \n}\n\n\n----- AFTER ACTION\n\nimport wobble.{Wibble}\n\npub fn main() {\n  Wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_basic_type_without_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble\\n\\npub fn identity(x: wobble.Wobble) -> wobble.Wobble {\\n    x\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble\n\npub fn identity(x: wobble.Wobble) -> wobble.Wobble {\n                         ▔↑                         \n    x\n}\n\n\n----- AFTER ACTION\n\nimport wobble.{type Wobble}\n\npub fn identity(x: Wobble) -> Wobble {\n    x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_basic_with_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_below_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\\nimport option\\n\"\n---\n----- BEFORE ACTION\n\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\nimport option\n\n\n----- AFTER ACTION\n\n\npub fn main() {\n  Some(1)\n}\n\nimport option.{Some}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_between_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\\nimport option\\n\\npub fn identity(x: option.Option(Int)) -> option.Option(Int) {\\n    option.Some(1)\\n    x\\n}\\n\"\n---\n----- BEFORE ACTION\n\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\nimport option\n\npub fn identity(x: option.Option(Int)) -> option.Option(Int) {\n    option.Some(1)\n    x\n}\n\n\n----- AFTER ACTION\n\n\npub fn main() {\n  Some(1)\n}\n\nimport option.{Some}\n\npub fn identity(x: option.Option(Int)) -> option.Option(Int) {\n    Some(1)\n    x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constant_multiple_occurrences.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\nconst a = option.None\\nconst b = option.Some(option.None)\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\nconst a = option.None\n                 ↑   \nconst b = option.Some(option.None)\n\n\n----- AFTER ACTION\n\nimport option.{None}\n\nconst a = None\nconst b = option.Some(None)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constructor_as_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n    option.map(option.Some(1), fn(x) { x + 1 })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n    option.map(option.Some(1), fn(x) { x + 1 })\n               ▔▔▔▔▔▔▔▔▔▔▔↑                    \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n    option.map(Some(1), fn(x) { x + 1 })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constructor_complex_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n    case [option.Some(1), option.None] {\\n        [option.None, ..] -> todo\\n        [option.Some(_), ..] -> todo\\n        _ -> todo\\n    }\\n    case option.Some(1), option.Some(2) {\\n        option.None, option.Some(_) -> todo\\n        option.Some(_), option.Some(val) -> todo\\n        _ -> todo\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n    case [option.Some(1), option.None] {\n          ▔▔▔▔▔▔▔↑                      \n        [option.None, ..] -> todo\n        [option.Some(_), ..] -> todo\n        _ -> todo\n    }\n    case option.Some(1), option.Some(2) {\n        option.None, option.Some(_) -> todo\n        option.Some(_), option.Some(val) -> todo\n        _ -> todo\n    }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n    case [Some(1), option.None] {\n        [option.None, ..] -> todo\n        [Some(_), ..] -> todo\n        _ -> todo\n    }\n    case Some(1), Some(2) {\n        option.None, Some(_) -> todo\n        Some(_), Some(val) -> todo\n        _ -> todo\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constructor_different_module_same_name_inner.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport opt\\n\\npub fn main() {\\n    option.Some(opt.Some(1))\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport opt\n\npub fn main() {\n    option.Some(opt.Some(1))\n                ▔▔▔▔▔▔▔▔↑   \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport option\nimport opt.{Some}\n\npub fn main() {\n    option.Some(Some(1))\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constructor_different_module_same_name_outer.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport opt\\n\\npub fn main() {\\n    option.Some(opt.Some(1))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport opt\n\npub fn main() {\n    option.Some(opt.Some(1))\n    ▔▔▔▔▔▔▔↑                \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\nimport opt\n\npub fn main() {\n    Some(opt.Some(1))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constructor_different_module_same_type_inner.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport opt\\n\\npub fn main() -> option.Option(opt.Option(Int)) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport opt\n\npub fn main() -> option.Option(opt.Option(Int)) {\n                               ▔▔▔▔▔▔▔▔▔▔↑       \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport option\nimport opt.{type Option}\n\npub fn main() -> option.Option(Option(Int)) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_constructor_different_module_same_type_outer.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport opt\\n\\npub fn main() -> option.Option(opt.Option(Int)) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport opt\n\npub fn main() -> option.Option(opt.Option(Int)) {\n                 ▔▔▔▔▔▔▔↑                        \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport option.{type Option}\nimport opt\n\npub fn main() -> Option(opt.Option(Int)) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_custom_type_record_declaration.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble\\n\\npub type Wibble {\\n  Wibble(wibble: wobble.Wobble)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble\n\npub type Wibble {\n  Wibble(wibble: wobble.Wobble)\n                       ▔↑      \n}\n\n\n----- AFTER ACTION\n\nimport wobble.{type Wobble}\n\npub type Wibble {\n  Wibble(wibble: Wobble)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_different_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n  option.Some(1)\\n  option.None\\n}\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n  option.None\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n  Some(1)\n  option.None\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_from_constant_also_updates_functions.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\nconst default = option.None\\n\\npub fn get_or_default(value: a) {\\n  case value {\\n    option.Some(x) -> x\\n    option.None -> value\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\nconst default = option.None\n                       ↑   \n\npub fn get_or_default(value: a) {\n  case value {\n    option.Some(x) -> x\n    option.None -> value\n  }\n}\n\n\n----- AFTER ACTION\n\nimport option.{None}\n\nconst default = None\n\npub fn get_or_default(value: a) {\n  case value {\n    option.Some(x) -> x\n    None -> value\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_from_function_also_updates_constants.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\nconst default = option.None\\n\\npub fn get_or_default(value: a) {\\n  case value {\\n    option.Some(x) -> x\\n    option.None -> value\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\nconst default = option.None\n\npub fn get_or_default(value: a) {\n  case value {\n    option.Some(x) -> x\n    option.None -> value\n           ↑            \n  }\n}\n\n\n----- AFTER ACTION\n\nimport option.{None}\n\nconst default = None\n\npub fn get_or_default(value: a) {\n  case value {\n    option.Some(x) -> x\n    None -> value\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_case_with_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main(x) {\\n  case option.Some(1) {\\n    option.Some(value) -> value\\n    option.None -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main(x) {\n  case option.Some(1) {\n             ▔▔▔▔▔↑    \n    option.Some(value) -> value\n    option.None -> 0\n  }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main(x) {\n  case Some(1) {\n    Some(value) -> value\n    option.None -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_case_without_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble\\n\\npub fn main() {\\n  case wobble.Wibble {\\n    wobble.Wibble -> 1\\n    wobble.Wubble(1) -> 2\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble\n\npub fn main() {\n  case wobble.Wibble {\n             ▔▔↑      \n    wobble.Wibble -> 1\n    wobble.Wubble(1) -> 2\n  }\n}\n\n\n----- AFTER ACTION\n\nimport wobble.{Wibble}\n\npub fn main() {\n  case Wibble {\n    Wibble -> 1\n    wobble.Wubble(1) -> 2\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_constant_record.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\nconst some = option.Some(1)\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\nconst some = option.Some(1)\n                    ↑      \n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\nconst some = Some(1)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_constant_var.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\nconst none = option.None\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\nconst none = option.None\n                    ↑   \n\n\n----- AFTER ACTION\n\nimport option.{None}\n\nconst none = None\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_list_and_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n    let list = [option.Some(1), option.None]\\n    let tuple = #(option.Some(2), option.None)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n    let list = [option.Some(1), option.None]\n                ▔▔▔▔▔▔▔▔▔▔▔↑                \n    let tuple = #(option.Some(2), option.None)\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n    let list = [Some(1), option.None]\n    let tuple = #(Some(2), option.None)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_nested_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\ntype Result(a) {\\n  Result(expected: a, actual: option.Option(a))\\n}\\n\\nconst zero = Result(0, option.None)\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\ntype Result(a) {\n  Result(expected: a, actual: option.Option(a))\n}\n\nconst zero = Result(0, option.None)\n                              ↑    \n\n\n----- AFTER ACTION\n\nimport option.{None}\n\ntype Result(a) {\n  Result(expected: a, actual: option.Option(a))\n}\n\nconst zero = Result(0, None)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() -> Int {\\n  case option.Some(1) {\\n    option.Some(value) -> value\\n    option.None -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() -> Int {\n  case option.Some(1) {\n    option.Some(value) -> value\n          ▔▔▔▔▔▔▔▔↑            \n    option.None -> 0\n  }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() -> Int {\n  case Some(1) {\n    Some(value) -> value\n    option.None -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_in_pattern_without_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wobble\\n\\npub fn main() {\\n  case wobble.Wibble {\\n    wobble.Wibble -> 1\\n    wobble.Wubble(1) -> 2\\n  }\\n  let wob = wobble.Wibble\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wobble\n\npub fn main() {\n  case wobble.Wibble {\n       ▔▔▔▔▔▔▔▔↑      \n    wobble.Wibble -> 1\n    wobble.Wubble(1) -> 2\n  }\n  let wob = wobble.Wibble\n  todo\n}\n\n\n----- AFTER ACTION\n\nimport wobble.{Wibble}\n\npub fn main() {\n  case Wibble {\n    Wibble -> 1\n    wobble.Wubble(1) -> 2\n  }\n  let wob = Wibble\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_generic_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport result\\n\\npub fn main() -> result.Result(Int, String) {\\n    result.Ok(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport result\n\npub fn main() -> result.Result(Int, String) {\n                       ▔▔▔▔▔▔▔↑              \n    result.Ok(1)\n}\n\n\n----- AFTER ACTION\n\nimport result.{type Result}\n\npub fn main() -> Result(Int, String) {\n    result.Ok(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_imports.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport wobble\\n\\npub fn main() {\\n  option.Some(2)\\n  wobble.Wibble(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport wobble\n\npub fn main() {\n  option.Some(2)\n  wobble.Wibble(1)\n        ▔▔▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option\nimport wobble.{Wibble}\n\npub fn main() {\n  option.Some(2)\n  Wibble(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_line.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{\\n    type Option,\\n    None,\\n}\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{\n    type Option,\n    None,\n}\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{\n    type Option,\n    None, Some\n}\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_line_aliased.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{\\n    type Option,\\n    None} as opt\\n\\npub fn main() {\\n  opt.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{\n    type Option,\n    None} as opt\n\npub fn main() {\n  opt.Some(1)\n     ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{\n    type Option,\n    None, Some} as opt\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_line_bad_format_multiple_whitespace.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{    }\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{    }\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some    }\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_line_bad_format_with_trailing_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type Option,\\n    None,\\n\\n}\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type Option,\n    None,\n\n}\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{type Option,\n    None, Some\n\n}\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_multiple_line_bad_format_without_trailing_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type Option,\\n    None\\n\\n}\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type Option,\n    None\n\n}\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{type Option,\n    None, Some\n\n}\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_nested_constructor_inner.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport wobble\\n\\npub fn main(x) -> option.Option(wobble.Wibble) {\\n    option.Some(wobble.Wobble(1))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport wobble\n\npub fn main(x) -> option.Option(wobble.Wibble) {\n    option.Some(wobble.Wobble(1))\n                      ▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\n\nimport option\nimport wobble.{Wobble}\n\npub fn main(x) -> option.Option(wobble.Wibble) {\n    option.Some(Wobble(1))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_nested_constructor_outer.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport wobble\\npub fn main(x) -> option.Option(wobble.Wibble) {\\n    option.Some(wobble.Wobble(1))\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport wobble\npub fn main(x) -> option.Option(wobble.Wibble) {\n    option.Some(wobble.Wobble(1))\n          ▔▔↑                    \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\nimport wobble\npub fn main(x) -> option.Option(wobble.Wibble) {\n    Some(wobble.Wobble(1))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_nested_type_inner.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport wobble\\n\\npub fn main(x) -> option.Option(wobble.Wibble) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport wobble\n\npub fn main(x) -> option.Option(wobble.Wibble) {\n                                ▔▔▔▔▔▔▔↑        \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport option\nimport wobble.{type Wibble}\n\npub fn main(x) -> option.Option(Wibble) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_nested_type_outer.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\nimport wobble\\npub fn main(x) -> option.Option(wobble.Wibble) {\\n    todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\nimport wobble\npub fn main(x) -> option.Option(wobble.Wibble) {\n                        ▔▔↑                     \n    todo\n}\n\n\n----- AFTER ACTION\n\nimport option.{type Option}\nimport wobble\npub fn main(x) -> Option(wobble.Wibble) {\n    todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main(x) -> option.Option(Int) {\\n    option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main(x) -> option.Option(Int) {\n                        ▔▔▔▔▔▔▔↑      \n    option.Some(1)\n}\n\n\n----- AFTER ACTION\n\nimport option.{type Option}\n\npub fn main(x) -> Option(Int) {\n    option.Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_when_unqualified_exists.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{Some}\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{Some}\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_with_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option as opt\\n\\npub fn main() {\\n  opt.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option as opt\n\npub fn main() {\n  opt.Some(1)\n  ▔▔▔▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some} as opt\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_with_alias_multiple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option as opt\\n\\npub fn main() {\\n  opt.Some(1)\\n  opt.Some(1)\\n}\\n\\npub fn identity(x: opt.Option(Int)) -> opt.Option(Int) {\\n    opt.Some(1)\\n    x\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option as opt\n\npub fn main() {\n  opt.Some(1)\n  ▔▔▔▔▔▔▔▔↑  \n  opt.Some(1)\n}\n\npub fn identity(x: opt.Option(Int)) -> opt.Option(Int) {\n    opt.Some(1)\n    x\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some} as opt\n\npub fn main() {\n  Some(1)\n  Some(1)\n}\n\npub fn identity(x: opt.Option(Int)) -> opt.Option(Int) {\n    Some(1)\n    x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_with_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{None, }\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{None, }\n\npub fn main() {\n  option.Some(1)\n        ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{None, Some }\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_import_with_comma_pos_not_end.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{None,   } as opt\\n\\npub fn main() {\\n  opt.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{None,   } as opt\n\npub fn main() {\n  opt.Some(1)\n     ▔▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{None, Some   } as opt\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__qualified_to_unqualified_record_value_constructor_module_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n  option.Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option\n\npub fn main() {\n  option.Some(1)\n  ↑             \n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn main() {\n  Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_aliased_unused_value.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport result.{is_ok as ok}\\nimport option\\n\\npub fn main() {\\n  result.is_ok\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport result.{is_ok as ok}\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\nimport option\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main() {\n↑              \n  result.is_ok\n}\n\n\n----- AFTER ACTION\n\n// test\nimport result.{}\n\npub fn main() {\n  result.is_ok\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_block_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    { 1 }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n    { 1 }\n      ↑  \n}\n\n\n----- AFTER ACTION\npub fn main() {\n     1 \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_block_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    { main() <> 2 }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n    { main() <> 2 }\n                  ↑\n}\n\n\n----- AFTER ACTION\npub fn main() {\n     main() <> 2 \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_block_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    case 1 {\\n      _ -> { main() <> 2 }\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main() {\n    case 1 {\n      _ -> { main() <> 2 }\n           ↑              \n    }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n    case 1 {\n      _ ->  main() <> 2 \n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_block_triggers_on_the_innermost_selected_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n    {\\n      main({\\n        1\\n      })\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n    {\n      main({\n        1\n        ↑\n      })\n    }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n    {\n      main(\n        1\n      )\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_block_unwraps_a_single_expression_in_a_binop.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n    { main(1) } * 3\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n    { main(1) } * 3\n      ↑            \n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n     main(1)  * 3\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2\n  ↑         \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_as_function_arg.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  wibble([], echo 1 + 2)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  wibble([], echo 1 + 2)\n                  ↑     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  wibble([], 1 + 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_before_pipeline.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo [1, 2, 3] |> wibble\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo [1, 2, 3] |> wibble\n  ↑                       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3] |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_before_pipeline_selecting_step.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo [1, 2, 3] |> wibble\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo [1, 2, 3] |> wibble\n                    ↑     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3] |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_in_pipeline_step.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> echo\\n  |> wibble\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> echo\n     ↑   \n  |> wibble\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_in_pipeline_step_with_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> echo as message\\n  |> wibble\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> echo as message\n     ↑              \n  |> wibble\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_in_single_line_pipeline_step.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3] |> echo |> wibble\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3] |> echo |> wibble\n               ↑             \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3] |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_in_single_line_pipeline_step_with_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3] |> echo as \\\"message\\\" |> wibble\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3] |> echo as \"message\" |> wibble\n               ↑                          \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3] |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_last_in_long_pipeline_step.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> wibble\\n  |> echo\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> echo\n     ↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_last_in_long_pipeline_step_with_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> wibble\\n  |> echo as \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> echo as \"message\"\n     ↑                \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_last_in_short_pipeline_step.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> echo\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> echo\n     ↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_last_in_short_pipeline_step_with_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  [1, 2, 3]\\n  |> echo as \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  [1, 2, 3]\n  |> echo as \"message\"\n     ↑                \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  [1, 2, 3]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_all_echos.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo wibble(echo 1, 2)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo wibble(echo 1, 2)\n              ↑         \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  wibble(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_all_echos_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 |> echo |> echo |> wibble |> echo\\n  echo wibble(echo 1, echo 2)\\n  echo 1\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 |> echo |> echo |> wibble |> echo\n            ↑                             \n  echo wibble(echo 1, echo 2)\n  echo 1\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 |> wibble\n  wibble(1, 2)\n  1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1\n  ↑     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return_of_a_fn.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  fn() {\\n    echo 1\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  fn() {\n    echo 1\n    ↑     \n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  fn() {\n    1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_entire_echo_statement_used_with_a_var.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let a = 1\\n  echo a\\n  Nil\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let a = 1\n  echo a\n  ↑     \n  Nil\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let a = 1\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_entire_echo_statement_used_with_literals.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1\\n  Nil\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1\n  ↑     \n  Nil\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_entire_echo_statement_used_with_literals_and_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 as \\\"message\\\"\\n  Nil\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 as \"message\"\n  ↑                  \n  Nil\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_entire_echo_statement_used_with_literals_in_a_fn.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  fn() {\\n    echo 1\\n    Nil\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  fn() {\n    echo 1\n    ↑     \n    Nil\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  fn() {\n    Nil\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_multiple_entire_echo_statement_used_with_literals.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1\\n  echo \\\"wibble\\\"\\n  Nil\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1\n  ↑     \n  echo \"wibble\"\n  Nil\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_multiple_entire_echo_statement_used_with_literals_but_stops_at_comments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1\\n\\n  // Oh no I hope I'm not deleted by the code action!!\\n  Nil\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1\n  ↑     \n\n  // Oh no I hope I'm not deleted by the code action!!\n  Nil\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  // Oh no I hope I'm not deleted by the code action!!\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_removes_multiple_entire_echo_statement_used_with_literals_in_a_fn.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  fn() {\\n    echo 1\\n    echo \\\"wibble\\\"\\n    Nil\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  fn() {\n    echo 1\n    ↑     \n    echo \"wibble\"\n    Nil\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  fn() {\n    Nil\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_selecting_expression.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2\n       ▔▔▔▔↑\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_selecting_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2 as \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2 as \"message\"\n                 ↑       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_with_message.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2 as \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2 as \"message\"\n  ↑                      \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_with_message_and_comment.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2\\n    // Hello!\\n    as \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2\n  ↑         \n    // Hello!\n    as \"message\"\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_with_message_and_comment_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2 as\\n    // Hello!\\n    \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2 as\n  ↑            \n    // Hello!\n    \"message\"\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_with_message_and_comment_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 + 2 as\\n    // Hello!\\n    \\\"message\\\"\\n\\n  Nil\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 + 2 as\n  ↑            \n    // Hello!\n    \"message\"\n\n  Nil\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1 + 2\n\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_echo_with_message_removes_does_not_remove_entire_echo_statement_if_its_the_return.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  echo 1 as \\\"message\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  echo 1 as \"message\"\n  ↑                  \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_entire_unused_import.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport result.{unused, unused_again}\\n\\npub fn main() {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport result.{unused, unused_again}\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main() {\n↑              \n  todo\n}\n\n\n----- AFTER ACTION\n\n// test\n\npub fn main() {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_multiple_redundant_tuple_with_catch_all_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  case #(1, 2), #(3, 4) {\\n    #(2, 2), #(2, 2) -> 0\\n    #(1, 2), _ -> 0\\n    _, #(1, 2) -> 0\\n    _, _ -> 1\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  case #(1, 2), #(3, 4) {\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑        \n    #(2, 2), #(2, 2) -> 0\n    #(1, 2), _ -> 0\n    _, #(1, 2) -> 0\n    _, _ -> 1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  case 1, 2, 3, 4 {\n    2, 2, 2, 2 -> 0\n    1, 2, _, _ -> 0\n    _, _, 1, 2 -> 0\n    _, _, _, _ -> 1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_multiple_unused_values.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport result.{type Unused, used, unused, unused_again, type Used, used_again}\\n\\npub fn main(x: Used) {\\n  #(used, used_again)\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport result.{type Unused, used, unused, unused_again, type Used, used_again}\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main(x: Used) {\n↑                     \n  #(used, used_again)\n}\n\n\n----- AFTER ACTION\n\n// test\nimport result.{used, type Used, used_again}\n\npub fn main(x: Used) {\n  #(used, used_again)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_multiple_unused_values_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport result.{type Unused, used, unused, type Used, unused_again}\\n\\npub fn main(x: Used) {\\n  used\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport result.{type Unused, used, unused, type Used, unused_again}\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main(x: Used) {\n↑                     \n  used\n}\n\n\n----- AFTER ACTION\n\n// test\nimport result.{used, type Used}\n\npub fn main(x: Used) {\n  used\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_opaque_from_private_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"opaque type Wibble {\\n  Wobble\\n}\\n\"\n---\n----- BEFORE ACTION\nopaque type Wibble {\n            ↑       \n  Wobble\n}\n\n\n----- AFTER ACTION\ntype Wibble {\n  Wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_redundant_tuple_in_case_retain_extras.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case\\n    #(\\n      // first comment\\n      1,\\n      // second comment\\n      2,\\n      3 // third comment before comma\\n\\n      ,\\n\\n      // fourth comment after comma\\n\\n    )\\n  {\\n    #(\\n      // first comment\\n      a,\\n      // second comment\\n      b,\\n      c // third comment before comma\\n\\n      ,\\n\\n      // fourth comment after comma\\n\\n    ) -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case\n    #(\n    ▔▔\n      // first comment\n▔▔▔▔▔▔↑               \n      1,\n      // second comment\n      2,\n      3 // third comment before comma\n\n      ,\n\n      // fourth comment after comma\n\n    )\n  {\n    #(\n      // first comment\n      a,\n      // second comment\n      b,\n      c // third comment before comma\n\n      ,\n\n      // fourth comment after comma\n\n    ) -> 0\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case\n    \n      // first comment\n      1,\n      // second comment\n      2,\n      3 // third comment before comma\n\n      \n\n      // fourth comment after comma\n\n    \n  {\n    \n      // first comment\n      a,\n      // second comment\n      b,\n      c // third comment before comma\n\n      \n\n      // fourth comment after comma\n\n     -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_redundant_tuple_in_case_subject_nested.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  case #(case #(0) { #(a) -> 0 }) { #(b) -> 0 }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  case #(case #(0) { #(a) -> 0 }) { #(b) -> 0 }\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑          \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  case case 0 { a -> 0 } { b -> 0 }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_redundant_tuple_in_case_subject_only_safe_remove.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  case #(0), #(1) {\\n    #(1), #(b) -> 0\\n    a, #(0) -> 1 // The first of this clause is not a tuple\\n    #(a), #(b) -> 2\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  case #(0), #(1) {\n       ▔▔▔▔▔▔↑     \n    #(1), #(b) -> 0\n    a, #(0) -> 1 // The first of this clause is not a tuple\n    #(a), #(b) -> 2\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  case #(0), 1 {\n    #(1), b -> 0\n    a, 0 -> 1 // The first of this clause is not a tuple\n    #(a), b -> 2\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_redundant_tuple_in_case_subject_simple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  case #(1) { #(a) -> 0 }\\n  case #(1, 2) { #(a, b) -> 0 }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  case #(1) { #(a) -> 0 }\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  case #(1, 2) { #(a, b) -> 0 }\n▔▔▔▔▔▔▔▔▔▔▔▔▔↑                 \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  case 1 { a -> 0 }\n  case 1, 2 { a, b -> 0 }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_redundant_tuple_with_catch_all_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  case #(1, 2) {\\n    #(1, 2) -> 0\\n    _ -> 1\\n  }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  case #(1, 2) {\n  ▔▔▔▔▔▔▔▔▔▔▔↑  \n    #(1, 2) -> 0\n    _ -> 1\n  }\n}\n\n\n----- AFTER ACTION\npub fn main() {\n  case 1, 2 {\n    1, 2 -> 0\n    _, _ -> 1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_unreachable_clauses.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main(x) {\\n  case x {\\n    Ok(n) -> 1\\n    Ok(_) -> 2\\n    Error(_) -> todo\\n    Ok(1) -> 3\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\npub fn main(x) {\n  case x {\n    Ok(n) -> 1\n    Ok(_) -> 2\n    Error(_) -> todo\n    Ok(1) -> 3\n    ↑         \n  }\n}\n\n\n----- AFTER ACTION\npub fn main(x) {\n  case x {\n    Ok(n) -> 1\n    \n    Error(_) -> todo\n    \n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_unused_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport result.{is_ok} as res\\nimport option\\n\\npub fn main() {\\n  is_ok\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport result.{is_ok} as res\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\nimport option\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main() {\n↑              \n  is_ok\n}\n\n\n----- AFTER ACTION\n\n// test\nimport result.{is_ok} \n\npub fn main() {\n  is_ok\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_unused_simple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport // comment\\nlist as lispy\\nimport result\\nimport option\\n\\npub fn main() {\\n  result.is_ok\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport // comment\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\nlist as lispy\n▔▔▔▔▔▔▔▔▔▔▔▔▔\nimport result\n▔▔▔▔▔▔▔▔▔▔▔▔▔\nimport option\n▔▔▔▔▔▔▔↑     \n\npub fn main() {\n  result.is_ok\n}\n\n\n----- AFTER ACTION\n\n// test\n\npub fn main() {\n  result.is_ok\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_unused_start_of_file.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"import option\\nimport result\\n\\npub fn main() {\\n  result.is_ok\\n}\\n\"\n---\n----- BEFORE ACTION\nimport option\n▔▔▔▔▔▔▔▔▔▔▔▔▔\nimport result\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main() {\n↑              \n  result.is_ok\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  result.is_ok\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__remove_unused_value.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n// test\\nimport result.{is_ok}\\nimport option\\n\\npub fn main() {\\n  result.is_ok\\n}\\n\"\n---\n----- BEFORE ACTION\n\n// test\n▔▔▔▔▔▔▔\nimport result.{is_ok}\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\nimport option\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main() {\n↑              \n  result.is_ok\n}\n\n\n----- AFTER ACTION\n\n// test\nimport result.{}\n\npub fn main() {\n  result.is_ok\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_bit_array_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert <<bitValue>> = <<73>>\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert <<bitValue>> = <<73>>\n               ▔▔▔▔▔▔▔▔▔▔↑          \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert <<bit_value>> = <<73>>\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_bit_array_pattern_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert <<_iDontCare>> = <<97>>\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert <<_iDontCare>> = <<97>>\n               ▔▔▔▔▔▔▔▔↑              \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert <<_i_dont_care>> = <<97>>\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_case_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    case 21 { twentyOne -> {Nil} }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    case 21 { twentyOne -> {Nil} }\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    case 21 { twenty_one -> {Nil} }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_case_variable_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    case 21 { _twentyOne -> {Nil} }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    case 21 { _twentyOne -> {Nil} }\n         ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑         \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    case 21 { _twenty_one -> {Nil} }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_const.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: const myInvalid_Constant = 42\n---\n----- BEFORE ACTION\nconst myInvalid_Constant = 42\n               ↑             \n\n\n----- AFTER ACTION\nconst my_invalid_constant = 42\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"type MyType { The_Constructor(Int) }\"\n---\n----- BEFORE ACTION\ntype MyType { The_Constructor(Int) }\n               ↑                    \n\n\n----- AFTER ACTION\ntype MyType { TheConstructor(Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_constructor_arg.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"type IntWrapper { IntWrapper(innerInt: Int) }\"\n---\n----- BEFORE ACTION\ntype IntWrapper { IntWrapper(innerInt: Int) }\n                  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n\n\n----- AFTER ACTION\ntype IntWrapper { IntWrapper(inner_int: Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_constructor_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type Box { Box(Int) }\\npub fn main() {\\n    let Box(innerValue) = Box(203)\\n}\"\n---\n----- BEFORE ACTION\npub type Box { Box(Int) }\npub fn main() {\n    let Box(innerValue) = Box(203)\n            ↑                     \n}\n\n\n----- AFTER ACTION\npub type Box { Box(Int) }\npub fn main() {\n    let Box(inner_value) = Box(203)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_constructor_pattern_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type Box { Box(Int) }\\npub fn main() {\\n    let Box(_ignoredInner) = Box(203)\\n}\"\n---\n----- BEFORE ACTION\npub type Box { Box(Int) }\npub fn main() {\n    let Box(_ignoredInner) = Box(203)\n            ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\npub type Box { Box(Int) }\npub fn main() {\n    let Box(_ignored_inner) = Box(203)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_custom_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"type Boxed_value { Box(Int) }\"\n---\n----- BEFORE ACTION\ntype Boxed_value { Box(Int) }\n     ▔▔▔▔▔↑                  \n\n\n----- AFTER ACTION\ntype BoxedValue { Box(Int) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn doStuff() {}\"\n---\n----- BEFORE ACTION\nfn doStuff() {}\n▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n\n\n----- AFTER ACTION\nfn do_stuff() {}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_function_type_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn identity(value: someType) { value }\"\n---\n----- BEFORE ACTION\nfn identity(value: someType) { value }\n                   ▔▔▔▔▔▔▔▔↑          \n\n\n----- AFTER ACTION\nfn identity(value: some_type) { value }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_list_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert [theElement] = [9.4]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert [theElement] = [9.4]\n        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert [the_element] = [9.4]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_list_pattern_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert [_elemOne] = [False]\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert [_elemOne] = [False]\n                     ↑             \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert [_elem_one] = [False]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn add(numA: Int, num_b: Int) { numA + num_b }\"\n---\n----- BEFORE ACTION\nfn add(numA: Int, num_b: Int) { numA + num_b }\n       ↑                                      \n\n\n----- AFTER ACTION\nfn add(num_a: Int, num_b: Int) { numA + num_b }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn ignore(_ignoreMe: Bool) { 98 }\"\n---\n----- BEFORE ACTION\nfn ignore(_ignoreMe: Bool) { 98 }\n   ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n\n\n----- AFTER ACTION\nfn ignore(_ignore_me: Bool) { 98 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_discard_name2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn ignore(labelled_discard _ignoreMe: Bool) { 98 }\"\n---\n----- BEFORE ACTION\nfn ignore(labelled_discard _ignoreMe: Bool) { 98 }\n   ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n\n\n----- AFTER ACTION\nfn ignore(labelled_discard _ignore_me: Bool) { 98 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_discard_name3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let ignore = fn(_ignoreMe: Bool) { 98 }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let ignore = fn(_ignoreMe: Bool) { 98 }\n        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let ignore = fn(_ignore_me: Bool) { 98 }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_label.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn func(thisIsALabel param: Int) { param }\"\n---\n----- BEFORE ACTION\nfn func(thisIsALabel param: Int) { param }\n        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑             \n\n\n----- AFTER ACTION\nfn func(this_is_a_label param: Int) { param }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_label2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn ignore(thisIsALabel _ignore: Int) { 25 }\"\n---\n----- BEFORE ACTION\nfn ignore(thisIsALabel _ignore: Int) { 25 }\n            ↑                              \n\n\n----- AFTER ACTION\nfn ignore(this_is_a_label _ignore: Int) { 25 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_name2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn pass(label paramName: Bool) { paramName }\"\n---\n----- BEFORE ACTION\nfn pass(label paramName: Bool) { paramName }\n              ↑                             \n\n\n----- AFTER ACTION\nfn pass(label param_name: Bool) { paramName }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_parameter_name3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let add = fn(numA: Int, num_b: Int) { numA + num_b }\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let add = fn(numA: Int, num_b: Int) { numA + num_b }\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑                           \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let add = fn(num_a: Int, num_b: Int) { numA + num_b }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_pattern_assignment.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert 42 as theAnswer = 42\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert 42 as theAnswer = 42\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert 42 as the_answer = 42\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_string_prefix_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert \\\"prefix\\\" <> coolSuffix = \\\"prefix-suffix\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert \"prefix\" <> coolSuffix = \"prefix-suffix\"\n                        ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert \"prefix\" <> cool_suffix = \"prefix-suffix\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_string_prefix_pattern_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert \\\"prefix\\\" as thePrefix <> _suffix = \\\"prefix-suffix\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert \"prefix\" as thePrefix <> _suffix = \"prefix-suffix\"\n                ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert \"prefix\" as the_prefix <> _suffix = \"prefix-suffix\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_string_prefix_pattern_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let assert \\\"prefix\\\" <> _boringSuffix = \\\"prefix-suffix\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let assert \"prefix\" <> _boringSuffix = \"prefix-suffix\"\n                        ▔▔▔▔▔▔▔▔▔▔↑                       \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let assert \"prefix\" <> _boring_suffix = \"prefix-suffix\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_tuple_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let #(a, secondValue) = #(1, 2)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let #(a, secondValue) = #(1, 2)\n             ▔▔▔▔↑                 \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let #(a, second_value) = #(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_tuple_pattern_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let #(a, _secondValue) = #(1, 2)\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let #(a, _secondValue) = #(1, 2)\n             ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑      \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let #(a, _second_value) = #(1, 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_type_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: type Fancy_Bool = Bool\n---\n----- BEFORE ACTION\ntype Fancy_Bool = Bool\n      ▔▔▔▔▔▔▔▔▔▔↑     \n\n\n----- AFTER ACTION\ntype FancyBool = Bool\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_type_alias_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: type Phantom(phantomType) = Int\n---\n----- BEFORE ACTION\ntype Phantom(phantomType) = Int\n             ▔▔▔▔▔▔▔▔▔▔▔↑      \n\n\n----- AFTER ACTION\ntype Phantom(phantom_type) = Int\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_type_parameter_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"type Wrapper(innerType) {}\"\n---\n----- BEFORE ACTION\ntype Wrapper(innerType) {}\n             ▔▔▔▔▔▔▔▔▔↑   \n\n\n----- AFTER ACTION\ntype Wrapper(inner_type) {}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn use_test(f) { f(Nil) }\\npub fn main() {use useVar <- use_test()}\"\n---\n----- BEFORE ACTION\nfn use_test(f) { f(Nil) }\npub fn main() {use useVar <- use_test()}\n               ▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑          \n\n\n----- AFTER ACTION\nfn use_test(f) { f(Nil) }\npub fn main() {use use_var <- use_test()}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_use_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"fn use_test(f) { f(Nil) }\\npub fn main() {use _discardVar <- use_test()}\"\n---\n----- BEFORE ACTION\nfn use_test(f) { f(Nil) }\npub fn main() {use _discardVar <- use_test()}\n                             ↑               \n\n\n----- AFTER ACTION\nfn use_test(f) { f(Nil) }\npub fn main() {use _discard_var <- use_test()}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let theAnswer = 42\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let theAnswer = 42\n        ▔▔▔↑          \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let the_answer = 42\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_invalid_variable_discard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n    let _boringNumber = 72\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n    let _boringNumber = 72\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑ \n}\n\n\n----- AFTER ACTION\npub fn main() {\n    let _boring_number = 72\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__rename_module_for_imported.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport gleam/io\\n\\npub fn main() {\\n  i.println(\\\"Hello, world!\\\")\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport gleam/io\n\npub fn main() {\n  i.println(\"Hello, world!\")\n  ▔▔↑                       \n}\n\n\n----- AFTER ACTION\n\nimport gleam/io\n\npub fn main() {\n  io.println(\"Hello, world!\")\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_nested_underscore_in_let_annotation.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() {\\n    let a: Result(Result(_, Nil), Nil) = Ok(Ok(\\\"hello\\\"))\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() {\n    let a: Result(Result(_, Nil), Nil) = Ok(Ok(\"hello\"))\n                         ↑                              \n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() {\n    let a: Result(Result(String, Nil), Nil) = Ok(Ok(\"hello\"))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_nested_underscore_with_function_return_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() -> Result(Result(_, Nil), Int) {\\n    Ok(Ok(\\\"hello\\\"))\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() -> Result(Result(_, Nil), Int) {\n                                 ↑              \n    Ok(Ok(\"hello\"))\n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() -> Result(Result(String, Nil), Int) {\n    Ok(Ok(\"hello\"))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_nested_underscore_with_generic_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() -> Result(a, _) {\\n    Ok(todo)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() -> Result(a, _) {\n                             ↑   \n    Ok(todo)\n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() -> Result(a, b) {\n    Ok(todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_nested_underscore_with_tuple_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() {\\n    let a: #(Int, _, Int) = #(1, \\\"hello\\\", 2)\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() {\n    let a: #(Int, _, Int) = #(1, \"hello\", 2)\n                  ↑                         \n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() {\n    let a: #(Int, String, Int) = #(1, \"hello\", 2)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_underscore_in_fn_expr_argument.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() {\\n    fn(a: _) { a + 2 }\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() {\n    fn(a: _) { a + 2 }\n          ↑           \n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() {\n    fn(a: Int) { a + 2 }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_underscore_in_function_argument.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble(a: _) -> Int {\\n    a + 2\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble(a: _) -> Int {\n                 ↑          \n    a + 2\n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble(a: Int) -> Int {\n    a + 2\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_underscore_in_let_annotation.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() {\\n    let a: _ = Ok(Ok(\\\"hello\\\"))\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() {\n    let a: _ = Ok(Ok(\"hello\"))\n           ↑                  \n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() {\n    let a: Result(Result(String, a), b) = Ok(Ok(\"hello\"))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_underscore_with_function_return_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() -> _ {\\n    12\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() -> _ {\n                   ↑  \n    12\n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() -> Int {\n    12\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__replace_underscore_with_type.snap",
    "content": "---\nsource: language-server/src/tests/action.rs\nexpression: \"\\npub fn wibble() -> Result(Result(_, Nil), Int) {\\n    Ok(Ok(\\\"hello\\\"))\\n}\\n    \"\n---\n----- BEFORE ACTION\n\npub fn wibble() -> Result(Result(_, Nil), Int) {\n                                 ↑              \n    Ok(Ok(\"hello\"))\n}\n    \n\n\n----- AFTER ACTION\n\npub fn wibble() -> Result(Result(String, Nil), Int) {\n    Ok(Ok(\"hello\"))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__selected_statements_do_not_select_outer_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  let c = {\\n    let a = 10\\n    let b = 20\\n    a + b\\n  }\\n\\n  echo c\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  let c = {\n    let a = 10\n    ▔▔▔▔▔▔▔▔▔▔\n    let b = 20\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    a + b\n▔▔▔▔▔▔↑  \n  }\n\n  echo c\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  let c = {\n    function()\n  }\n\n  echo c\n}\n\nfn function() -> Int {\n  let a = 10\n    let b = 20\n    a + b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__split_string.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble wobble woo\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble wobble woo\"\n          ↑          \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  \"wibble \" <> todo <> \"wobble woo\"\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__splitting_string_as_first_pipeline_step_inserts_brackets.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  \\\"wibble  wobble\\\" |> io.println\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  \"wibble  wobble\" |> io.println\n          ↑                     \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  { \"wibble \" <> todo <> \" wobble\" } |> io.println\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_starts_from_innermost_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(10, 20, fn(a) {\\n    wibble(30, 40, fn(b) {\\n      a + b\\n    })\\n  })\\n}\\n\\nfn wibble(m, n, f) {\\n  f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(10, 20, fn(a) {\n    wibble(30, 40, fn(b) {\n           ▔▔▔▔↑          \n      a + b\n    })\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  wibble(10, 20, fn(a) {\n    use b <- wibble(30, 40)\n    a + b\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_with_another_use_in_the_way.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(10, 20, fn(a) {\\n    use b <- wibble(30, 40)\\n    a + b\\n  })\\n}\\n\\nfn wibble(m, n, f) {\\n  f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(10, 20, fn(a) {\n    use b <- wibble(30, 40)\n    ↑                      \n    a + b\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a <- wibble(10, 20)\n  use b <- wibble(30, 40)\n  a + b\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_with_fn_with_no_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(fn() { todo })\\n}\\n\\nfn wibble(f) {\\n  f()\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(fn() { todo })\n  ↑                    \n}\n\nfn wibble(f) {\n  f()\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use <- wibble\n  todo\n}\n\nfn wibble(f) {\n  f()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_with_last_function_in_a_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  {\\n    wibble(10, 20, fn(a) { todo })\\n    wibble(1, 11, fn(a) { todo })\\n  }\\n  Nil\\n}\\n\\nfn wibble(m, n, f) {\\n  f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  {\n    wibble(10, 20, fn(a) { todo })\n    wibble(1, 11, fn(a) { todo })\n    ▔▔▔▔▔▔▔▔▔▔↑                  \n  }\n  Nil\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  {\n    wibble(10, 20, fn(a) { todo })\n    use a <- wibble(1, 11)\n    todo\n  }\n  Nil\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_with_module_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport other\\npub fn main() {\\n  other.wibble(10, 20, fn(a) {\\n    todo\\n    a + b\\n  })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport other\npub fn main() {\n  other.wibble(10, 20, fn(a) {\n        ↑                     \n    todo\n    a + b\n  })\n}\n\n\n----- AFTER ACTION\n\nimport other\npub fn main() {\n  use a <- other.wibble(10, 20)\n  todo\n  a + b\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_with_out_of_order_arguments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  fold(0, over: [], with: fn (a, b) { todo })\\n}\\n\\nfn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  fold(0, over: [], with: fn (a, b) { todo })\n  ↑                                          \n}\n\nfn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {\n  todo\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a, b <- fold(0, over: [])\n  todo\n}\n\nfn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_into_use_with_single_line_body.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(fn(a, b) { todo })\\n}\\n\\nfn wibble(f) {\\n  f(todo, todo)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(fn(a, b) { todo })\n  ↑                        \n}\n\nfn wibble(f) {\n  f(todo, todo)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a, b <- wibble\n  todo\n}\n\nfn wibble(f) {\n  f(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_with_fn_with_type_annotations_into_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1, 2, fn(a: Int) {\\n    todo\\n  })\\n}\\n\\nfn wibble(m, n, f) {\\n  f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a: Int) {\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑        \n    todo\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a: Int <- wibble(1, 2)\n  todo\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_with_multiline_fn_into_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1, 2, fn(a) {\\n    todo\\n    case todo {\\n      _ -> todo\\n    }\\n  })\\n}\\n\\nfn wibble(m, n, f) {\\n  f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a) {\n         ▔▔▔▔▔▔↑      \n    todo\n    case todo {\n      _ -> todo\n    }\n  })\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a <- wibble(1, 2)\n  todo\n  case todo {\n    _ -> todo\n  }\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__turn_call_with_multiple_arguments_into_use.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn main() {\\n  wibble(1, 2, fn(a) { todo })\\n}\\n\\nfn wibble(m, n, f) {\\n  f(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub fn main() {\n  wibble(1, 2, fn(a) { todo })\n                       ↑      \n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n\n\n----- AFTER ACTION\n\npub fn main() {\n  use a <- wibble(1, 2)\n  todo\n}\n\nfn wibble(m, n, f) {\n  f(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__type_variables_are_not_duplicated_when_adding_annotations.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn wibble(a: a, b: b, c: c) -> d { todo }\\n\\nfn many_args(a, b, c, d: d, e: a, f, g) {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn many_args(a, b, c, d: d, e: a, f, g) {\n   ↑                                     \n  todo\n}\n\n\n----- AFTER ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn many_args(a: b, b: c, c: e, d: d, e: a, f: f, g: g) -> h {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__type_variables_from_other_functions_do_not_change_annotations.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn wibble(a: a, b: b, c: c) -> d { todo }\\n\\nfn pair(a, b) {\\n  #(a, b)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn pair(a, b) {\n   ↑           \n  #(a, b)\n}\n\n\n----- AFTER ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn pair(a: a, b: b) -> #(a, b) {\n  #(a, b)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__type_variables_from_other_functions_do_not_change_annotations_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn wibble(a: a, b: b, c: c) -> d { todo }\\n\\nconst empty = []\\n\"\n---\n----- BEFORE ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nconst empty = []\n      ↑         \n\n\n----- AFTER ACTION\n\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nconst empty: List(a) = []\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__type_variables_in_let_bindings_are_considered_when_adding_annotations.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nfn wibble(a, b, c) {\\n  let x: a = todo\\n  fn(a: b, b: c) -> d {\\n    todo\\n  }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nfn wibble(a, b, c) {\n   ↑                \n  let x: a = todo\n  fn(a: b, b: c) -> d {\n    todo\n  }\n}\n\n\n----- AFTER ACTION\n\nfn wibble(a: e, b: f, c: g) -> fn(b, c) -> d {\n  let x: a = todo\n  fn(a: b, b: c) -> d {\n    todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_after_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn create_user(name: String) -> User {\\n    User(name: name, id: 1)\\n}\\n\\nimport user.{type User, User}\\n\"\n---\n----- BEFORE ACTION\n\npub fn create_user(name: String) -> User {\n    User(name: name, id: 1)\n    ▔▔▔▔▔↑                 \n}\n\nimport user.{type User, User}\n\n\n----- AFTER ACTION\n\npub fn create_user(name: String) -> User {\n    user.User(name: name, id: 1)\n}\n\nimport user.{type User, }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_bad_formatted_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type    Option    , Some}\\n\\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\\n    case x {\\n        Some(value) -> Some(value + 1)\\n        _ -> x\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type    Option    , Some}\n\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\n                          ▔▔▔↑                         \n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn maybe_increment(x: option.Option(Int)) -> option.Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_bad_formatted_type_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type    Option, Some}\\n\\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\\n    case x {\\n        Some(value) -> Some(value + 1)\\n        _ -> x\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type    Option, Some}\n\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\n                          ▔▔▔↑                         \n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn maybe_increment(x: option.Option(Int)) -> option.Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_bad_formatted_type_constructor_with_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type    Option    as Maybe, Some}\\n\\npub fn maybe_increment(x: Maybe(Int)) -> Maybe(Int) {\\n    case x {\\n        Some(value) -> Some(value + 1)\\n        _ -> x\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type    Option    as Maybe, Some}\n\npub fn maybe_increment(x: Maybe(Int)) -> Maybe(Int) {\n                          ▔▔▔↑                       \n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn maybe_increment(x: option.Option(Int)) -> option.Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_between_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn create_user(name: String) -> User {\\n    User(name: name, id: 1)\\n}\\n\\nimport user.{type User, User}\\n\\npub fn user_list(users: List(User)) -> List(String) {\\n    [User(name: \\\"John\\\", id: 1),\\n    User(name: \\\"Jane\\\", id: 2)]\\n}\\n\\n\"\n---\n----- BEFORE ACTION\n\npub fn create_user(name: String) -> User {\n    User(name: name, id: 1)\n    ▔▔▔▔▔↑                 \n}\n\nimport user.{type User, User}\n\npub fn user_list(users: List(User)) -> List(String) {\n    [User(name: \"John\", id: 1),\n    User(name: \"Jane\", id: 2)]\n}\n\n\n\n----- AFTER ACTION\n\npub fn create_user(name: String) -> User {\n    user.User(name: name, id: 1)\n}\n\nimport user.{type User, }\n\npub fn user_list(users: List(User)) -> List(String) {\n    [user.User(name: \"John\", id: 1),\n    user.User(name: \"Jane\", id: 2)]\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport mymath.{pi}\\n\\npub fn circle_area(radius: Float) -> Float {\\n    pi *. radius *. radius\\n}\\n\\npub fn circle_circumference(radius: Float) -> Float {\\n    2. *. pi *. radius\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport mymath.{pi}\n\npub fn circle_area(radius: Float) -> Float {\n    pi *. radius *. radius\n    ▔▔▔▔▔↑                \n}\n\npub fn circle_circumference(radius: Float) -> Float {\n    2. *. pi *. radius\n}\n\n\n----- AFTER ACTION\n\nimport mymath.{}\n\npub fn circle_area(radius: Float) -> Float {\n    mymath.pi *. radius *. radius\n}\n\npub fn circle_circumference(radius: Float) -> Float {\n    2. *. mymath.pi *. radius\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_constructor_complex_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{None, Some}\\n\\npub fn main() {\\n    case [Some(1), None] {\\n        [None, ..] -> todo\\n        [Some(_), ..] -> todo\\n        _ -> todo\\n    }\\n    case Some(1), Some(2) {\\n        None, Some(_) -> todo\\n        Some(_), Some(val) -> todo\\n        _ -> todo\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{None, Some}\n\npub fn main() {\n    case [Some(1), None] {\n          ▔▔▔▔▔↑          \n        [None, ..] -> todo\n        [Some(_), ..] -> todo\n        _ -> todo\n    }\n    case Some(1), Some(2) {\n        None, Some(_) -> todo\n        Some(_), Some(val) -> todo\n        _ -> todo\n    }\n}\n\n\n----- AFTER ACTION\n\nimport option.{None, }\n\npub fn main() {\n    case [option.Some(1), None] {\n        [None, ..] -> todo\n        [option.Some(_), ..] -> todo\n        _ -> todo\n    }\n    case option.Some(1), option.Some(2) {\n        None, option.Some(_) -> todo\n        option.Some(_), option.Some(val) -> todo\n        _ -> todo\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport list.{map}\\n\\npub fn main() {\\n    let identity = map([1, 2, 3], fn(x) { x })\\n    let double = map([1, 2, 3], fn(x) { x * 2 })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport list.{map}\n\npub fn main() {\n    let identity = map([1, 2, 3], fn(x) { x })\n                   ▔▔▔▔↑                      \n    let double = map([1, 2, 3], fn(x) { x * 2 })\n}\n\n\n----- AFTER ACTION\n\nimport list.{}\n\npub fn main() {\n    let identity = list.map([1, 2, 3], fn(x) { x })\n    let double = list.map([1, 2, 3], fn(x) { x * 2 })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_in_constant_record.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{Some}\\n\\nconst some = Some(1)\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{Some}\n\nconst some = Some(1)\n             ↑      \n\n\n----- AFTER ACTION\n\nimport option.{}\n\nconst some = option.Some(1)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_in_constant_var.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{None}\\n\\nconst none = None\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{None}\n\nconst none = None\n             ↑   \n\n\n----- AFTER ACTION\n\nimport option.{}\n\nconst none = option.None\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_in_list_and_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{Some}\\n\\npub fn main() {\\n    let list = [Some(1), option.None]\\n    let tuple = #(Some(2), option.None)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{Some}\n\npub fn main() {\n    let list = [Some(1), option.None]\n                ▔▔▔▔▔↑               \n    let tuple = #(Some(2), option.None)\n}\n\n\n----- AFTER ACTION\n\nimport option.{}\n\npub fn main() {\n    let list = [option.Some(1), option.None]\n    let tuple = #(option.Some(2), option.None)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_in_nested_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type Option, None}\\n\\ntype Result(a) {\\n  Result(expected: a, actual: Option(a))\\n}\\n\\nconst zero = Result(0, None)\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type Option, None}\n\ntype Result(a) {\n  Result(expected: a, actual: Option(a))\n}\n\nconst zero = Result(0, None)\n                       ↑    \n\n\n----- AFTER ACTION\n\nimport option.{type Option, }\n\ntype Result(a) {\n  Result(expected: a, actual: Option(a))\n}\n\nconst zero = Result(0, option.None)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_in_pattern_matching.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport result.{type Result, Ok, Error}\\n\\npub fn process_result(res: Result(Int, String)) -> Int {\\n    case res {\\n        Ok(value) -> value\\n        Error(_) -> 0\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport result.{type Result, Ok, Error}\n\npub fn process_result(res: Result(Int, String)) -> Int {\n    case res {\n        Ok(value) -> value\n        ▔▔▔↑              \n        Error(_) -> 0\n    }\n}\n\n\n----- AFTER ACTION\n\nimport result.{type Result, Error}\n\npub fn process_result(res: Result(Int, String)) -> Int {\n    case res {\n        result.Ok(value) -> value\n        Error(_) -> 0\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_multiple_line_aliased.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{\\n    type Option,\\n    None,\\n    Some\\n} as opt\\n\\npub fn main() {\\n  Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{\n    type Option,\n    None,\n    Some\n} as opt\n\npub fn main() {\n  Some(1)\n  ▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{\n    type Option,\n    None,\n    \n} as opt\n\npub fn main() {\n  opt.Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_multiple_line_bad_format_without_trailing_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type Option,\\n    Some\\n\\n}\\n\\npub fn main() {\\n  Some(1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type Option,\n    Some\n\n}\n\npub fn main() {\n  Some(1)\n  ▔▔▔▔↑  \n}\n\n\n----- AFTER ACTION\n\nimport option.{type Option,\n    \n\n}\n\npub fn main() {\n  option.Some(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_multiple_occurrences.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport list.{map, filter}\\n\\npub fn process_list(items: List(Int)) -> List(Int) {\\n    items\\n    |> map(fn(x) { x + 1 })\\n    |> map(fn(x) { x * 2 })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport list.{map, filter}\n\npub fn process_list(items: List(Int)) -> List(Int) {\n    items\n    |> map(fn(x) { x + 1 })\n    ▔▔▔▔▔▔↑                \n    |> map(fn(x) { x * 2 })\n}\n\n\n----- AFTER ACTION\n\nimport list.{filter}\n\npub fn process_list(items: List(Int)) -> List(Int) {\n    items\n    |> list.map(fn(x) { x + 1 })\n    |> list.map(fn(x) { x * 2 })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_nested_function_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport list.{map, flatten}\\nimport operation.{double}\\n\\npub fn process_names(names: List(List(Int))) -> List(Int) {\\n    names\\n    |> flatten\\n    |> map(double)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport list.{map, flatten}\nimport operation.{double}\n\npub fn process_names(names: List(List(Int))) -> List(Int) {\n    names\n    |> flatten\n    |> map(double)\n          ▔▔▔▔↑   \n}\n\n\n----- AFTER ACTION\n\nimport list.{map, flatten}\nimport operation.{}\n\npub fn process_names(names: List(List(Int))) -> List(Int) {\n    names\n    |> flatten\n    |> map(operation.double)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_record_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport user.{type User, User}\\n\\npub fn create_user(name: String) -> User {\\n    User(name: name, id: 1)\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport user.{type User, User}\n\npub fn create_user(name: String) -> User {\n    User(name: name, id: 1)\n    ▔▔▔▔▔↑                 \n}\n\n\n----- AFTER ACTION\n\nimport user.{type User, }\n\npub fn create_user(name: String) -> User {\n    user.User(name: name, id: 1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_type_annotation.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport option.{type Option, Some}\\n\\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\\n    case x {\\n        Some(value) -> Some(value + 1)\\n        _ -> x\\n    }\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport option.{type Option, Some}\n\npub fn maybe_increment(x: Option(Int)) -> Option(Int) {\n                          ▔▔▔↑                         \n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n\n\n----- AFTER ACTION\n\nimport option.{Some}\n\npub fn maybe_increment(x: option.Option(Int)) -> option.Option(Int) {\n    case x {\n        Some(value) -> Some(value + 1)\n        _ -> x\n    }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_variable_shadowing.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\n\\nimport wibble.{wobble}\\n\\npub fn example() {\\n  echo wobble\\n\\n  let wobble = 1\\n\\n  echo wobble\\n\\n  let _ = fn(wobble) {\\n    echo wobble\\n  }\\n\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\n\nimport wibble.{wobble}\n\npub fn example() {\n  echo wobble\n       ▔▔▔↑  \n\n  let wobble = 1\n\n  echo wobble\n\n  let _ = fn(wobble) {\n    echo wobble\n  }\n\n  todo\n}\n\n\n----- AFTER ACTION\n\n\nimport wibble.{}\n\npub fn example() {\n  echo wibble.wobble\n\n  let wobble = 1\n\n  echo wobble\n\n  let _ = fn(wobble) {\n    echo wobble\n  }\n\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_with_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport list.{map as transform}\\n\\npub fn double_list(items: List(Int)) -> List(Int) {\\n    transform(items, fn(x) { x * 2 })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport list.{map as transform}\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    transform(items, fn(x) { x * 2 })\n    ▔▔▔▔▔▔▔▔▔▔↑                      \n}\n\n\n----- AFTER ACTION\n\nimport list.{}\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    list.map(items, fn(x) { x * 2 })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualified_to_qualified_import_with_alias_and_module_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport list.{map as transform} as lst\\n\\npub fn double_list(items: List(Int)) -> List(Int) {\\n    transform(items, fn(x) { x * 2 })\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport list.{map as transform} as lst\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    transform(items, fn(x) { x * 2 })\n    ▔▔▔▔▔▔▔▔▔▔↑                      \n}\n\n\n----- AFTER ACTION\n\nimport list.{} as lst\n\npub fn double_list(items: List(Int)) -> List(Int) {\n    lst.map(items, fn(x) { x * 2 })\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__unqualify_already_imported_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\nimport wibble.{type Wibble}\\n\\npub fn main() -> wibble.Wibble {\\n  todo\\n}\\n\"\n---\n----- BEFORE ACTION\n\nimport wibble.{type Wibble}\n\npub fn main() -> wibble.Wibble {\n                 ↑              \n  todo\n}\n\n\n----- AFTER ACTION\n\nimport wibble.{type Wibble}\n\npub fn main() -> Wibble {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__use_label_shorthand_works_for_alternative_patterns.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(arg: Int, arg2: String) }\\n\\npub fn main() {\\n  case Wibble(1, \\\"wibble\\\") {\\n    Wibble(arg2: arg2, ..) | Wibble(arg: 1, arg2: arg2) -> todo\\n  }\\n}\\n \"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: String) }\n\npub fn main() {\n       ▔▔▔▔▔▔▔▔\n  case Wibble(1, \"wibble\") {\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    Wibble(arg2: arg2, ..) | Wibble(arg: 1, arg2: arg2) -> todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n  }\n}\n \n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: String) }\n\npub fn main() {\n  case Wibble(1, \"wibble\") {\n    Wibble(arg2: , ..) | Wibble(arg: 1, arg2: ) -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__use_label_shorthand_works_for_nested_calls.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn wibble(arg arg: Int) -> Int { arg }\\n\\npub fn main() {\\n  let arg = 1\\n  wibble(wibble(arg: arg))\\n}\\n \"\n---\n----- BEFORE ACTION\n\npub fn wibble(arg arg: Int) -> Int { arg }\n\npub fn main() {\n       ▔▔▔▔▔▔▔▔\n  let arg = 1\n▔▔▔▔▔▔▔▔▔▔▔▔▔\n  wibble(wibble(arg: arg))\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n↑\n \n\n\n----- AFTER ACTION\n\npub fn wibble(arg arg: Int) -> Int { arg }\n\npub fn main() {\n  let arg = 1\n  wibble(wibble(arg: ))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__use_label_shorthand_works_for_nested_patterns.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\\npub type Wobble { Wobble(arg: Int, arg2: String) }\\n\\npub fn main() {\\n  let Wibble(arg2: Wobble(arg: arg, arg2: arg2), ..) = todo\\n}\\n \"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\npub type Wobble { Wobble(arg: Int, arg2: String) }\n\npub fn main() {\n       ▔▔▔▔▔▔▔▔\n  let Wibble(arg2: Wobble(arg: arg, arg2: arg2), ..) = todo\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑   \n}\n \n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\npub type Wobble { Wobble(arg: Int, arg2: String) }\n\npub fn main() {\n  let Wibble(arg2: Wobble(arg: , arg2: ), ..) = todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__use_label_shorthand_works_for_nested_record_updates.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\\npub type Wobble { Wobble(arg: Int, arg2: String) }\\n\\npub fn main() {\\n  let arg = 1\\n  let arg2 = \\\"a\\\"\\n  Wibble(..todo, arg2: Wobble(arg: arg, arg2: arg2))\\n}\\n \"\n---\n----- BEFORE ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\npub type Wobble { Wobble(arg: Int, arg2: String) }\n\npub fn main() {\n  let arg = 1\n  let arg2 = \"a\"\n  Wibble(..todo, arg2: Wobble(arg: arg, arg2: arg2))\n           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑           \n}\n \n\n\n----- AFTER ACTION\n\npub type Wibble { Wibble(arg: Int, arg2: Wobble) }\npub type Wobble { Wobble(arg: Int, arg2: String) }\n\npub fn main() {\n  let arg = 1\n  let arg2 = \"a\"\n  Wibble(..todo, arg2: Wobble(arg: , arg2: ))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_assignment_value_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub fn main() {\\n  let var = \\\"value\\\"\\n}\"\n---\n----- BEFORE ACTION\npub fn main() {\n  let var = \"value\"\n             ▔▔▔▔↑ \n}\n\n\n----- AFTER ACTION\npub fn main() {\n  let var = {\n    \"value\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_case_assignment_of_record_access_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub type Record {\\n  R(left: Int, right: Int)\\n}\\n\\npub fn main() {\\n  let r = R(1, 2)\\n  let l = r.left\\n  l\\n}\\n\"\n---\n----- BEFORE ACTION\n\npub type Record {\n  R(left: Int, right: Int)\n}\n\npub fn main() {\n  let r = R(1, 2)\n  let l = r.left\n            ↑   \n  l\n}\n\n\n----- AFTER ACTION\n\npub type Record {\n  R(left: Int, right: Int)\n}\n\npub fn main() {\n  let r = R(1, 2)\n  let l = {\n    r.left\n  }\n  l\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_case_clause_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn f(option) {\\n  case option {\\n    Some(content) -> content\\n    None -> panic\\n  }\\n}\"\n---\n----- BEFORE ACTION\n\npub fn f(option) {\n  case option {\n    Some(content) -> content\n                     ↑      \n    None -> panic\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn f(option) {\n  case option {\n    Some(content) -> {\n      content\n    }\n    None -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_case_clause_inside_assignment_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type PokemonType {\\n  Air\\n  Water\\n  Fire\\n}\\n\\n  pub fn f(pokemon_type: PokemonType) {\\n    let damage = case pokemon_type {\\n      Water -> soak()\\n      Fire -> burn()\\n    }\\n\\n    \\\"Pokemon did \\\" <> damage\\n  }\"\n---\n----- BEFORE ACTION\npub type PokemonType {\n  Air\n  Water\n  Fire\n}\n\n  pub fn f(pokemon_type: PokemonType) {\n    let damage = case pokemon_type {\n      Water -> soak()\n      Fire -> burn()\n              ↑     \n    }\n\n    \"Pokemon did \" <> damage\n  }\n\n\n----- AFTER ACTION\npub type PokemonType {\n  Air\n  Water\n  Fire\n}\n\n  pub fn f(pokemon_type: PokemonType) {\n    let damage = case pokemon_type {\n      Water -> soak()\n      Fire -> {\n        burn()\n      }\n    }\n\n    \"Pokemon did \" <> damage\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_case_clause_with_guard_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn f(option) {\\n  case option {\\n    Some(integer) if integer > 0 -> integer\\n    Some(integer) -> 0\\n    None -> panic\\n  }\\n}\"\n---\n----- BEFORE ACTION\n\npub fn f(option) {\n  case option {\n    Some(integer) if integer > 0 -> integer\n                                    ↑      \n    Some(integer) -> 0\n    None -> panic\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn f(option) {\n  case option {\n    Some(integer) if integer > 0 -> {\n      integer\n    }\n    Some(integer) -> 0\n    None -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_case_clause_with_multiple_patterns_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"pub type PokemonType {\\n  Air\\n  Water\\n  Fire\\n}\\n\\n  pub fn f(pokemon_type: PokemonType) {\\n    case pokemon_type {\\n      Water | Air -> soak()\\n      Fire -> burn()\\n    }\\n  }\"\n---\n----- BEFORE ACTION\npub type PokemonType {\n  Air\n  Water\n  Fire\n}\n\n  pub fn f(pokemon_type: PokemonType) {\n    case pokemon_type {\n      Water | Air -> soak()\n                     ↑     \n      Fire -> burn()\n    }\n  }\n\n\n----- AFTER ACTION\npub type PokemonType {\n  Air\n  Water\n  Fire\n}\n\n  pub fn f(pokemon_type: PokemonType) {\n    case pokemon_type {\n      Water | Air -> {\n        soak()\n      }\n      Fire -> burn()\n    }\n  }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__action__wrap_nested_case_clause_in_block.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/action.rs\nexpression: \"\\npub fn f(result) {\\n  case result {\\n    Ok(reresult) -> {\\n      case reresult {\\n        Ok(w) -> w\\n        Error(_) -> panic\\n      }\\n    }\\n    Error(_) -> panic\\n  }\\n}\"\n---\n----- BEFORE ACTION\n\npub fn f(result) {\n  case result {\n    Ok(reresult) -> {\n      case reresult {\n        Ok(w) -> w\n                 ↑\n        Error(_) -> panic\n      }\n    }\n    Error(_) -> panic\n  }\n}\n\n\n----- AFTER ACTION\n\npub fn f(result) {\n  case result {\n    Ok(reresult) -> {\n      case reresult {\n        Ok(w) -> {\n          w\n        }\n        Error(_) -> panic\n      }\n    }\n    Error(_) -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__argument_shadowing.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main(x: Int) {\\n  fn(x: Float) {\\n\\n  }\\n}\\n\"\n---\npub fn main(x: Int) {\n  fn(x: Float) {\n|\n  }\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn(Int) -> fn(Float) -> a\n  sort:   03_main\n  desc:   app\n  edits:\n    [3:0-3:0]: \"main\"\nx\n  kind:   Variable\n  detail: Float\n  sort:   3_x\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"x\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__argument_variable_shadowing.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main(x: Int) {\\n  let x = [1, 2]\\n\\n}\\n\"\n---\npub fn main(x: Int) {\n  let x = [1, 2]\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn(Int) -> List(Int)\n  sort:   3_main\n  desc:   app\n  edits:\n    [3:0-3:0]: \"main\"\nx\n  kind:   Variable\n  detail: List(Int)\n  sort:   3_x\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"x\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__autocomplete_doesnt_delete_the_piece_of_code_that_comes_after.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: \"\\nimport list\\npub fn main(x: Int) {\\n  list.list.filter([1, 2, 3], todo)\\n}\\n\"\n---\nimport list\npub fn main(x: Int) {\n  list.|list.filter([1, 2, 3], todo)\n}\n\n\n----- After applying completion -----\n\nimport list\npub fn main(x: Int) {\n  list.maplist.filter([1, 2, 3], todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__autocomplete_doesnt_delete_the_piece_of_code_that_comes_after_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: \"\\nimport list\\npub fn main(x: Int) {\\n  list.mlist.filter([1, 2, 3], todo)\\n}\\n\"\n---\nimport list\npub fn main(x: Int) {\n  list.m|list.filter([1, 2, 3], todo)\n}\n\n\n----- After applying completion -----\n\nimport list\npub fn main(x: Int) {\n  list.maplist.filter([1, 2, 3], todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__case_subject.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: \"\\npub fn main(something: Bool) {\\n  case so\\n}\\n\"\n---\npub fn main(something: Bool) {\n  case so|\n}\n\n\n----- After applying completion -----\n\npub fn main(something: Bool) {\n  case something\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__complete_echo_keyword.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"pub fn main() { e wibble }\"\n---\npub fn main() { e| wibble }\n\n\n----- After applying completion -----\npub fn main() { echo wibble }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__complete_keyword_being_typed.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"pub fn main() { t }\"\n---\npub fn main() { t| }\n\n\n----- After applying completion -----\npub fn main() { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__complete_panic_keyword.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"pub fn main() { wibble(p) }\"\n---\npub fn main() { wibble(p|) }\n\n\n----- After applying completion -----\npub fn main() { wibble(panic) }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completion_for_partially_correct_existing_module_select.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport gleam/list\\n\\npub fn new() {\\n  list.fer\\n//      ^ cursor right after the 'f'\\n}\\n\"\n---\nimport gleam/list\n\npub fn new() {\n  list.f|er\n//      ^ cursor right after the 'f'\n}\n\n\n----- Completion content -----\nlist.filter\n  kind:   Function\n  detail: fn() -> a\n  sort:   4_list.filter\n  desc:   app\n  edits:\n    [4:2-4:10]: \"list.filter\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completion_for_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"pub fn new() -> wibble.Wibble {}\"\n---\npub fn new() -> wibble.|Wibble {}\n\n\n----- Completion content -----\nwibble.Wibble\n  kind:   Class\n  detail: Type\n  sort:   6_wibble.Wibble\n    [0:0-0:0]: \"import wibble\\n\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_a_const_annotation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n\\nconst wibble: Int = 7\\n\\npub fn main() {\\n  let wibble: Int = 7\\n}\\n\"\n---\nconst wibble: In|t = 7\n\npub fn main() {\n  let wibble: Int = 7\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_a_function_arg_annotation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\npub fn wibble(\n  _: String|,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_a_function_return_annotation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\npub fn wibble(\n  _: String,\n) -> Ni|l {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_a_var_annotation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let wibble: Int = 7\\n}\\n\"\n---\npub fn main() {\n  let wibble: In|t = 7\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport dep|\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\ngleam\n  kind:   Module\n  edits:\n    [0:7-0:10]: \"gleam\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_from_dependency.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nexample_module\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"example_module\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_from_dependency_with_docs.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"//// Main package\\n//// documentation!\\n\\nimport gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\n//// Main package\n//// documentation!\n\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nexample_module\n  kind:   Module\n  edits:\n    [3:7-3:12]: \"example_module\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_no_test.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_not_from_dev_dependency.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nexample_module\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"example_module\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_not_from_dev_dependency_in_dev.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\\n\"\n---\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\napp\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"app\"\nexample_module\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"example_module\"\nindirect_module\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"indirect_module\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_not_from_dev_dependency_in_test.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: completions\n---\n[\n    CompletionItem {\n        label: \"app\",\n        label_details: None,\n        kind: Some(\n            Module,\n        ),\n        detail: None,\n        documentation: None,\n        deprecated: None,\n        preselect: None,\n        sort_text: None,\n        filter_text: None,\n        insert_text: None,\n        insert_text_format: None,\n        insert_text_mode: None,\n        text_edit: Some(\n            Edit(\n                TextEdit {\n                    range: Range {\n                        start: Position {\n                            line: 0,\n                            character: 7,\n                        },\n                        end: Position {\n                            line: 0,\n                            character: 12,\n                        },\n                    },\n                    new_text: \"app\",\n                },\n            ),\n        ),\n        additional_text_edits: None,\n        command: None,\n        commit_characters: None,\n        data: None,\n        tags: None,\n    },\n    CompletionItem {\n        label: \"example_module\",\n        label_details: None,\n        kind: Some(\n            Module,\n        ),\n        detail: None,\n        documentation: None,\n        deprecated: None,\n        preselect: None,\n        sort_text: None,\n        filter_text: None,\n        insert_text: None,\n        insert_text_format: None,\n        insert_text_mode: None,\n        text_edit: Some(\n            Edit(\n                TextEdit {\n                    range: Range {\n                        start: Position {\n                            line: 0,\n                            character: 7,\n                        },\n                        end: Position {\n                            line: 0,\n                            character: 12,\n                        },\n                    },\n                    new_text: \"example_module\",\n                },\n            ),\n        ),\n        additional_text_edits: None,\n        command: None,\n        commit_characters: None,\n        data: None,\n        tags: None,\n    },\n    CompletionItem {\n        label: \"indirect_module\",\n        label_details: None,\n        kind: Some(\n            Module,\n        ),\n        detail: None,\n        documentation: None,\n        deprecated: None,\n        preselect: None,\n        sort_text: None,\n        filter_text: None,\n        insert_text: None,\n        insert_text_format: None,\n        insert_text_mode: None,\n        text_edit: Some(\n            Edit(\n                TextEdit {\n                    range: Range {\n                        start: Position {\n                            line: 0,\n                            character: 7,\n                        },\n                        end: Position {\n                            line: 0,\n                            character: 12,\n                        },\n                    },\n                    new_text: \"indirect_module\",\n                },\n            ),\n        ),\n        additional_text_edits: None,\n        command: None,\n        commit_characters: None,\n        data: None,\n        tags: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_not_from_indirect_dependency.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nexample_module\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"example_module\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_preceeding_whitespace.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \" import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\n i|mport gleam\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\ndep\n  kind:   Module\n  edits:\n    [0:7-0:13]: \"dep\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_start.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\n|import gleam\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\ndep\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"dep\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_while_in_dev.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport gleam|\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\napp\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"app\"\ndev_helper\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"dev_helper\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_while_in_test.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: completions\n---\n[\n    CompletionItem {\n        label: \"app\",\n        label_details: None,\n        kind: Some(\n            Module,\n        ),\n        detail: None,\n        documentation: None,\n        deprecated: None,\n        preselect: None,\n        sort_text: None,\n        filter_text: None,\n        insert_text: None,\n        insert_text_format: None,\n        insert_text_mode: None,\n        text_edit: Some(\n            Edit(\n                TextEdit {\n                    range: Range {\n                        start: Position {\n                            line: 0,\n                            character: 7,\n                        },\n                        end: Position {\n                            line: 0,\n                            character: 12,\n                        },\n                    },\n                    new_text: \"app\",\n                },\n            ),\n        ),\n        additional_text_edits: None,\n        command: None,\n        commit_characters: None,\n        data: None,\n        tags: None,\n    },\n    CompletionItem {\n        label: \"test_helper\",\n        label_details: None,\n        kind: Some(\n            Module,\n        ),\n        detail: None,\n        documentation: None,\n        deprecated: None,\n        preselect: None,\n        sort_text: None,\n        filter_text: None,\n        insert_text: None,\n        insert_text_format: None,\n        insert_text_mode: None,\n        text_edit: Some(\n            Edit(\n                TextEdit {\n                    range: Range {\n                        start: Position {\n                            line: 0,\n                            character: 7,\n                        },\n                        end: Position {\n                            line: 0,\n                            character: 12,\n                        },\n                    },\n                    new_text: \"test_helper\",\n                },\n            ),\n        ),\n        additional_text_edits: None,\n        command: None,\n        commit_characters: None,\n        data: None,\n        tags: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_import_with_docs.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport gle|am\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\ndep\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"dep\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_unqualified_import.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep.{}\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport dep.{|}\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nWibble\n  kind:   Class\n  detail: Type\n  sort:   4_Wibble\n  edits:\n    [1:12-1:12]: \"type Wibble\"\nmyfun\n  kind:   Function\n  detail: fn() -> Int\n  sort:   4_myfun\n  desc:   dep\n  edits:\n    [1:12-1:12]: \"myfun\"\nwabble\n  kind:   Constant\n  detail: String\n  sort:   4_wabble\n  desc:   dep\n  edits:\n    [1:12-1:12]: \"wabble\"\nwibble\n  kind:   Constant\n  detail: String\n  sort:   4_wibble\n  desc:   dep\n  edits:\n    [1:12-1:12]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_unqualified_import_already_imported.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep.{wibble,wabble,type Wibble}\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport dep.{|wibble,wabble,type Wibble}\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nmyfun\n  kind:   Function\n  detail: fn() -> Int\n  sort:   4_myfun\n  desc:   dep\n  edits:\n    [1:12-1:12]: \"myfun\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_an_unqualified_import_on_new_line.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep.{\\n  wibble,\\n\\n}\\n\\npub fn main() {\\n  0\\n}\"\n---\nimport dep.{\n  wibble,\n|\n}\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nWibble\n  kind:   Class\n  detail: Type\n  sort:   4_Wibble\n  edits:\n    [3:0-3:0]: \"type Wibble\"\nmyfun\n  kind:   Function\n  detail: fn() -> Int\n  sort:   4_myfun\n  desc:   dep\n  edits:\n    [3:0-3:0]: \"myfun\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_function_labels.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn wibble(wibble arg1: String, wobble arg2: String) {\\n  arg1 <> arg2\\n}\\n\\nfn fun() { // completion inside parens below includes labels\\n  let wibble = wibble()\\n}\\n\"\n---\nfn wibble(wibble arg1: String, wobble arg2: String) {\n  arg1 <> arg2\n}\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = wibble(|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nfun\n  kind:   Function\n  detail: fn() -> String\n  sort:   3_fun\n  desc:   app\n  edits:\n    [6:22-6:22]: \"fun\"\nwibble\n  kind:   Function\n  detail: fn(String, String) -> String\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [6:22-6:22]: \"wibble\"\nwibble:\n  kind:   Field\n  detail: String\n  sort:   1_wibble:\nwobble:\n  kind:   Field\n  detail: String\n  sort:   1_wobble:\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_imported_function_labels.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\\nfn fun() { // completion inside parens below includes labels\\n  let wibble = dep.wibble()\\n}\\n\"\n---\nimport dep\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = dep.wibble(|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wibble\n  kind:   Function\n  detail: fn(String, String) -> String\n  sort:   4_dep.wibble\n  desc:   app\n  edits:\n    [4:26-4:26]: \"dep.wibble\"\nfun\n  kind:   Function\n  detail: fn() -> String\n  sort:   3_fun\n  desc:   app\n  edits:\n    [4:26-4:26]: \"fun\"\nwibble:\n  kind:   Field\n  detail: String\n  sort:   1_wibble:\nwobble:\n  kind:   Field\n  detail: String\n  sort:   1_wobble:\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_imported_record_fields.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\\nfn fun(wibble: dep.Wibble) {\\n  wibble.\\n  //     ^ We should see wibble and wobble completions here!\\n}\\n\"\n---\nimport dep\n\nfn fun(wibble: dep.Wibble) {\n  wibble.|\n  //     ^ We should see wibble and wobble completions here!\n}\n\n\n----- Completion content -----\nwibble\n  kind:   Field\n  detail: String\n  sort:   2_wibble\nwobble\n  kind:   Field\n  detail: Int\n  sort:   2_wobble\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_imported_record_labels.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\\nfn fun() { // completion inside parens below includes labels\\n  let wibble = dep.Wibble()\\n}\\n\"\n---\nimport dep\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = dep.Wibble(|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.Wibble\n  kind:   Constructor\n  detail: fn(String, Int) -> Wibble\n  sort:   4_dep.Wibble\n  desc:   app\n  edits:\n    [4:26-4:26]: \"dep.Wibble\"\nfun\n  kind:   Function\n  detail: fn() -> Wibble\n  sort:   3_fun\n  desc:   app\n  edits:\n    [4:26-4:26]: \"fun\"\nwibble:\n  kind:   Field\n  detail: String\n  sort:   1_wibble:\nwobble:\n  kind:   Field\n  detail: Int\n  sort:   1_wobble:\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_internal_record_fields_inside_the_same_module.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n@internal\\npub type Wibble {\\n    Wibble(wibble: String, wobble: Int)\\n}\\n\\nfn fun(wibble: Wibble) {\\n  wibble.\\n  //     ^ We should see some completions here!\\n}\\n\"\n---\n@internal\npub type Wibble {\n    Wibble(wibble: String, wobble: Int)\n}\n\nfn fun(wibble: Wibble) {\n  wibble.|\n  //     ^ We should see some completions here!\n}\n\n\n----- Completion content -----\nwibble\n  kind:   Field\n  detail: String\n  sort:   2_wibble\nwobble\n  kind:   Field\n  detail: Int\n  sort:   2_wobble\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_labels_in_record_update.snap.new",
    "content": "---\nsource: language-server/src/tests/completion.rs\nassertion_line: 2430\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Int, woo: Int)\\n}\\n\\npub fn main() {\\n  Wibble(..todo, w)\\n}\\n\\npub fn wibble() { todo }\\n\"\nsnapshot_kind: text\n---\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int, woo: Int)\n}\n\npub fn main() {\n  Wibble(..todo, w|)\n}\n\npub fn wibble() { todo }\n\n\n----- Completion content -----\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_outside_a_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: \"\\n\\npub fn main() {\\n  0\\n}\"\n---\n|\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_prelude_values.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let my_bool = T\\n}\\n\"\n---\npub fn main() {\n  let my_bool = T|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [2:16-2:17]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_private_record_access.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: Int, wobble: Int)\\n  Wobble(wabble: Int, wobble: Int)\\n}\\n\\nfn fun() {\\n  let wibble = Wibble(1, 2)\\n  wibble.wobble\\n}\\n\"\n---\ntype Wibble {\n  Wibble(wibble: Int, wobble: Int)\n  Wobble(wabble: Int, wobble: Int)\n}\n\nfn fun() {\n  let wibble = Wibble(1, 2)\n  wibble.wobble|\n}\n\n\n----- Completion content -----\nwibble\n  kind:   Field\n  detail: Int\n  sort:   02_wibble\nwobble\n  kind:   Field\n  detail: Int\n  sort:   02_wobble\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_record_access.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Int)\\n  Wobble(wabble: Int, wobble: Int)\\n}\\n\\nfn fun() {\\n  let wibble = Wibble(1, 2)\\n  wibble.wobble\\n}\\n\"\n---\npub type Wibble {\n  Wibble(wibble: Int, wobble: Int)\n  Wobble(wabble: Int, wobble: Int)\n}\n\nfn fun() {\n  let wibble = Wibble(1, 2)\n  wibble.wobble|\n}\n\n\n----- Completion content -----\nwibble\n  kind:   Field\n  detail: Int\n  sort:   02_wibble\nwobble\n  kind:   Field\n  detail: Int\n  sort:   02_wobble\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_record_access_known_variant.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Int, c: Int, d: Int)\\n  Wobble(z: Bool)\\n}\\n\\nfn fun(some_wibble: Wibble) {\\n  case some_wibble {\\n    Wibble(..) as w -> w.a\\n    Wobble(..) -> panic\\n  }\\n}\\n\"\n---\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int, d: Int)\n  Wobble(z: Bool)\n}\n\nfn fun(some_wibble: Wibble) {\n  case some_wibble {\n    Wibble(..) as w -> w.a|\n    Wobble(..) -> panic\n  }\n}\n\n\n----- Completion content -----\na\n  kind:   Field\n  detail: Int\n  sort:   02_a\nb\n  kind:   Field\n  detail: Int\n  sort:   02_b\nc\n  kind:   Field\n  detail: Int\n  sort:   02_c\nd\n  kind:   Field\n  detail: Int\n  sort:   02_d\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_record_access_unknown_variant.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Int, c: Int, d: Int)\\n  Wobble(a: Int, z: Bool)\\n}\\n\\nfn fun(some_wibble: Wibble) {\\n  some_wibble.a\\n}\\n\"\n---\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int, d: Int)\n  Wobble(a: Int, z: Bool)\n}\n\nfn fun(some_wibble: Wibble) {\n  some_wibble.a|\n}\n\n\n----- Completion content -----\na\n  kind:   Field\n  detail: Int\n  sort:   02_a\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_record_labels.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: String, wobble: Int)\\n}\\n\\nfn fun() { // completion inside parens below includes labels\\n  let wibble = Wibble()\\n}\\n\"\n---\npub type Wibble {\n  Wibble(wibble: String, wobble: Int)\n}\n\nfn fun() { // completion inside parens below includes labels\n  let wibble = Wibble(|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWibble\n  kind:   Constructor\n  detail: fn(String, Int) -> Wibble\n  sort:   3_Wibble\n  desc:   app\n  edits:\n    [6:22-6:22]: \"Wibble\"\nfun\n  kind:   Function\n  detail: fn() -> Wibble\n  sort:   3_fun\n  desc:   app\n  edits:\n    [6:22-6:22]: \"fun\"\nwibble:\n  kind:   Field\n  detail: String\n  sort:   1_wibble:\nwobble:\n  kind:   Field\n  detail: Int\n  sort:   1_wobble:\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__completions_for_type_import_completions_without_brackets.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: import dep.\n---\nimport dep.|\n\n\n----- Completion content -----\nWibble\n  kind:   Class\n  detail: Type\n  sort:   4_Wibble\n  edits:\n    [0:11-0:11]: \"{type Wibble}\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__constant.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nconst hello = 10\\nconst world = he\\n\"\n---\nconst hello = 10\nconst world = he|\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nhello\n  kind:   Constant\n  detail: Int\n  sort:   3_hello\n  desc:   app\n  edits:\n    [2:14-2:16]: \"hello\"\nworld\n  kind:   Constant\n  detail: a\n  sort:   3_world\n  desc:   app\n  edits:\n    [2:14-2:16]: \"world\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__constant_with_many_options.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport wibble.{Wobble}\\n\\ntype Wibble {\\n  Wibble\\n}\\n\\nconst pi = 3.14159\\n\\nfn some_function() {\\n  todo\\n}\\n\\nconst my_constant = a\\n\"\n---\nimport wibble.{Wobble}\n\ntype Wibble {\n  Wibble\n}\n\nconst pi = 3.14159\n\nfn some_function() {\n  todo\n}\n\nconst my_constant = a|\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWibble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   3_Wibble\n  desc:   app\n  edits:\n    [13:20-13:21]: \"Wibble\"\nWobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   4_Wobble\n  desc:   app\n  edits:\n    [13:20-13:21]: \"Wobble\"\nmy_constant\n  kind:   Constant\n  detail: a\n  sort:   3_my_constant\n  desc:   app\n  edits:\n    [13:20-13:21]: \"my_constant\"\npi\n  kind:   Constant\n  detail: Float\n  sort:   3_pi\n  desc:   app\n  edits:\n    [13:20-13:21]: \"pi\"\nsome_function\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_some_function\n  desc:   app\n  edits:\n    [13:20-13:21]: \"some_function\"\nwibble.Wobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   4_wibble.Wobble\n  desc:   app\n  edits:\n    [13:20-13:21]: \"wibble.Wobble\"\nwibble.Wubble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   4_wibble.Wubble\n  desc:   app\n  edits:\n    [13:20-13:21]: \"wibble.Wubble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__constant_with_module_select.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport wibble\\n\\ntype Wibble {\\n  Wibble\\n}\\n\\nconst pi = 3.14159\\n\\nfn some_function() {\\n  todo\\n}\\n\\nconst my_constant = wibble.W\\n\"\n---\nimport wibble\n\ntype Wibble {\n  Wibble\n}\n\nconst pi = 3.14159\n\nfn some_function() {\n  todo\n}\n\nconst my_constant = wibble.W|\n\n\n----- Completion content -----\nwibble.Wobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   4_wibble.Wobble\n  desc:   app\n  edits:\n    [13:20-13:28]: \"wibble.Wobble\"\nwibble.Wubble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   4_wibble.Wubble\n  desc:   app\n  edits:\n    [13:20-13:28]: \"wibble.Wubble\"\nwibble.some_constant\n  kind:   Constant\n  detail: Int\n  sort:   4_wibble.some_constant\n  desc:   app\n  edits:\n    [13:20-13:28]: \"wibble.some_constant\"\nwibble.some_function\n  kind:   Function\n  detail: fn() -> a\n  sort:   4_wibble.some_function\n  desc:   app\n  edits:\n    [13:20-13:28]: \"wibble.some_function\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__do_not_show_completions_when_typing_a_number.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() { 2 }\\npub fn window_by_2() {}\\npub fn to_base_32() {}\\n\"\n---\npub fn main() { 2| }\npub fn window_by_2() {}\npub fn to_base_32() {}\n\n\n----- Completion content -----\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__for_custom_type_definition.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wobble\\n}\"\n---\npub type Wibble {\n|  Wobble\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\nWibble\n  kind:   Class\n  detail: Type\n  sort:   3_Wibble\n  edits:\n    [2:0-2:0]: \"Wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__for_function_arguments.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__for_type_alias.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble = Result(\\n  String,\\n  String\\n)\\n\"\n---\npub type Wibble = Result(\n|  String,\n  String\n)\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\nWibble\n  kind:   Class\n  detail: Type\n  sort:   3_Wibble\n  edits:\n    [2:0-2:0]: \"Wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_adds_extra_new_line_if_import_exists_below_other_definitions.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep2\\n\"\n---\n|\nimport dep2\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   dep\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import dep\\n\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_adds_extra_new_line_if_no_imports.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\"\n---\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   dep\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import dep\\n\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_does_not_add_extra_new_line_if_imports_exist.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\"\n---\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   dep\n  edits:\n    [3:0-3:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import dep\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_does_not_add_extra_new_line_if_newline_exists.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\"\n---\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   dep\n  edits:\n    [2:0-2:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import dep\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_module_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n\"\n---\n|\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   dep\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import dep\\n\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_module_function_from_deep_module.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n\"\n---\n|\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   a/b/dep\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import a/b/dep\\n\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_module_function_with_existing_imports.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n//// Some module comments\\n// Some other whitespace\\n\\nimport dep2\\n\"\n---\n|\n//// Some module comments\n// Some other whitespace\n\nimport dep2\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   6_dep.wobble\n  desc:   dep\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\n    [0:0-0:0]: \"import dep\\n\\n\"\ndep2.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   4_dep2.wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep2.wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   6_dep.Zoo\n  edits:\n    [3:0-3:0]: \"dep.Zoo\"\n    [0:0-0:0]: \"import dep\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_type_from_deep_module.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   6_dep.Zoo\n  edits:\n    [3:0-3:0]: \"dep.Zoo\"\n    [0:0-0:0]: \"import a/b/dep\\n\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_type_with_existing_imports.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n//// Some module comments\\n// Some other whitespace\\n\\nimport dep2\\n\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\n//// Some module comments\n// Some other whitespace\n\nimport dep2\n\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   6_dep.Zoo\n  edits:\n    [7:0-7:0]: \"dep.Zoo\"\n    [4:0-4:0]: \"import dep\\n\"\ndep2.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep2.Zoo\n  edits:\n    [7:0-7:0]: \"dep2.Zoo\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__importable_type_with_existing_imports_at_top.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep2\\n\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep2\n\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   6_dep.Zoo\n  edits:\n    [3:0-3:0]: \"dep.Zoo\"\n    [0:0-0:0]: \"import dep\\n\"\ndep2.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep2.Zoo\n  edits:\n    [3:0-3:0]: \"dep2.Zoo\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_module_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\"\n---\n|\nimport dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   4_dep.wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_public_enum.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\"\n---\n|\nimport dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.Left\n  kind:   EnumMember\n  detail: Direction\n  sort:   4_dep.Left\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Left\"\ndep.Right\n  kind:   EnumMember\n  detail: Direction\n  sort:   4_dep.Right\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Right\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_public_record.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\"\n---\n|\nimport dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.Box\n  kind:   Constructor\n  detail: fn(Int) -> Box\n  sort:   4_dep.Box\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Box\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep\n\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Zoo\n  edits:\n    [3:0-3:0]: \"dep.Zoo\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_type_cursor_after_dot.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn wibble(\\n  _: dep.Zoo,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep\n\npub fn wibble(\n  _: dep.Zoo|,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Zoo\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_type_cursor_after_dot_other_matching_modules.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\nimport dep2\\n\\npub fn wibble(\\n  _: dep.Zoo,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep\nimport dep2\n\npub fn wibble(\n  _: dep.Zoo|,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Zoo\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_type_cursor_after_dot_other_modules.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn wibble(\\n  _: dep.Zoo,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep\n\npub fn wibble(\n  _: dep.Zoo|,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Zoo\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_type_cursor_mid_phrase_other_modules.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn wibble(\\n  _: dep.Zoo,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep\n\npub fn wibble(\n  _: dep|.Zoo,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Zoo\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_unqualified_module_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep.{wobble}\\n\"\n---\n|\nimport dep.{wobble}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.wobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   4_dep.wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.wobble\"\nwobble\n  kind:   Function\n  detail: fn() -> Nil\n  sort:   4_wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_unqualified_public_enum.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep.{Left}\\n\"\n---\n|\nimport dep.{Left}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nLeft\n  kind:   EnumMember\n  detail: Direction\n  sort:   4_Left\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Left\"\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.Left\n  kind:   EnumMember\n  detail: Direction\n  sort:   4_dep.Left\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Left\"\ndep.Right\n  kind:   EnumMember\n  detail: Direction\n  sort:   4_dep.Right\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Right\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__imported_unqualified_public_record.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep.{Box}\\n\"\n---\n|\nimport dep.{Box}\n\n\n----- Completion content -----\nBox\n  kind:   Constructor\n  detail: fn(Int) -> Box\n  sort:   4_Box\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Box\"\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.Box\n  kind:   Constructor\n  detail: fn(Int) -> Box\n  sort:   4_dep.Box\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Box\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__in_custom_type_definition.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: import dep\n---\n|import dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_modules_from_same_package_are_included.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import gleam\\n\\npub fn main() {\\n  0\\n}\"\n---\n|import gleam\n\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\napp/internal\n  kind:   Module\n  edits:\n    [0:7-0:12]: \"app/internal\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_types_from_a_dependency_are_ignored.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn wibble(\\n    _: String,\\n) -> Nil {\\n    Nil\\n}\"\n---\nimport dep\n\npub fn wibble(\n|    _: String,\n) -> Nil {\n    Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_types_from_root_package_are_in_the_completions.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep\\n\\npub fn wibble(\\n    _: String,\\n) -> Nil {\\n    Nil\\n}\"\n---\nimport dep\n\npub fn wibble(\n|    _: String,\n) -> Nil {\n    Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\ndep.Alias\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Alias\n  edits:\n    [3:0-3:0]: \"dep.Alias\"\ndep.AnotherType\n  kind:   Class\n  detail: Type\n  sort:   4_dep.AnotherType\n  edits:\n    [3:0-3:0]: \"dep.AnotherType\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_types_from_the_same_module_are_in_the_completions.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n@internal pub type Alias = Result(Int, String)\\n@internal pub type AnotherType {\\n  Wibble\\n}\\n\"\n---\n@internal pub type Alias = Result(Int, String)\n@internal pub type AnotherType {\n|  Wibble\n}\n\n\n----- Completion content -----\nAlias\n  kind:   Class\n  detail: Type\n  sort:   3_Alias\n  edits:\n    [3:0-3:0]: \"Alias\"\nAnotherType\n  kind:   Class\n  detail: Type\n  sort:   3_AnotherType\n  edits:\n    [3:0-3:0]: \"AnotherType\"\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_values_from_a_dependency_are_ignored.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: import dep\n---\n|import dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_values_from_root_package_are_in_the_completions.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: import dep\n---\n|import dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\ndep.Wobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   4_dep.Wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.Wobble\"\ndep.main\n  kind:   Function\n  detail: fn() -> Int\n  sort:   4_dep.main\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.main\"\ndep.random_float\n  kind:   Function\n  detail: fn() -> Float\n  sort:   4_dep.random_float\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.random_float\"\ndep.wibble\n  kind:   Constant\n  detail: Int\n  sort:   4_dep.wibble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"dep.wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__internal_values_from_the_same_module_are_in_the_completions.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n@external(erlang, \\\"rand\\\", \\\"uniform\\\")\\n@internal pub fn random_float() -> Float\\n@internal pub fn main() { 0 }\\n@internal pub type Wibble { Wobble }\\n@internal pub const wibble = 1\\n\"\n---\n|\n@external(erlang, \"rand\", \"uniform\")\n@internal pub fn random_float() -> Float\n@internal pub fn main() { 0 }\n@internal pub type Wibble { Wobble }\n@internal pub const wibble = 1\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   3_Wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Wobble\"\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [1:0-1:0]: \"main\"\nrandom_float\n  kind:   Function\n  detail: fn() -> Float\n  sort:   3_random_float\n  desc:   app\n  edits:\n    [1:0-1:0]: \"random_float\"\nwibble\n  kind:   Constant\n  detail: Int\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__labelled_arguments.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Float)\\n}\\n\\npub fn main() {\\n  Wibble(w)\\n}\\n\"\n---\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble(w|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWibble\n  kind:   Constructor\n  detail: fn(Int, Float) -> Wibble\n  sort:   3_Wibble\n  desc:   app\n  edits:\n    [6:9-6:10]: \"Wibble\"\nmain\n  kind:   Function\n  detail: fn() -> Wibble\n  sort:   3_main\n  desc:   app\n  edits:\n    [6:9-6:10]: \"main\"\nwibble:\n  kind:   Field\n  detail: Int\n  sort:   1_wibble:\nwobble:\n  kind:   Field\n  detail: Float\n  sort:   1_wobble:\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__labelled_arguments_after_label.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Float)\\n}\\n\\npub fn main() {\\n  Wibble(wibble: w)\\n}\\n\"\n---\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble(wibble: w|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWibble\n  kind:   Constructor\n  detail: fn(Int, Float) -> Wibble\n  sort:   3_Wibble\n  desc:   app\n  edits:\n    [6:17-6:18]: \"Wibble\"\nmain\n  kind:   Function\n  detail: fn() -> Wibble\n  sort:   3_main\n  desc:   app\n  edits:\n    [6:17-6:18]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__labelled_arguments_from_different_module.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.divide(10, b)\\n}\\n\"\n---\nimport wibble\n\npub fn main() {\n  wibble.divide(10, b|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nby:\n  kind:   Field\n  detail: Int\n  sort:   1_by:\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [4:20-4:21]: \"main\"\nwibble.divide\n  kind:   Function\n  detail: fn(Int, Int) -> Int\n  sort:   4_wibble.divide\n  desc:   app\n  edits:\n    [4:20-4:21]: \"wibble.divide\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__labelled_arguments_function_call.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn divide(x: Int, by y: Int) { x / y }\\n\\npub fn main() {\\n  divide(10, b)\\n}\\n\"\n---\npub fn divide(x: Int, by y: Int) { x / y }\n\npub fn main() {\n  divide(10, b|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nby:\n  kind:   Field\n  detail: Int\n  sort:   1_by:\ndivide\n  kind:   Function\n  detail: fn(Int, Int) -> Int\n  sort:   3_divide\n  desc:   app\n  edits:\n    [4:13-4:14]: \"divide\"\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [4:13-4:14]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__labelled_arguments_with_existing_label.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Float)\\n}\\n\\npub fn main() {\\n  Wibble(wibble: 10, w)\\n}\\n\"\n---\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble(wibble: 10, w|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWibble\n  kind:   Constructor\n  detail: fn(Int, Float) -> Wibble\n  sort:   3_Wibble\n  desc:   app\n  edits:\n    [6:21-6:22]: \"Wibble\"\nmain\n  kind:   Function\n  detail: fn() -> Wibble\n  sort:   3_main\n  desc:   app\n  edits:\n    [6:21-6:22]: \"main\"\nwobble:\n  kind:   Field\n  detail: Float\n  sort:   1_wobble:\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_private_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\ntype Zoo = Int\\n\\npub fn wibble(\\n  x: String,\\n) -> String {\\n  \\\"ok\\\"\\n}\\n\"\n---\ntype Zoo = Int\n\npub fn wibble(\n|  x: String,\n) -> String {\n  \"ok\"\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\nZoo\n  kind:   Class\n  detail: Type\n  sort:   3_Zoo\n  edits:\n    [4:0-4:0]: \"Zoo\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_public_enum.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Direction {\\n  Left\\n  Right\\n}\\n\"\n---\n|\npub type Direction {\n  Left\n  Right\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nLeft\n  kind:   EnumMember\n  detail: Direction\n  sort:   3_Left\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Left\"\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nRight\n  kind:   EnumMember\n  detail: Direction\n  sort:   3_Right\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Right\"\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_public_enum_with_documentation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Direction {\\n  /// Hello\\n  Left\\n  /// Goodbye\\n  Right\\n}\\n\"\n---\n|\npub type Direction {\n  /// Hello\n  Left\n  /// Goodbye\n  Right\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nLeft\n  kind:   EnumMember\n  detail: Direction\n  sort:   3_Left\n  desc:   app\n  docs:   \" Hello\\n\"\n  edits:\n    [1:0-1:0]: \"Left\"\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nRight\n  kind:   EnumMember\n  detail: Direction\n  sort:   3_Right\n  desc:   app\n  docs:   \" Goodbye\\n\"\n  edits:\n    [1:0-1:0]: \"Right\"\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_public_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  0\\n}\"\n---\n|\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [1:0-1:0]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_public_function_with_documentation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\n/// Hello\\npub fn main() {\\n  0\\n}\"\n---\n|\n/// Hello\npub fn main() {\n  0\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  docs:   \" Hello\\n\"\n  edits:\n    [1:0-1:0]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_public_record.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Box {\\n/// Hello\\n  Box(Int, Int, Float)\\n}\\n\"\n---\n|\npub type Box {\n/// Hello\n  Box(Int, Int, Float)\n}\n\n\n----- Completion content -----\nBox\n  kind:   Constructor\n  detail: fn(Int, Int, Float) -> Box\n  sort:   3_Box\n  desc:   app\n  docs:   \" Hello\\n\"\n  edits:\n    [1:0-1:0]: \"Box\"\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_public_record_with_documentation.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Box {\\n  Box(Int, Int, Float)\\n}\\n\"\n---\n|\npub type Box {\n  Box(Int, Int, Float)\n}\n\n\n----- Completion content -----\nBox\n  kind:   Constructor\n  detail: fn(Int, Int, Float) -> Box\n  sort:   3_Box\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Box\"\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main(wibble: Int) {\\n  let wobble = 1\\n  w\\n\\n  let wabble = 2\\n}\\n\"\n---\npub fn main(wibble: Int) {\n  let wobble = 1\n  w|\n\n  let wabble = 2\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn(Int) -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [3:2-3:3]: \"main\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   3_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:2-3:3]: \"wibble\"\nwobble\n  kind:   Variable\n  detail: Int\n  sort:   3_wobble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:2-3:3]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_anonymous_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let add_one = fn(wibble: Int) { wibble + 1 }\\n  add_one(1)\\n}\\n\"\n---\npub fn main() {\n  let add_one = fn(wibble: Int) { wibble| + 1 }\n  add_one(1)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   03_main\n  desc:   app\n  edits:\n    [2:34-2:40]: \"main\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   03_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [2:34-2:40]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_as.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn wibble() {\\n  let b as c = 5\\n\\n}\\n\"\n---\nfn wibble() {\n  let b as c = 5\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nb\n  kind:   Variable\n  detail: Int\n  sort:   3_b\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"b\"\nc\n  kind:   Variable\n  detail: Int\n  sort:   3_c\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"c\"\nwibble\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [3:0-3:0]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_bit_array.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn wibble() {\\n  let assert <<h:1>> as i = <<1:1>>\\n\\n}\\n\"\n---\nfn wibble() {\n  let assert <<h:1>> as i = <<1:1>>\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nh\n  kind:   Variable\n  detail: Int\n  sort:   3_h\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"h\"\ni\n  kind:   Variable\n  detail: BitArray\n  sort:   3_i\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"i\"\nwibble\n  kind:   Function\n  detail: fn() -> BitArray\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [3:0-3:0]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_case_expression.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  case True {\\n    True as wibble -> { todo }\\n    False -> { todo }\\n  }\\n}\\n\"\n---\npub fn main() {\n  case True {\n    True as wibble -> { t|odo }\n    False -> { todo }\n  }\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [3:24-3:25]: \"main\"\ntodo\n  kind:   Keyword\n  sort:   00_todo\nwibble\n  kind:   Variable\n  detail: Bool\n  sort:   3_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:24-3:28]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_function_call.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn add_one(wibble: Int) -> Int {\\n  wibble + 1\\n}\\n\\npub fn main() {\\n  let wobble = 1\\n  add_one(wobble)\\n}\\n\"\n---\nfn add_one(wibble: Int) -> Int {\n  wibble + 1\n}\n\npub fn main() {\n  let wobble = 1\n  add_one(wobble|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd_one\n  kind:   Function\n  detail: fn(Int) -> Int\n  sort:   3_add_one\n  desc:   app\n  edits:\n    [7:10-7:16]: \"add_one\"\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [7:10-7:16]: \"main\"\nwobble\n  kind:   Variable\n  detail: Int\n  sort:   3_wobble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [7:10-7:16]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_ignore_anonymous_function_args.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let add_one = fn(wibble: Int) { wibble + 1 }\\n  let wobble = 1\\n  w\\n}\\n\"\n---\npub fn main() {\n  let add_one = fn(wibble: Int) { wibble + 1 }\n  let wobble = 1\n  w|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd_one\n  kind:   Variable\n  detail: fn(Int) -> Int\n  sort:   3_add_one\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:2-4:3]: \"add_one\"\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [4:2-4:3]: \"main\"\nwobble\n  kind:   Variable\n  detail: Int\n  sort:   3_wobble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:2-4:3]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_ignore_anonymous_function_args_nested.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let add_one = fn(wibble: Int) {\\n    let wabble = 1\\n    let add_two = fn(wobble: Int) { wobble + 2 }\\n    wibble + add_two(1)\\n  }\\n  add_one(1)\\n}\\n\"\n---\npub fn main() {\n  let add_one = fn(wibble: Int) {\n    let wabble = 1\n    let add_two = fn(wobble: Int) { wobble + 2 }\n    wibble| + add_two(1)\n  }\n  add_one(1)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd_two\n  kind:   Variable\n  detail: fn(Int) -> Int\n  sort:   03_add_two\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"add_two\"\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   03_main\n  desc:   app\n  edits:\n    [5:4-5:10]: \"main\"\nwabble\n  kind:   Variable\n  detail: Int\n  sort:   03_wabble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"wabble\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   03_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_ignore_anonymous_function_returned.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  fn(wibble: Int) {\\n    let wabble = 1\\n    let add_two = fn(wobble: Int) { wobble + 2 }\\n    wibble + add_two(1)\\n  }\\n}\\n\"\n---\npub fn main() {\n  fn(wibble: Int) {\n    let wabble = 1\n    let add_two = fn(wobble: Int) { wobble + 2 }\n    wibble| + add_two(1)\n  }\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd_two\n  kind:   Variable\n  detail: fn(Int) -> Int\n  sort:   03_add_two\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"add_two\"\nmain\n  kind:   Function\n  detail: fn() -> fn(Int) -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [5:4-5:10]: \"main\"\nwabble\n  kind:   Variable\n  detail: Int\n  sort:   03_wabble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"wabble\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   03_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_ignore_within_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/completion.rs\nexpression: \"\\nfn main(a, b, z) {\\n    Nil\\n}\\n\"\n---\nfn main(a, b, |z) {\n    Nil\n}\n\n\n----- Completion content -----\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_ignored.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn wibble() {\\n  let a = 1\\n  let _b = 2\\n\\n}\\n\"\n---\nfn wibble() {\n  let a = 1\n  let _b = 2\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\na\n  kind:   Variable\n  detail: Int\n  sort:   3_a\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:0-4:0]: \"a\"\nwibble\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [4:0-4:0]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_inside_nested_exprs.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\ntype Wibble { Wobble(List(#(Bool))) }\\nfn wibble() {\\n  Wobble([#(!{\\n    let wibble = True\\n    wibble\\n  })])\\n  todo\\n}\\n\"\n---\ntype Wibble { Wobble(List(#(Bool))) }\nfn wibble() {\n  Wobble([#(!{\n    let wibble = True\n    wib|ble\n  })])\n  todo\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   05_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   05_True\nWobble\n  kind:   Constructor\n  detail: fn(List(#(Bool))) -> Wibble\n  sort:   3_Wobble\n  desc:   app\n  edits:\n    [5:4-5:7]: \"Wobble\"\nwibble\n  kind:   Variable\n  detail: Bool\n  sort:   03_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:4-5:10]: \"wibble\"\nwibble\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_wibble\n  desc:   app\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_nested_anonymous_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let add_one = fn(wibble: Int) {\\n    let wabble = 1\\n    let add_two = fn(wobble: Int) { wobble + 2 }\\n    wibble + add_two(1)\\n  }\\n  add_one(1)\\n}\\n\"\n---\npub fn main() {\n  let add_one = fn(wibble: Int) {\n    let wabble = 1\n    let add_two = fn(wobble: Int) { wobble| + 2 }\n    wibble + add_two(1)\n  }\n  add_one(1)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   03_main\n  desc:   app\n  edits:\n    [4:36-4:42]: \"main\"\nwabble\n  kind:   Variable\n  detail: Int\n  sort:   03_wabble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:36-4:42]: \"wabble\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   03_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:36-4:42]: \"wibble\"\nwobble\n  kind:   Variable\n  detail: Int\n  sort:   03_wobble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:36-4:42]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_pipe.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let add_one = fn(wibble: Int) { wibble + 1 }\\n  let wobble = 1\\n  wobble |> add_one\\n}\\n\"\n---\npub fn main() {\n  let add_one = fn(wibble: Int) { wibble + 1 }\n  let wobble = 1\n  wobble |> add_one|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd_one\n  kind:   Variable\n  detail: fn(Int) -> Int\n  sort:   03_add_one\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:12-4:19]: \"add_one\"\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [4:12-4:19]: \"main\"\nwobble\n  kind:   Variable\n  detail: Int\n  sort:   3_wobble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:12-4:19]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_pipe_with_args.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let add_one = fn(wibble: Int, wobble: Int) { wibble + wobble }\\n  let wobble = 1\\n  let wibble = 2\\n  wobble |> add_one(1, wibble)\\n}\\n\"\n---\npub fn main() {\n  let add_one = fn(wibble: Int, wobble: Int) { wibble + wobble }\n  let wobble = 1\n  let wibble = 2\n  wobble |> add_one(1, wibble|)\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd_one\n  kind:   Variable\n  detail: fn(Int, Int) -> Int\n  sort:   3_add_one\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:23-5:29]: \"add_one\"\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [5:23-5:29]: \"main\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   3_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:23-5:29]: \"wibble\"\nwobble\n  kind:   Variable\n  detail: Int\n  sort:   3_wobble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:23-5:29]: \"wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_string.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn wibble() {\\n  let assert \\\"a\\\" <> j = \\\"ab\\\"\\n\\n}\\n\"\n---\nfn wibble() {\n  let assert \"a\" <> j = \"ab\"\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nj\n  kind:   Variable\n  detail: String\n  sort:   3_j\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"j\"\nwibble\n  kind:   Function\n  detail: fn() -> String\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [3:0-3:0]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__local_variable_tuple.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn wibble() {\\n  let assert #([d, e] as f, g) = #([0, 1], 2)\\n\\n}\\n\"\n---\nfn wibble() {\n  let assert #([d, e] as f, g) = #([0, 1], 2)\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nd\n  kind:   Variable\n  detail: Int\n  sort:   3_d\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"d\"\ne\n  kind:   Variable\n  detail: Int\n  sort:   3_e\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"e\"\nf\n  kind:   Variable\n  detail: List(Int)\n  sort:   3_f\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"f\"\ng\n  kind:   Variable\n  detail: Int\n  sort:   3_g\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:0-3:0]: \"g\"\nwibble\n  kind:   Function\n  detail: fn() -> #(List(Int), Int)\n  sort:   3_wibble\n  desc:   app\n  edits:\n    [3:0-3:0]: \"wibble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_completions_for_imported_internal_record_fields.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nimport dep\\n\\nfn fun(wibble: dep.Wibble) {\\n  wibble.\\n  //     ^ We should see no completions here!\\n}\\n\"\n---\nimport dep\n\nfn fun(wibble: dep.Wibble) {\n  wibble.|\n  //     ^ We should see no completions here!\n}\n\n\n----- Completion content -----\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_label_completions_in_nested_expression.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(wibble: Int, wobble: Float)\\n}\\n\\npub fn main() {\\n  Wibble([w])\\n}\\n\"\n---\npub type Wibble {\n  Wibble(wibble: Int, wobble: Float)\n}\n\npub fn main() {\n  Wibble([w|])\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWibble\n  kind:   Constructor\n  detail: fn(Int, Float) -> Wibble\n  sort:   3_Wibble\n  desc:   app\n  edits:\n    [6:10-6:11]: \"Wibble\"\nmain\n  kind:   Function\n  detail: fn() -> Wibble\n  sort:   3_main\n  desc:   app\n  edits:\n    [6:10-6:11]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_after_anonymous_function_scope.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  fn() {\\n    let something = 10\\n  }\\n  s\\n}\\n\"\n---\npub fn main() {\n  fn() {\n    let something = 10\n  }\n  s|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [5:2-5:3]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_after_block_scope.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  {\\n    let something = 10\\n  }\\n  s\\n}\\n\"\n---\npub fn main() {\n  {\n    let something = 10\n  }\n  s|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [5:2-5:3]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_after_case_clause_scope.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    something -> Nil\\n    something_else -> s\\n  }\\n  s\\n}\\n\"\n---\npub fn main() {\n  case todo {\n    something -> Nil\n    something_else -> s|\n  }\n  s\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   05_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [4:22-4:23]: \"main\"\nsomething_else\n  kind:   Variable\n  detail: a\n  sort:   03_something_else\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:22-4:23]: \"something_else\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_after_case_scope.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    something -> Nil\\n  }\\n  s\\n}\\n\"\n---\npub fn main() {\n  case todo {\n    something -> Nil\n  }\n  s|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [5:2-5:3]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_before_case_clause.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  case todo {\\n    something -> s\\n    something_else -> Nil\\n  }\\n  s\\n}\\n\"\n---\npub fn main() {\n  case todo {\n    something -> s|\n    something_else -> Nil\n  }\n  s\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   05_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> a\n  sort:   3_main\n  desc:   app\n  edits:\n    [3:17-3:18]: \"main\"\nsomething\n  kind:   Variable\n  detail: a\n  sort:   03_something\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [3:17-3:18]: \"something\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_before_declaration_in_anonymous_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  fn() {\\n    s\\n    let something = 10\\n  }\\n}\\n\"\n---\npub fn main() {\n  fn() {\n    s|\n    let something = 10\n  }\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [3:4-3:5]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__no_variable_completions_before_declaration_in_block.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  {\\n    s\\n    let something = 10\\n  }\\n}\\n\"\n---\npub fn main() {\n  {\n    s|\n    let something = 10\n  }\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_main\n  desc:   app\n  edits:\n    [3:4-3:5]: \"main\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__opaque_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub opaque type Wibble {\\n  Wobble\\n}\\n\"\n---\n|\npub opaque type Wibble {\n  Wobble\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   3_Wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__prefer_function_which_returns_expected_generic_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() -> Result(Int, Nil) {\\n  let result = Ok(12)\\n  let result2 = Error(True)\\n  r\\n}\\n\"\n---\npub fn main() -> Result(Int, Nil) {\n  let result = Ok(12)\n  let result2 = Error(True)\n  r|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   05_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   05_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> Result(Int, Nil)\n  sort:   03_main\n  desc:   app\n  edits:\n    [4:2-4:3]: \"main\"\nresult\n  kind:   Variable\n  detail: Result(Int, a)\n  sort:   03_result\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:2-4:3]: \"result\"\nresult2\n  kind:   Variable\n  detail: Result(a, Bool)\n  sort:   3_result2\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:2-4:3]: \"result2\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__prefer_function_which_returns_expected_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() -> Int {\\n  a\\n}\\n\\nfn add(a, b) { a + b }\\nfn sub(a, b) { a - b }\\nfn addf(a, b) { a +. b }\\n\"\n---\npub fn main() -> Int {\n  a|\n}\n\nfn add(a, b) { a + b }\nfn sub(a, b) { a - b }\nfn addf(a, b) { a +. b }\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nadd\n  kind:   Function\n  detail: fn(Int, Int) -> Int\n  sort:   03_add\n  desc:   app\n  edits:\n    [2:2-2:3]: \"add\"\naddf\n  kind:   Function\n  detail: fn(Float, Float) -> Float\n  sort:   3_addf\n  desc:   app\n  edits:\n    [2:2-2:3]: \"addf\"\nmain\n  kind:   Function\n  detail: fn() -> Int\n  sort:   03_main\n  desc:   app\n  edits:\n    [2:2-2:3]: \"main\"\nsub\n  kind:   Function\n  detail: fn(Int, Int) -> Int\n  sort:   03_sub\n  desc:   app\n  edits:\n    [2:2-2:3]: \"sub\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__prefer_values_matching_expected_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() -> Bool {\\n  let wibble = 123\\n  let wubble = True\\n  let Wobble = 1.5\\n  w\\n}\\n\"\n---\npub fn main() -> Bool {\n  let wibble = 123\n  let wubble = True\n  let Wobble = 1.5\n  w|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   05_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   05_True\nmain\n  kind:   Function\n  detail: fn() -> Bool\n  sort:   03_main\n  desc:   app\n  edits:\n    [5:2-5:3]: \"main\"\nwibble\n  kind:   Variable\n  detail: Int\n  sort:   3_wibble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:2-5:3]: \"wibble\"\nwubble\n  kind:   Variable\n  detail: Bool\n  sort:   03_wubble\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [5:2-5:3]: \"wubble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__private_function.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\nfn private() {\\n  1\\n}\\n\"\n---\n|\nfn private() {\n  1\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nprivate\n  kind:   Function\n  detail: fn() -> Int\n  sort:   3_private\n  desc:   app\n  edits:\n    [1:0-1:0]: \"private\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__private_function_in_dep.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: import dep\n---\n|import dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__private_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\ntype Wibble {\\n  Wobble\\n}\\n\"\n---\n|\ntype Wibble {\n  Wobble\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nWobble\n  kind:   EnumMember\n  detail: Wibble\n  sort:   3_Wobble\n  desc:   app\n  edits:\n    [1:0-1:0]: \"Wobble\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__private_type_in_dep.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: import dep\n---\n|import dep\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__unqualified_imported_type.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"import dep.{type Zoo}\\n\\npub fn wibble(\\n  _: String,\\n) -> Nil {\\n  Nil\\n}\\n\"\n---\nimport dep.{type Zoo}\n\npub fn wibble(\n|  _: String,\n) -> Nil {\n  Nil\n}\n\n\n----- Completion content -----\nBitArray\n  kind:   Class\n  detail: Type\n  sort:   5_BitArray\nBool\n  kind:   Class\n  detail: Type\n  sort:   5_Bool\nFloat\n  kind:   Class\n  detail: Type\n  sort:   5_Float\nInt\n  kind:   Class\n  detail: Type\n  sort:   5_Int\nList\n  kind:   Class\n  detail: Type\n  sort:   5_List\nNil\n  kind:   Class\n  detail: Type\n  sort:   5_Nil\nResult\n  kind:   Class\n  detail: Type\n  sort:   5_Result\nString\n  kind:   Class\n  detail: Type\n  sort:   5_String\nUtfCodepoint\n  kind:   Class\n  detail: Type\n  sort:   5_UtfCodepoint\nZoo\n  kind:   Class\n  detail: Type\n  sort:   4_Zoo\n  edits:\n    [3:0-3:0]: \"Zoo\"\ndep.Zoo\n  kind:   Class\n  detail: Type\n  sort:   4_dep.Zoo\n  edits:\n    [3:0-3:0]: \"dep.Zoo\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__completion__variable_shadowing.snap",
    "content": "---\nsource: language-server/src/tests/completion.rs\nexpression: \"\\npub fn main() {\\n  let x = 1\\n  let x = [1, 2]\\n\\n}\\n\"\n---\npub fn main() {\n  let x = 1\n  let x = [1, 2]\n|\n}\n\n\n----- Completion content -----\nError\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Error\nFalse\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_False\nNil\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_Nil\nOk\n  kind:   Constructor\n  detail: gleam\n  sort:   5_Ok\nTrue\n  kind:   EnumMember\n  detail: gleam\n  sort:   5_True\nmain\n  kind:   Function\n  detail: fn() -> List(Int)\n  sort:   3_main\n  desc:   app\n  edits:\n    [4:0-4:0]: \"main\"\nx\n  kind:   Variable\n  detail: List(Int)\n  sort:   3_x\n  desc:   app\n  docs:   \"A locally defined variable.\"\n  edits:\n    [4:0-4:0]: \"x\"\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nconst value = 25\n\nconst my_constant = value\n                     ↑   \n\n----- Jumped to `src/app.gleam`\n\nconst value = 25\n↑▔▔▔▔▔▔▔▔▔▔     \n\nconst my_constant = value\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_constant_imported_record.snap",
    "content": "---\nsource: language-server/src/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport wibble\n\nconst my_constant = wibble.Wibble(10)\n                           ↑         \n\n----- Jumped to `build/packages/hex/src/wibble.gleam`\npub type Wibble { Wibble(Int) }\n                  ↑▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_constant_record.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\ntype Wibble {\n  Wibble(Int)\n}\n\nconst wibble = Wibble(10)\n                   ↑     \n\n----- Jumped to `src/app.gleam`\n\ntype Wibble {\n  Wibble(Int)\n  ↑▔▔▔▔▔▔▔▔▔▔\n}\n\nconst wibble = Wibble(10)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_deep_type_in_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn make_var() -> example_module.Wabble(example_module.Wibble(example_module.Wobble)) {\n                                                                             ↑        \n  example_module.Wabble(example_module.Wibble(example_module.Wobble(1)))\n}\n\n----- Jumped to `build/packages/hex/src/example_module.gleam`\n\npub type Wobble {\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔  \n  Wobble(Int)\n}\n\npub type Wibble(a) {\n  Wibble(a)\n}\n\npub type Wabble(a) {\n  Wabble(a)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_external_module_constants.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.my_num\n                     ↑ \n}\n\n----- Jumped to `build/packages/hex/src/example_module.gleam`\npub const my_num = 1\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_external_module_function_calls.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.my_fn\n                 ↑    \n}\n\n----- Jumped to `build/packages/hex/src/example_module.gleam`\npub fn my_fn() { Nil }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_external_module_records.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.Var1(1)\n                   ↑    \n}\n\n----- Jumped to `build/packages/hex/src/example_module.gleam`\n\npub type Rec {\n  Var1(Int)\n  ↑▔▔▔▔▔▔▔▔\n  Var2(Int, Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_from_alternative_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\ntype Wibble {\n  Wibble\n  Wobble\n}\n\nfn warble(wibble: Wibble) {\n  case wibble {\n    Wibble | Wobble -> 0\n             ↑          \n  }\n}\n\n----- Jumped to `src/app.gleam`\n\ntype Wibble {\n  Wibble\n  Wobble\n  ↑▔▔▔▔▔\n}\n\nfn warble(wibble: Wibble) {\n  case wibble {\n    Wibble | Wobble -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_from_anonymous_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\npub type Wibble\n\npub fn main() {\n  fn(w: Wibble) { todo }\n         ↑              \n}\n\n----- Jumped to `src/app.gleam`\n\npub type Wibble\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\npub fn main() {\n  fn(w: Wibble) { todo }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_import.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\n           ↑         \nfn main() {\n  example_module.my_num\n}\n\n----- Jumped to `src/example_module.gleam`\npub const my_num = 1\n↑\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_import_aliased.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module as example\n                          ↑     \nfn main() {\n  example.my_num\n}\n\n----- Jumped to `src/example_module.gleam`\npub const my_num = 1\n↑\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_import_unqualified_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module.{type MyType}\n                              ↑    \nfn main() -> MyType {\n  0\n}\n\n----- Jumped to `src/example_module.gleam`\npub type MyType = Int\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_import_unqualified_value.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module.{my_num}\n                         ↑    \nfn main() {\n  my_num\n}\n\n----- Jumped to `src/example_module.gleam`\npub const my_num = 1\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_imported_constant.snap",
    "content": "---\nsource: language-server/src/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport wibble\n\nconst my_constant = wibble.value\n                           ↑    \n\n----- Jumped to `build/packages/hex/src/wibble.gleam`\npub const value = 10\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_imported_module_constants.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.my_num\n                 ↑     \n}\n\n----- Jumped to `src/example_module.gleam`\npub const my_num = 1\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_imported_module_records.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.Var1(1)\n                 ↑      \n}\n\n----- Jumped to `src/example_module.gleam`\n\npub type Rec {\n  Var1(Int)\n  ↑▔▔▔▔▔▔▔▔\n  Var2(Int, Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\npub fn main() {\n  let x = 1\n  x\n  ↑\n}\n\n----- Jumped to `src/app.gleam`\n\npub fn main() {\n  let x = 1\n      ↑    \n  x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport wibble\n\npub fn main() {\n  wibble.wibble()\n   ↑             \n}\n\n----- Jumped to `src/wibble.gleam`\npub fn wibble() {}\n↑\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_module_function_calls.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.my_fn\n                 ↑    \n}\n\n----- Jumped to `src/example_module.gleam`\npub fn my_fn() { Nil }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_of_external_function_in_same_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\n@external(erlang, \"wibble\", \"wobble\")\nfn external_function() -> Nil\n\nfn main() {\n  external_function()\n         ↑           \n}\n\n----- Jumped to `src/app.gleam`\n\n@external(erlang, \"wibble\", \"wobble\")\nfn external_function() -> Nil\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔       \n\nfn main() {\n  external_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_of_local_variable_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n             ↑               \n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\n----- Jumped to `src/app.gleam`\n\npub fn main() {\n  let wibble = True\n  let wobble = False\n      ↑▔▔▔▔▔        \n  case wibble {\n    True if wobble -> !wibble\n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_of_module_select_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n                ↑                    \n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\n----- Jumped to `src/mod.gleam`\npub const wibble = 10\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_of_record_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\ntype Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  let wibble = True\n  let wobble = Wibble\n  case wibble {\n    True if wobble == Wibble -> !wibble\n                          ↑            \n    False if wobble == Wobble -> wibble\n    _ -> Wibble\n  }\n}\n\n----- Jumped to `src/app.gleam`\n\ntype Wibble {\n  Wibble\n  ↑▔▔▔▔▔\n  Wobble\n}\n\npub fn main() {\n  let wibble = True\n  let wobble = Wibble\n  case wibble {\n    True if wobble == Wibble -> !wibble\n    False if wobble == Wobble -> wibble\n    _ -> Wibble\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_of_record_module_select_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport mod\n\npub fn main() {\n  let wibble = True\n  let wobble = mod.Wibble\n  case wibble {\n    True if wobble == mod.Wobble -> !wibble\n    False if wobble == mod.Wibble -> wibble\n                            ↑              \n    _ -> mod.Wibble\n  }\n}\n\n----- Jumped to `src/mod.gleam`\npub type Wobble { Wibble Wobble }\n                  ↑▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_path_module_function_calls.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn main() {\n  example_module.my_fn\n                  ↑   \n}\n\n----- Jumped to `dep/src/example_module.gleam`\npub fn my_fn() { Nil }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_record_update.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\npub type Wibble { Wibble(one: Int, two: Int) }\n\npub fn main() {\n  Wibble(..todo, one: 1)\n  ↑                     \n}\n\n----- Jumped to `src/app.gleam`\n\npub type Wibble { Wibble(one: Int, two: Int) }\n                  ↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔  \n\npub fn main() {\n  Wibble(..todo, one: 1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_same_module_constants.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nconst x = 1\n\npub fn main() {\n  x\n  ↑\n}\n\n----- Jumped to `src/app.gleam`\n\nconst x = 1\n↑▔▔▔▔▔▔    \n\npub fn main() {\n  x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_same_module_functions.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nfn add_2(x) {\n  x + 2\n}\n\npub fn main() {\n  add_2(1)\n  ↑       \n}\n\n----- Jumped to `src/app.gleam`\n\nfn add_2(x) {\n↑▔▔▔▔▔▔▔▔▔▔  \n  x + 2\n}\n\npub fn main() {\n  add_2(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_same_module_records.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\npub fn main() {\n  let a = Var1(1)\n          ↑      \n  let b = Var2(2, 3)\n}\n\n----- Jumped to `src/app.gleam`\n\npub type Rec {\n  Var1(Int)\n  ↑▔▔▔▔▔▔▔▔\n  Var2(Int, Int)\n}\n\npub fn main() {\n  let a = Var1(1)\n  let b = Var2(2, 3)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\npub type Rec {\n  Var1(Int)\n  Var2(Int, Int)\n}\n\npub fn make_var() -> Rec {\n                     ↑    \n  Var1(1)\n}\n\n----- Jumped to `src/app.gleam`\n\npub type Rec {\n↑▔▔▔▔▔▔▔▔▔▔▔  \n  Var1(Int)\n  Var2(Int, Int)\n}\n\npub fn make_var() -> Rec {\n  Var1(1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_type_in_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn make_var() -> example_module.Rec {\n                                ↑    \n  example_module.Var1(1)\n}\n\n----- Jumped to `build/packages/hex/src/example_module.gleam`\n\npub type Rec {\n↑▔▔▔▔▔▔▔▔▔▔▔  \n  Var1(Int)\n  Var2(Int, Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_type_in_path_dep.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module\nfn make_var() -> example_module.Rec {\n                                ↑    \n  example_module.Var1(1)\n}\n\n----- Jumped to `dep/src/example_module.gleam`\n\npub type Rec {\n↑▔▔▔▔▔▔▔▔▔▔▔  \n  Var1(Int)\n  Var2(Int, Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_unqualified_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport wibble.{wobble}\nfn main() {\n  wobble()\n   ↑      \n}\n\n----- Jumped to `src/wibble.gleam`\npub fn wobble() {}\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_unqualified_imported_module_constants.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module.{my_num}\nfn main() {\n  my_num\n  ↑     \n}\n\n----- Jumped to `src/example_module.gleam`\npub const my_num = 1\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_definition_unqualified_imported_module_records.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\n----- Jumping from `src/app.gleam`\n\nimport example_module.{Var1}\nfn main() {\n  Var1(1)\n   ↑     \n}\n\n----- Jumped to `src/example_module.gleam`\n\npub type Rec {\n  Var1(Int)\n  ↑▔▔▔▔▔▔▔▔\n  Var2(Int, Int)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_type_definition_can_jump_to_all_types_in_a_function_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\nJumping to type definition\n\n----- Jumping from `src/app.gleam`\n\nimport wibble.{type Wibble}\nimport wobble.{type Wobble}\nimport box.{type Box}\n\npub fn main() {\n  let a = fn(wibble: Wibble) { box.Box(wobble.Wobble) }\n  ↑                                                    \n}\n\n----- Jumped to `dep/src/wibble.gleam`\npub type Wibble { Wibble }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔           \n\n\n----- Jumped to `dep/src/box.gleam`\npub type Box(a) { Box(a) }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔           \n\n\n----- Jumped to `dep/src/wobble.gleam`\npub type Wobble { Wobble }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_type_definition_can_jump_to_all_types_in_a_tuple.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\nJumping to type definition\n\n----- Jumping from `src/app.gleam`\n\nimport wibble.{type Wibble}\nimport wobble.{type Wobble}\nimport box.{type Box}\n\npub fn main() {\n  let a: #(Box(Wibble), Wobble) = todo\n  ↑                                   \n}\n\n----- Jumped to `dep/src/box.gleam`\npub type Box(a) { Box(a) }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔           \n\n\n----- Jumped to `dep/src/wibble.gleam`\npub type Wibble { Wibble }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔           \n\n\n----- Jumped to `dep/src/wobble.gleam`\npub type Wobble { Wobble }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_type_definition_can_jump_to_multiple_types.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\nJumping to type definition\n\n----- Jumping from `src/app.gleam`\n\nimport wibble.{type Wibble, Wibble}\nimport box.{Box}\n\npub fn main() {\n  let a = Box(Wibble)\n  ↑                  \n}\n\n----- Jumped to `dep/src/box.gleam`\npub type Box(a) { Box(a) }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔           \n\n\n----- Jumped to `dep/src/wibble.gleam`\npub type Wibble { Wibble }\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_type_definition_in_different_file_of_dependency.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\nJumping to type definition\n\n----- Jumping from `src/app.gleam`\n\nimport wibble.{type Wibble}\n\npub fn main() {\n  use_wibble(todo)\n             ↑    \n}\n\npub fn use_wibble(wibble: Wibble) { todo }\n\n----- Jumped to `dep/src/wibble.gleam`\npub type Wibble\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_type_definition_in_different_file_of_same_project.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\nJumping to type definition\n\n----- Jumping from `src/app.gleam`\n\nimport wibble.{type Wibble}\n\npub fn main() {\n  use_wibble(todo)\n             ↑    \n}\n\npub fn use_wibble(wibble: Wibble) { todo }\n\n----- Jumped to `src/wibble.gleam`\npub type Wibble\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__definition__goto_type_definition_in_same_file.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/definition.rs\nexpression: output\n---\nJumping to type definition\n\n----- Jumping from `src/app.gleam`\n\npub type Wibble {\n  Wibble\n}\n\npub fn main() {\n  let x = Wibble\n  x\n  ↑\n}\n\n----- Jumped to `src/app.gleam`\n\npub type Wibble {\n↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔  \n  Wibble\n}\n\npub fn main() {\n  let x = Wibble\n  x\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"my_const\",\n        detail: Some(\n            \"Int\",\n        ),\n        kind: Constant,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 2,\n                character: 22,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 2,\n                character: 10,\n            },\n            end: Position {\n                line: 2,\n                character: 18,\n            },\n        },\n        children: None,\n    },\n    DocumentSymbol {\n        name: \"my_const2\",\n        detail: Some(\n            \"List(Int)\",\n        ),\n        kind: Constant,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 4,\n                character: 0,\n            },\n            end: Position {\n                line: 4,\n                character: 26,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 4,\n                character: 10,\n            },\n            end: Position {\n                line: 4,\n                character: 19,\n            },\n        },\n        children: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"super_func\",\n        detail: Some(\n            \"fn(Int) -> List(Int)\",\n        ),\n        kind: Function,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 4,\n                character: 1,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 2,\n                character: 7,\n            },\n            end: Position {\n                line: 2,\n                character: 17,\n            },\n        },\n        children: None,\n    },\n    DocumentSymbol {\n        name: \"super_func2\",\n        detail: Some(\n            \"fn(Int) -> List(Int)\",\n        ),\n        kind: Function,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 6,\n                character: 0,\n            },\n            end: Position {\n                line: 8,\n                character: 1,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 6,\n                character: 7,\n            },\n            end: Position {\n                line: 6,\n                character: 18,\n            },\n        },\n        children: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_alias.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"FFF\",\n        detail: Some(\n            \"gleam.Int\",\n        ),\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 2,\n                character: 18,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 2,\n                character: 9,\n            },\n            end: Position {\n                line: 2,\n                character: 12,\n            },\n        },\n        children: None,\n    },\n    DocumentSymbol {\n        name: \"FFFF\",\n        detail: Some(\n            \"gleam.List(gleam.Int)\",\n        ),\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 4,\n                character: 0,\n            },\n            end: Position {\n                line: 4,\n                character: 25,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 4,\n                character: 9,\n            },\n            end: Position {\n                line: 4,\n                character: 13,\n            },\n        },\n        children: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_constructor_labeled_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"B\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 12,\n                character: 1,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 1,\n                character: 9,\n            },\n            end: Position {\n                line: 1,\n                character: 10,\n            },\n        },\n        children: Some(\n            [\n                DocumentSymbol {\n                    name: \"C\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 16,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 5,\n                        },\n                    },\n                    children: Some(\n                        [\n                            DocumentSymbol {\n                                name: \"argc\",\n                                detail: Some(\n                                    \"Int\",\n                                ),\n                                kind: Field,\n                                tags: None,\n                                deprecated: None,\n                                range: Range {\n                                    start: Position {\n                                        line: 2,\n                                        character: 6,\n                                    },\n                                    end: Position {\n                                        line: 2,\n                                        character: 15,\n                                    },\n                                },\n                                selection_range: Range {\n                                    start: Position {\n                                        line: 2,\n                                        character: 6,\n                                    },\n                                    end: Position {\n                                        line: 2,\n                                        character: 10,\n                                    },\n                                },\n                                children: None,\n                            },\n                        ],\n                    ),\n                },\n                DocumentSymbol {\n                    name: \"D\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 4,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 5,\n                            character: 22,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 5,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 5,\n                            character: 5,\n                        },\n                    },\n                    children: Some(\n                        [\n                            DocumentSymbol {\n                                name: \"argd\",\n                                detail: Some(\n                                    \"List(Int)\",\n                                ),\n                                kind: Field,\n                                tags: None,\n                                deprecated: None,\n                                range: Range {\n                                    start: Position {\n                                        line: 5,\n                                        character: 6,\n                                    },\n                                    end: Position {\n                                        line: 5,\n                                        character: 21,\n                                    },\n                                },\n                                selection_range: Range {\n                                    start: Position {\n                                        line: 5,\n                                        character: 6,\n                                    },\n                                    end: Position {\n                                        line: 5,\n                                        character: 10,\n                                    },\n                                },\n                                children: None,\n                            },\n                        ],\n                    ),\n                },\n                DocumentSymbol {\n                    name: \"E\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 7,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 11,\n                            character: 5,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 8,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 8,\n                            character: 5,\n                        },\n                    },\n                    children: Some(\n                        [\n                            DocumentSymbol {\n                                name: \"arge\",\n                                detail: Some(\n                                    \"Result(Int, Bool)\",\n                                ),\n                                kind: Field,\n                                tags: None,\n                                deprecated: None,\n                                range: Range {\n                                    start: Position {\n                                        line: 9,\n                                        character: 8,\n                                    },\n                                    end: Position {\n                                        line: 10,\n                                        character: 31,\n                                    },\n                                },\n                                selection_range: Range {\n                                    start: Position {\n                                        line: 10,\n                                        character: 8,\n                                    },\n                                    end: Position {\n                                        line: 10,\n                                        character: 12,\n                                    },\n                                },\n                                children: None,\n                            },\n                        ],\n                    ),\n                },\n            ],\n        ),\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_constructor_no_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"B\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 7,\n                character: 1,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 1,\n                character: 9,\n            },\n            end: Position {\n                line: 1,\n                character: 10,\n            },\n        },\n        children: Some(\n            [\n                DocumentSymbol {\n                    name: \"C\",\n                    detail: None,\n                    kind: EnumMember,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 5,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 5,\n                        },\n                    },\n                    children: None,\n                },\n                DocumentSymbol {\n                    name: \"D\",\n                    detail: None,\n                    kind: EnumMember,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 3,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 3,\n                            character: 5,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 3,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 3,\n                            character: 5,\n                        },\n                    },\n                    children: None,\n                },\n                DocumentSymbol {\n                    name: \"E\",\n                    detail: None,\n                    kind: EnumMember,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 5,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 6,\n                            character: 5,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 6,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 6,\n                            character: 5,\n                        },\n                    },\n                    children: None,\n                },\n            ],\n        ),\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_constructor_pos_and_labeled_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"B\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 14,\n                character: 1,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 1,\n                character: 9,\n            },\n            end: Position {\n                line: 1,\n                character: 10,\n            },\n        },\n        children: Some(\n            [\n                DocumentSymbol {\n                    name: \"C\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 21,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 5,\n                        },\n                    },\n                    children: Some(\n                        [\n                            DocumentSymbol {\n                                name: \"argc\",\n                                detail: Some(\n                                    \"Int\",\n                                ),\n                                kind: Field,\n                                tags: None,\n                                deprecated: None,\n                                range: Range {\n                                    start: Position {\n                                        line: 2,\n                                        character: 11,\n                                    },\n                                    end: Position {\n                                        line: 2,\n                                        character: 20,\n                                    },\n                                },\n                                selection_range: Range {\n                                    start: Position {\n                                        line: 2,\n                                        character: 11,\n                                    },\n                                    end: Position {\n                                        line: 2,\n                                        character: 15,\n                                    },\n                                },\n                                children: None,\n                            },\n                        ],\n                    ),\n                },\n                DocumentSymbol {\n                    name: \"D\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 4,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 5,\n                            character: 27,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 5,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 5,\n                            character: 5,\n                        },\n                    },\n                    children: Some(\n                        [\n                            DocumentSymbol {\n                                name: \"argd\",\n                                detail: Some(\n                                    \"List(Int)\",\n                                ),\n                                kind: Field,\n                                tags: None,\n                                deprecated: None,\n                                range: Range {\n                                    start: Position {\n                                        line: 5,\n                                        character: 11,\n                                    },\n                                    end: Position {\n                                        line: 5,\n                                        character: 26,\n                                    },\n                                },\n                                selection_range: Range {\n                                    start: Position {\n                                        line: 5,\n                                        character: 11,\n                                    },\n                                    end: Position {\n                                        line: 5,\n                                        character: 15,\n                                    },\n                                },\n                                children: None,\n                            },\n                        ],\n                    ),\n                },\n                DocumentSymbol {\n                    name: \"E\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 7,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 13,\n                            character: 5,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 8,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 8,\n                            character: 5,\n                        },\n                    },\n                    children: Some(\n                        [\n                            DocumentSymbol {\n                                name: \"arge\",\n                                detail: Some(\n                                    \"Result(Int, Bool)\",\n                                ),\n                                kind: Field,\n                                tags: None,\n                                deprecated: None,\n                                range: Range {\n                                    start: Position {\n                                        line: 11,\n                                        character: 8,\n                                    },\n                                    end: Position {\n                                        line: 12,\n                                        character: 31,\n                                    },\n                                },\n                                selection_range: Range {\n                                    start: Position {\n                                        line: 12,\n                                        character: 8,\n                                    },\n                                    end: Position {\n                                        line: 12,\n                                        character: 12,\n                                    },\n                                },\n                                children: None,\n                            },\n                        ],\n                    ),\n                },\n            ],\n        ),\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_constructor_pos_args.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"B\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 11,\n                character: 1,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 1,\n                character: 9,\n            },\n            end: Position {\n                line: 1,\n                character: 10,\n            },\n        },\n        children: Some(\n            [\n                DocumentSymbol {\n                    name: \"C\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 10,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 2,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 2,\n                            character: 5,\n                        },\n                    },\n                    children: None,\n                },\n                DocumentSymbol {\n                    name: \"D\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 4,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 5,\n                            character: 16,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 5,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 5,\n                            character: 5,\n                        },\n                    },\n                    children: None,\n                },\n                DocumentSymbol {\n                    name: \"E\",\n                    detail: None,\n                    kind: Constructor,\n                    tags: None,\n                    deprecated: None,\n                    range: Range {\n                        start: Position {\n                            line: 7,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 10,\n                            character: 5,\n                        },\n                    },\n                    selection_range: Range {\n                        start: Position {\n                            line: 8,\n                            character: 4,\n                        },\n                        end: Position {\n                            line: 8,\n                            character: 5,\n                        },\n                    },\n                    children: None,\n                },\n            ],\n        ),\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_no_constructors.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"A\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 1,\n                character: 10,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 1,\n                character: 9,\n            },\n            end: Position {\n                line: 1,\n                character: 10,\n            },\n        },\n        children: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_no_constructors_starting_at_documentation.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"A\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 1,\n                character: 0,\n            },\n            end: Position {\n                line: 2,\n                character: 10,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 2,\n                character: 9,\n            },\n            end: Position {\n                line: 2,\n                character: 10,\n            },\n        },\n        children: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__document_symbols__doc_symbols_type_no_constructors_starting_at_empty_doc.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/document_symbols.rs\nexpression: \"doc_symbols(TestProject::for_source(code))\"\n---\n[\n    DocumentSymbol {\n        name: \"A\",\n        detail: None,\n        kind: Class,\n        tags: None,\n        deprecated: None,\n        range: Range {\n            start: Position {\n                line: 3,\n                character: 0,\n            },\n            end: Position {\n                line: 4,\n                character: 10,\n            },\n        },\n        selection_range: Range {\n            start: Position {\n                line: 4,\n                character: 9,\n            },\n            end: Position {\n                line: 4,\n                character: 10,\n            },\n        },\n        children: None,\n    },\n]\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_import_block.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"import one\\nimport two\\nimport three\\n\\npub fn main() { 1 }\"\nsnapshot_kind: text\n---\n----- Code -----\nimport one\nimport two\nimport three\n\npub fn main() { 1 }\n\n----- Ranges -----\n1. lines 0..2 kind: imports\n\n----- Fold 1 (lines 0..2) -----\nimport one ...\n\npub fn main() { 1 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_mixed_definitions_in_source_order.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"import one\\nimport two\\n\\npub type W {\\n  W(Int)\\n}\\n\\npub const xs = [\\n  1,\\n  2,\\n]\\n\\npub fn main() {\\n  1\\n}\"\nsnapshot_kind: text\n---\n----- Code -----\nimport one\nimport two\n\npub type W {\n  W(Int)\n}\n\npub const xs = [\n  1,\n  2,\n]\n\npub fn main() {\n  1\n}\n\n----- Ranges -----\n1. lines 0..1 kind: imports\n2. lines 3..5 kind: none\n3. lines 7..10 kind: none\n4. lines 12..14 kind: none\n\n----- Fold 1 (lines 0..1) -----\nimport one ...\n\npub type W {\n  W(Int)\n}\n\npub const xs = [\n  1,\n  2,\n]\n\npub fn main() {\n  1\n}\n\n----- Fold 2 (lines 3..5) -----\nimport one\nimport two\n\npub type W { ...\n\npub const xs = [\n  1,\n  2,\n]\n\npub fn main() {\n  1\n}\n\n----- Fold 3 (lines 7..10) -----\nimport one\nimport two\n\npub type W {\n  W(Int)\n}\n\npub const xs = [ ...\n\npub fn main() {\n  1\n}\n\n----- Fold 4 (lines 12..14) -----\nimport one\nimport two\n\npub type W {\n  W(Int)\n}\n\npub const xs = [\n  1,\n  2,\n]\n\npub fn main() { ...\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_multiline_constant.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"pub const xs = [\\n  1,\\n  2,\\n]\"\nsnapshot_kind: text\n---\n----- Code -----\npub const xs = [\n  1,\n  2,\n]\n\n----- Ranges -----\n1. lines 0..3 kind: none\n\n----- Fold 1 (lines 0..3) -----\npub const xs = [ ...\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_multiline_custom_type.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"pub type W {\\n  W(Int)\\n}\"\nsnapshot_kind: text\n---\n----- Code -----\npub type W {\n  W(Int)\n}\n\n----- Ranges -----\n1. lines 0..2 kind: none\n\n----- Fold 1 (lines 0..2) -----\npub type W { ...\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_multiline_function_body.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"pub fn main() {\\n  let x = 1\\n  x\\n}\"\nsnapshot_kind: text\n---\n----- Code -----\npub fn main() {\n  let x = 1\n  x\n}\n\n----- Ranges -----\n1. lines 0..3 kind: none\n\n----- Fold 1 (lines 0..3) -----\npub fn main() { ...\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_multiline_type_alias.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"pub type Pair =\\n  #(Int, Int)\"\nsnapshot_kind: text\n---\n----- Code -----\npub type Pair =\n  #(Int, Int)\n\n----- Ranges -----\n1. lines 0..1 kind: none\n\n----- Fold 1 (lines 0..1) -----\npub type Pair = ...\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_only_multiline_functions_in_source_order.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"pub fn one() {\\n  1\\n}\\n\\npub fn two() { 2 }\\n\\npub fn three() {\\n  3\\n}\"\nsnapshot_kind: text\n---\n----- Code -----\npub fn one() {\n  1\n}\n\npub fn two() { 2 }\n\npub fn three() {\n  3\n}\n\n----- Ranges -----\n1. lines 0..2 kind: none\n2. lines 6..8 kind: none\n\n----- Fold 1 (lines 0..2) -----\npub fn one() { ...\n\npub fn two() { 2 }\n\npub fn three() {\n  3\n}\n\n----- Fold 2 (lines 6..8) -----\npub fn one() {\n  1\n}\n\npub fn two() { 2 }\n\npub fn three() { ...\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__folding_range__folds_separated_import_blocks.snap",
    "content": "---\nsource: language-server/src/tests/folding_range.rs\nexpression: \"import one\\nimport two\\n\\nimport three\\nimport four\\n\\npub fn main() { 1 }\"\nsnapshot_kind: text\n---\n----- Code -----\nimport one\nimport two\n\nimport three\nimport four\n\npub fn main() { 1 }\n\n----- Ranges -----\n1. lines 0..1 kind: imports\n2. lines 3..4 kind: imports\n\n----- Fold 1 (lines 0..1) -----\nimport one ...\n\nimport three\nimport four\n\npub fn main() { 1 }\n\n----- Fold 2 (lines 3..4) -----\nimport one\nimport two\n\nimport three ...\n\npub fn main() { 1 }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__documentation_for_shared_record_field_when_variant_is_known.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(\\n    /// This is some documentation about the wibble field.\\n    wibble: Int\\n  )\\n  Wobble(\\n    /// This won't show up because it's a Wibble variant\\n    wibble: Int\\n  )\\n}\\n\\npub fn wibble(w: Wibble) {\\n  let assert Wibble(..) = w\\n  w.wibble\\n}\\n\"\n---\npub type Wibble {\n  Wibble(\n    /// This is some documentation about the wibble field.\n    wibble: Int\n  )\n  Wobble(\n    /// This won't show up because it's a Wibble variant\n    wibble: Int\n  )\n}\n\npub fn wibble(w: Wibble) {\n  let assert Wibble(..) = w\n  w.wibble\n  ▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n This is some documentation about the wibble field.\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_assignment_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn wibble() {\\n    let wobble: Int = 7\\n    wobble\\n}\\n\"\n---\nfn wibble() {\n    let wobble: Int = 7\n                ▔▔↑    \n    wobble\n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\nconst value = wobble.Wobble\\n\"\n---\nimport wibble/wobble\nconst value = wobble.Wobble\n▔▔▔▔▔▔↑▔▔▔▔                \n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_aliased.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\ntype Local = wobble.Wibble\\nconst value = wobble.Wobble\\n\"\n---\nimport wibble/wobble\ntype Local = wobble.Wibble\nconst value = wobble.Wobble\n▔▔▔▔▔▔↑▔▔▔▔                \n\n\n----- Hover content (markdown) -----\n```gleam\nLocal\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_aliased_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble as wubble\\nconst value = wubble.Wobble\\n\"\n---\nimport wibble/wobble as wubble\nconst value = wubble.Wobble\n▔▔▔▔▔▔↑▔▔▔▔                \n\n\n----- Hover content (markdown) -----\n```gleam\nwubble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\n\\nfn make_wibble() -> wobble.Wibble { wobble.Wibble }\\n\"\n---\nimport wibble/wobble\n\nfn make_wibble() -> wobble.Wibble { wobble.Wibble }\n                    ▔▔▔▔▔▔▔▔↑▔▔▔▔                  \n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_annotation_aliased.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\n\\ntype Wubble = wobble.Wibble\\n\\nfn main(wibble: Wubble) {\\n  wibble\\n}\\n\"\n---\nimport wibble/wobble\n\ntype Wubble = wobble.Wibble\n\nfn main(wibble: Wubble) {\n                ▔▔▔▔▔↑   \n  wibble\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_annotation_aliased_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble as wubble\\n\\nfn main(wibble: wubble.Wibble) {\\n  wibble\\n}\\n\"\n---\nimport wibble/wobble as wubble\n\nfn main(wibble: wubble.Wibble) {\n                ▔▔▔▔▔▔▔↑▔▔▔▔▔   \n  wibble\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwubble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_annotation_prelude.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add_one(a: Int) -> Int {\\n  a + 1\\n}\\n\"\n---\nfn add_one(a: Int) -> Int {\n                      ↑▔▔  \n  a + 1\n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_annotation_unqualified.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{type Wibble}\\n\\nfn main(wibble: Wibble) {\\n  wibble\\n}\\n\"\n---\nimport wibble/wobble.{type Wibble}\n\nfn main(wibble: Wibble) {\n                ↑▔▔▔▔▔   \n  wibble\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_annotation_unqualified_aliased.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{type Wibble as Wubble}\\n\\nfn main(wibble: Wubble) {\\n  wibble\\n}\\n\"\n---\nimport wibble/wobble.{type Wibble as Wubble}\n\nfn main(wibble: Wubble) {\n                ↑▔▔▔▔▔   \n  wibble\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_arg.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\n\\nfn do_things(wibble: wobble.Wibble) { wibble }\\n\"\n---\nimport wibble/wobble\n\nfn do_things(wibble: wobble.Wibble) { wibble }\n             ↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔            \n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_expression.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\n\\npub fn main() {\\n  let wibble = wobble.Wibble\\n}\\n\"\n---\nimport wibble/wobble\n\npub fn main() {\n  let wibble = wobble.Wibble\n               ▔▔▔▔▔▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/wibble/wobble.html#Wibble)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_function.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\ntype MyInt = Int\\nfn func(value: wobble.Wibble) -> MyInt { 1 }\\n\"\n---\nimport wibble/wobble\ntype MyInt = Int\nfn func(value: wobble.Wibble) -> MyInt { 1 }\n▔▔▔↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔      \n\n\n----- Hover content (markdown) -----\n```gleam\nfn(wobble.Wibble) -> MyInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_pattern.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{Wibble, Wobble, Wubble}\\n\\npub fn cycle(wibble: wobble.Wibble) {\\n  case wibble {\\n    Wibble -> Wobble\\n    Wobble -> Wubble\\n    Wubble -> Wibble\\n  }\\n}\\n\"\n---\nimport wibble/wobble.{Wibble, Wobble, Wubble}\n\npub fn cycle(wibble: wobble.Wibble) {\n  case wibble {\n    Wibble -> Wobble\n    Wobble -> Wubble\n    Wubble -> Wibble\n    ▔↑▔▔▔▔          \n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwobble.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_pattern_spread.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{type Wibble as Wobble}\\n\\ntype Thing {\\n  Thing(id: Int, value: Wobble)\\n}\\n\\npub fn main(thing: Thing) {\\n  case thing {\\n    Thing(id: 0, ..) -> 12\\n    _ -> 14\\n  }\\n}\\n\"\n---\nimport wibble/wobble.{type Wibble as Wobble}\n\ntype Thing {\n  Thing(id: Int, value: Wobble)\n}\n\npub fn main(thing: Thing) {\n  case thing {\n    Thing(id: 0, ..) -> 12\n                 ↑▔       \n    _ -> 14\n  }\n}\n\n\n----- Hover content (markdown) -----\nUnused labelled fields:\n- `value: Wobble`\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_unqualified.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{type Wibble}\\nconst value = wobble.Wobble\\n\"\n---\nimport wibble/wobble.{type Wibble}\nconst value = wobble.Wobble\n▔▔▔▔▔▔↑▔▔▔▔                \n\n\n----- Hover content (markdown) -----\n```gleam\nWibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_unqualified_aliased.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{type Wibble as Wobble}\\nconst value = wobble.Wobble\\n\"\n---\nimport wibble/wobble.{type Wibble as Wobble}\nconst value = wobble.Wobble\n▔▔▔▔▔▔↑▔▔▔▔                \n\n\n----- Hover content (markdown) -----\n```gleam\nWobble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_contextual_type_unqualified_import.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble.{type Wibble as Wobble, Wobble}\\n\"\n---\nimport wibble/wobble.{type Wibble as Wobble, Wobble}\n                                             ↑▔▔▔▔▔ \n\n\n----- Hover content (markdown) -----\n```gleam\nWobble\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/wibble/wobble.html#Wobble)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_expressions_in_function_body.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn append(x, y) {\\n  x <> y\\n}\\n\"\n---\nfn append(x, y) {\n  x <> y\n  ↑     \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\nA locally defined variable.\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_function_with_another_value_same_name.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport a/example_module.{my_const as discarded}\\nimport b/example_module.{my_const} as _\\nfn main() {\\n    my_const\\n}\\n\"\n---\nimport a/example_module.{my_const as discarded}\nimport b/example_module.{my_const} as _\nfn main() {\n    my_const\n    ▔▔▔▔↑▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/b/example_module.html#my_const)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_constants.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module\\nfn main() {\\n  example_module.my_const\\n}\\n\"\n---\nimport example_module\nfn main() {\n  example_module.my_const\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔▔▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_const)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_ffi_renamed_function.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module\\nfn main() {\\n    example_module.my_fn\\n}\\n\"\n---\nimport example_module\nfn main() {\n    example_module.my_fn\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_fn)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_function.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module\\nfn main() {\\n  example_module.my_fn\\n}\\n\"\n---\nimport example_module\nfn main() {\n  example_module.my_fn\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_fn)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_function_nested_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport my/nested/example_module\\nfn main() {\\n    example_module.my_fn\\n}\\n\"\n---\nimport my/nested/example_module\nfn main() {\n    example_module.my_fn\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/my/nested/example_module.html#my_fn)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_function_renamed_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module as renamed_module\\nfn main() {\\n    renamed_module.my_fn\\n}\\n\"\n---\nimport example_module as renamed_module\nfn main() {\n    renamed_module.my_fn\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_fn)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_unqualified_constants.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module.{my_const}\\nfn main() {\\n  my_const\\n}\\n\"\n---\nimport example_module.{my_const}\nfn main() {\n  my_const\n  ▔▔▔↑▔▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_const)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_imported_unqualified_function.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module.{my_fn}\\nfn main() {\\n  my_fn\\n}\\n\"\n---\nimport example_module.{my_fn}\nfn main() {\n  my_fn\n  ▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_fn)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_unqualified_imported_function_renamed_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module.{my_fn} as renamed_module\\nfn main() {\\n    my_fn\\n}\\n\"\n---\nimport example_module.{my_fn} as renamed_module\nfn main() {\n    my_fn\n    ▔▔↑▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_fn)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_external_value_with_two_modules_same_name.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport a/example_module as _\\nimport b/example_module\\nfn main() {\\n    example_module.my_const\\n}\\n\"\n---\nimport a/example_module as _\nimport b/example_module\nfn main() {\n    example_module.my_const\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n\nView on [HexDocs](https://hexdocs.pm/hex/b/example_module.html#my_const)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_annotation_in_use.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  use something: Int <- todo\\n  todo\\n}\\n\"\n---\npub fn main() {\n  use something: Int <- todo\n                 ▔↑▔        \n  todo\n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_anonymous_function_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// An example type.\\npub type Wibble\\n\\npub fn main() {\\n  fn(w: Wibble) { todo }\\n}\\n\"\n---\n/// An example type.\npub type Wibble\n\npub fn main() {\n  fn(w: Wibble) { todo }\n        ▔▔↑▔▔▔          \n}\n\n\n----- Hover content (markdown) -----\n```gleam\napp.Wibble\n```\n An example type.\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_bit_array.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst bits = <<1:2, 3:4>>\\n\"\n---\nconst bits = <<1:2, 3:4>>\n                 ▔↑      \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_bit_array_segment.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst bits = <<1:2, 3:4>>\\n\"\n---\nconst bits = <<1:2, 3:4>>\n               ↑         \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_bit_array_segment_option.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst bits = <<1:size(2), 3:4>>\\n\"\n---\nconst bits = <<1:size(2), 3:4>>\n                      ↑        \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_float.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst pi = 3.14\\n\"\n---\nconst pi = 3.14\n           ↑▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nFloat\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_int.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst ten = 10\\n\"\n---\nconst ten = 10\n            ↑▔\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_list.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst numbers = [2, 4, 6, 8]\\n\"\n---\nconst numbers = [2, 4, 6, 8]\n                ↑▔▔▔▔▔▔▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nList(Int)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_list_element.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst numbers = [2, 4, 6, 8]\\n\"\n---\nconst numbers = [2, 4, 6, 8]\n                    ↑       \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_other_constant.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst constant1 = 10\\nconst constant2 = constant1\\n\"\n---\nconst constant1 = 10\nconst constant2 = constant1\n                  ▔▔▔↑▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_record.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(Int)\\n}\\n\\nconst w = Wibble(10)\\n\"\n---\ntype Wibble {\n  Wibble(Int)\n}\n\nconst w = Wibble(10)\n          ▔↑▔▔▔▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nWibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_string.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst message = \\\"Hello!\\\"\\n\"\n---\nconst message = \"Hello!\"\n                ▔▔▔▔▔▔↑▔\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_string_concatenation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst name = \\\"Bob\\\"\\nconst message = \\\"Hello \\\" <> name\\n\"\n---\nconst name = \"Bob\"\nconst message = \"Hello \" <> name\n                ▔▔▔▔▔▔▔▔▔↑▔▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_string_concatenation_side.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst name = \\\"Bob\\\"\\nconst message = \\\"Hello \\\" <> name\\n\"\n---\nconst name = \"Bob\"\nconst message = \"Hello \" <> name\n                            ↑▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_tuple.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst tuple = #(1, 3.5, False)\\n\"\n---\nconst tuple = #(1, 3.5, False)\n              ↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\n#(Int, Float, Bool)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_constant_tuple_element.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst tuple = #(1, 3.5, False)\\n\"\n---\nconst tuple = #(1, 3.5, False)\n                        ↑▔▔▔▔ \n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_custom_type.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"/// Exciting documentation\\n/// Maybe even multiple lines\\ntype Wibble {\\n  /// Some more exciting documentation\\n  Wibble(String)\\n  /// The most exciting documentation\\n  Wobble(arg: Int)\\n}\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n▔▔▔▔▔↑▔▔▔▔▔▔▔\n  /// Some more exciting documentation\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wibble(String)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  /// The most exciting documentation\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n  Wobble(arg: Int)\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n}\n▔\n\n\n----- Hover content (markdown) -----\n```gleam\nWibble\n```\n Exciting documentation\n Maybe even multiple lines\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_invalid_record_update_1.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: True, b: 1)\\n}\\n\"\n---\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n                        ↑▔▔▔       \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_invalid_record_update_2.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: True, b: 1)\\n}\\n\"\n---\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n                                 ↑ \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_invalid_record_update_3.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: True, b: 1)\\n}\\n\"\n---\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n    ↑▔▔▔▔▔                         \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int, Bool) -> Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_invalid_record_update_4.snap.new",
    "content": "---\nsource: language-server/src/tests/hover.rs\nassertion_line: 2134\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Bool)\\n}\\n\\npub fn go(wibble: Wibble) {\\n    Wibble(..wibble, a: True, b: 1)\\n}\\n\"\nsnapshot_kind: text\n---\ntype Wibble {\n  Wibble(a: Int, b: Bool)\n}\n\npub fn go(wibble: Wibble) {\n    Wibble(..wibble, a: True, b: 1)\n                     ↑▔▔▔▔▔▔       \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_label_in_expression.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add(wibble a, wobble b) {\\n  a + b\\n}\\n\\npub fn main() {\\n  add(wibble: 1, wobble: 2)\\n}\\n\"\n---\nfn add(wibble a, wobble b) {\n  a + b\n}\n\npub fn main() {\n  add(wibble: 1, wobble: 2)\n      ▔↑▔▔▔▔▔▔▔            \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_label_in_pattern.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: Int, wobble: Int)\\n}\\n\\npub fn main() {\\n  let Wibble(wibble: _, wobble: _) = todo\\n  todo\\n}\\n\"\n---\ntype Wibble {\n  Wibble(wibble: Int, wobble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble: _, wobble: _) = todo\n             ▔▔▔▔↑▔▔▔▔                   \n  todo\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_local_variable_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  let wobble = False\\n  case wibble {\\n    True if wobble -> !wibble\\n    False if !wobble -> wibble\\n    _ -> wobble\\n  }\\n}\\n\"\n---\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n            ▔↑▔▔▔▔           \n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_module_select_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    True if mod.wibble < 5 -> !wibble\\n    False if mod.wibble != 10 -> wibble\\n    _ -> mod.wibble + 1\\n  }\\n}\\n\"\n---\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n            ▔▔▔▔↑▔▔▔▔▔               \n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_module_select_pattern.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport mod\\npub fn go(x: mod.Wibble) {\\n  case x {\\n    mod.Wibble -> 1\\n  }\\n}\\n\"\n---\nimport mod\npub fn go(x: mod.Wibble) {\n  case x {\n    mod.Wibble -> 1\n    ▔▔▔▔↑▔▔▔▔▔     \n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nmod.Wibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_nested_constant.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble\\n  Wobble(BitArray)\\n}\\n\\nconst value = #(1, 2, [Wibble, Wobble(<<1, 2, 3>>), Wibble])\\n\"\n---\ntype Wibble {\n  Wibble\n  Wobble(BitArray)\n}\n\nconst value = #(1, 2, [Wibble, Wobble(<<1, 2, 3>>), Wibble])\n                                              ↑             \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_pattern_in_use.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(Int, Float)\\n}\\n\\npub fn main() {\\n  use Wibble(int, float) <- todo\\n  todo\\n}\\n\"\n---\ntype Wibble {\n  Wibble(Int, Float)\n}\n\npub fn main() {\n  use Wibble(int, float) <- todo\n             ↑▔▔                \n  todo\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_pattern_spread_ignoring_all_fields.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Model {\\n  Model(\\n    Int,\\n    Float,\\n    label1: Int,\\n    label2: String,\\n  )\\n}\\n\\npub fn main() {\\n  case todo {\\n    Model(..) -> todo\\n  }\\n}\\n\"\n---\npub type Model {\n  Model(\n    Int,\n    Float,\n    label1: Int,\n    label2: String,\n  )\n}\n\npub fn main() {\n  case todo {\n    Model(..) -> todo\n          ↑▔         \n  }\n}\n\n\n----- Hover content (markdown) -----\nUnused positional fields:\n- `Int`\n- `Float`\n\nUnused labelled fields:\n- `label1: Int`\n- `label2: String`\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_pattern_spread_ignoring_all_positional_fields.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Model {\\n  Model(\\n    Int,\\n    Float,\\n    label1: Int,\\n    label2: String,\\n  )\\n}\\n\\npub fn main() {\\n  case todo {\\n    Model(_, _, _, ..) -> todo\\n  }\\n}\\n\"\n---\npub type Model {\n  Model(\n    Int,\n    Float,\n    label1: Int,\n    label2: String,\n  )\n}\n\npub fn main() {\n  case todo {\n    Model(_, _, _, ..) -> todo\n                   ↑▔         \n  }\n}\n\n\n----- Hover content (markdown) -----\nUnused labelled fields:\n- `label2: String`\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_pattern_spread_ignoring_some_fields.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Model {\\n  Model(\\n    Int,\\n    Float,\\n    label1: Int,\\n    label2: String,\\n  )\\n}\\n\\npub fn main() {\\n  case todo {\\n    Model(_, label1: _, ..) -> todo\\n  }\\n}\\n\"\n---\npub type Model {\n  Model(\n    Int,\n    Float,\n    label1: Int,\n    label2: String,\n  )\n}\n\npub fn main() {\n  case todo {\n    Model(_, label1: _, ..) -> todo\n                        ▔↑         \n  }\n}\n\n\n----- Hover content (markdown) -----\nUnused positional fields:\n- `Float`\n\nUnused labelled fields:\n- `label2: String`\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_record_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n  Wibble\\n  Wobble\\n}\\n\\npub fn main() {\\n  let wibble = True\\n  let wobble = Wibble\\n  case wibble {\\n    True if wobble == Wibble -> !wibble\\n    False if wobble == Wobble -> wibble\\n    _ -> Wibble\\n  }\\n}\\n\"\n---\ntype Wibble {\n  Wibble\n  Wobble\n}\n\npub fn main() {\n  let wibble = True\n  let wobble = Wibble\n  case wibble {\n    True if wobble == Wibble -> !wibble\n                      ▔▔▔▔↑▔           \n    False if wobble == Wobble -> wibble\n    _ -> Wibble\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nWibble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_record_module_select_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let wibble = True\\n  let wobble = mod.Wibble\\n  case wibble {\\n    True if wobble == mod.Wobble -> !wibble\\n    False if wobble == mod.Wibble -> wibble\\n    _ -> mod.Wibble\\n  }\\n}\\n\"\n---\nimport mod\n\npub fn main() {\n  let wibble = True\n  let wobble = mod.Wibble\n  case wibble {\n    True if wobble == mod.Wobble -> !wibble\n    False if wobble == mod.Wibble -> wibble\n                       ▔▔▔▔▔↑▔▔▔▔          \n    _ -> mod.Wibble\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nmod.Wobble\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_string_prefix_pattern.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  case \\\"wibble\\\" {\\n    \\\"wib\\\" as alias <> suffix -> alias <> suffix\\n    other -> other\\n  }\\n}\\n\"\n---\npub fn main() {\n  case \"wibble\" {\n    \"wib\" as alias <> suffix -> alias <> suffix\n    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔▔▔▔▔▔▔▔                   \n    other -> other\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_string_prefix_pattern_prefix_alias.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  case \\\"wibble\\\" {\\n    \\\"wib\\\" as alias <> suffix -> alias <> suffix\\n    other -> other\\n  }\\n}\\n\"\n---\npub fn main() {\n  case \"wibble\" {\n    \"wib\" as alias <> suffix -> alias <> suffix\n             ↑▔▔▔▔                             \n    other -> other\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_string_prefix_pattern_prefix_alias_alternative_definition.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  case \\\"wibble\\\" {\\n    \\\"wib\\\" as prefix <> rest | \\\"wob\\\" as prefix <> rest -> prefix <> rest\\n    other -> other\\n  }\\n}\\n\"\n---\npub fn main() {\n  case \"wibble\" {\n    \"wib\" as prefix <> rest | \"wob\" as prefix <> rest -> prefix <> rest\n                                       ↑▔▔▔▔▔                          \n    other -> other\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_string_prefix_pattern_suffix_variable.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  case \\\"wibble\\\" {\\n    \\\"wib\\\" as alias <> suffix -> alias <> suffix\\n    other -> other\\n  }\\n}\\n\"\n---\npub fn main() {\n  case \"wibble\" {\n    \"wib\" as alias <> suffix -> alias <> suffix\n                      ↑▔▔▔▔▔                   \n    other -> other\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_string_prefix_pattern_suffix_variable_alternative_definition.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  case \\\"wibble\\\" {\\n    \\\"wib\\\" <> rest | \\\"wob\\\" <> rest -> rest\\n    other -> other\\n  }\\n}\\n\"\n---\npub fn main() {\n  case \"wibble\" {\n    \"wib\" <> rest | \"wob\" <> rest -> rest\n                             ↑▔▔▔        \n    other -> other\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_for_string_prefix_pattern_suffix_variable_discard.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  case \\\"wibble\\\" {\\n    \\\"wib\\\" <> _discard -> Nil\\n    other -> Nil\\n  }\\n}\\n\"\n---\npub fn main() {\n  case \"wibble\" {\n    \"wib\" <> _discard -> Nil\n    ▔▔▔▔▔▔▔▔▔↑▔▔▔▔▔▔▔       \n    other -> Nil\n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_arg_annotation_2.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nfn append(x: String, y: String) -> String {\\n  x <> y\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x: String, y: String) -> String {\n             ▔▔▔▔↑▔                        \n  x <> y\n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.String\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_arg_annotation_with_documentation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\ntype Wibble {\\n    Wibble(arg: String)\\n}\\n\\nfn identity(x: Wibble) -> Wibble {\\n  x\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    Wibble(arg: String)\n}\n\nfn identity(x: Wibble) -> Wibble {\n               ▔▔▔▔▔↑             \n  x\n}\n\n\n----- Hover content (markdown) -----\n```gleam\napp.Wibble\n```\n Exciting documentation\n Maybe even multiple lines\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_argument.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nfn append(x, y) {\\n  x <> y\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x, y) {\n          ↑      \n  x <> y\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_definition.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add_2(x) {\\n  x + 2\\n}\\n\"\n---\nfn add_2(x) {\n▔▔▔↑▔▔▔▔▔▔▔  \n  x + 2\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int) -> Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_definition_with_docs.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nfn append(x, y) {\\n  x <> y\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x, y) {\n▔▔▔↑▔▔▔▔▔▔▔▔▔▔▔  \n  x <> y\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(String, String) -> String\n```\n Exciting documentation\n Maybe even multiple lines\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_return_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nfn append(x: String, y: String) -> String {\\n  x <> y\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x: String, y: String) -> String {\n                                   ▔▔▔▔↑▔  \n  x <> y\n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.String\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_function_return_annotation_with_tuple.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nfn append(x: String, y: String) -> #(String, String) {\\n  #(x, y)\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nfn append(x: String, y: String) -> #(String, String) {\n                                     ▔▔↑▔▔▔           \n  #(x, y)\n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.String\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_import_unqualified_type.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module.{type MyType, MyType}\\nfn main() -> MyType {\\n  MyType\\n}\\n\"\n---\nimport example_module.{type MyType, MyType}\n                       ▔▔▔▔▔▔▔▔▔▔↑         \nfn main() -> MyType {\n  MyType\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nexample_module.MyType\n```\n Exciting documentation\n Maybe even multiple lines\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_import_unqualified_value.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module.{my_num}\\nfn main() {\\n  my_num\\n}\\n\"\n---\nimport example_module.{my_num}\n                       ▔▔▔↑▔▔ \nfn main() {\n  my_num\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n Exciting documentation\n Maybe even multiple lines\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_import_unqualified_value_from_hex.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module.{my_num}\\nfn main() {\\n  my_num\\n}\\n\"\n---\nimport example_module.{my_num}\n                       ▔▔▔↑▔▔ \nfn main() {\n  my_num\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n Exciting documentation\n Maybe even multiple lines\n\nView on [HexDocs](https://hexdocs.pm/hex/example_module.html#my_num)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_imported_function.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport example_module\\nfn main() {\\n  example_module.my_fn\\n}\\n\"\n---\nimport example_module\nfn main() {\n  example_module.my_fn\n  ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔↑▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_label_shorthand_in_call_arg.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn wibble(arg1 arg1: Int, arg2 arg2: Bool) { Nil }\\n\\nfn main() {\\n  let arg1 = 1\\n  let arg2 = True\\n  wibble(arg2:, arg1:)\\n}\\n\"\n---\nfn wibble(arg1 arg1: Int, arg2 arg2: Bool) { Nil }\n\nfn main() {\n  let arg1 = 1\n  let arg2 = True\n  wibble(arg2:, arg1:)\n         ↑▔▔▔▔        \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\nA locally defined variable.\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_label_shorthand_in_pattern_call_arg.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Wibble { Wibble(arg1: Int, arg2: Bool) }\\n\\npub fn main() {\\n  case todo {\\n    Wibble(arg2:, ..) -> todo\\n  }\\n}\\n\"\n---\npub type Wibble { Wibble(arg1: Int, arg2: Bool) }\n\npub fn main() {\n  case todo {\n    Wibble(arg2:, ..) -> todo\n           ▔▔▔▔↑             \n  }\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_label_shorthand_in_pattern_call_arg_2.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Wibble { Wibble(arg1: Int, arg2: Bool) }\\n\\npub fn main() {\\n  let Wibble(arg2:, ..) = todo\\n}\\n\"\n---\npub type Wibble { Wibble(arg1: Int, arg2: Bool) }\n\npub fn main() {\n  let Wibble(arg2:, ..) = todo\n             ▔↑▔▔▔            \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nBool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_local_function.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn my_fn() {\\n  Nil\\n}\\n\\nfn main() {\\n  my_fn\\n}\\n\"\n---\nfn my_fn() {\n  Nil\n}\n\nfn main() {\n  my_fn\n  ▔↑▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_local_function_in_pipe.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add1(num: Int) -> Int {\\n  num + 1\\n}\\n\\npub fn main() {\\n  add1(1)\\n\\n  1\\n  |> add1\\n  |> add1\\n  |> add1\\n}\\n\"\n---\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n  ▔↑▔▔   \n\n  1\n  |> add1\n  |> add1\n  |> add1\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int) -> Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_local_function_in_pipe_1.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add1(num: Int) -> Int {\\n  num + 1\\n}\\n\\npub fn main() {\\n  add1(1)\\n\\n  1\\n  |> add1\\n  |> add1\\n  |> add1\\n}\\n\"\n---\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n     ▔▔↑▔\n  |> add1\n  |> add1\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int) -> Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_local_function_in_pipe_2.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add1(num: Int) -> Int {\\n  num + 1\\n}\\n\\npub fn main() {\\n  add1(1)\\n\\n  1\\n  |> add1\\n  |> add1\\n  |> add1\\n}\\n\"\n---\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n  |> add1\n     ▔▔↑▔\n  |> add1\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int) -> Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_local_function_in_pipe_3.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn add1(num: Int) -> Int {\\n  num + 1\\n}\\n\\npub fn main() {\\n  add1(1)\\n\\n  1\\n  |> add1\\n  |> add1\\n  |> add1\\n}\\n\"\n---\nfn add1(num: Int) -> Int {\n  num + 1\n}\n\npub fn main() {\n  add1(1)\n\n  1\n  |> add1\n  |> add1\n  |> add1\n     ▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int) -> Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_module_constant.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nconst one = 1\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nconst one = 1\n▔▔▔▔▔▔↑▔▔    \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n Exciting documentation\n Maybe even multiple lines\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_module_constant_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\nconst one: Int = 1\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\nconst one: Int = 1\n           ▔▔↑    \n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(wibble)\\n  |> filter(fn(value) { value })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  ↑▔▔▔▔▔▔▔▔\n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\n\n----- Hover content (markdown) -----\n```gleam\nList(Int)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_1.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(wibble)\\n  |> filter(fn(value) { value })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n   ↑       \n  |> map(wibble)\n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_2.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(wibble)\\n  |> filter(fn(value) { value })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n     ↑▔▔        \n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(List(Int), fn(Int) -> Bool) -> List(Bool)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_3.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(wibble)\\n  |> filter(fn(value) { value })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n         ↑▔▔▔▔▔ \n  |> filter(fn(value) { value })\n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Int) -> Bool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_4.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(wibble)\\n  |> filter(fn(value) { value })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n     ↑▔▔▔▔▔                     \n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) {}\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(List(Bool), fn(Bool) -> Bool) -> List(Bool)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_5.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> map(wibble)\\n  |> filter(fn(value) { value })\\n}\\n\\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  |> map(wibble)\n  |> filter(fn(value) { value })\n            ↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ \n}\n\nfn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Bool) -> Bool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_6.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> wibble\\n  |> filter(fn(value) { value })\\n}\\n\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n     ↑▔▔▔▔▔\n  |> filter(fn(value) { value })\n}\n\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(List(Int)) -> List(Bool)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_on_pipe_with_invalid_step_8.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, 3]\\n  |> wibble\\n  |> filter(fn(value) { value })\\n}\\n\\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\\n\"\n---\npub fn main() {\n  [1, 2, 3]\n  |> wibble\n  |> filter(fn(value) { value })\n            ↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ \n}\n\nfn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo }\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(Bool) -> Bool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_over_block_in_list_spread.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub fn main() {\\n  [1, 2, ..{\\n    let x = 1\\n    [x]\\n  }]\\n}\\n\"\n---\npub fn main() {\n  [1, 2, ..{\n    let x = 1\n        ↑    \n    [x]\n  }]\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_over_imported_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble\\n\"\n---\nimport wibble\n▔▔▔▔▔▔▔↑▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nwibble\n```\n This is the wibble module.\n Here is some documentation about it.\n This module does stuff\n\nView on [HexDocs](https://hexdocs.pm/hex/wibble.html)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_over_module_name.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble\\n\\npub fn main() {\\n  wibble.wibble()\\n}\\n\"\n---\nimport wibble\n\npub fn main() {\n  wibble.wibble()\n  ↑▔▔▔▔▔         \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwibble\n```\n This is the wibble module.\n Here is some documentation about it.\n This module does stuff\n\nView on [HexDocs](https://hexdocs.pm/hex/wibble.html)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_over_module_name_in_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble\\n\\npub fn main(w: wibble.Wibble) {\\n  todo\\n}\\n\"\n---\nimport wibble\n\npub fn main(w: wibble.Wibble) {\n               ↑▔▔▔▔▔          \n  todo\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwibble\n```\n This is the wibble module.\n Here is some documentation about it.\n This module does stuff\n\nView on [HexDocs](https://hexdocs.pm/hex/wibble.html)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_over_module_with_path.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble/wobble\\n\\npub fn main() {\\n  wobble.wibble()\\n}\\n\"\n---\nimport wibble/wobble\n\npub fn main() {\n  wobble.wibble()\n  ↑▔▔▔▔▔         \n}\n\n\n----- Hover content (markdown) -----\n```gleam\nwibble/wobble\n```\n The module documentation\n\nView on [HexDocs](https://hexdocs.pm/hex/wibble/wobble.html)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_prelude_type.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nconst number = 100\\n\"\n---\nconst number = 100\n▔▔▔▔▔▔▔▔▔↑▔▔      \n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_alias_when_parameters_match.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype MyResult(a, b) = Result(a, b)\\n\\nfn do_thing() -> MyResult(Int, Int) {\\n  Error(1)\\n}\\n\"\n---\ntype MyResult(a, b) = Result(a, b)\n\nfn do_thing() -> MyResult(Int, Int) {\n▔▔▔↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔  \n  Error(1)\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> MyResult(Int, Int)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_aliased_imported_generic_type.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport gleam/option.{type Option as Maybe}\\n\\nconst none: Maybe(Int) = option.None\\n\"\n---\nimport gleam/option.{type Option as Maybe}\n\nconst none: Maybe(Int) = option.None\n▔▔▔▔▔▔▔▔▔↑▔▔▔▔▔▔▔▔▔▔▔▔              \n\n\n----- Hover content (markdown) -----\n```gleam\nMaybe(Int)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_imported_alias.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport aliases.{type Aliased}\\nconst thing: Aliased = 10\\n\"\n---\nimport aliases.{type Aliased}\nconst thing: Aliased = 10\n▔▔▔▔▔▔▔▔▔▔↑▔▔▔▔▔▔▔▔▔     \n\n\n----- Hover content (markdown) -----\n```gleam\nAliased\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_qualified_prelude_type_when_shadowed_by_alias.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Result = #(Bool, String)\\nconst ok = Ok(10)\\n\"\n---\ntype Result = #(Bool, String)\nconst ok = Ok(10)\n▔▔▔▔▔▔▔↑         \n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Result(Int, a)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_qualified_prelude_type_when_shadowed_by_imported_alias.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport alias.{type Bool}\\nconst value = True\\n\"\n---\nimport alias.{type Bool}\nconst value = True\n▔▔▔▔▔▔↑▔▔▔▔       \n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Bool\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_type_variable_names.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn main(value: Result(ok, error)) {\\n  let v = value\\n  v\\n}\\n\"\n---\nfn main(value: Result(ok, error)) {\n  let v = value\n      ↑        \n  v\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nResult(ok, error)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_unbound_type_variable_name_without_conflicts.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn make_ok(value: a) {\\n  let result = Ok(value)\\n  result\\n}\\n\"\n---\nfn make_ok(value: a) {\n  let result = Ok(value)\n      ▔▔↑▔▔▔            \n  result\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nResult(a, b)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_unbound_type_variable_names.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn make_ok(value: some_type) {\\n  let result = Ok(value)\\n  result\\n}\\n\"\n---\nfn make_ok(value: some_type) {\n  let result = Ok(value)\n      ▔▔↑▔▔▔            \n  result\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nResult(some_type, a)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_underlying_for_alias_with_parameters.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype LocalResult = Result(String, Int)\\n\\nfn do_thing() -> LocalResult {\\n  Error(1)\\n}\\n\"\n---\ntype LocalResult = Result(String, Int)\n\nfn do_thing() -> LocalResult {\n▔▔▔↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔  \n  Error(1)\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Result(String, Int)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_print_underlying_for_imported_alias.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport alias.{type A}\\n\\nfn wibble() -> Result(Int, String) {\\n  todo\\n}\\n\"\n---\nimport alias.{type A}\n\nfn wibble() -> Result(Int, String) {\n▔▔▔▔▔▔▔↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔  \n  todo\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Result(Int, String)\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_shadowed_prelude_type.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Int { Int }\\nconst number = 100\\n\"\n---\ntype Int { Int }\nconst number = 100\n▔▔▔▔▔▔▔▔▔↑▔▔      \n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_shadowed_prelude_type_imported.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport numbers.{type Int}\\nconst number = 100\\n\"\n---\nimport numbers.{type Int}\nconst number = 100\n▔▔▔▔▔▔▔▔▔↑▔▔      \n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_type_alias_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: type Wibble = Int\n---\ntype Wibble = Int\n              ▔↑▔\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.Int\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_type_constructor_annotation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\ntype Wibble {\\n    Wibble(arg: String)\\n}\\n\"\n---\ntype Wibble {\n    Wibble(arg: String)\n                ▔▔▔▔↑▔ \n}\n\n\n----- Hover content (markdown) -----\n```gleam\ngleam.String\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_type_constructor_with_label.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\ntype Wibble {\\n    /// Some more exciting documentation\\n    Wibble(arg: String)\\n    /// The most exciting documentation\\n    Wobble(Int)\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    /// Some more exciting documentation\n    Wibble(arg: String)\n    ↑▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n    /// The most exciting documentation\n    Wobble(Int)\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nWibble(arg: String)\n```\n Some more exciting documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_type_constructor_with_no_fields.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\ntype Wibble {\\n    /// Some more exciting documentation\\n    Wibble\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    /// Some more exciting documentation\n    Wibble\n    ↑▔▔▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nWibble\n```\n Some more exciting documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_type_constructor_with_no_label.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\n/// Exciting documentation\\n/// Maybe even multiple lines\\ntype Wibble {\\n    /// Some more exciting documentation\\n    Wibble(arg: String)\\n    /// The most exciting documentation\\n    Wobble(Int)\\n}\\n\"\n---\n/// Exciting documentation\n/// Maybe even multiple lines\ntype Wibble {\n    /// Some more exciting documentation\n    Wibble(arg: String)\n    /// The most exciting documentation\n    Wobble(Int)\n    ↑▔▔▔▔▔▔▔▔▔▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nWobble(Int)\n```\n The most exciting documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_variable_in_use_expression.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn b(fun: fn(Int) -> String) {\\n  fun(42)\\n}\\n\\nfn do_stuff() {\\n  let c = \\\"done\\\"\\n\\n  use a <- b\\n  c\\n}\\n\"\n---\nfn b(fun: fn(Int) -> String) {\n  fun(42)\n}\n\nfn do_stuff() {\n  let c = \"done\"\n\n  use a <- b\n      ↑     \n  c\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_variable_in_use_expression_1.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn b(fun: fn(Int) -> String) {\\n  fun(42)\\n}\\n\\nfn do_stuff() {\\n  let c = \\\"done\\\"\\n\\n  use a <- b\\n  c\\n}\\n\"\n---\nfn b(fun: fn(Int) -> String) {\n  fun(42)\n}\n\nfn do_stuff() {\n  let c = \"done\"\n\n  use a <- b\n           ↑\n  c\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nfn(fn(Int) -> String) -> String\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_variable_in_use_expression_2.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn b(fun: fn(Int) -> String) {\\n  fun(42)\\n}\\n\\nfn do_stuff() {\\n  let c = \\\"done\\\"\\n\\n  use a <- b\\n  c\\n}\\n\"\n---\nfn b(fun: fn(Int) -> String) {\n  fun(42)\n}\n\nfn do_stuff() {\n  let c = \"done\"\n\n  use a <- b\n  c\n  ↑\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nString\n```\nA locally defined variable.\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__hover_works_even_for_invalid_code.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nfn invalid() { 1 + Nil }\\nfn valid() { Nil }\\n\"\n---\nfn invalid() { 1 + Nil }\nfn valid() { Nil }\n▔▔▔↑▔▔▔▔▔▔        \n\n\n----- Hover content (markdown) -----\n```gleam\nfn() -> Nil\n```\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__no_documentation_for_shared_record_field.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(\\n    /// This is some documentation about the wibble field.\\n    wibble: Int\\n  )\\n  Wobble(\\n    /// Here's some documentation explaining a field of Wobble\\n    wibble: Int\\n  )\\n}\\n\\npub fn wibble(w: Wibble) {\\n  w.wibble\\n}\\n\"\n---\npub type Wibble {\n  Wibble(\n    /// This is some documentation about the wibble field.\n    wibble: Int\n  )\n  Wobble(\n    /// Here's some documentation explaining a field of Wobble\n    wibble: Int\n  )\n}\n\npub fn wibble(w: Wibble) {\n  w.wibble\n  ▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n## Wibble\n\n This is some documentation about the wibble field.\n\n## Wobble\n\n Here's some documentation explaining a field of Wobble\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__no_hexdocs_link_when_hovering_over_local_module.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\nimport wibble\\n\"\n---\nimport wibble\n▔▔▔▔▔▔▔↑▔▔▔▔▔\n\n\n----- Hover content (markdown) -----\n```gleam\nwibble\n```\n This is the wibble module.\n Here is some documentation about it.\n This module does stuff\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__hover__record_field_documentation.snap",
    "content": "---\nsource: language-server/src/tests/hover.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(\\n    /// This is some documentation about the wibble field.\\n    wibble: Int\\n  )\\n}\\n\\npub fn wibble(w: Wibble) {\\n  w.wibble\\n}\\n\"\n---\npub type Wibble {\n  Wibble(\n    /// This is some documentation about the wibble field.\n    wibble: Int\n  )\n}\n\npub fn wibble(w: Wibble) {\n  w.wibble\n  ▔▔▔▔▔▔↑▔\n}\n\n\n----- Hover content (markdown) -----\n```gleam\nInt\n```\n This is some documentation about the wibble field.\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_aliased_const.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub const wibble = 123\\n\\npub fn main() {\\n  wibble\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{wibble as other}\n            ▔▔▔▔▔▔          \n\nfn wobble() {\n  other\n  ▔▔▔▔▔\n}\n\n\n-- app.gleam\n\npub const wibble = 123\n          ▔▔▔▔▔▔      \n\npub fn main() {\n  wibble\n  ↑▔▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_aliased_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub fn wibble() {\\n  123\\n}\\n\\npub fn main() {\\n  wibble()\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{wibble as other}\n            ▔▔▔▔▔▔          \n\nfn wobble() {\n  other()\n  ▔▔▔▔▔  \n}\n\n\n-- app.gleam\n\npub fn wibble() {\n       ▔▔▔▔▔▔    \n  123\n}\n\npub fn main() {\n  wibble()\n  ↑▔▔▔▔▔  \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_aliased_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub type Wibble { Wibble }\\n\\npub fn main() -> Wibble {\\n  todo\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{type Wibble as Wobble}\n                 ▔▔▔▔▔▔           \n\nfn wobble() -> Wobble {\n               ▔▔▔▔▔▔  \n  todo\n}\n\nfn other(w: app.Wibble) {\n                ▔▔▔▔▔▔   \n  todo\n}\n\n\n-- app.gleam\n\npub type Wibble { Wibble }\n         ▔▔▔▔▔▔           \n\npub fn main() -> Wibble {\n                 ↑▔▔▔▔▔  \n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_aliased_value.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub type Wibble { Wibble }\\n\\npub fn main() {\\n  Wibble\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{Wibble as Wobble}\n            ▔▔▔▔▔▔           \n\nfn wobble() {\n  Wobble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\npub type Wibble { Wibble }\n                  ↑▔▔▔▔▔  \n\npub fn main() {\n  Wibble\n  ▔▔▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_constant_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let value = mod.wibble\\n  mod.wibble + value\\n}\\n\"\n---\n-- mod.gleam\n\npub const wibble = 10\n          ▔▔▔▔▔▔     \n\nfn wobble() {\n  wibble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let value = mod.wibble\n                  ↑▔▔▔▔▔\n  mod.wibble + value\n      ▔▔▔▔▔▔        \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_constant_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod.{wibble}\\n\\npub fn main() {\\n  let value = mod.wibble\\n  wibble + value\\n}\\n\"\n---\n-- mod.gleam\n\npub const wibble = 10\n          ▔▔▔▔▔▔     \n\nfn wobble() {\n  wibble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\nimport mod.{wibble}\n            ▔▔▔▔▔▔ \n\npub fn main() {\n  let value = mod.wibble\n                  ▔▔▔▔▔▔\n  wibble + value\n  ↑▔▔▔▔▔        \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_function_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let value = mod.wibble()\\n  mod.wibble()\\n  value\\n}\\n\"\n---\n-- mod.gleam\n\npub fn wibble() {\n       ▔▔▔▔▔▔    \n  wibble()\n  ▔▔▔▔▔▔  \n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let value = mod.wibble()\n                  ↑▔▔▔▔▔  \n  mod.wibble()\n      ▔▔▔▔▔▔  \n  value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_function_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod.{wibble}\\n\\npub fn main() {\\n  let value = wibble()\\n  mod.wibble()\\n  value\\n}\\n\"\n---\n-- mod.gleam\n\npub fn wibble() {\n       ▔▔▔▔▔▔    \n  wibble()\n  ▔▔▔▔▔▔  \n}\n\n\n-- app.gleam\n\nimport mod.{wibble}\n            ▔▔▔▔▔▔ \n\npub fn main() {\n  let value = wibble()\n              ↑▔▔▔▔▔  \n  mod.wibble()\n      ▔▔▔▔▔▔  \n  value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  let wobble = wibble + 1\\n  wibble + wobble\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n      ▔▔▔▔▔▔     \n  let wobble = wibble + 1\n               ↑▔▔▔▔▔    \n  wibble + wobble\n  ▔▔▔▔▔▔         \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_local_variable_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  let wobble = wibble + 1\\n  wibble + wobble\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n      ↑▔▔▔▔▔     \n  let wobble = wibble + 1\n               ▔▔▔▔▔▔    \n  wibble + wobble\n  ▔▔▔▔▔▔         \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_local_variable_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  let wobble = False\\n  case wibble {\\n    True if wobble -> !wibble\\n    False if !wobble -> wibble\\n    _ -> wobble\\n  }\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() {\n  let wibble = True\n  let wobble = False\n      ▔▔▔▔▔▔        \n  case wibble {\n    True if wobble -> !wibble\n            ▔↑▔▔▔▔           \n    False if !wobble -> wibble\n              ▔▔▔▔▔▔          \n    _ -> wobble\n         ▔▔▔▔▔▔\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_module_select_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    True if mod.wibble < 5 -> !wibble\\n    False if mod.wibble != 10 -> wibble\\n    _ -> mod.wibble + 1\\n  }\\n}\\n\"\n---\n-- mod.gleam\npub const wibble = 10\n          ▔▔▔▔▔▔     \n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n                ↑▔▔▔▔▔               \n    False if mod.wibble != 10 -> wibble\n                 ▔▔▔▔▔▔                \n    _ -> mod.wibble + 1\n             ▔▔▔▔▔▔    \n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_and_suffix_complex_guard.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\nfn main() {\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" as digit <> rest if digit == \\\"1\\\" && rest == \\\"-wibble\\\" -> #(digit, rest)\\n    _ -> #(\\\"\\\", \\\"\\\")\\n  }\\n}\\n\"\n---\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" as digit <> rest if digit == \"1\" && rest == \"-wibble\" -> #(digit, rest)\n           ↑▔▔▔▔            ▔▔▔▔▔                                  ▔▔▔▔▔       \n    _ -> #(\"\", \"\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_in_case.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let digit = case wibble {\\n    \\\"1\\\" as digit <> _rest -> digit\\n    other -> other\\n  }\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let digit = case wibble {\n    \"1\" as digit <> _rest -> digit\n           ↑▔▔▔▔             ▔▔▔▔▔\n    other -> other\n  }\n  digit\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_in_case_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let digit = case wibble {\\n    \\\"1\\\" as digit <> _rest -> digit\\n    other -> other\\n  }\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let digit = case wibble {\n    \"1\" as digit <> _rest -> digit\n           ▔▔▔▔▔             ↑▔▔▔▔\n    other -> other\n  }\n  digit\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_in_let_assert.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let assert \\\"1\\\" as digit <> _rest = \\\"1-wibble\\\"\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let assert \"1\" as digit <> _rest = \"1-wibble\"\n                    ↑▔▔▔▔                      \n  digit\n  ▔▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_in_let_assert_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let assert \\\"1\\\" as digit <> _rest = \\\"1-wibble\\\"\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let assert \"1\" as digit <> _rest = \"1-wibble\"\n                    ▔▔▔▔▔                      \n  digit\n  ↑▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_used_in_guard.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\nfn main() {\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" as digit <> _rest if digit == \\\"1\\\" -> digit\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" as digit <> _rest if digit == \"1\" -> digit\n           ↑▔▔▔▔             ▔▔▔▔▔           ▔▔▔▔▔\n    _ -> \"\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_with_alternative_definitions_in_case.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let digit = case wibble {\\n    \\\"1\\\" as digit <> _rest | \\\"2\\\" as digit <> _rest -> digit\\n    other -> other\\n  }\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let digit = case wibble {\n    \"1\" as digit <> _rest | \"2\" as digit <> _rest -> digit\n           ↑▔▔▔▔                   ▔▔▔▔▔             ▔▔▔▔▔\n    other -> other\n  }\n  digit\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_with_alternative_definitions_triggered_from_second_pattern.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let digit = case wibble {\\n    \\\"1\\\" as digit <> _rest | \\\"2\\\" as digit <> _rest -> digit\\n    other -> other\\n  }\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let digit = case wibble {\n    \"1\" as digit <> _rest | \"2\" as digit <> _rest -> digit\n           ▔▔▔▔▔                   ↑▔▔▔▔             ▔▔▔▔▔\n    other -> other\n  }\n  digit\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_alias_with_alternative_definitions_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let digit = case wibble {\\n    \\\"1\\\" as digit <> _rest | \\\"2\\\" as digit <> _rest -> digit\\n    other -> other\\n  }\\n  digit\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let digit = case wibble {\n    \"1\" as digit <> _rest | \"2\" as digit <> _rest -> digit\n           ▔▔▔▔▔                   ▔▔▔▔▔             ↑▔▔▔▔\n    other -> other\n  }\n  digit\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_shadowing_outer_variable.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\nfn main() {\\n  let rest = \\\"outer\\\"\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" <> rest -> rest\\n    _ -> rest\\n  }\\n}\\n\"\n---\n-- app.gleam\n\nfn main() {\n  let rest = \"outer\"\n  case \"1-wibble\" {\n    \"1\" <> rest -> rest\n           ↑▔▔▔    ▔▔▔▔\n    _ -> rest\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_used_in_guard.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\nfn main() {\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" <> rest if rest == \\\"-wibble\\\" -> rest\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" <> rest if rest == \"-wibble\" -> rest\n           ↑▔▔▔    ▔▔▔▔                 ▔▔▔▔\n    _ -> \"\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_in_case.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let rest = case wibble {\\n    \\\"1\\\" <> rest -> rest\\n    other -> other\\n  }\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let rest = case wibble {\n    \"1\" <> rest -> rest\n           ↑▔▔▔    ▔▔▔▔\n    other -> other\n  }\n  rest\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_in_case_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let rest = case wibble {\\n    \\\"1\\\" <> rest -> rest\\n    other -> other\\n  }\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let rest = case wibble {\n    \"1\" <> rest -> rest\n           ▔▔▔▔    ↑▔▔▔\n    other -> other\n  }\n  rest\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_in_let_assert.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let assert \"1\" <> rest = \"1-wibble\"\n                    ↑▔▔▔             \n  rest\n  ▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_in_let_assert_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let assert \"1\" <> rest = \"1-wibble\"\n                    ▔▔▔▔             \n  rest\n  ↑▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_nested_in_tuple.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\nfn main() {\\n  case #(\\\"1-wibble\\\", 0) {\\n    #(\\\"1\\\" <> rest, _) -> rest\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n-- app.gleam\n\nfn main() {\n  case #(\"1-wibble\", 0) {\n    #(\"1\" <> rest, _) -> rest\n             ↑▔▔▔        ▔▔▔▔\n    _ -> \"\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_with_alternative_definition_in_case.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let rest = case wibble {\\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\\n    other -> other\\n  }\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let rest = case wibble {\n    \"1\" <> rest | \"2\" <> rest -> rest\n           ↑▔▔▔          ▔▔▔▔    ▔▔▔▔\n    other -> other\n  }\n  rest\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_with_alternative_definition_triggered_from_second_pattern.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let rest = case wibble {\\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\\n    other -> other\\n  }\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let rest = case wibble {\n    \"1\" <> rest | \"2\" <> rest -> rest\n           ▔▔▔▔          ↑▔▔▔    ▔▔▔▔\n    other -> other\n  }\n  rest\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_prefix_string_suffix_variable_with_alternative_definition_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/reference.rs\nexpression: \"\\npub fn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  let rest = case wibble {\\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\\n    other -> other\\n  }\\n  rest\\n}\\n\"\n---\n-- app.gleam\n\npub fn main() -> String {\n  let wibble = \"1-wibble\"\n  let rest = case wibble {\n    \"1\" <> rest | \"2\" <> rest -> rest\n           ▔▔▔▔          ▔▔▔▔    ↑▔▔▔\n    other -> other\n  }\n  rest\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nconst wibble = 10\\n\\npub fn main() {\\n  let _ = wibble\\n  wibble + 4\\n}\\n\\nfn wobble() {\\n  wibble + wobble()\\n}\\n\"\n---\n-- app.gleam\n\nconst wibble = 10\n      ↑▔▔▔▔▔     \n\npub fn main() {\n  let _ = wibble\n          ▔▔▔▔▔▔\n  wibble + 4\n  ▔▔▔▔▔▔    \n}\n\nfn wobble() {\n  wibble + wobble()\n  ▔▔▔▔▔▔           \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_constant_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nconst wibble = 10\\n\\npub fn main() {\\n  let _ = wibble\\n  wibble + 4\\n}\\n\\nfn wobble() {\\n  wibble + wobble()\\n}\\n\"\n---\n-- app.gleam\n\nconst wibble = 10\n      ▔▔▔▔▔▔     \n\npub fn main() {\n  let _ = wibble\n          ↑▔▔▔▔▔\n  wibble + 4\n  ▔▔▔▔▔▔    \n}\n\nfn wobble() {\n  wibble + wobble()\n  ▔▔▔▔▔▔           \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nfn wibble() {\\n  wibble()\\n}\\n\\npub fn main() {\\n  let _ = wibble()\\n  wibble() + 4\\n}\\n\\nfn wobble() {\\n  wibble() || wobble()\\n}\\n\"\n---\n-- app.gleam\n\nfn wibble() {\n   ↑▔▔▔▔▔    \n  wibble()\n  ▔▔▔▔▔▔  \n}\n\npub fn main() {\n  let _ = wibble()\n          ▔▔▔▔▔▔  \n  wibble() + 4\n  ▔▔▔▔▔▔      \n}\n\nfn wobble() {\n  wibble() || wobble()\n  ▔▔▔▔▔▔              \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_function_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nfn wibble() {\\n  wibble()\\n}\\n\\npub fn main() {\\n  let _ = wibble()\\n  wibble() + 4\\n}\\n\\nfn wobble() {\\n  wibble() || wobble()\\n}\\n\"\n---\n-- app.gleam\n\nfn wibble() {\n   ▔▔▔▔▔▔    \n  wibble()\n  ↑▔▔▔▔▔  \n}\n\npub fn main() {\n  let _ = wibble()\n          ▔▔▔▔▔▔  \n  wibble() + 4\n  ▔▔▔▔▔▔      \n}\n\nfn wobble() {\n  wibble() || wobble()\n  ▔▔▔▔▔▔              \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\ntype Wibble { Wibble }\\n\\nfn main() -> Wibble {\\n  todo\\n}\\n\\nfn wobble(w: Wibble) {\\n  todo\\n}\\n\"\n---\n-- app.gleam\n\ntype Wibble { Wibble }\n     ↑▔▔▔▔▔           \n\nfn main() -> Wibble {\n             ▔▔▔▔▔▔  \n  todo\n}\n\nfn wobble(w: Wibble) {\n             ▔▔▔▔▔▔   \n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_type_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\ntype Wibble { Wibble }\\n\\nfn main() -> Wibble {\\n  todo\\n}\\n\\nfn wobble(w: Wibble) {\\n  todo\\n}\\n\"\n---\n-- app.gleam\n\ntype Wibble { Wibble }\n     ▔▔▔▔▔▔           \n\nfn main() -> Wibble {\n             ↑▔▔▔▔▔  \n  todo\n}\n\nfn wobble(w: Wibble) {\n             ▔▔▔▔▔▔   \n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_type_variant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\ntype Wibble { Wibble }\\n\\nfn main() {\\n  let _ = Wibble\\n  Wibble\\n}\\n\\nfn wobble() {\\n  Wibble\\n  wobble()\\n}\\n\"\n---\n-- app.gleam\n\ntype Wibble { Wibble }\n              ↑▔▔▔▔▔  \n\nfn main() {\n  let _ = Wibble\n          ▔▔▔▔▔▔\n  Wibble\n  ▔▔▔▔▔▔\n}\n\nfn wobble() {\n  Wibble\n  ▔▔▔▔▔▔\n  wobble()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_private_type_variant_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\ntype Wibble { Wibble }\\n\\nfn main() {\\n  let _ = Wibble\\n  Wibble\\n}\\n\\nfn wobble() {\\n  Wibble\\n  wobble()\\n}\\n\"\n---\n-- app.gleam\n\ntype Wibble { Wibble }\n              ▔▔▔▔▔▔  \n\nfn main() {\n  let _ = Wibble\n          ↑▔▔▔▔▔\n  Wibble\n  ▔▔▔▔▔▔\n}\n\nfn wobble() {\n  Wibble\n  ▔▔▔▔▔▔\n  wobble()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_public_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub const wibble = 10\\n\\npub fn main() {\\n  wibble\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{wibble}\n            ▔▔▔▔▔▔ \n\nfn wobble() {\n  app.wibble\n      ▔▔▔▔▔▔\n}\n\nfn other() {\n  wibble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\npub const wibble = 10\n          ▔▔▔▔▔▔     \n\npub fn main() {\n  wibble\n  ↑▔▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_public_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub fn wibble() {\\n  wibble()\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{wibble}\n            ▔▔▔▔▔▔ \n\nfn wobble() {\n  app.wibble()\n      ▔▔▔▔▔▔  \n}\n\nfn other() {\n  wibble()\n  ▔▔▔▔▔▔  \n}\n\n\n-- app.gleam\n\npub fn wibble() {\n       ▔▔▔▔▔▔    \n  wibble()\n  ↑▔▔▔▔▔  \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_public_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub type Wibble { Wibble }\\n\\npub fn main() -> Wibble {\\n  todo\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{type Wibble}\n                 ▔▔▔▔▔▔ \n\nfn wobble() -> Wibble {\n               ▔▔▔▔▔▔  \n  todo\n}\n\nfn other(w: app.Wibble) {\n                ▔▔▔▔▔▔   \n  todo\n}\n\n\n-- app.gleam\n\npub type Wibble { Wibble }\n         ↑▔▔▔▔▔           \n\npub fn main() -> Wibble {\n                 ▔▔▔▔▔▔  \n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_public_type_variant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\npub type Wibble { Wibble }\\n\\npub fn main() {\\n  Wibble\\n}\\n\"\n---\n-- mod.gleam\n\nimport app.{Wibble}\n            ▔▔▔▔▔▔ \n\nfn wobble() {\n  app.Wibble\n      ▔▔▔▔▔▔\n}\n\nfn other() {\n  Wibble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\npub type Wibble { Wibble }\n                  ↑▔▔▔▔▔  \n\npub fn main() {\n  Wibble\n  ▔▔▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_type_from_let_annotation.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod.{type Wibble}\\n\\npub fn main() -> Wibble {\\n  let _: mod.Wibble = todo\\n}\\n\"\n---\n-- mod.gleam\n\npub type Wibble { Wibble }\n         ▔▔▔▔▔▔           \n\nfn wobble() -> Wibble {\n               ▔▔▔▔▔▔  \n  todo\n}\n\n\n-- app.gleam\n\nimport mod.{type Wibble}\n                 ▔▔▔▔▔▔ \n\npub fn main() -> Wibble {\n                 ▔▔▔▔▔▔  \n  let _: mod.Wibble = todo\n             ↑▔▔▔▔▔       \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_type_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod\\n\\npub fn main() -> mod.Wibble {\\n  let _: mod.Wibble = todo\\n}\\n\"\n---\n-- mod.gleam\n\npub type Wibble { Wibble }\n         ▔▔▔▔▔▔           \n\nfn wobble() -> Wibble {\n               ▔▔▔▔▔▔  \n  todo\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() -> mod.Wibble {\n                     ↑▔▔▔▔▔  \n  let _: mod.Wibble = todo\n             ▔▔▔▔▔▔       \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_type_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod.{type Wibble}\\n\\npub fn main() -> Wibble {\\n  let _: mod.Wibble = todo\\n}\\n\"\n---\n-- mod.gleam\n\npub type Wibble { Wibble }\n         ▔▔▔▔▔▔           \n\nfn wobble() -> Wibble {\n               ▔▔▔▔▔▔  \n  todo\n}\n\n\n-- app.gleam\n\nimport mod.{type Wibble}\n                 ▔▔▔▔▔▔ \n\npub fn main() -> Wibble {\n                 ↑▔▔▔▔▔  \n  let _: mod.Wibble = todo\n             ▔▔▔▔▔▔       \n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_type_variant_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let value = mod.Wibble\\n  mod.Wibble\\n  value\\n}\\n\"\n---\n-- mod.gleam\n\npub type Wibble { Wibble }\n                  ▔▔▔▔▔▔  \n\nfn wobble() {\n  Wibble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let value = mod.Wibble\n                  ↑▔▔▔▔▔\n  mod.Wibble\n      ▔▔▔▔▔▔\n  value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__reference__references_for_type_variant_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/reference.rs\nexpression: \"\\nimport mod.{Wibble}\\n\\npub fn main() {\\n  let value = mod.Wibble\\n  Wibble\\n}\\n\"\n---\n-- mod.gleam\n\npub type Wibble { Wibble }\n                  ▔▔▔▔▔▔  \n\nfn wobble() {\n  Wibble\n  ▔▔▔▔▔▔\n}\n\n\n-- app.gleam\n\nimport mod.{Wibble}\n            ▔▔▔▔▔▔ \n\npub fn main() {\n  let value = mod.Wibble\n                  ▔▔▔▔▔▔\n  Wibble\n  ↑▔▔▔▔▔\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__alias_imported_module_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    True if mod.wibble < 5 -> !wibble\\n    False if mod.wibble != 10 -> wibble\\n    _ -> mod.wibble + 1\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\npub const wibble = 10\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n            ↑▔▔                      \n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\npub const wibble = 10\n\n-- app.gleam\n\nimport mod as module\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if module.wibble < 5 -> !wibble\n    False if module.wibble != 10 -> wibble\n    _ -> module.wibble + 1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__no_rename_constant_with_invalid_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nconst value = 10\\n\"\n---\nError response message:\n\nTen is not a valid name\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__no_rename_function_with_invalid_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  wibble\\n}\\n\"\n---\nError response message:\n\nNot_AValid_Name is not a valid name\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__no_rename_invalid_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  wibble\\n}\\n\"\n---\nError response message:\n\nNot_AValid_Name is not a valid name\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__no_rename_type_variant_with_invalid_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Constructor(Int)\\n}\\n\"\n---\nError response message:\n\nname_in_snake_case is not a valid name\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__no_rename_type_with_invalid_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\ntype Wibble { Wobble }\\n\"\n---\nError response message:\n\na_type_name is not a valid name\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__reanem_module_from_import_with_unqualified_values.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"import   option   .   {    Some, None }\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option   .   {    Some, None }\n         ↑▔▔▔▔▔                        \n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option   .   {    Some, None } as opt\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_aliased_constant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub const something = 10\\n\\npub fn main() {\\n  something + { 4 * something }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app.{something as some_constant}\n\nfn wibble() {\n  some_constant\n}\n\n\n-- app.gleam\n\npub const something = 10\n          ↑▔▔▔▔▔▔▔▔     \n\npub fn main() {\n  something + { 4 * something }\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app.{ten as some_constant}\n\nfn wibble() {\n  some_constant\n}\n\n\n-- app.gleam\n\npub const ten = 10\n\npub fn main() {\n  ten + { 4 * ten }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_aliased_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn something() {\\n  something()\\n}\\n\\nfn something_else() {\\n  something()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app.{something as something_else}\n\nfn wibble() {\n  something_else()\n}\n\n\n-- app.gleam\n\npub fn something() {\n       ↑▔▔▔▔▔▔▔▔    \n  something()\n}\n\nfn something_else() {\n  something()\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app.{some_function as something_else}\n\nfn wibble() {\n  something_else()\n}\n\n\n-- app.gleam\n\npub fn some_function() {\n  some_function()\n}\n\nfn something_else() {\n  some_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_aliased_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble { Constructor }\\n\\npub fn main(w: Wibble) -> Wibble { todo }\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app.{type Wibble as Wobble}\n\nfn wibble() -> Wobble { todo }\n\n\n-- app.gleam\n\npub type Wibble { Constructor }\n         ↑▔▔▔▔▔                \n\npub fn main(w: Wibble) -> Wibble { todo }\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app.{type SomeType as Wobble}\n\nfn wibble() -> Wobble { todo }\n\n\n-- app.gleam\n\npub type SomeType { Constructor }\n\npub fn main(w: SomeType) -> SomeType { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_aliased_type_variant.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Constructor(Int)\\n}\\n\\npub fn main() {\\n  Constructor(42)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app.{Constructor as ValueConstructor}\n\nfn wibble() {\n  ValueConstructor(172)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n  Constructor(Int)\n  ↑▔▔▔▔▔▔▔▔▔▔     \n}\n\npub fn main() {\n  Constructor(42)\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app.{MakeAWibble as ValueConstructor}\n\nfn wibble() {\n  ValueConstructor(172)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n  MakeAWibble(Int)\n}\n\npub fn main() {\n  MakeAWibble(42)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_aliased_value.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble { Wibble }\\n\\npub fn main() {\\n  Wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app.{Wibble as Wobble}\n\nfn wobble() {\n  Wobble\n}\n\n\n-- app.gleam\n\npub type Wibble { Wibble }\n                  ↑▔▔▔▔▔  \n\npub fn main() {\n  Wibble\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app.{Wubble as Wobble}\n\nfn wobble() {\n  Wobble\n}\n\n\n-- app.gleam\n\npub type Wibble { Wubble }\n\npub fn main() {\n  Wubble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->\\n      wibble + wobble\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->\n      ↑▔▔▔▔▔                                                                    \n      wibble + wobble\n    _ -> 0\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    #(new_name, [wobble]) | #(wobble, [new_name, _]) | #(_, [new_name, wobble, ..]) ->\n      new_name + wobble\n    _ -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_alias_and_variable_1.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] as list | [_, ..list] -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as list | [_, ..list] -> list\n          ↑▔▔▔                      \n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as new_name | [_, ..new_name] -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_alias_and_variable_2.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] as list | [_, ..list] -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as list | [_, ..list] -> list\n                       ↑▔▔▔         \n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as new_name | [_, ..new_name] -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_alias_and_variable_3.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [_, ..list] | [] as list -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [_, ..list] | [] as list -> list\n          ↑▔▔▔                      \n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [_, ..new_name] | [] as new_name -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_alias_and_variable_4.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [_, ..list] | [] as list -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [_, ..list] | [] as list -> list\n                        ↑▔▔▔        \n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [_, ..new_name] | [] as new_name -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_aliases.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] as list | [_] as list -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as list | [_] as list -> list\n          ↑▔▔▔                      \n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as new_name | [_] as new_name -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_aliases_from_alternative.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] as list | [_] as list -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as list | [_] as list -> list\n                        ↑▔▔▔        \n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as new_name | [_] as new_name -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_aliases_from_usage.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    [] as list | [_] as list -> list\\n    _ -> []\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as list | [_] as list -> list\n                                ↑▔▔▔\n    _ -> []\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    [] as new_name | [_] as new_name -> new_name\n    _ -> []\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_alternative_pattern_from_usage.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  case x {\\n    #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->\\n      wibble + wobble\\n    _ -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->\n      wibble + wobble\n      ↑▔▔▔▔▔         \n    _ -> 0\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  case x {\n    #(new_name, [wobble]) | #(wobble, [new_name, _]) | #(_, [new_name, wobble, ..]) ->\n      new_name + wobble\n    _ -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_constant_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub const something = 10\\n\\npub fn main() {\\n  something + { 4 * something }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.something\n}\n\n\n-- app.gleam\n\npub const something = 10\n          ↑▔▔▔▔▔▔▔▔     \n\npub fn main() {\n  something + { 4 * something }\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.ten\n}\n\n\n-- app.gleam\n\npub const ten = 10\n\npub fn main() {\n  ten + { 4 * ten }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_constant_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  mod.something\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub const something = 10\n\nfn wibble() {\n  something\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  mod.something\n      ↑▔▔▔▔▔▔▔▔\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub const ten = 10\n\nfn wibble() {\n  ten\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  mod.ten\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_constant_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub const something = 10\\n\\npub fn main() {\\n  something + { 4 * something }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.something\n}\n\n\n-- app.gleam\n\npub const something = 10\n\npub fn main() {\n  something + { 4 * something }\n  ↑▔▔▔▔▔▔▔▔                    \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.ten\n}\n\n\n-- app.gleam\n\npub const ten = 10\n\npub fn main() {\n  ten + { 4 * ten }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_constant_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod.{something}\\n\\npub fn main() {\\n  something + mod.something\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub const something = 10\n\nfn wibble() {\n  something\n}\n\n\n-- app.gleam\n\nimport mod.{something}\n\npub fn main() {\n  something + mod.something\n  ↑▔▔▔▔▔▔▔▔                \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub const something = 10\n\nfn wibble() {\n  something\n}\n\n\n-- app.gleam\n\nimport mod.{something as ten}\n\npub fn main() {\n  ten + mod.something\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_constant_shadowed_by_field_access.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub const something = 10\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\ntype App {\n  App(something: Int)\n}\n\npub fn main() {\n  let app = App(10)\n  app.something\n}\n\n\n-- app.gleam\n\npub const something = 10\n          ↑▔▔▔▔▔▔▔▔     \n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\ntype App {\n  App(something: Int)\n}\n\npub fn main() {\n  let app = App(10)\n  app.something\n}\n\n\n-- app.gleam\n\npub const constant = 10\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_constant_shadowing_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport gleam/list\\n\\nconst list = []\\n\\npub fn main() {\\n  list.map(todo, todo)\\n}\\n    \"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nimport gleam/list\n\nconst list = []\n      ↑▔▔▔     \n\npub fn main() {\n  list.map(todo, todo)\n}\n    \n\n\n----- AFTER RENAME\n-- app.gleam\n\nimport gleam/list\n\nconst empty_list = []\n\npub fn main() {\n  list.map(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_custom_type_variant_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Type {\\n  X\\n  Y\\n}\\n\\npub fn main(t) {\\n  case t {\\n    X -> 0\\n    Y -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub type Type {\n  X\n  ↑\n  Y\n}\n\npub fn main(t) {\n  case t {\n    X -> 0\n    Y -> 0\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub type Type {\n  Renamed\n  Y\n}\n\npub fn main(t) {\n  case t {\n    Renamed -> 0\n    Y -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_external_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() { wibble() }\\n\\n@external(erlang, \\\"a\\\", \\\"a\\\")\\nfn wibble() -> Nil\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() { wibble() }\n\n@external(erlang, \"a\", \"a\")\nfn wibble() -> Nil\n   ↑▔▔▔▔▔         \n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() { new_name() }\n\n@external(erlang, \"a\", \"a\")\nfn new_name() -> Nil\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_external_javascript_function_with_pure_gleam_fallback.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() { wibble() }\\n\\n@external(javascript, \\\"a\\\", \\\"a\\\")\\nfn wibble() -> Nil {\\n  Nil\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() { wibble() }\n\n@external(javascript, \"a\", \"a\")\nfn wibble() -> Nil {\n   ↑▔▔▔▔▔           \n  Nil\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() { new_name() }\n\n@external(javascript, \"a\", \"a\")\nfn new_name() -> Nil {\n  Nil\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_function_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn something() {\\n  something()\\n}\\n\\nfn something_else() {\\n  something()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.something()\n}\n\n\n-- app.gleam\n\npub fn something() {\n       ↑▔▔▔▔▔▔▔▔    \n  something()\n}\n\nfn something_else() {\n  something()\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.some_function()\n}\n\n\n-- app.gleam\n\npub fn some_function() {\n  some_function()\n}\n\nfn something_else() {\n  some_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_function_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  mod.wibble()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub fn wibble() {\n  wibble()\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  mod.wibble()\n      ↑▔▔▔▔▔  \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub fn some_function() {\n  some_function()\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  mod.some_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_function_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn something() {\\n  something()\\n}\\n\\nfn something_else() {\\n  something()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.something()\n}\n\n\n-- app.gleam\n\npub fn something() {\n  something()\n  ↑▔▔▔▔▔▔▔▔  \n}\n\nfn something_else() {\n  something()\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.some_function()\n}\n\n\n-- app.gleam\n\npub fn some_function() {\n  some_function()\n}\n\nfn something_else() {\n  some_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_function_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod.{wibble}\\n\\npub fn main() {\\n  wibble()\\n  mod.wibble()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub fn wibble() {\n  wibble()\n}\n\n\n-- app.gleam\n\nimport mod.{wibble}\n\npub fn main() {\n  wibble()\n  ↑▔▔▔▔▔  \n  mod.wibble()\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub fn wibble() {\n  wibble()\n}\n\n\n-- app.gleam\n\nimport mod.{wibble as some_function}\n\npub fn main() {\n  some_function()\n  mod.wibble()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_function_shadowed_by_field_access.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn something() {\\n  todo\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\ntype App {\n  App(something: Int)\n}\n\npub fn main() {\n  let app = App(10)\n  app.something\n}\n\n\n-- app.gleam\n\npub fn something() {\n       ↑▔▔▔▔▔▔▔▔    \n  todo\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\ntype App {\n  App(something: Int)\n}\n\npub fn main() {\n  let app = App(10)\n  app.something\n}\n\n\n-- app.gleam\n\npub fn function() {\n  todo\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_function_shadowing_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport gleam/list\\n\\npub fn list() {\\n  []\\n}\\n\\npub fn main() {\\n  list.map(todo, todo)\\n}\\n    \"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nimport gleam/list\n\npub fn list() {\n       ↑▔▔▔    \n  []\n}\n\npub fn main() {\n  list.map(todo, todo)\n}\n    \n\n\n----- AFTER RENAME\n-- app.gleam\n\nimport gleam/list\n\npub fn empty_list() {\n  []\n}\n\npub fn main() {\n  list.map(todo, todo)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_imported_custom_type_variant_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Type {\\n  X\\n  Y\\n}\\n\"\n---\n----- BEFORE RENAME\n-- other.gleam\n\nimport app\n\npub fn main(t) {\n  case t {\n    app.X -> 0\n    app.Y -> 0\n  }\n}\n\n\n-- app.gleam\n\npub type Type {\n  X\n  ↑\n  Y\n}\n\n\n----- AFTER RENAME\n-- other.gleam\n\nimport app\n\npub fn main(t) {\n  case t {\n    app.Renamed -> 0\n    app.Y -> 0\n  }\n}\n\n\n-- app.gleam\n\npub type Type {\n  Renamed\n  Y\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_imported_unqualified_custom_type_variant_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Type {\\n  X\\n  Y\\n}\\n\"\n---\n----- BEFORE RENAME\n-- other.gleam\n\nimport app.{X, Y}\n\npub fn main(t) {\n  case t {\n    X -> 0\n    Y -> 0\n  }\n}\n\n\n-- app.gleam\n\npub type Type {\n  X\n  ↑\n  Y\n}\n\n\n----- AFTER RENAME\n-- other.gleam\n\nimport app.{Renamed, Y}\n\npub fn main(t) {\n  case t {\n    Renamed -> 0\n    Y -> 0\n  }\n}\n\n\n-- app.gleam\n\npub type Type {\n  Renamed\n  Y\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n  wibble\n  ↑▔▔▔▔▔\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let wobble = 10\n  wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn add(first_number: Int, x: Int) -> Int {\\n  x + first_number\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn add(first_number: Int, x: Int) -> Int {\n  x + first_number\n  ↑               \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn add(first_number: Int, second_number: Int) -> Int {\n  second_number + first_number\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_argument_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn wibble(wibble: Float) {\\n  wibble /. 0.3\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn wibble(wibble: Float) {\n              ↑▔▔▔▔▔          \n  wibble /. 0.3\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn wibble(wobble: Float) {\n  wobble /. 0.3\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_assignment_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let assert Error(12 as something) = Error(12)\\n  something\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let assert Error(12 as something) = Error(12)\n  something\n  ↑▔▔▔▔▔▔▔▔\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let assert Error(12 as the_error) = Error(12)\n  the_error\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_from_bit_array_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\\n  let prefix_size = bit_size(prefix)\\n\\n  case bits {\\n    <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n  let prefix_size = bit_size(prefix)\n\n  case bits {\n    <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True\n                     ↑▔▔▔▔▔▔▔▔▔▔                                     \n    _ -> False\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n  let size_of_prefix = bit_size(prefix)\n\n  case bits {\n    <<pref:bits-size(size_of_prefix), _:bits>> if pref == prefix -> True\n    _ -> False\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  let wobble = wibble + 1\\n  wobble - wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n      ↑▔▔▔▔▔     \n  let wobble = wibble + 1\n  wobble - wibble\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let some_value = 10\n  let wobble = some_value + 1\n  wobble - some_value\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_from_definition_assignment_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let assert Error(12 as something) = Error(12)\\n  something\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let assert Error(12 as something) = Error(12)\n                         ↑▔▔▔▔▔▔▔▔             \n  something\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let assert Error(12 as the_error) = Error(12)\n  the_error\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_from_definition_nested_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let assert Ok([_, wibble, ..]) = Error(12)\\n  wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let assert Ok([_, wibble, ..]) = Error(12)\n                    ↑▔▔▔▔▔                  \n  wibble\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let assert Ok([_, second_element, ..]) = Error(12)\n  second_element\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  let wobble = False\\n  case wibble {\\n    True if wobble -> !wibble\\n    False if !wobble -> wibble\\n    _ -> wobble\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = True\n  let wobble = False\n  case wibble {\n    True if wobble -> !wibble\n            ↑▔▔▔▔▔           \n    False if !wobble -> wibble\n    _ -> wobble\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = True\n  let something_else = False\n  case wibble {\n    True if something_else -> !wibble\n    False if !something_else -> wibble\n    _ -> something_else\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_from_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: Int)\\n}\\n\\npub fn main() {\\n  let wibble = todo\\n  Wibble(wibble:)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let wibble = todo\n  Wibble(wibble:)\n         ↑▔▔▔▔▔  \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let wobble = todo\n  Wibble(wibble: wobble)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_guard_clause.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = True\\n  case Nil {\\n    Nil if wibble -> todo\\n    _ -> panic\\n  }\\n  wibble || False\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = True\n  case Nil {\n    Nil if wibble -> todo\n    _ -> panic\n  }\n  wibble || False\n  ↑▔▔▔▔▔         \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let wobble = True\n  case Nil {\n    Nil if wobble -> todo\n    _ -> panic\n  }\n  wobble || False\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_in_bit_array_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\\n  let prefix_size = bit_size(prefix)\\n\\n  case bits {\\n    <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True\\n    _ -> False\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n  let prefix_size = bit_size(prefix)\n      ↑▔▔▔▔▔▔▔▔▔▔                   \n\n  case bits {\n    <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True\n    _ -> False\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n  let size_of_prefix = bit_size(prefix)\n\n  case bits {\n    <<pref:bits-size(size_of_prefix), _:bits>> if pref == prefix -> True\n    _ -> False\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: Int)\\n}\\n\\npub fn main() {\\n  let Wibble(wibble:) = todo\\n  wibble + 1\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble:) = todo\n  wibble + 1\n  ↑▔▔▔▔▔    \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble: wobble) = todo\n  wobble + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_label_shorthand_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: Int)\\n}\\n\\npub fn main() {\\n  let Wibble(wibble:) = todo\\n  wibble + 1\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble:) = todo\n             ↑▔▔▔▔▔         \n  wibble + 1\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let Wibble(wibble: wobble) = todo\n  wobble + 1\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_record_access.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(wibble: Int)\\n}\\n\\npub fn main() {\\n  let wibble = Wibble(wibble: 1)\\n  wibble.wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let wibble = Wibble(wibble: 1)\n  wibble.wibble\n  ↑▔▔▔▔▔       \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(wibble: Int)\n}\n\npub fn main() {\n  let wobble = Wibble(wibble: 1)\n  wobble.wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_local_variable_with_label_shorthand.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(first: Int, second: Int)\\n}\\n\\npub fn main() {\\n  let second = 2\\n  Wibble(first: 1, second:)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub type Wibble {\n  Wibble(first: Int, second: Int)\n}\n\npub fn main() {\n  let second = 2\n      ↑▔▔▔▔▔    \n  Wibble(first: 1, second:)\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub type Wibble {\n  Wibble(first: Int, second: Int)\n}\n\npub fn main() {\n  let something = 2\n  Wibble(first: 1, second: something)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_access_in_clause_guard.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub const something = 10\\n\"\n---\n----- BEFORE RENAME\n-- wibble.gleam\n\nimport app\n\npub fn main() {\n  case app.something {\n    thing if thing == app.something -> True\n    _ -> False\n  }\n}\n\n\n-- app.gleam\n\npub const something = 10\n          ↑▔▔▔▔▔▔▔▔     \n\n\n----- AFTER RENAME\n-- wibble.gleam\n\nimport app\n\npub fn main() {\n  case app.new_name {\n    thing if thing == app.new_name -> True\n    _ -> False\n  }\n}\n\n\n-- app.gleam\n\npub const new_name = 10\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_alias_use.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport maths  as     m\\n\\npub fn main() {\\n  echo m      .pi\\n}\\n\"\n---\n----- BEFORE RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths  as     m\n\npub fn main() {\n  echo m      .pi\n       ↑         \n}\n\n\n----- AFTER RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths  as mth\n\npub fn main() {\n  echo mth      .pi\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_constant_in_clause_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport maths\\n\\npub fn count_pi(list) {\\n  case list {\\n    [number, ..rest] if number == maths  . pi -> 1 + count_pi(rest)\\n    [_, ..rest] -> count_pi(rest)\\n    [] -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths\n\npub fn count_pi(list) {\n  case list {\n    [number, ..rest] if number == maths  . pi -> 1 + count_pi(rest)\n                                  ↑▔▔▔▔                            \n    [_, ..rest] -> count_pi(rest)\n    [] -> 0\n  }\n}\n\n\n----- AFTER RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths as m\n\npub fn count_pi(list) {\n  case list {\n    [number, ..rest] if number == m  . pi -> 1 + count_pi(rest)\n    [_, ..rest] -> count_pi(rest)\n    [] -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_constant_in_const.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport maths\\n\\nconst x = maths   .  pi\\n\"\n---\n----- BEFORE RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths\n\nconst x = maths   .  pi\n          ↑▔▔▔▔        \n\n\n----- AFTER RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths as m\n\nconst x = m   .  pi\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_constant_in_expression.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport maths\\n\\npub fn main() {\\n  echo maths  .    pi\\n}\\n\"\n---\n----- BEFORE RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths\n\npub fn main() {\n  echo maths  .    pi\n       ↑▔▔▔▔         \n}\n\n\n----- AFTER RENAME\n-- maths.gleam\npub const pi = 3.14\n\n-- app.gleam\n\nimport maths as m\n\npub fn main() {\n  echo m  .    pi\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_function_call.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nassertion_line: 2130\nexpression: \"\\nimport option\\n\\npub fn main() {\\n  option.is_some(option.Some(1))\\n}\\n\"\nsnapshot_kind: text\n---\n----- BEFORE RENAME\n-- option.gleam\n\npub type Option(a) {\n  Some(a)\n  None\n}\n\npub fn is_some(option: Option(a)) -> Bool {\n  case option {\n    Some(_) -> True\n    None -> False\n  }\n}\n\n\n-- app.gleam\n\nimport option\n\npub fn main() {\n  option.is_some(option.Some(1))\n  ↑▔▔▔▔▔                        \n}\n\n\n----- AFTER RENAME\n-- option.gleam\n\npub type Option(a) {\n  Some(a)\n  None\n}\n\npub fn is_some(option: Option(a)) -> Bool {\n  case option {\n    Some(_) -> True\n    None -> False\n  }\n}\n\n\n-- app.gleam\n\nimport option as opt\n\npub fn main() {\n  opt.is_some(opt.Some(1))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: import      option\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport      option\n            ↑▔▔▔▔▔\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport      option as opt\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_namespaced.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"import   std /   option  \"\n---\n----- BEFORE RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option  \n                 ↑▔▔▔▔▔  \n\n\n----- AFTER RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option as opt\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_namespaced_with_alias.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: import   std /   option   as     opt\n---\n----- BEFORE RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option   as     opt\n                                 ↑▔▔\n\n\n----- AFTER RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option   as o\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_namespaced_with_unqualified_value_and_alias.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"import   std /   option   .   {    Some, None }   as     opt\"\n---\n----- BEFORE RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option   .   {    Some, None }   as     opt\n                                                         ↑▔▔\n\n\n----- AFTER RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option   .   {    Some, None }   as o\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_namespaced_with_unqualified_values.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"import   std /   option   .   {    Some, None }\"\n---\n----- BEFORE RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option   .   {    Some, None }\n                 ↑▔▔▔▔▔                        \n\n\n----- AFTER RENAME\n-- std/option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   std /   option   .   {    Some, None } as opt\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_with_alias.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: import   option    as      opt\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option    as      opt\n                           ↑▔▔\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option    as o\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_with_alias_to_original_name.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: import   option   as     opt\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option   as     opt\n                         ↑▔▔\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_import_with_unqualified_value_and_alias.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"import   option  .     {Some, None}   as     opt\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option  .     {Some, None}   as     opt\n                                             ↑▔▔\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\nimport   option  .     {Some, None}   as o\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_type_in_annotation.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\nconst x: option.Option(Int) = option.Some(1)\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\nconst x: option.Option(Int) = option.Some(1)\n         ↑▔▔▔▔▔                             \n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\nconst x: opt.Option(Int) = opt.Some(1)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_type_in_custom_type.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\ntype Value(a) {\\n  Value(option.Option(a))\\n}\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\ntype Value(a) {\n  Value(option.Option(a))\n        ↑▔▔▔▔▔           \n}\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\ntype Value(a) {\n  Value(opt.Option(a))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_type_in_type_alias.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\ntype Option(a) =\\n  option.Option(a)\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\ntype Option(a) =\n  option.Option(a)\n  ↑▔▔▔▔▔          \n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\ntype Option(a) =\n  opt.Option(a)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_variant_in_clause_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\npub fn count_none(list) {\\n  case list {\\n    [option, ..rest] if option == option  . None -> 1 + count_none(rest)\\n    [_, ..rest] -> count_none(rest)\\n    [] -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\npub fn count_none(list) {\n  case list {\n    [option, ..rest] if option == option  . None -> 1 + count_none(rest)\n                                  ↑▔▔▔▔▔                                \n    [_, ..rest] -> count_none(rest)\n    [] -> 0\n  }\n}\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\npub fn count_none(list) {\n  case list {\n    [option, ..rest] if option == opt  . None -> 1 + count_none(rest)\n    [_, ..rest] -> count_none(rest)\n    [] -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_variant_in_const.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\nconst x = option   .None\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\nconst x = option   .None\n          ↑▔▔▔▔▔        \n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\nconst x = opt   .None\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_variant_in_expression.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\npub fn main() {\\n  echo option     . None\\n}\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\npub fn main() {\n  echo option     . None\n       ↑▔▔▔▔▔           \n}\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\npub fn main() {\n  echo opt     . None\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_from_variant_in_pattern.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport option\\n\\npub fn is_some(option) {\\n  case option {\\n    option.  Some(_) -> True\\n    option  .None -> False\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option\n\npub fn is_some(option) {\n  case option {\n    option.  Some(_) -> True\n    ↑▔▔▔▔▔                  \n    option  .None -> False\n  }\n}\n\n\n----- AFTER RENAME\n-- option.gleam\npub type Option(a) { Some(a) None }\n\n-- app.gleam\n\nimport option as opt\n\npub fn is_some(option) {\n  case option {\n    opt.  Some(_) -> True\n    opt  .None -> False\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_module_select_from_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  let wibble = True\\n  case wibble {\\n    True if mod.wibble < 5 -> !wibble\\n    False if mod.wibble != 10 -> wibble\\n    _ -> mod.wibble + 1\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\npub const wibble = 10\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.wibble < 5 -> !wibble\n                ↑▔▔▔▔▔               \n    False if mod.wibble != 10 -> wibble\n    _ -> mod.wibble + 1\n  }\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\npub const ten = 10\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  let wibble = True\n  case wibble {\n    True if mod.ten < 5 -> !wibble\n    False if mod.ten != 10 -> wibble\n    _ -> mod.ten + 1\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_nested_aliased_pattern.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\npub fn go(x) {\\n  case x {\\n    [[nested, ..] as wibble, ..] -> todo\\n    _ -> todo\\n  }\\n}\\n        \"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn go(x) {\n  case x {\n    [[nested, ..] as wibble, ..] -> todo\n      ↑▔▔▔▔▔                            \n    _ -> todo\n  }\n}\n        \n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn go(x) {\n  case x {\n    [[new_name, ..] as wibble, ..] -> todo\n    _ -> todo\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_and_suffix_complex_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() {\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" as digit <> rest if digit == \\\"1\\\" && rest == \\\"-wibble\\\" -> #(digit, rest)\\n    _ -> #(\\\"\\\", \\\"\\\")\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" as digit <> rest if digit == \"1\" && rest == \"-wibble\" -> #(digit, rest)\n           ↑▔▔▔▔                                                               \n    _ -> #(\"\", \"\")\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" as new_name <> rest if new_name == \"1\" && rest == \"-wibble\" -> #(new_name, rest)\n    _ -> #(\"\", \"\")\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_in_case.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" as digit <> rest -> digit <> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as digit <> rest -> digit <> rest\n           ↑▔▔▔▔                         \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as new_name <> rest -> new_name <> rest\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_in_case_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" as digit <> rest -> digit <> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as digit <> rest -> digit <> rest\n                            ↑▔▔▔▔        \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as new_name <> rest -> new_name <> rest\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_in_let_assert.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let assert \\\"1\\\" as digit <> rest = \\\"1-wibble\\\"\\n  digit\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" as digit <> rest = \"1-wibble\"\n                    ↑▔▔▔▔                     \n  digit\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" as new_name <> rest = \"1-wibble\"\n  new_name\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_in_let_assert_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let assert \\\"1\\\" as digit <> rest = \\\"1-wibble\\\"\\n  digit\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" as digit <> rest = \"1-wibble\"\n  digit\n  ↑▔▔▔▔\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" as new_name <> rest = \"1-wibble\"\n  new_name\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_used_in_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() {\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" as digit <> _rest if digit == \\\"1\\\" -> digit\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" as digit <> _rest if digit == \"1\" -> digit\n           ↑▔▔▔▔                                  \n    _ -> \"\"\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" as new_name <> _rest if new_name == \"1\" -> new_name\n    _ -> \"\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_with_alternative_definitions_in_case.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" as digit <> rest | \\\"2\\\" as digit <> rest -> digit <> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as digit <> rest | \"2\" as digit <> rest -> digit <> rest\n           ↑▔▔▔▔                                                \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as new_name <> rest | \"2\" as new_name <> rest -> new_name <> rest\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_alias_with_alternative_definitions_triggered_from_second_pattern.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" as digit <> rest | \\\"2\\\" as digit <> rest -> digit <> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as digit <> rest | \"2\" as digit <> rest -> digit <> rest\n                                  ↑▔▔▔▔                         \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" as new_name <> rest | \"2\" as new_name <> rest -> new_name <> rest\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_shadowing_outer_variable.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() {\\n  let rest = \\\"outer\\\"\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" <> rest -> rest\\n    _ -> rest\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() {\n  let rest = \"outer\"\n  case \"1-wibble\" {\n    \"1\" <> rest -> rest\n           ↑▔▔▔        \n    _ -> rest\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() {\n  let rest = \"outer\"\n  case \"1-wibble\" {\n    \"1\" <> new_name -> new_name\n    _ -> rest\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_used_in_guard.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() {\\n  case \\\"1-wibble\\\" {\\n    \\\"1\\\" <> rest if rest == \\\"-wibble\\\" -> rest\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" <> rest if rest == \"-wibble\" -> rest\n           ↑▔▔▔                             \n    _ -> \"\"\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() {\n  case \"1-wibble\" {\n    \"1\" <> new_name if new_name == \"-wibble\" -> new_name\n    _ -> \"\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_in_case.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" <> rest -> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> rest -> rest\n           ↑▔▔▔        \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> new_name -> new_name\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_in_case_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" <> rest -> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> rest -> rest\n                   ↑▔▔▔\n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> new_name -> new_name\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_in_let_assert.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\\n  rest\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" <> rest = \"1-wibble\"\n                    ↑▔▔▔             \n  rest\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" <> new_name = \"1-wibble\"\n  new_name\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_in_let_assert_triggered_from_usage.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let assert \\\"1\\\" <> rest = \\\"1-wibble\\\"\\n  rest\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" <> rest = \"1-wibble\"\n  rest\n  ↑▔▔▔\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let assert \"1\" <> new_name = \"1-wibble\"\n  new_name\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_nested_in_tuple.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() {\\n  case #(\\\"1-wibble\\\", 0) {\\n    #(\\\"1\\\" <> rest, _) -> rest\\n    _ -> \\\"\\\"\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() {\n  case #(\"1-wibble\", 0) {\n    #(\"1\" <> rest, _) -> rest\n             ↑▔▔▔            \n    _ -> \"\"\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() {\n  case #(\"1-wibble\", 0) {\n    #(\"1\" <> new_name, _) -> new_name\n    _ -> \"\"\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_with_alternative_definition_in_case.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> rest | \"2\" <> rest -> rest\n           ↑▔▔▔                      \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> new_name | \"2\" <> new_name -> new_name\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prefix_string_suffix_variable_with_alternative_definition_triggered_from_second_pattern.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn main() -> String {\\n  let wibble = \\\"1-wibble\\\"\\n  case wibble {\\n    \\\"1\\\" <> rest | \\\"2\\\" <> rest -> rest\\n    other -> other\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> rest | \"2\" <> rest -> rest\n                         ↑▔▔▔        \n    other -> other\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn main() -> String {\n  let wibble = \"1-wibble\"\n  case wibble {\n    \"1\" <> new_name | \"2\" <> new_name -> new_name\n    other -> other\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() -> Result(Int, Nil) {\\n  Ok(10)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() -> Result(Int, Nil) {\n                 ↑▔▔▔▔▔            \n  Ok(10)\n}\n\n\n----- AFTER RENAME\n-- app.gleam\nimport gleam.{type Result as SuccessOrFailure}\n\npub fn main() -> SuccessOrFailure(Int, Nil) {\n  Ok(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_type_with_prelude_value_imported_with_trailing_comma.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport gleam.{Error,}\\n\\npub fn main() -> Result(Int, Nil) {\\n  Error(10)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nimport gleam.{Error,}\n\npub fn main() -> Result(Int, Nil) {\n                 ↑▔▔▔▔▔            \n  Error(10)\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nimport gleam.{Error, type Result as OkOrError}\n\npub fn main() -> OkOrError(Int, Nil) {\n  Error(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_value.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  Ok(10)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  Ok(10)\n  ↑▔    \n}\n\n\n----- AFTER RENAME\n-- app.gleam\nimport gleam.{Ok as Success}\n\npub fn main() {\n  Success(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_value_with_other_module_imported.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport something\\n\\npub fn main() {\\n  Ok(10)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- something.gleam\npub type Something\n\n-- app.gleam\n\nimport something\n\npub fn main() {\n  Ok(10)\n  ↑▔    \n}\n\n\n----- AFTER RENAME\n-- something.gleam\npub type Something\n\n-- app.gleam\n\nimport gleam.{Ok as Success}\nimport something\n\npub fn main() {\n  Success(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_value_with_other_prelude_value_imported.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport gleam.{Error}\\n\\npub fn main() {\\n  Ok(Error(10))\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nimport gleam.{Error}\n\npub fn main() {\n  Ok(Error(10))\n  ↑▔           \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nimport gleam.{Error, Ok as Success}\n\npub fn main() {\n  Success(Error(10))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_value_with_prelude_already_imported.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport gleam\\n\\npub fn main() {\\n  Ok(gleam.Error(10))\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nimport gleam\n\npub fn main() {\n  Ok(gleam.Error(10))\n  ↑▔                 \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nimport gleam.{Ok as Success}\n\npub fn main() {\n  Success(gleam.Error(10))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_prelude_value_with_prelude_import_with_empty_braces.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport gleam.{}\\n\\npub fn main() {\\n  Ok(gleam.Error(10))\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nimport gleam.{}\n\npub fn main() {\n  Ok(gleam.Error(10))\n  ↑▔                 \n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\nimport gleam.{Ok as Success}\n\npub fn main() {\n  Success(gleam.Error(10))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_shadowed_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  let wibble = wibble / 2\\n  wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n  let wibble = wibble / 2\n               ↑▔▔▔▔▔    \n  wibble\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let wobble = 10\n  let wibble = wobble / 2\n  wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_shadowing_local_variable.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main() {\\n  let wibble = 10\\n  let wibble = wibble / 2\\n  wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n  let wibble = wibble / 2\n  wibble\n  ↑▔▔▔▔▔\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main() {\n  let wibble = 10\n  let wobble = wibble / 2\n  wobble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble { Constructor }\\n\\npub fn main(w: Wibble) -> Wibble { todo }\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() -> app.Wibble { todo }\n\n\n-- app.gleam\n\npub type Wibble { Constructor }\n         ↑▔▔▔▔▔                \n\npub fn main(w: Wibble) -> Wibble { todo }\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() -> app.SomeType { todo }\n\n\n-- app.gleam\n\npub type SomeType { Constructor }\n\npub fn main(w: SomeType) -> SomeType { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub fn main(w: mod.Wibble) -> mod.Wibble { todo }\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub type Wibble { Constructor }\n\nfn wibble(w: Wibble) -> Wibble { todo }\n\n\n-- app.gleam\n\nimport mod\n\npub fn main(w: mod.Wibble) -> mod.Wibble { todo }\n                   ↑▔▔▔▔▔                        \n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub type SomeType { Constructor }\n\nfn wibble(w: SomeType) -> SomeType { todo }\n\n\n-- app.gleam\n\nimport mod\n\npub fn main(w: mod.SomeType) -> mod.SomeType { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble { Constructor }\\n\\npub fn main(w: Wibble) -> Wibble { todo }\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() -> app.Wibble { todo }\n\n\n-- app.gleam\n\npub type Wibble { Constructor }\n\npub fn main(w: Wibble) -> Wibble { todo }\n               ↑▔▔▔▔▔                    \n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() -> app.SomeType { todo }\n\n\n-- app.gleam\n\npub type SomeType { Constructor }\n\npub fn main(w: SomeType) -> SomeType { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod.{type Wibble}\\n\\npub fn main(w: Wibble) -> mod.Wibble { todo }\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub type Wibble { Constructor }\n\nfn wibble(w: Wibble) -> Wibble { todo }\n\n\n-- app.gleam\n\nimport mod.{type Wibble}\n\npub fn main(w: Wibble) -> mod.Wibble { todo }\n               ↑▔▔▔▔▔                        \n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub type Wibble { Constructor }\n\nfn wibble(w: Wibble) -> Wibble { todo }\n\n\n-- app.gleam\n\nimport mod.{type Wibble as SomeType}\n\npub fn main(w: SomeType) -> mod.Wibble { todo }\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_from_variant_constructor_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub type Wobble {\\n  Wobble(w: mod.Wibble)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub type Wibble {\n  Wibble\n}\n\npub fn main() {\n  let wibble = Wibble\n}\n\n\n-- app.gleam\n\nimport mod\n\npub type Wobble {\n  Wobble(w: mod.Wibble)\n                ↑▔▔▔▔▔ \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub type SomeType {\n  Wibble\n}\n\npub fn main() {\n  let wibble = Wibble\n}\n\n\n-- app.gleam\n\nimport mod\n\npub type Wobble {\n  Wobble(w: mod.SomeType)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_referenced_in_variant_constructor_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Wibble\\n}\\n\\npub fn main() {\\n  let wibble = Wibble\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\npub type Wobble {\n  Wobble(w: app.Wibble)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n         ↑▔▔▔▔▔  \n  Wibble\n}\n\npub fn main() {\n  let wibble = Wibble\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\npub type Wobble {\n  Wobble(w: app.SomeType)\n}\n\n\n-- app.gleam\n\npub type SomeType {\n  Wibble\n}\n\npub fn main() {\n  let wibble = Wibble\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_variant_from_definition.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Constructor(Int)\\n}\\n\\npub fn main() {\\n  Constructor(10)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.Constructor(4)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n  Constructor(Int)\n  ↑▔▔▔▔▔▔▔▔▔▔     \n}\n\npub fn main() {\n  Constructor(10)\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.Wibble(4)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn main() {\n  Wibble(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_variant_from_pattern.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Type {\\n  X\\n  Y\\n}\\n\\npub fn main(t) {\\n  case t {\\n    X -> 0\\n    Y -> 0\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub type Type {\n  X\n  Y\n}\n\npub fn main(t) {\n  case t {\n    X -> 0\n    ↑     \n    Y -> 0\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub type Type {\n  Renamed\n  Y\n}\n\npub fn main(t) {\n  case t {\n    Renamed -> 0\n    Y -> 0\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_variant_from_qualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod\\n\\npub fn main() {\\n  mod.Constructor\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub type Wibble {\n  Constructor(Int)\n}\n\nfn wibble() {\n  Constructor(42)\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  mod.Constructor\n      ↑▔▔▔▔▔▔▔▔▔▔\n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub type Wibble {\n  Variant(Int)\n}\n\nfn wibble() {\n  Variant(42)\n}\n\n\n-- app.gleam\n\nimport mod\n\npub fn main() {\n  mod.Variant\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_variant_from_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Constructor(Int)\\n}\\n\\npub fn main() {\\n  Constructor(10)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.Constructor(4)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n  Constructor(Int)\n}\n\npub fn main() {\n  Constructor(10)\n  ↑▔▔▔▔▔▔▔▔▔▔    \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\nimport app\n\nfn wibble() {\n  app.Wibble(4)\n}\n\n\n-- app.gleam\n\npub type Wibble {\n  Wibble(Int)\n}\n\npub fn main() {\n  Wibble(10)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_variant_from_unqualified_reference.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod.{Constructor}\\n\\npub fn main() {\\n  #(Constructor(75), mod.Constructor(57))\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub type Wibble {\n  Constructor(Int)\n}\n\nfn wibble() {\n  Constructor(81)\n}\n\n\n-- app.gleam\n\nimport mod.{Constructor}\n\npub fn main() {\n  #(Constructor(75), mod.Constructor(57))\n    ↑▔▔▔▔▔▔▔▔▔▔                          \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub type Wibble {\n  Constructor(Int)\n}\n\nfn wibble() {\n  Constructor(81)\n}\n\n\n-- app.gleam\n\nimport mod.{Constructor as Number}\n\npub fn main() {\n  #(Number(75), mod.Constructor(57))\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_type_variant_pattern_with_arguments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub type Wibble {\\n  Wibble(Int)\\n  Wobble(Float)\\n}\\n\\nfn wibble() {\\n  case Wibble(10) {\\n    Wibble(20) -> todo\\n    Wibble(_) -> panic\\n  }\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub type Wibble {\n  Wibble(Int)\n  Wobble(Float)\n}\n\nfn wibble() {\n  case Wibble(10) {\n       ↑▔▔▔▔▔      \n    Wibble(20) -> todo\n    Wibble(_) -> panic\n  }\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub type Wibble {\n  Variant(Int)\n  Wobble(Float)\n}\n\nfn wibble() {\n  case Variant(10) {\n    Variant(20) -> todo\n    Variant(_) -> panic\n  }\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_value_in_aliased_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport mod as the_module\\n\\npub fn main() {\\n  the_module.wibble()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- mod.gleam\n\npub fn wibble() {\n  wibble()\n}\n\n\n-- app.gleam\n\nimport mod as the_module\n\npub fn main() {\n  the_module.wibble()\n             ↑▔▔▔▔▔  \n}\n\n\n----- AFTER RENAME\n-- mod.gleam\n\npub fn some_function() {\n  some_function()\n}\n\n\n-- app.gleam\n\nimport mod as the_module\n\npub fn main() {\n  the_module.some_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_value_in_nested_module.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\nimport sub/mod\\n\\npub fn main() {\\n  mod.wibble()\\n}\\n\"\n---\n----- BEFORE RENAME\n-- sub/mod.gleam\n\npub fn wibble() {\n  wibble()\n}\n\n\n-- app.gleam\n\nimport sub/mod\n\npub fn main() {\n  mod.wibble()\n      ↑▔▔▔▔▔  \n}\n\n\n----- AFTER RENAME\n-- sub/mod.gleam\n\npub fn some_function() {\n  some_function()\n}\n\n\n-- app.gleam\n\nimport sub/mod\n\npub fn main() {\n  mod.some_function()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_variable_used_in_record_update.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\ntype Wibble {\\n  Wibble(a: Int, b: Int, c: Int)\\n}\\n\\nfn wibble(wibble: Wibble) {\\n  Wibble(..wibble, c: 1)\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int)\n}\n\nfn wibble(wibble: Wibble) {\n          ↑▔▔▔▔▔           \n  Wibble(..wibble, c: 1)\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\ntype Wibble {\n  Wibble(a: Int, b: Int, c: Int)\n}\n\nfn wibble(value: Wibble) {\n  Wibble(..value, c: 1)\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_variable_with_alternative_pattern_with_same_name.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/rename.rs\nexpression: \"\\npub fn main(x) {\\n  let some_var = 10\\n\\n  case x {\\n    #(some_var, []) | #(_, [some_var]) ->\\n      some_var\\n    _ -> 0\\n  }\\n\\n  some_var\\n}\\n\"\n---\n----- BEFORE RENAME\n-- app.gleam\n\npub fn main(x) {\n  let some_var = 10\n      ↑▔▔▔▔▔▔▔     \n\n  case x {\n    #(some_var, []) | #(_, [some_var]) ->\n      some_var\n    _ -> 0\n  }\n\n  some_var\n}\n\n\n----- AFTER RENAME\n-- app.gleam\n\npub fn main(x) {\n  let new_name = 10\n\n  case x {\n    #(some_var, []) | #(_, [some_var]) ->\n      some_var\n    _ -> 0\n  }\n\n  new_name\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__rename__rename_works_when_error_is_present.snap",
    "content": "---\nsource: language-server/src/tests/rename.rs\nexpression: \"\\nfn wibble() {\\n  \\\"test string\\\"\\n}\\n\\npub fn main() {\\n  1 + \\\"1\\\"\\n  echo wibble()\\n}\\n  \"\n---\n----- BEFORE RENAME\n-- app.gleam\n\nfn wibble() {\n   ↑▔▔▔▔▔    \n  \"test string\"\n}\n\npub fn main() {\n  1 + \"1\"\n  echo wibble()\n}\n  \n\n\n----- AFTER RENAME\n-- app.gleam\n\nfn wobble() {\n  \"test string\"\n}\n\npub fn main() {\n  1 + \"1\"\n  echo wobble()\n}\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_aliased_qualified_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\nimport example as wibble\\npub fn main() {\\n  wibble.example_fn()\\n}\\n\"\n---\nimport example as wibble\npub fn main() {\n  wibble.example_fn()\n                    ↑\n}\n\n\n----- Signature help -----\nwibble.example_fn(Int, String) -> Nil\n                  ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_aliased_unqualified_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\nimport example.{example_fn as wibble}\\npub fn main() {\\n  wibble()\\n}\\n\"\n---\nimport example.{example_fn as wibble}\npub fn main() {\n  wibble()\n         ↑\n}\n\n\n----- Signature help -----\nwibble(Int, String) -> Nil\n       ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_calling_local_variable_first_arg.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn main() {\\n  let wibble = fn(a: Int, b: String) { 1.0 }\\n  wibble()\\n}\\n\"\n---\npub fn main() {\n  let wibble = fn(a: Int, b: String) { 1.0 }\n  wibble()\n         ↑\n}\n\n\n----- Signature help -----\nwibble(Int, String) -> Float\n       ▔▔▔\n\nDocumentation:\nMarkupContent(\n    MarkupContent {\n        kind: Markdown,\n        value: \"A locally defined variable.\",\n    },\n)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_calling_local_variable_last_arg.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn main() {\\n  let wibble = fn(a: Int, b: String) { 1.0 }\\n  wibble(1,)\\n}\\n\"\n---\npub fn main() {\n  let wibble = fn(a: Int, b: String) { 1.0 }\n  wibble(1,)\n           ↑\n}\n\n\n----- Signature help -----\nwibble(Int, String) -> Float\n            ▔▔▔▔▔▔\n\nDocumentation:\nMarkupContent(\n    MarkupContent {\n        kind: Markdown,\n        value: \"A locally defined variable.\",\n    },\n)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_calling_local_variable_referencing_constant_referencing_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b: String) { 1.0 }\\nconst wobble = wibble\\n\\npub fn main() {\\n  let woo = wobble\\n  woo()\\n}\\n\"\n---\npub fn wibble(a: Int, b: String) { 1.0 }\nconst wobble = wibble\n\npub fn main() {\n  let woo = wobble\n  woo()\n      ↑\n}\n\n\n----- Signature help -----\nwoo(Int, String) -> Float\n    ▔▔▔\n\nDocumentation:\nMarkupContent(\n    MarkupContent {\n        kind: Markdown,\n        value: \"A locally defined variable.\",\n    },\n)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_calling_local_variable_with_module_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b: String) { 1.0 }\\n\\npub fn main() {\\n  let wobble = fn(a: Int, b: String) { 1.0 }\\n  wobble(1,)\\n}\\n\"\n---\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  let wobble = fn(a: Int, b: String) { 1.0 }\n  wobble(1,)\n           ↑\n}\n\n\n----- Signature help -----\nwobble(Int, String) -> Float\n            ▔▔▔▔▔▔\n\nDocumentation:\nMarkupContent(\n    MarkupContent {\n        kind: Markdown,\n        value: \"A locally defined variable.\",\n    },\n)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_calling_module_constant_referencing_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b: String) { 1.0 }\\nconst wobble = wibble\\n\\npub fn main() {\\n  wobble()\\n}\\n\"\n---\npub fn wibble(a: Int, b: String) { 1.0 }\nconst wobble = wibble\n\npub fn main() {\n  wobble()\n         ↑\n}\n\n\n----- Signature help -----\nwobble(Int, String) -> Float\n       ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_calling_module_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b: String) { 1.0 }\\n\\npub fn main() {\\n  wibble()\\n}\\n\"\n---\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  wibble()\n         ↑\n}\n\n\n----- Signature help -----\nwibble(Int, String) -> Float\n       ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_piped_function_starts_from_second_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a a: Int, b b: Int, c c: String) { 1.0 }\\n\\npub fn main() {\\n    1 |> wibble()\\n}\\n    \"\n---\npub fn wibble(a a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    1 |> wibble()\n                ↑\n}\n    \n\n\n----- Signature help -----\nwibble(a: Int, b: Int, c: String) -> Float\n               ▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_piped_imported_function_starts_from_second_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\nimport example\\npub fn main() {\\n    1 |> example.example_fn()\\n}\\n    \"\n---\nimport example\npub fn main() {\n    1 |> example.example_fn()\n                            ↑\n}\n    \n\n\n----- Signature help -----\nexample.example_fn(Int, String) -> Nil\n                        ▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_qualified_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\nimport example\\npub fn main() {\\n  example.example_fn()\\n}\\n\"\n---\nimport example\npub fn main() {\n  example.example_fn()\n                     ↑\n}\n\n\n----- Signature help -----\nexample.example_fn(Int, String) -> Nil\n                   ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_unqualified_call.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\nimport example.{example_fn}\\npub fn main() {\\n  example_fn()\\n}\\n\"\n---\nimport example.{example_fn}\npub fn main() {\n  example_fn()\n             ↑\n}\n\n\n----- Signature help -----\nexample_fn(Int, String) -> Nil\n           ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_use_function_call_starts_from_first_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b: Int, c: fn() -> Int) { 1.0 }\\n\\npub fn main() {\\n    use <- wibble()\\n}\\n    \"\n---\npub fn wibble(a: Int, b: Int, c: fn() -> Int) { 1.0 }\n\npub fn main() {\n    use <- wibble()\n                  ↑\n}\n    \n\n\n----- Signature help -----\nwibble(Int, Int, fn() -> Int) -> Float\n       ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_use_function_call_uses_concrete_types_when_late_ubound.snap",
    "content": "---\nsource: language-server/src/tests/signature_help.rs\nexpression: \"\\nfn identity(x: a) -> a { x }\\n\\nfn main() {\\n  let a = Ok(10)\\n  identity( a)\\n}\\n\"\nsnapshot_kind: text\n---\nfn identity(x: a) -> a { x }\n\nfn main() {\n  let a = Ok(10)\n  identity( a)\n           ↑  \n}\n\n\n----- Signature help -----\nidentity(Result(Int, b)) -> Result(Int, b)\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_use_function_call_uses_concrete_types_when_possible_or_generic_names_when_unbound.snap",
    "content": "---\nsource: language-server/src/tests/signature_help.rs\nexpression: \"\\npub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\\npub fn main() {\\n    wibble(1, )\\n}\\n\"\nsnapshot_kind: text\n---\npub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\npub fn main() {\n    wibble(1, )\n              ↑\n}\n\n\n----- Signature help -----\nwibble(Int, fn() -> Int, anything) -> Nil\n            ▔▔▔▔▔▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_use_function_call_uses_generic_names_when_missing_all_arguments.snap",
    "content": "---\nsource: language-server/src/tests/signature_help.rs\nexpression: \"\\npub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\\npub fn main() {\\n    wibble( )\\n}\\n\"\nsnapshot_kind: text\n---\npub fn wibble(x: something, y: fn() -> something, z: anything) { Nil }\npub fn main() {\n    wibble( )\n           ↑ \n}\n\n\n----- Signature help -----\nwibble(something, fn() -> something, anything) -> Nil\n       ▔▔▔▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_use_function_call_uses_precise_types_when_missing_some_arguments.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn guard(a: Bool, b: a, c: fn() -> a) { 1.0 }\\n\\npub fn main() {\\n    use <- guard(True,)\\n}\\n    \"\n---\npub fn guard(a: Bool, b: a, c: fn() -> a) { 1.0 }\n\npub fn main() {\n    use <- guard(True,)\n                      ↑\n}\n    \n\n\n----- Signature help -----\nguard(Bool, a, fn() -> a) -> Float\n            ▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_for_use_function_shows_next_unlabelled_argument.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn guard(a a: Bool, b b: a, c c: fn() -> a) { 1.0 }\\n\\npub fn main() {\\n    use <- guard(b: 1,)\\n}\\n    \"\n---\npub fn guard(a a: Bool, b b: a, c c: fn() -> a) { 1.0 }\n\npub fn main() {\n    use <- guard(b: 1,)\n                      ↑\n}\n    \n\n\n----- Signature help -----\nguard(a: Bool, b: a, c: fn() -> a) -> Float\n      ▔▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_shows_documentation_for_imported_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\nimport example\\npub fn main() {\\n  example.example_fn()\\n}\\n\"\n---\nimport example\npub fn main() {\n  example.example_fn()\n                     ↑\n}\n\n\n----- Signature help -----\nexample.example_fn(Int, String) -> Nil\n                   ▔▔▔\n\nDocumentation:\nMarkupContent(\n    MarkupContent {\n        kind: Markdown,\n        value: \" Some doc!\\n\",\n    },\n)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_shows_documentation_for_local_function.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\n/// Some doc!\\npub fn wibble(a: Int, b: String) { 1.0 }\\n\\npub fn main() {\\n  wibble()\\n}\\n\"\n---\n/// Some doc!\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  wibble()\n         ↑\n}\n\n\n----- Signature help -----\nwibble(Int, String) -> Float\n       ▔▔▔\n\nDocumentation:\nMarkupContent(\n    MarkupContent {\n        kind: Markdown,\n        value: \" Some doc!\\n\",\n    },\n)\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_shows_first_missing_labelled_argument_if_out_of_order.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a a: Int, b b: Int, c c: String) { 1.0 }\\n\\npub fn main() {\\n    wibble(c: \\\"c\\\",)\\n}\\n    \"\n---\npub fn wibble(a a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    wibble(c: \"c\",)\n                  ↑\n}\n    \n\n\n----- Signature help -----\nwibble(a: Int, b: Int, c: String) -> Float\n       ▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_shows_labelled_argument_after_all_unlabelled.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b b: Int, c c: String) { 1.0 }\\n\\npub fn main() {\\n    wibble(1,)\\n}\\n    \"\n---\npub fn wibble(a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    wibble(1,)\n             ↑\n}\n    \n\n\n----- Signature help -----\nwibble(Int, b: Int, c: String) -> Float\n            ▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_shows_labels.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b b: Int, c c: String) { 1.0 }\\n\\npub fn main() {\\n    wibble()\\n}\\n    \"\n---\npub fn wibble(a: Int, b b: Int, c c: String) { 1.0 }\n\npub fn main() {\n    wibble()\n           ↑\n}\n    \n\n\n----- Signature help -----\nwibble(Int, b: Int, c: String) -> Float\n       ▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_still_shows_up_even_if_an_argument_has_the_wrong_type.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub fn wibble(a: Int, b: String) { 1.0 }\\n\\npub fn main() {\\n  wibble(\\\"wrong\\\",)\\n}\\n\"\n---\npub fn wibble(a: Int, b: String) { 1.0 }\n\npub fn main() {\n  wibble(\"wrong\",)\n                 ↑\n}\n\n\n----- Signature help -----\nwibble(Int, String) -> Float\n            ▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests/snapshots/gleam_language_server__tests__signature_help__help_with_labelled_constructor.snap",
    "content": "---\nsource: compiler-core/src/language_server/tests/signature_help.rs\nexpression: \"\\npub type Pokemon {\\n    Pokemon(name: String, types: List(String), moves: List(String))\\n}\\n\\npub fn main() {\\n    Pokemon(name: \\\"Jirachi\\\",)\\n}\\n    \"\n---\npub type Pokemon {\n    Pokemon(name: String, types: List(String), moves: List(String))\n}\n\npub fn main() {\n    Pokemon(name: \"Jirachi\",)\n                            ↑\n}\n    \n\n\n----- Signature help -----\nPokemon(name: String, types: List(String), moves: List(String)) -> Pokemon\n                      ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔\n\nNo documentation\n"
  },
  {
    "path": "language-server/src/tests.rs",
    "content": "mod action;\nmod compilation;\nmod completion;\nmod definition;\nmod document_symbols;\nmod folding_range;\nmod hover;\nmod reference;\nmod rename;\nmod router;\nmod signature_help;\n\nuse std::{\n    collections::{HashMap, HashSet},\n    sync::{Arc, Mutex},\n    time::SystemTime,\n};\n\nuse ecow::EcoString;\nuse hexpm::version::{Range, Version};\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse itertools::Itertools;\nuse lsp_types::{Position, TextDocumentIdentifier, TextDocumentPositionParams, Url};\n\nuse gleam_core::{\n    Result,\n    config::PackageConfig,\n    io::{\n        BeamCompiler, Command, CommandExecutor, FileSystemReader, FileSystemWriter, ReadDir,\n        WrappedReader, memory::InMemoryFileSystem,\n    },\n    line_numbers::LineNumbers,\n    manifest::{Base16Checksum, Manifest, ManifestPackage, ManifestPackageSource},\n    paths::ProjectPaths,\n    requirement::Requirement,\n};\n\nuse super::{\n    DownloadDependencies, LockGuard, Locker, MakeLocker, engine::LanguageServerEngine,\n    files::FileSystemProxy, progress::ProgressReporter,\n};\n\npub const LSP_TEST_ROOT_PACKAGE_NAME: &str = \"app\";\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum Action {\n    CompilationStarted,\n    CompilationFinished,\n    DependencyDownloadingStarted,\n    DependencyDownloadingFinished,\n    DownloadDependencies,\n    LockBuild,\n    UnlockBuild,\n}\n\n#[derive(Debug, Clone)]\nstruct LanguageServerTestIO {\n    io: InMemoryFileSystem,\n    paths: ProjectPaths,\n    actions: Arc<Mutex<Vec<Action>>>,\n    manifest: Manifest,\n}\n\nfn default_manifest_package() -> ManifestPackage {\n    ManifestPackage {\n        name: Default::default(),\n        build_tools: Default::default(),\n        otp_app: Default::default(),\n        requirements: Default::default(),\n        version: Version::new(1, 0, 0),\n        source: ManifestPackageSource::Hex {\n            outer_checksum: Base16Checksum(vec![]),\n        },\n    }\n}\n\nimpl LanguageServerTestIO {\n    fn new() -> Self {\n        Self {\n            io: Default::default(),\n            actions: Default::default(),\n            paths: ProjectPaths::at_filesystem_root(),\n            manifest: Manifest {\n                requirements: HashMap::new(),\n                packages: vec![],\n            },\n        }\n    }\n\n    /// Panics if there are other references to the actions.\n    pub fn into_actions(self) -> Vec<Action> {\n        Arc::try_unwrap(self.actions).unwrap().into_inner().unwrap()\n    }\n\n    pub fn src_module(&self, name: &str, code: &str) -> Utf8PathBuf {\n        let src_dir = self.paths.src_directory();\n        let path = src_dir.join(name).with_extension(\"gleam\");\n        self.module(&path, code);\n        path\n    }\n\n    pub fn test_module(&self, name: &str, code: &str) -> Utf8PathBuf {\n        let test_dir = self.paths.test_directory();\n        let path = test_dir.join(name).with_extension(\"gleam\");\n        self.module(&path, code);\n        path\n    }\n\n    pub fn dev_module(&self, name: &str, code: &str) -> Utf8PathBuf {\n        let dev_directory = self.paths.dev_directory();\n        let path = dev_directory.join(name).with_extension(\"gleam\");\n        self.module(&path, code);\n        path\n    }\n\n    pub fn path_dep_module(&self, dep: &str, name: &str, code: &str) -> Utf8PathBuf {\n        let dep_dir = self.paths.root().join(dep).join(\"src\");\n        let path = dep_dir.join(name).with_extension(\"gleam\");\n        self.module(&path, code);\n        path\n    }\n\n    pub fn hex_dep_module(&self, dep: &str, name: &str, code: &str) -> Utf8PathBuf {\n        let dep_dir = self.paths.build_packages_package(dep).join(\"src\");\n        let path = dep_dir.join(name).with_extension(\"gleam\");\n        self.module(&path, code);\n        path\n    }\n\n    pub fn add_hex_package(&mut self, name: &str) {\n        self.manifest.packages.push(ManifestPackage {\n            name: name.into(),\n            source: ManifestPackageSource::Hex {\n                outer_checksum: Base16Checksum(vec![]),\n            },\n            build_tools: vec![\"gleam\".into()],\n            ..default_manifest_package()\n        });\n    }\n\n    fn module(&self, path: &Utf8Path, code: &str) {\n        self.io.write(path, code).unwrap();\n        self.io\n            .try_set_modification_time(path, SystemTime::now())\n            .unwrap();\n    }\n\n    fn record(&self, action: Action) {\n        self.actions.lock().unwrap().push(action);\n    }\n}\n\nimpl FileSystemReader for LanguageServerTestIO {\n    fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir> {\n        self.io.read_dir(path)\n    }\n\n    fn read(&self, path: &Utf8Path) -> Result<String> {\n        self.io.read(path)\n    }\n\n    fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>> {\n        self.io.read_bytes(path)\n    }\n\n    fn reader(&self, path: &Utf8Path) -> Result<WrappedReader> {\n        self.io.reader(path)\n    }\n\n    fn is_file(&self, path: &Utf8Path) -> bool {\n        self.io.is_file(path)\n    }\n\n    fn is_directory(&self, path: &Utf8Path) -> bool {\n        self.io.is_directory(path)\n    }\n\n    fn modification_time(&self, path: &Utf8Path) -> Result<SystemTime> {\n        self.io.modification_time(path)\n    }\n\n    fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, gleam_core::Error> {\n        self.io.canonicalise(path)\n    }\n}\n\nimpl FileSystemWriter for LanguageServerTestIO {\n    fn mkdir(&self, path: &Utf8Path) -> Result<()> {\n        self.io.mkdir(path)\n    }\n\n    fn delete_directory(&self, path: &Utf8Path) -> Result<()> {\n        self.io.delete_directory(path)\n    }\n\n    fn copy(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.copy(from, to)\n    }\n\n    fn copy_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.copy_dir(from, to)\n    }\n\n    fn hardlink(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.hardlink(from, to)\n    }\n\n    fn symlink_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> {\n        self.io.symlink_dir(from, to)\n    }\n\n    fn delete_file(&self, path: &Utf8Path) -> Result<()> {\n        self.io.delete_file(path)\n    }\n\n    fn write(&self, path: &Utf8Path, content: &str) -> Result<(), gleam_core::Error> {\n        self.io.write(path, content)\n    }\n\n    fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<(), gleam_core::Error> {\n        self.io.write_bytes(path, content)\n    }\n\n    fn exists(&self, path: &Utf8Path) -> bool {\n        self.io.exists(path)\n    }\n}\n\nimpl DownloadDependencies for LanguageServerTestIO {\n    fn download_dependencies(&self, _paths: &ProjectPaths) -> Result<Manifest> {\n        self.record(Action::DownloadDependencies);\n        Ok(self.manifest.clone())\n    }\n}\n\nimpl CommandExecutor for LanguageServerTestIO {\n    fn exec(&self, command: Command) -> Result<i32> {\n        let Command {\n            program,\n            args,\n            env,\n            cwd,\n            stdio,\n        } = command;\n        panic!(\"exec({program:?}, {args:?}, {env:?}, {cwd:?}, {stdio:?}) is not implemented\")\n    }\n}\n\nimpl BeamCompiler for LanguageServerTestIO {\n    fn compile_beam(\n        &self,\n        out: &Utf8Path,\n        lib: &Utf8Path,\n        modules: &HashSet<Utf8PathBuf>,\n        stdio: gleam_core::io::Stdio,\n    ) -> Result<Vec<String>> {\n        panic!(\"compile_beam({out:?}, {lib:?}, {modules:?}, {stdio:?}) is not implemented\")\n    }\n}\n\nimpl MakeLocker for LanguageServerTestIO {\n    fn make_locker(\n        &self,\n        _paths: &ProjectPaths,\n        _target: gleam_core::build::Target,\n    ) -> Result<Box<dyn Locker>> {\n        Ok(Box::new(TestLocker {\n            actions: self.actions.clone(),\n        }))\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct TestLocker {\n    actions: Arc<Mutex<Vec<Action>>>,\n}\n\nimpl TestLocker {\n    fn record(&self, action: Action) {\n        self.actions.lock().unwrap().push(action);\n    }\n}\n\nimpl Locker for TestLocker {\n    fn lock_for_build(&self) -> Result<LockGuard> {\n        self.record(Action::LockBuild);\n        Ok(LockGuard(Box::new(Guard(self.actions.clone()))))\n    }\n}\n\nstruct Guard(Arc<Mutex<Vec<Action>>>);\n\nimpl Drop for Guard {\n    fn drop(&mut self) {\n        self.0.lock().unwrap().push(Action::UnlockBuild);\n    }\n}\n\nimpl ProgressReporter for LanguageServerTestIO {\n    fn compilation_started(&self) {\n        self.record(Action::CompilationStarted);\n    }\n\n    fn compilation_finished(&self) {\n        self.record(Action::CompilationFinished);\n    }\n\n    fn dependency_downloading_started(&self) {\n        self.record(Action::DependencyDownloadingStarted);\n    }\n\n    fn dependency_downloading_finished(&self) {\n        self.record(Action::DependencyDownloadingFinished);\n    }\n}\n\nfn add_package_from_manifest<B>(\n    engine: &mut LanguageServerEngine<LanguageServerTestIO, B>,\n    toml_path: Utf8PathBuf,\n    package: ManifestPackage,\n) {\n    let compiler = &mut engine.compiler.project_compiler;\n    _ = compiler.config.dependencies.insert(\n        package.name.clone(),\n        match package.source {\n            ManifestPackageSource::Hex { .. } => Requirement::Hex {\n                version: Range::new(\"1.0.0\".into()).unwrap(),\n            },\n            ManifestPackageSource::Local { ref path } => Requirement::Path { path: path.into() },\n            ManifestPackageSource::Git {\n                ref repo,\n                ref commit,\n            } => Requirement::Git {\n                git: repo.clone(),\n                ref_: commit.clone(),\n            },\n        },\n    );\n    write_toml_from_manifest(engine, toml_path, package);\n}\n\nfn add_dev_package_from_manifest<B>(\n    engine: &mut LanguageServerEngine<LanguageServerTestIO, B>,\n    toml_path: Utf8PathBuf,\n    package: ManifestPackage,\n) {\n    let compiler = &mut engine.compiler.project_compiler;\n    _ = compiler.config.dev_dependencies.insert(\n        package.name.clone(),\n        match package.source {\n            ManifestPackageSource::Hex { .. } => Requirement::Hex {\n                version: Range::new(\"1.0.0\".into()).unwrap(),\n            },\n            ManifestPackageSource::Local { ref path } => Requirement::Path { path: path.into() },\n            ManifestPackageSource::Git {\n                ref repo,\n                ref commit,\n            } => Requirement::Git {\n                git: repo.clone(),\n                ref_: commit.clone(),\n            },\n        },\n    );\n    write_toml_from_manifest(engine, toml_path, package);\n}\n\nfn write_toml_from_manifest<B>(\n    engine: &mut LanguageServerEngine<LanguageServerTestIO, B>,\n    toml_path: Utf8PathBuf,\n    package: ManifestPackage,\n) {\n    let compiler = &mut engine.compiler.project_compiler;\n    let toml = format!(\n        r#\"name = \"{}\"\n    version = \"{}\"\"#,\n        &package.name, &package.version\n    );\n\n    _ = compiler.packages.insert(package.name.to_string(), package);\n    compiler.io.write(toml_path.as_path(), &toml).unwrap();\n}\n\nfn add_path_dep<B>(engine: &mut LanguageServerEngine<LanguageServerTestIO, B>, name: &str) {\n    let path = engine.paths.root().join(name);\n    add_package_from_manifest(\n        engine,\n        path.join(\"gleam.toml\"),\n        ManifestPackage {\n            name: name.into(),\n            version: Version::new(1, 0, 0),\n            build_tools: vec![\"gleam\".into()],\n            otp_app: None,\n            requirements: vec![],\n            source: ManifestPackageSource::Local { path: path.clone() },\n        },\n    )\n}\n\nfn setup_engine(\n    io: &LanguageServerTestIO,\n) -> LanguageServerEngine<LanguageServerTestIO, LanguageServerTestIO> {\n    let mut config = PackageConfig::default();\n    config.name = LSP_TEST_ROOT_PACKAGE_NAME.into();\n    LanguageServerEngine::new(\n        config,\n        io.clone(),\n        FileSystemProxy::new(io.clone()),\n        io.paths.clone(),\n    )\n    .unwrap()\n}\n\nstruct TestProject<'a> {\n    src: &'a str,\n    root_package_modules: Vec<(&'a str, &'a str)>,\n    dependency_modules: Vec<(&'a str, &'a str)>,\n    test_modules: Vec<(&'a str, &'a str)>,\n    dev_modules: Vec<(&'a str, &'a str)>,\n    hex_modules: Vec<(&'a str, &'a str)>,\n    dev_hex_modules: Vec<(&'a str, &'a str)>,\n    indirect_hex_modules: Vec<(&'a str, &'a str)>,\n    package_modules: HashMap<&'a str, Vec<(&'a str, &'a str)>>,\n}\n\nimpl<'a> TestProject<'a> {\n    pub fn for_source(src: &'a str) -> Self {\n        TestProject {\n            src,\n            root_package_modules: vec![],\n            dependency_modules: vec![],\n            test_modules: vec![],\n            dev_modules: vec![],\n            hex_modules: vec![],\n            dev_hex_modules: vec![],\n            indirect_hex_modules: vec![],\n            package_modules: HashMap::new(),\n        }\n    }\n\n    pub fn module_name_from_url(&self, url: &Url) -> Option<String> {\n        Some(\n            url.path_segments()?\n                .skip_while(|segment| *segment != \"src\")\n                .skip(1)\n                .join(\"/\")\n                .trim_end_matches(\".gleam\")\n                .into(),\n        )\n    }\n\n    pub fn src_from_module_url(&self, url: &Url) -> Option<&str> {\n        let module_name: EcoString = self.module_name_from_url(url)?.into();\n\n        if module_name == \"app\" {\n            return Some(self.src);\n        }\n\n        let find_module = |modules: &Vec<(&'a str, &'a str)>| {\n            modules\n                .iter()\n                .find(|(name, _)| *name == module_name)\n                .map(|(_, src)| *src)\n        };\n\n        find_module(&self.root_package_modules)\n            .or_else(|| find_module(&self.dependency_modules))\n            .or_else(|| find_module(&self.test_modules))\n            .or_else(|| find_module(&self.hex_modules))\n            .or_else(|| find_module(&self.dev_hex_modules))\n            .or_else(|| find_module(&self.indirect_hex_modules))\n    }\n\n    pub fn add_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.root_package_modules.push((name, src));\n        self\n    }\n\n    pub fn add_dep_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.dependency_modules.push((name, src));\n        self\n    }\n\n    pub fn add_test_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.test_modules.push((name, src));\n        self\n    }\n\n    pub fn add_dev_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.dev_modules.push((name, src));\n        self\n    }\n\n    pub fn add_hex_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.hex_modules.push((name, src));\n        self\n    }\n\n    pub fn add_dev_hex_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.dev_hex_modules.push((name, src));\n        self\n    }\n\n    pub fn add_indirect_hex_module(mut self, name: &'a str, src: &'a str) -> Self {\n        self.indirect_hex_modules.push((name, src));\n        self\n    }\n\n    pub fn add_package_module(mut self, package: &'a str, name: &'a str, src: &'a str) -> Self {\n        self.package_modules\n            .entry(package)\n            .or_default()\n            .push((name, src));\n        self\n    }\n\n    pub fn build_engine(\n        &self,\n        io: &mut LanguageServerTestIO,\n    ) -> LanguageServerEngine<LanguageServerTestIO, LanguageServerTestIO> {\n        io.add_hex_package(\"hex\");\n        self.hex_modules.iter().for_each(|(name, code)| {\n            _ = io.hex_dep_module(\"hex\", name, code);\n        });\n\n        self.dev_hex_modules.iter().for_each(|(name, code)| {\n            _ = io.hex_dep_module(\"dev_hex\", name, code);\n        });\n\n        self.indirect_hex_modules.iter().for_each(|(name, code)| {\n            _ = io.hex_dep_module(\"indirect_hex\", name, code);\n        });\n\n        for (package, modules) in self.package_modules.iter() {\n            io.add_hex_package(package);\n            for (module, code) in modules {\n                _ = io.hex_dep_module(package, module, code);\n            }\n        }\n\n        let mut engine = setup_engine(io);\n\n        // Add an external dependency and all its modules\n        add_path_dep(&mut engine, \"dep\");\n        self.dependency_modules.iter().for_each(|(name, code)| {\n            let _ = io.path_dep_module(\"dep\", name, code);\n        });\n\n        // Add all the modules belonging to the root package\n        self.root_package_modules.iter().for_each(|(name, code)| {\n            let _ = io.src_module(name, code);\n        });\n\n        // Add all the test modules\n        self.test_modules.iter().for_each(|(name, code)| {\n            let _ = io.test_module(name, code);\n        });\n\n        // Add all the dev modules\n        self.dev_modules.iter().for_each(|(name, code)| {\n            let _ = io.dev_module(name, code);\n        });\n\n        for package in &io.manifest.packages {\n            let toml_path = engine.paths.build_packages_package_config(&package.name);\n            add_package_from_manifest(&mut engine, toml_path, package.clone());\n        }\n\n        // Add an indirect dependency manifest\n        let toml_path = engine.paths.build_packages_package_config(\"indirect_hex\");\n        write_toml_from_manifest(\n            &mut engine,\n            toml_path,\n            ManifestPackage {\n                name: \"indirect_hex\".into(),\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![]),\n                },\n                build_tools: vec![\"gleam\".into()],\n                ..default_manifest_package()\n            },\n        );\n\n        // Add a dev dependency\n        let toml_path = engine.paths.build_packages_package_config(\"dev_hex\");\n        add_dev_package_from_manifest(\n            &mut engine,\n            toml_path,\n            ManifestPackage {\n                name: \"dev_hex\".into(),\n                source: ManifestPackageSource::Hex {\n                    outer_checksum: Base16Checksum(vec![]),\n                },\n                build_tools: vec![\"gleam\".into()],\n                ..default_manifest_package()\n            },\n        );\n\n        engine\n    }\n\n    pub fn build_path(&self, position: Position) -> TextDocumentPositionParams {\n        let path = Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n            r\"\\\\?\\C:\\src\\app.gleam\"\n        } else {\n            \"/src/app.gleam\"\n        });\n\n        let url = Url::from_file_path(path).unwrap();\n\n        TextDocumentPositionParams::new(TextDocumentIdentifier::new(url), position)\n    }\n\n    pub fn build_test_path(\n        &self,\n        position: Position,\n        test_name: &str,\n    ) -> TextDocumentPositionParams {\n        let path = Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n            format!(r\"\\\\?\\C:\\test\\{test_name}.gleam\")\n        } else {\n            format!(\"/test/{test_name}.gleam\")\n        });\n\n        let url = Url::from_file_path(path).unwrap();\n\n        TextDocumentPositionParams::new(TextDocumentIdentifier::new(url), position)\n    }\n\n    pub fn build_dev_path(\n        &self,\n        position: Position,\n        test_name: &str,\n    ) -> TextDocumentPositionParams {\n        let path = Utf8PathBuf::from(if cfg!(target_family = \"windows\") {\n            format!(r\"\\\\?\\C:\\dev\\{test_name}.gleam\")\n        } else {\n            format!(\"/dev/{test_name}.gleam\")\n        });\n\n        let url = Url::from_file_path(path).unwrap();\n\n        TextDocumentPositionParams::new(TextDocumentIdentifier::new(url), position)\n    }\n\n    pub fn positioned_with_io(\n        &self,\n        position: Position,\n    ) -> (\n        LanguageServerEngine<LanguageServerTestIO, LanguageServerTestIO>,\n        TextDocumentPositionParams,\n    ) {\n        let mut io = LanguageServerTestIO::new();\n        let mut engine = self.build_engine(&mut io);\n\n        // Add the final module we're going to be positioning the cursor in.\n        _ = io.src_module(\"app\", self.src);\n\n        let _response = engine.compile_please();\n\n        let param = self.build_path(position);\n\n        (engine, param)\n    }\n\n    pub fn positioned_with_io_in_test(\n        &self,\n        position: Position,\n        test_name: &str,\n    ) -> (\n        LanguageServerEngine<LanguageServerTestIO, LanguageServerTestIO>,\n        TextDocumentPositionParams,\n    ) {\n        let mut io = LanguageServerTestIO::new();\n        let mut engine = self.build_engine(&mut io);\n\n        // Add the final module we're going to be positioning the cursor in.\n        _ = io.src_module(\"app\", self.src);\n\n        let response = engine.compile_please();\n        assert!(response.result.is_ok());\n\n        let param = self.build_test_path(position, test_name);\n\n        (engine, param)\n    }\n\n    pub fn positioned_with_io_in_dev(\n        &self,\n        position: Position,\n        test_name: &str,\n    ) -> (\n        LanguageServerEngine<LanguageServerTestIO, LanguageServerTestIO>,\n        TextDocumentPositionParams,\n    ) {\n        let mut io = LanguageServerTestIO::new();\n        let mut engine = self.build_engine(&mut io);\n\n        // Add the final module we're going to be positioning the cursor in.\n        _ = io.src_module(\"app\", self.src);\n\n        let response = engine.compile_please();\n        assert!(response.result.is_ok());\n\n        let param = self.build_dev_path(position, test_name);\n\n        (engine, param)\n    }\n\n    pub fn at<T>(\n        &self,\n        position: Position,\n        executor: impl FnOnce(\n            &mut LanguageServerEngine<LanguageServerTestIO, LanguageServerTestIO>,\n            TextDocumentPositionParams,\n            EcoString,\n        ) -> T,\n    ) -> T {\n        let (mut engine, params) = self.positioned_with_io(position);\n\n        executor(&mut engine, params, self.src.into())\n    }\n}\n\n#[derive(Clone)]\npub struct PositionFinder {\n    value: EcoString,\n    offset: usize,\n    nth_occurrence: usize,\n}\n\npub struct RangeSelector {\n    from: PositionFinder,\n    to: PositionFinder,\n}\n\nimpl RangeSelector {\n    pub fn find_range(&self, src: &str) -> lsp_types::Range {\n        lsp_types::Range {\n            start: self.from.find_position(src),\n            end: self.to.find_position(src),\n        }\n    }\n}\n\nimpl PositionFinder {\n    pub fn with_char_offset(self, offset: usize) -> Self {\n        Self {\n            value: self.value,\n            offset,\n            nth_occurrence: self.nth_occurrence,\n        }\n    }\n\n    pub fn under_char(self, char: char) -> Self {\n        Self {\n            offset: self.value.find(char).unwrap_or(0),\n            value: self.value,\n            nth_occurrence: self.nth_occurrence,\n        }\n    }\n\n    pub fn under_last_char(self) -> Self {\n        let len = self.value.len();\n        self.with_char_offset(len - 1)\n    }\n\n    pub fn nth_occurrence(self, nth_occurrence: usize) -> Self {\n        Self {\n            value: self.value,\n            offset: self.offset,\n            nth_occurrence,\n        }\n    }\n\n    pub fn for_value(value: &str) -> Self {\n        Self {\n            value: value.into(),\n            offset: 0,\n            nth_occurrence: 1,\n        }\n    }\n\n    pub fn find_position(&self, src: &str) -> Position {\n        let PositionFinder {\n            value,\n            offset,\n            nth_occurrence,\n        } = self;\n\n        let byte_index = src\n            .match_indices(value.as_str())\n            .nth(nth_occurrence - 1)\n            .expect(\"no match for position\")\n            .0;\n\n        byte_index_to_position(src, byte_index + offset)\n    }\n\n    pub fn select_until(self, end: PositionFinder) -> RangeSelector {\n        RangeSelector {\n            from: self,\n            to: end,\n        }\n    }\n\n    pub fn to_selection(self) -> RangeSelector {\n        RangeSelector {\n            from: self.clone(),\n            to: self,\n        }\n    }\n}\n\npub fn find_position_of(value: &str) -> PositionFinder {\n    PositionFinder::for_value(value)\n}\n\nfn byte_index_to_position(src: &str, byte_index: usize) -> Position {\n    let mut line = 0;\n    let mut col = 0;\n\n    for (i, char) in src.bytes().enumerate() {\n        if i == byte_index {\n            break;\n        }\n\n        if char == b'\\n' {\n            line += 1;\n            col = 0;\n        } else {\n            col += 1;\n        }\n    }\n\n    Position::new(line, col)\n}\n\n/// This function replicates how the text editor applies TextEdit.\n///\npub fn apply_code_edit(src: &str, mut change: Vec<lsp_types::TextEdit>) -> String {\n    let mut result = src.to_string();\n    let line_numbers = LineNumbers::new(src);\n    let mut offset = 0;\n\n    change.sort_by_key(|edit| (edit.range.start.line, edit.range.start.character));\n    for edit in change {\n        let start = line_numbers.byte_index(edit.range.start) as i32 - offset;\n        let end = line_numbers.byte_index(edit.range.end) as i32 - offset;\n        let range = (start as usize)..(end as usize);\n        offset += end - start;\n        offset -= edit.new_text.len() as i32;\n        result.replace_range(range, &edit.new_text);\n    }\n\n    result\n}\n"
  },
  {
    "path": "test/assert/.gitignore",
    "content": "build\n"
  },
  {
    "path": "test/assert/Makefile",
    "content": ".PHONY: test-all\ntest-all:\n\t@echo test/assert\n\t@./run_tests.sh\n"
  },
  {
    "path": "test/assert/gleam.toml",
    "content": "name = \"project\"\nversion = \"1.0.0\"\ndescription = \"A Gleam project\"\n\n[dependencies]\ngleam_stdlib = \">= 0.58.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/assert/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.58.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"091F2D2C4A3A4E2047986C47E2C2C9D728A4E068ABB31FDA17B0D347E6248467\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.58.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/assert/run_tests.sh",
    "content": "#/usr/bin/env sh\n\nset -eu\n\nshould_succeed() {\n    echo\n    echo Running: \"$@\"\n\n    EXIT_CODE=0\n    cargo run -- $@ > /dev/null 2>&1 || EXIT_CODE=$?\n    if [ $EXIT_CODE -ne 0 ]\n    then\n        echo ERROR: Command should have succeeded\n        exit 1\n    else\n        echo Test Passed '(command run successfully)'\n    fi\n}\n\nshould_fail() {\n    echo\n    echo Running: \"$@\"\n\n    EXIT_CODE=0\n    cargo run -- $@ > /dev/null 2>&1 || EXIT_CODE=$?\n\n    if [ $EXIT_CODE -eq 0 ]\n    then\n        echo ERROR: Command should have failed\n        exit 1\n    else\n        echo Test Passed '(command errored as expected)'\n    fi\n}\n\nall_targets() {\n  $@ --target erlang\n  $@ --target javascript --runtime nodejs\n  $@ --target javascript --runtime deno\n  $@ --target javascript --runtime bun\n}\n\n# Ensure the project builds correctly\nshould_succeed build --target erlang\nshould_succeed build --target javascript\n\nall_targets should_succeed run --module passing\n\n# Since a single failing `assert` will exit immediately, we must test each\n# failing case individually as separate modules.\nall_targets should_fail run --module failing1\nall_targets should_fail run --module failing2\nall_targets should_fail run --module failing3\nall_targets should_fail run --module failing4\n"
  },
  {
    "path": "test/assert/src/failing1.gleam",
    "content": "pub fn main() {\n  let x = True\n  assert !x\n}\n"
  },
  {
    "path": "test/assert/src/failing2.gleam",
    "content": "import gleam/int\n\npub fn main() {\n  assert int.is_even(47)\n}\n"
  },
  {
    "path": "test/assert/src/failing3.gleam",
    "content": "import gleam/bool\nimport gleam/result\n\npub fn main() {\n  assert bool.negate(False) && result.is_ok(Error(81))\n}\n"
  },
  {
    "path": "test/assert/src/failing4.gleam",
    "content": "import gleam/int\n\npub fn main() {\n  assert int.add(4, 5) > int.absolute_value(-11)\n}\n"
  },
  {
    "path": "test/assert/src/passing.gleam",
    "content": "import gleam/bool\nimport gleam/int\nimport gleam/result\n\n/// All these assertions should succeed\npub fn main() {\n  let x = True\n  assert x\n  assert case x && False {\n    True -> False\n    False -> True\n  }\n\n  assert result.is_ok(Ok(10))\n  assert result.is_error(Error(\"Hello\"))\n\n  assert int.add(5, 6) == 11\n  assert int.add(1, 4) < 9\n  assert int.add(8, 12) >= 20\n  assert bool.negate(False) && result.is_ok(Ok(42))\n  assert int.is_even(3) || int.is_even(4)\n\n  // This should short-circuit so we don't panic here\n  assert True || panic\n}\n"
  },
  {
    "path": "test/compile_package0/.gitignore",
    "content": "out\nbuild\n"
  },
  {
    "path": "test/compile_package0/Makefile",
    "content": ".PHONY: build\nbuild:\n\t# Remove any previously compiled code\n\trm -rf out\n\tcargo run -- compile-package --out out --target erlang --lib . --package .\n\terl -pa out/ebin -noshell -eval \"erlang:display(two:main()),erlang:display(three:test_()),halt()\"\n"
  },
  {
    "path": "test/compile_package0/gleam.toml",
    "content": "name = \"package\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test/compile_package0/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n]\n\n[requirements]\n"
  },
  {
    "path": "test/compile_package0/src/one.gleam",
    "content": "pub fn hello() -> String {\n  \"Hello\"\n}\n"
  },
  {
    "path": "test/compile_package0/src/two.gleam",
    "content": "import one\n\npub fn main() -> String {\n  one.hello()\n}\n"
  },
  {
    "path": "test/compile_package0/test/three.gleam",
    "content": "import one\nimport two\n\npub fn test_() -> Bool {\n  one.hello() == two.main()\n}\n"
  },
  {
    "path": "test/compile_package1/.gitignore",
    "content": "out1\nout2\n"
  },
  {
    "path": "test/compile_package1/Makefile",
    "content": ".PHONY: build\nbuild:\n\trm -rf out1 out2\n\tcargo run -- compile-package --package app1 --target erlang --out out2 --lib .\n\tcargo run -- compile-package --package app2 --target erlang --out out2 --lib .\n\terl -pa out1/ebin out2/ebin -noshell -eval \"erlang:display(two:main()),halt()\"\n"
  },
  {
    "path": "test/compile_package1/app1/gleam.toml",
    "content": "name = \"app1\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test/compile_package1/app1/src/one/nested.gleam",
    "content": "//// This module is used to test resolution of nested modules\n\npub fn id(a) {\n  a\n}\n"
  },
  {
    "path": "test/compile_package1/app1/src/one.gleam",
    "content": "pub fn hello() -> String {\n  \"Hello\"\n}\n"
  },
  {
    "path": "test/compile_package1/app2/gleam.toml",
    "content": "name = \"app2\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test/compile_package1/app2/src/two.gleam",
    "content": "import one\nimport one/nested\n\npub fn main() {\n  one.hello()\n  |> nested.id\n}\n"
  },
  {
    "path": "test/erlang_shipment_no_dev_deps/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "test/erlang_shipment_no_dev_deps/gleam.toml",
    "content": "name = \"shipment_test\"\nversion = \"0.1.0\"\n\n[dependencies]\ngleam_stdlib = \"~> 0.34\"\n# hpack_erl has otp_app = \"hpack\" (different from package name)\n# This tests that packages with different OTP app names are included correctly\nhpack_erl = \"~> 0.3\"\n\n[dev_dependencies]\ngleeunit = \"~> 1.0\"\n"
  },
  {
    "path": "test/erlang_shipment_no_dev_deps/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.68.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"F7FAEBD8EF260664E86A46C8DBA23508D1D11BB3BCC6EE1B89B3BC3E5C83FF1E\" },\n  { name = \"gleeunit\", version = \"1.9.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C\" },\n  { name = \"hpack_erl\", version = \"0.3.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"hpack\", source = \"hex\", outer_checksum = \"D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \"~> 0.34\" }\ngleeunit = { version = \"~> 1.0\" }\nhpack_erl = { version = \"~> 0.3\" }\n"
  },
  {
    "path": "test/erlang_shipment_no_dev_deps/src/shipment_test.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello from shipment test!\")\n}\n"
  },
  {
    "path": "test/erlang_shipment_no_dev_deps/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Building erlang shipment\ng export erlang-shipment\n\necho Checking that gleam_stdlib IS in the shipment\nif [ ! -d \"build/erlang-shipment/gleam_stdlib\" ]; then\n  echo \"ERROR: gleam_stdlib should be in the shipment but was not found\"\n  exit 1\nfi\necho \"gleam_stdlib found in shipment\"\n\necho Checking that hpack IS in the shipment\necho \"(hpack_erl package has otp_app=hpack, so directory is named hpack)\"\nif [ ! -d \"build/erlang-shipment/hpack\" ]; then\n  echo \"ERROR: hpack (from hpack_erl package) should be in the shipment but was not found\"\n  exit 1\nfi\necho \"hpack found in shipment\"\n\necho Checking that gleeunit is NOT in the shipment\nif [ -d \"build/erlang-shipment/gleeunit\" ]; then\n  echo \"ERROR: gleeunit is a dev dependency and should NOT be in the shipment\"\n  exit 1\nfi\necho \"gleeunit correctly excluded from shipment\"\n\necho Checking that the root package IS in the shipment\nif [ ! -d \"build/erlang-shipment/shipment_test\" ]; then\n  echo \"ERROR: shipment_test (root package) should be in the shipment but was not found\"\n  exit 1\nfi\necho \"shipment_test found in shipment\"\n\necho\necho Success!\necho\n"
  },
  {
    "path": "test/errors/type_unify_int_string/.gitignore",
    "content": "build\n"
  },
  {
    "path": "test/errors/type_unify_int_string/gleam.toml",
    "content": "name = \"type_unify_int_string\"\n\n# [docs]\n# links = [\n#   { title = 'GitHub', href = 'https://github.com/username/project_name' }\n# ]\n"
  },
  {
    "path": "test/errors/type_unify_int_string/src/type_unify_int_string.gleam",
    "content": "pub fn hello_world() {\n  let x: Int = \"Eh?\"\n  x\n}\n"
  },
  {
    "path": "test/external_only_erlang/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "test/external_only_erlang/README.md",
    "content": "# external_only_erlang\n\nA project that can only be run on Erlang due to an external function.\n"
  },
  {
    "path": "test/external_only_erlang/gleam.toml",
    "content": "name = \"external_only_erlang\"\nversion = \"1.0.0\"\ntarget = \"erlang\"\n\n[dependencies]\nhello_joe = \"~> 1.0\"\n\n[dev_dependencies]\n"
  },
  {
    "path": "test/external_only_erlang/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n  { name = \"hello_joe\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"hello_joe\", source = \"hex\", outer_checksum = \"CC896BC24A45528DE6C59A705171E2DD9F1EA4C3C031428E4A533539EF461519\" },\n]\n\n[requirements]\nhello_joe = { version = \"~> 1.0\" }\n"
  },
  {
    "path": "test/external_only_erlang/src/external_only_erlang.gleam",
    "content": "// This function is only implemented for Erlang, so if we try and call it from\n// JavaScript, or build this package for JavaScript, then the compiler will\n// (should) emit an error.\n@external(erlang, \"external_only_erlang_ffi\", \"main\")\npub fn main() -> Nil\n"
  },
  {
    "path": "test/external_only_erlang/src/external_only_erlang_ffi.erl",
    "content": "-module(external_only_erlang_ffi).\n-export([main/0]).\n\nmain() ->\n    io:format(\"Hello!\\n\", []).\n"
  },
  {
    "path": "test/external_only_erlang/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho This should succeed regardless of target as it is a dependency module\ng run --module=hello_joe\ng run --module=hello_joe --target=erlang\ng run --module=hello_joe --target=javascript\n\necho Building and running for Erlang should succeed\ng build --target=erlang\ng run --target=erlang\n\necho Building for JavaScript should fail, even if previously a JavaScript dependency was built\nif g build --target=javascript; then\n  echo \"Expected build to fail\"\n  exit 1\nfi\n\necho Running for JavaScript should fail, even if previously a JavaScript dependency was built\nif g run --target=javascript; then\n  echo \"Expected run to fail\"\n  exit 1\nfi\n\necho Running erlang shipment should succeed\ng export erlang-shipment\ngrep \"external_only_erlang_ffi\" \"build/erlang-shipment/external_only_erlang/ebin/external_only_erlang.app\"\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/external_only_javascript/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "test/external_only_javascript/README.md",
    "content": "# external_only_javascript\n\nA project that can only be run on JavaScript due to an external function.\n"
  },
  {
    "path": "test/external_only_javascript/gleam.toml",
    "content": "name = \"external_only_javascript\"\nversion = \"1.0.0\"\ntarget = \"javascript\"\n\n[dependencies]\nhello_joe = \"~> 1.0\"\n\n[dev_dependencies]\n"
  },
  {
    "path": "test/external_only_javascript/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n  { name = \"hello_joe\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"hello_joe\", source = \"hex\", outer_checksum = \"CC896BC24A45528DE6C59A705171E2DD9F1EA4C3C031428E4A533539EF461519\" },\n]\n\n[requirements]\nhello_joe = { version = \"~> 1.0\" }\n"
  },
  {
    "path": "test/external_only_javascript/src/external_only_javascript.gleam",
    "content": "// This function is only implemented for JavaScript, so if we try and call it\n// from Erlang, or build this package for Erlang, then the compiler will\n// (should) emit an error.\n@external(javascript, \"./external_only_javascript_ffi.mjs\", \"main\")\npub fn main() -> Nil\n"
  },
  {
    "path": "test/external_only_javascript/src/external_only_javascript_ffi.mjs",
    "content": "export function main() {\n  console.log(\"Hello\");\n}\n"
  },
  {
    "path": "test/external_only_javascript/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho This should succeed regardless of target as it is a dependency module\ng run --module=hello_joe\ng run --module=hello_joe --target=erlang\ng run --module=hello_joe --target=javascript\n\necho Building and running for JavaScript should succeed\ng build --target=javascript\ng run --target=javascript\n\necho Building for Erlang should fail, even if previously a Erlang dependency was built\nif g build --target=erlang; then\n  echo \"Expected build to fail\"\n  exit 1\nfi\n\necho Running for Erlang should fail, even if previously a Erlang dependency was built\nif g run --target=erlang; then\n  echo \"Expected run to fail\"\n  exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/hello_world/.gitignore",
    "content": ".rebar3\n_*\n.eunit\n*.o\n*.beam\n*.plt\n*.swp\n*.swo\n.erlang.cookie\nebin\nlog\nerl_crash.dump\n.rebar\nlogs\n_build\nbuild\n.idea\n*.iml\nrebar3.crashdump\ndoc\ngen\n"
  },
  {
    "path": "test/hello_world/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2018, Louis Pilfold <louis@lpil.uk>.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "test/hello_world/README.md",
    "content": "hello_world\n=====\n\nAn OTP library\n\nBuild\n-----\n\n    $ rebar3 compile\n"
  },
  {
    "path": "test/hello_world/gleam.toml",
    "content": "name = \"hello_world\"\ntool = \"other\"\n"
  },
  {
    "path": "test/hello_world/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n]\n\n[requirements]\n"
  },
  {
    "path": "test/hello_world/rebar.config",
    "content": "{erl_opts, [debug_info]}.\n{src_dirs, [\"src\", \"gen/src\"]}.\n\n{profiles, [\n    {test, [\n        {src_dirs, [\"src\", \"test\", \"gen/src\", \"gen/test\"]}\n    ]}\n]}.\n\n{deps, [\n]}.\n"
  },
  {
    "path": "test/hello_world/src/hello_world.app.src",
    "content": "{application, hello_world,\n [{description, \"An OTP library\"},\n  {vsn, \"0.1.0\"},\n  {registered, []},\n  {applications,\n   [kernel,\n    stdlib\n   ]},\n  {env,[]},\n  {modules, []},\n\n  {maintainers, []},\n  {licenses, [\"Apache 2.0\"]},\n  {links, []}\n ]}.\n"
  },
  {
    "path": "test/hello_world/src/hello_world.gleam",
    "content": "\n"
  },
  {
    "path": "test/hello_world/src/nest/bird!.gleam",
    "content": "\n"
  },
  {
    "path": "test/hello_world/src/nest/bird.gleam",
    "content": "\n"
  },
  {
    "path": "test/hello_world/src/nest/bird.js",
    "content": ""
  },
  {
    "path": "test/hello_world/src/other.gleam",
    "content": "pub fn add(a, b) {\n  a + b\n}\n\npub fn main() {\n  1\n  |> add()\n}\n"
  },
  {
    "path": "test/hello_world/test/hello_test.gleam",
    "content": "import hello_world\n\nfn run(x, y) {\n  x + y\n}\n"
  },
  {
    "path": "test/hextarball/.gitignore",
    "content": "build\n"
  },
  {
    "path": "test/hextarball/Makefile",
    "content": "# TODO: migrate to Rust shell commands, possibly ./compiler-cli/src/fs/tests.rs\ntest:\n\t# remove old tarball && create one && make will fail when it wasn't\n\tcargo run clean && cargo run export hex-tarball && make build/hextarball-0.1.0.tar\n"
  },
  {
    "path": "test/hextarball/gleam.toml",
    "content": "name = \"hextarball\"\nversion = \"0.1.0\"\ndescription = \"Test project to construct a hex tarball\"\nlicences = [\"Apache-2.0\"]\n"
  },
  {
    "path": "test/hextarball/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n]\n\n[requirements]\n"
  },
  {
    "path": "test/hextarball/src/hextarball.gleam",
    "content": "pub fn something() {\n  \"Just a thing to export\"\n}\n"
  },
  {
    "path": "test/javascript_prelude/.gitignore",
    "content": "prelude.*js\n"
  },
  {
    "path": "test/javascript_prelude/Makefile",
    "content": ".PHONY: test\ntest:\n\t@echo test/javascript_prelude\n\t@cp ../../compiler-core/templates/prelude.mjs prelude.mjs\n\t@node main.mjs\n\t@rm prelude.mjs\n"
  },
  {
    "path": "test/javascript_prelude/main.mjs",
    "content": "import {\n  BitArray,\n  BitArray$BitArray,\n  BitArray$BitArray$data,\n  BitArray$isBitArray,\n  CustomType,\n  Error,\n  List,\n  Ok,\n  UtfCodepoint,\n  codepointBits,\n  divideFloat,\n  divideInt,\n  isEqual,\n  stringBits,\n  toBitArray,\n  toList,\n  sizedInt,\n  sizedFloat,\n  bitArraySlice,\n  bitArraySliceToInt,\n  bitArraySliceToFloat,\n} from \"./prelude.mjs\";\n\nlet failures = 0;\nlet passes = 0;\n\nfunction pass() {\n  process.stdout.write(`\\u001b[${32}m.\\u001b[${0}m`);\n  passes++;\n}\n\nfunction fail(message) {\n  console.log(\"\");\n  console.assert(false, message);\n  failures++;\n}\n\nfunction inspect(a) {\n  if (typeof a === \"object\" && a !== null && typeof a.inspect === \"function\") {\n    return a.inspect();\n  } else {\n    return JSON.stringify(a);\n  }\n}\n\nfunction assertEqual(a, b) {\n  if (isEqual(a, b)) {\n    pass();\n  } else {\n    fail(`\\n\\t${inspect(a)}\\n\\t!=\\n\\t${inspect(b)}`);\n  }\n}\n\nfunction assertNotEqual(a, b) {\n  if (isEqual(a, b)) {\n    fail(`\\n\\t${inspect(a)}\\n\\t==\\n\\t${inspect(b)}`);\n  } else {\n    pass();\n  }\n}\n\nfunction assertThrows(msg, callable) {\n  try {\n    callable();\n    fail(msg);\n  } catch (error) {\n    pass();\n  }\n}\n\nfunction assert(msg, value) {\n  if (value) {\n    pass();\n  } else {\n    fail(msg);\n  }\n}\n\nclass ExampleRecordImpl extends CustomType {\n  constructor(first, detail, boop) {\n    super();\n    this[0] = first;\n    this.detail = detail;\n    this.boop = boop;\n  }\n}\n\nlet fmt = new Intl.DateTimeFormat(\"en-GB\", { timeStyle: \"medium\" });\nconsole.log(`Running tests at ${fmt.format(new Date())}\\n`);\n\n// Equality of Gleam values\n\nassertEqual(true, true);\nassertEqual(false, false);\nassertEqual(undefined, undefined);\nassertNotEqual(true, false);\nassertNotEqual(false, true);\nassertNotEqual(undefined, false);\nassertNotEqual(undefined, true);\nassertNotEqual(true, undefined);\nassertNotEqual(false, undefined);\n\nassertEqual(1, 1);\nassertNotEqual(1, 2);\nassertEqual(1.1, 1.1);\nassertNotEqual(2.1, 1.1);\nassertEqual(-1, -1);\nassertNotEqual(-1, 1);\nassertEqual(-1.1, -1.1);\nassertNotEqual(-1.1, 1.1);\n\nassertEqual(\"\", \"\");\nassertEqual(\"123\", \"123\");\nassertEqual(\"👽\", \"👽\");\nassertNotEqual(\"👽\", \"👾\");\n\nassertEqual(new Ok(1), new Ok(1));\nassertEqual(new Ok(2), new Ok(2));\nassertEqual(new Ok(new Ok(2)), new Ok(new Ok(2)));\nassertNotEqual(new Ok(1), new Ok(2));\nassertNotEqual(new Ok(new Ok(2)), new Ok(new Ok(3)));\n\nassertEqual(new Error(1), new Error(1));\nassertEqual(new Error(2), new Error(2));\nassertEqual(new Error(new Error(2)), new Error(new Error(2)));\nassertNotEqual(new Error(2), new Error(3));\nassertNotEqual(new Error(new Error(2)), new Error(new Error(3)));\n\nassertEqual(\n  new ExampleRecordImpl(undefined, 1, new Ok(2.1)),\n  new ExampleRecordImpl(undefined, 1, new Ok(2.1)),\n);\nassertNotEqual(\n  new ExampleRecordImpl(undefined, 1, new Ok(\"2.1\")),\n  new ExampleRecordImpl(undefined, 1, new Ok(2.1)),\n);\n\nassertEqual(List.fromArray([]), List.fromArray([]));\nassertEqual(\n  List.fromArray([1, 2, new Ok(1)]),\n  List.fromArray([1, 2, new Ok(1)]),\n);\nassertNotEqual(\n  List.fromArray([1, 2, new Ok(1)]),\n  List.fromArray([1, 2, new Ok(2)]),\n);\nassertNotEqual(List.fromArray([1, 2]), List.fromArray([1, 2, new Ok(2)]));\nassertNotEqual(List.fromArray([1]), List.fromArray([]));\nassertNotEqual(List.fromArray([]), List.fromArray([1]));\n\nassertEqual(new UtfCodepoint(128013), new UtfCodepoint(128013));\nassertNotEqual(new UtfCodepoint(128013), new UtfCodepoint(128014));\n\n// new BitArray()\n\nassertEqual(\n  new BitArray(new Uint8Array([1, 2, 3])),\n  new BitArray(new Uint8Array([1, 2, 3]), 24),\n);\n\nassertThrows(\"`new BitArray()` throws with an ArrayBuffer\", () => {\n  new BitArray(new ArrayBuffer(8));\n});\n\nassertThrows(\n  \"`new BitArray()` throws with a raw array\",\n  () => new BitArray([1, 2]),\n);\n\nassertThrows(\n  \"`new BitArray()` throws with invalid bit size\",\n  () => new BitArray(new Uint8Array([2]), -1),\n);\n\nassertThrows(\n  \"`new BitArray()` throws with too many bytes for the bit size\",\n  () => new BitArray(new Uint8Array([1, 2]), 7),\n);\n\nassertThrows(\n  \"`new BitArray()` throws with too few bytes for the bit size\",\n  () => new BitArray(new Uint8Array([1, 2]), 17),\n);\n\nassertThrows(\n  \"`new BitArray()` throws with an invalid bit offset\",\n  () => new BitArray(new Uint8Array([1]), 0, -1),\n);\n\nassertThrows(\n  \"`new BitArray()` throws with an invalid bit offset\",\n  () => new BitArray(new Uint8Array([1]), 0, 8),\n);\n\n// toBitArray()\n\nassertEqual(\n  new BitArray(new Uint8Array([1, 2])),\n  toBitArray([new BitArray(new Uint8Array([1, 2]))]),\n);\n\nassertEqual(new BitArray(new Uint8Array([])), toBitArray([]));\n\nconst testValues = [\n  { input: 0, u8: 0 },\n  { input: 1, u8: 1 },\n  { input: 127, u8: 127 },\n  { input: 128, u8: 128 },\n  { input: 129, u8: 129 },\n  { input: 255, u8: 255 },\n  { input: 256, u8: 0 },\n  { input: 257, u8: 1 },\n  { input: 2000, u8: 208 },\n  { input: 0, u8: 0 },\n  { input: -1, u8: 255 },\n  { input: -127, u8: 129 },\n  { input: -128, u8: 128 },\n  { input: -129, u8: 127 },\n  { input: -255, u8: 1 },\n  { input: -256, u8: 0 },\n  { input: -257, u8: 255 },\n  { input: -2000, u8: 48 },\n];\n\nfor (const { input, u8 } of testValues) {\n  assertEqual(new BitArray(new Uint8Array([u8])), toBitArray([input]));\n}\n\nassertEqual(new BitArray(new Uint8Array([])), toBitArray([new Uint8Array([])]));\nassertEqual(\n  new BitArray(new Uint8Array([1, 2, 4, 8])),\n  toBitArray([new Uint8Array([1, 2, 4, 8])]),\n);\n\nassertEqual(\n  new BitArray(new Uint8Array(testValues.map((t) => t.u8))),\n  toBitArray(testValues.map((t) => t.input)),\n);\n\nassertEqual(\n  new BitArray(\n    new Uint8Array([1, 2, 4, 8, ...testValues.map((t) => t.u8), 80, 90, 100]),\n  ),\n  toBitArray([\n    new Uint8Array([]),\n    new Uint8Array([1, 2, 4, 8]),\n    ...testValues.map((t) => t.input),\n    new Uint8Array([80, 90]),\n    new Uint8Array([]),\n    new Uint8Array([100]),\n  ]),\n);\n\nassertEqual(\n  new BitArray(new Uint8Array([97, 98, 99])),\n  toBitArray([stringBits(\"abc\")]),\n);\n\nassertEqual(\n  new BitArray(new Uint8Array([97])),\n  toBitArray([codepointBits(new UtfCodepoint(97))]),\n);\n\nassertEqual(\n  new BitArray(new Uint8Array([240, 159, 144, 141])),\n  toBitArray([codepointBits(new UtfCodepoint(128013))]),\n);\n\nassertEqual(\n  new BitArray(new Uint8Array([240, 159, 144, 141, 0xfe]), 39),\n  toBitArray([\n    new BitArray(new Uint8Array([240, 159, 144])),\n    new BitArray(new Uint8Array([141])),\n    new BitArray(new Uint8Array([0xfe]), 7),\n  ]),\n);\n\nassertEqual(\n  new BitArray(\n    new Uint8Array([240, 159, 144, 0xa9, 0b11101010, 0xf7, 0x39, 0xae]),\n    64,\n  ),\n  toBitArray([\n    new BitArray(new Uint8Array([240, 159, 144])),\n    new BitArray(new Uint8Array([0b10110101]), 4, 3),\n    new BitArray(new Uint8Array([0x9f]), 7),\n    new BitArray(new Uint8Array([0b00010100]), 4, 2),\n    new BitArray(new Uint8Array([0]), 1),\n    new BitArray(new Uint8Array([0xaf, 0x73, 0x9a, 0xee]), 24, 4),\n  ]),\n);\n\nassertEqual(\n  new BitArray(\n    new Uint8Array([\n      129, 145, 57, 255, 255, 255, 255, 255, 191, 157, 243, 182, 246, 62, 104,\n      49, 62, 31, 110, 200, 120, 13, 88,\n    ]),\n    181,\n  ),\n  toBitArray([\n    sizedInt(2, 2, false),\n    sizedInt(0, 2, false),\n    sizedInt(200, 11, true),\n    sizedInt(-100, 49, false),\n    sizedFloat(-1.234, 32, true),\n    sizedFloat(-8.2e40, 64, false),\n    sizedInt(0xf, 5, false),\n    new Uint8Array([1]),\n    0xab,\n  ]),\n);\n\n// BitArray.equals()\n\nassertEqual(new BitArray(new Uint8Array([])), new BitArray(new Uint8Array([])));\nassertEqual(\n  new BitArray(new Uint8Array([1, 2, 3])),\n  new BitArray(new Uint8Array([1, 2, 3])),\n);\nassertNotEqual(\n  new BitArray(new Uint8Array([1, 2])),\n  new BitArray(new Uint8Array([1, 2, 3])),\n);\nassertNotEqual(\n  new BitArray(new Uint8Array([1, 0xf0]), 12),\n  new BitArray(new Uint8Array([2, 0xf0]), 12),\n);\nassertNotEqual(\n  new BitArray(new Uint8Array([1, 0xf0]), 12),\n  new BitArray(new Uint8Array([1, 0xf0]), 13),\n);\nassertNotEqual(\n  new BitArray(new Uint8Array([0x12, 0x30]), 12),\n  new BitArray(new Uint8Array([0x12, 0x4f]), 12),\n);\nassertEqual(\n  new BitArray(new Uint8Array([0x12, 0x30]), 12),\n  new BitArray(new Uint8Array([0x12, 0x3f]), 12),\n);\nassertEqual(\n  new BitArray(new Uint8Array([0b10110110, 0b01101001]), 8, 3),\n  new BitArray(new Uint8Array([0b10110011]), 8),\n);\nassertEqual(\n  new BitArray(new Uint8Array([0b10110110, 0b01101001, 0b10011010]), 17, 5),\n  new BitArray(new Uint8Array([0b11001101, 0b00110011, 0b01000001]), 17),\n);\nassertEqual(\n  new BitArray(new Uint8Array([0b11001101, 0b00110011]), 14, 1),\n  new BitArray(new Uint8Array([0b11100110, 0b10011001]), 14, 2),\n);\nassertEqual(\n  new BitArray(new Uint8Array([0b10110110]), 4, 2),\n  new BitArray(new Uint8Array([0b10111011]), 4, 3),\n);\nassertNotEqual(\n  new BitArray(new Uint8Array([0b10110110, 0b10110110]), 9, 2),\n  new BitArray(new Uint8Array([0b10110111, 0b10100110]), 9, 2),\n);\nassertNotEqual(\n  new BitArray(new Uint8Array([0b10110110, 0b10110110]), 9, 2),\n  new BitArray(new Uint8Array([0b10110110, 0b10000110]), 9, 2),\n);\n\n// toList\n\nassertEqual(toList([]), List.fromArray([]));\nassertEqual(toList([1, 2, 3]), List.fromArray([1, 2, 3]));\nassertEqual(toList([1, 2], toList([3, 4])), List.fromArray([1, 2, 3, 4]));\nassertEqual(toList([1, 2, 3], toList([4, 5])), List.fromArray([1, 2, 3, 4, 5]));\n\n// Equality of JavaScript values\n\nassertEqual([], []);\nassertEqual([1, 2], [1, 2]);\nassertEqual([new Ok([1, 2])], [new Ok([1, 2])]);\nassertNotEqual([], [[]]);\nassertNotEqual([], [1, []]);\nassertNotEqual([1, []], []);\n\nassertEqual({}, {});\nassertEqual({ a: 1 }, { a: 1 });\nassertEqual({ a: 1, b: 2 }, { b: 2, a: 1 });\nassertEqual({ a: new Ok(1) }, { a: new Ok(1) });\nassertNotEqual({ a: new Ok(2) }, { a: new Ok(1) });\n\nassertEqual(new Date(0), new Date(0));\nassertNotEqual(new Date(1), new Date(0));\n\nassertEqual(new Uint8Array([1, 2]), new Uint8Array([1, 2]));\nassertEqual(new Uint16Array([1, 2]), new Uint16Array([1, 2]));\nassertEqual(new Uint32Array([1, 2]), new Uint32Array([1, 2]));\nassertNotEqual(new Uint8Array([1, 3]), new Uint8Array([1, 2]));\nassertNotEqual(new Uint16Array([1, 3]), new Uint16Array([1, 2]));\nassertNotEqual(new Uint32Array([1, 3]), new Uint32Array([1, 2]));\n\n// Promises are not equal unless they have reference equality\nlet promise = Promise.resolve(1);\nassertEqual(promise, promise);\nassertNotEqual(Promise.resolve(1), Promise.resolve(1));\n\n// Functions are not equal unless they have reference equality\nlet fun = () => 1;\nassertEqual(fun, fun);\nassertNotEqual(\n  () => 1,\n  () => 1,\n);\n\n// Maps are compared structurally\nlet map = new Map([[\"a\", 1]]);\nassertEqual(map, map);\nassertEqual(new Map([[\"a\", 1]]), new Map([[\"a\", 1]]));\nassertNotEqual(\n  new Map([\n    [\"a\", 1],\n    [\"b\", 2],\n  ]),\n  new Map([[\"a\", 1]]),\n);\nassertNotEqual(\n  new Map([[\"a\", 1]]),\n  new Map([\n    [\"a\", 1],\n    [\"b\", 2],\n  ]),\n);\nassertNotEqual(new Map([[\"a\", 1]]), new Map([[\"b\", 1]]));\nassertEqual(\n  new Map([[\"a\", new Map([[\"a\", []]])]]),\n  new Map([[\"a\", new Map([[\"a\", []]])]]),\n);\n\nassertNotEqual(new Map([]), new Map([[\"b\", 1]]));\n\n// Sets are compared structurally\nlet set = new Set([\"a\", 1]);\nassertEqual(set, set);\nassertEqual(new Set([\"a\", 1]), new Set([\"a\", 1]));\nassertNotEqual(new Set([\"a\", 1]), new Set([\"b\", 1]));\nassertNotEqual(new Set([\"a\", 1, \"b\"]), new Set([\"a\", 1]));\nassertNotEqual(new Set([\"a\", 1]), new Set([\"a\", 1, \"b\"]));\nassertNotEqual(\n  new Set([\"a\", new Map([[\"a\", []]])]),\n  new Set([\"a\", new Map([[\"a\", []]])]),\n);\n\n// WeakMaps are not equal unless they have reference equality\nlet weak_map = new WeakMap([[map, 1]]);\nassertEqual(weak_map, weak_map);\nassertNotEqual(new WeakMap([[map, 1]]), new WeakMap([[map, 1]]));\n\n// WeakSets are not equal unless they have reference equality\nlet weak_set = new WeakSet([map, set]);\nassertEqual(weak_set, weak_set);\nassertNotEqual(new WeakSet([map, set]), new WeakSet([map, set]));\n\n// RegExp are compared structurally\nlet re = new RegExp(\"test\", \"g\");\nlet re_literal = /test/g;\nassertEqual(re, re);\nassertEqual(re_literal, re_literal);\nassertEqual(re, re_literal);\nassertNotEqual(re, new RegExp(\"test\", \"i\"));\nassertNotEqual(re, new RegExp(\"test\"));\nassertNotEqual(re_literal, new RegExp(\"test\", \"i\"));\nassertNotEqual(re_literal, /test/);\nassertNotEqual(re_literal, new RegExp(\"test\", \"i\"));\nassertNotEqual(re, /test/i);\n\nclass ExampleA {\n  constructor(x) {\n    this.x = x;\n  }\n}\n\nclass ExampleB {\n  constructor(x) {\n    this.x = x;\n  }\n}\n\nassertEqual(new ExampleA(1), new ExampleA(1));\nassertEqual(new ExampleB(1), new ExampleB(1));\nassertNotEqual(new ExampleA(1), new ExampleA(2));\nassertNotEqual(new ExampleA(1), new ExampleB(1));\n\n// Custom .equals() method\nclass NoCustomEquals {\n  constructor(id, notImportant) {\n    this.id = id;\n    this.notImportant = notImportant;\n  }\n}\nclass HasCustomEqualsThatThrows {\n  constructor(id, notImportant) {\n    this.id = id;\n    this.notImportant = notImportant;\n  }\n  equals() {\n    throw \"not today\";\n  }\n}\nclass HasCustomEquals {\n  constructor(id, notImportant) {\n    this.id = id;\n    this.notImportant = notImportant;\n  }\n  equals(o) {\n    return this.id === o.id;\n  }\n}\nfunction testCustomEquals(o) {\n  this.id === o.id;\n}\nconst hasEqualsField = {\n  id: 1,\n  notImportant: 2,\n  equals: testCustomEquals,\n};\nconst hasEqualsField2 = {\n  id: 1,\n  notImportant: 3,\n  equals: testCustomEquals,\n};\n// no custom equals, use structural equality\nassertEqual(new NoCustomEquals(1, 1), new NoCustomEquals(1, 1));\nassertNotEqual(new NoCustomEquals(1, 1), new NoCustomEquals(1, 2));\n// custom equals throws, fallback to structural equality\nassertEqual(\n  new HasCustomEqualsThatThrows(1, 1),\n  new HasCustomEqualsThatThrows(1, 1),\n);\nassertNotEqual(\n  new HasCustomEqualsThatThrows(1, 1),\n  new HasCustomEqualsThatThrows(1, 2),\n);\n// custom equals works, use it\nassertEqual(new HasCustomEquals(1, 1), new HasCustomEquals(1, 1));\nassertEqual(new HasCustomEquals(1, 1), new HasCustomEquals(1, 2));\nassertNotEqual(new HasCustomEquals(1, 1), new HasCustomEquals(2, 1));\n// custom equals defined on object instead of prototype, don't use it\nassertEqual(hasEqualsField, { ...hasEqualsField });\nassertNotEqual(hasEqualsField, hasEqualsField2);\n\n// Objects\nassertEqual({ a: 1 }, { a: 1 });\nassertEqual({ a: 1, b: 2 }, { b: 2, a: 1 });\n\nassertEqual({ a: {} }, { a: {} });\nassertEqual({ a: 1, b: { c: 3 } }, { a: 1, b: { c: 3 } });\n\nassertNotEqual({ a: 1 }, {});\nassertNotEqual({ a: 1, b: 2 }, { b: 2 });\nassertNotEqual({}, { a: 1 });\nassertNotEqual({ b: 2 }, { a: 1, b: 2 });\n\n// BitArray\n\nassertEqual(new BitArray(new Uint8Array([1, 2, 3])).byteAt(0), 1);\nassertEqual(new BitArray(new Uint8Array([1, 2, 3])).byteAt(2), 3);\n\n// bitArraySlice\n\nassertThrows(\"`bitArraySlice()` throws if start is less than zero\", () =>\n  bitArraySlice(new BitArray(new Uint8Array([1])), -1, 8),\n);\n\nassertThrows(\n  \"`bitArraySlice()` throws if start is greater than the bit size\",\n  () => bitArraySlice(new BitArray(new Uint8Array([1])), 9, 8),\n);\n\nassertThrows(\"`bitArraySlice()` throws if end is before start\", () =>\n  bitArraySlice(new BitArray(new Uint8Array([1])), 4, 2),\n);\n\nassertThrows(\n  \"`bitArraySlice()` throws if end is greater than the bit size\",\n  () => bitArraySlice(new Uint8Array([1]), 0, 10),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([1, 2, 3])), 0, 0),\n  new BitArray(new Uint8Array([])),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([0xbe, 0xff])), 0, 2),\n  new BitArray(new Uint8Array([0xbe]), 2),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([0x12, 0b10101101, 0xff])), 10, 14),\n  new BitArray(new Uint8Array([0b10110100]), 4),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([1, 2, 3])), 8, 24),\n  new BitArray(new Uint8Array([2, 3])),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([1, 2, 3, 4, 5])), 8, 32),\n  new BitArray(new Uint8Array([2, 3, 4])),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([1, 0xfe, 0xa1])), 8, 19),\n  new BitArray(new Uint8Array([0xfe, 0xa1]), 11),\n);\n\nassertEqual(\n  bitArraySlice(\n    new BitArray(new Uint8Array([17, 79, 190, 151, 98, 222, 101])),\n    19,\n    51,\n  ),\n  new BitArray(new Uint8Array([244, 187, 22, 243]), 32),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([0, 0, 0, 0, 0xff, 0xe0])), 37, 41),\n  new BitArray(new Uint8Array([0b11111100]), 4),\n);\n\nassertEqual(\n  bitArraySliceToFloat(\n    bitArraySlice(\n      new BitArray(new Uint8Array([0xaa, 0xbb, 0xff, 0, 0, 0])),\n      8,\n      48,\n    ),\n    8,\n    40,\n    false,\n  ),\n  3.5733110840282835e-43,\n);\n\nassertEqual(\n  bitArraySlice(\n    bitArraySlice(new BitArray(new Uint8Array([1, 2, 3, 4, 5])), 8, 32),\n    8,\n  ),\n  new BitArray(new Uint8Array([3, 4])),\n);\n\nassertEqual(\n  bitArraySlice(\n    new BitArray(new Uint8Array([0b00000001, 0b00000010, 0b00000011]), 20, 2),\n    4,\n    10,\n  ),\n  new BitArray(new Uint8Array([0b00000001, 0b00000010]), 6, 6),\n);\n\nassertEqual(\n  bitArraySlice(new BitArray(new Uint8Array([1])), 1),\n  new BitArray(new Uint8Array([0b00000010]), 7),\n);\n\n// sizedFloat()\n\nassertEqual(sizedFloat(0.0, 16, true), new Uint8Array([0x00, 0x00]));\nassertEqual(sizedFloat(1.0, 16, true), new Uint8Array([0x3c, 0x00]));\nassertEqual(sizedFloat(-1.0, 16, false), new Uint8Array([0x00, 0xbc]));\nassertEqual(sizedFloat(1.234375, 16, true), new Uint8Array([0x3c, 0xf0]));\nassertEqual(sizedFloat(-65_504.0, 16, false), new Uint8Array([0xff, 0xfb]));\nassertEqual(\n  sizedFloat(-0.00001519918441772461, 16, true),\n  new Uint8Array([0x80, 0xff]),\n);\nassertEqual(sizedFloat(Infinity, 16, true), new Uint8Array([0x7c, 0x00]));\nassertEqual(sizedFloat(-Infinity, 16, false), new Uint8Array([0x00, 0xfc]));\nassertEqual(sizedFloat(NaN, 16, true), new Uint8Array([0x7e, 0x00]));\nassertEqual(sizedFloat(1_000_000.0, 16, true), new Uint8Array([0x7c, 0x00]));\nassertEqual(sizedFloat(-1_000_000.0, 16, true), new Uint8Array([0xfc, 0x00]));\n\nassertEqual(sizedFloat(16.25, 32, true), new Uint8Array([65, 130, 0, 0]));\nassertEqual(sizedFloat(-16.25, 32, false), new Uint8Array([0, 0, 130, 193]));\nassertEqual(\n  sizedFloat(1000.5, 64, true),\n  new Uint8Array([64, 143, 68, 0, 0, 0, 0, 0]),\n);\nassertEqual(\n  sizedFloat(-1000.5, 64, false),\n  new Uint8Array([0, 0, 0, 0, 0, 68, 143, 192]),\n);\n\n// sizedInt()\n\nassertEqual(sizedInt(100, -8, true), new Uint8Array([]));\nassertEqual(sizedInt(100, 0, true), new Uint8Array([]));\nassertEqual(sizedInt(100, 8, true), new Uint8Array([100]));\nassertEqual(sizedInt(-10, 8, true), new Uint8Array([246]));\n\nassertEqual(sizedInt(1, 1, true), new BitArray(new Uint8Array([0x80]), 1));\nassertEqual(sizedInt(2, 2, true), new BitArray(new Uint8Array([0x80]), 2));\nassertEqual(sizedInt(15, 4, true), new BitArray(new Uint8Array([0xf0]), 4));\nassertEqual(sizedInt(100, 7, true), new BitArray(new Uint8Array([200]), 7));\nassertEqual(sizedInt(-44, 7, true), new BitArray(new Uint8Array([168]), 7));\nassertEqual(sizedInt(-1, 6, true), new BitArray(new Uint8Array([252]), 6));\nassertEqual(sizedInt(-1231, 3, true), new BitArray(new Uint8Array([32]), 3));\nassertEqual(sizedInt(1231, 5, true), new BitArray(new Uint8Array([120]), 5));\n\nassertEqual(\n  sizedInt(773, 10, true),\n  new BitArray(new Uint8Array([193, 64]), 10),\n);\nassertEqual(\n  sizedInt(-276, 10, false),\n  new BitArray(new Uint8Array([236, 128]), 10),\n);\nassertEqual(sizedInt(80000, 16, true), new Uint8Array([56, 128]));\nassertEqual(sizedInt(-80000, 16, true), new Uint8Array([199, 128]));\nassertEqual(sizedInt(1, 24, true), new Uint8Array([0, 0, 1]));\nassertEqual(\n  sizedInt(-100, 31, false),\n  new BitArray(new Uint8Array([156, 255, 255, 254]), 31),\n);\nassertEqual(sizedInt(0, 32, true), new Uint8Array([0, 0, 0, 0]));\nassertEqual(sizedInt(-1, 32, true), new Uint8Array([255, 255, 255, 255]));\nassertEqual(\n  sizedInt(-10, 33, true),\n  new BitArray(new Uint8Array([255, 255, 255, 251, 0]), 33),\n);\nassertEqual(\n  sizedInt(-489_391_639_457_909_760, 56, true),\n  new Uint8Array([53, 84, 229, 150, 16, 180, 0]),\n);\nassertEqual(\n  sizedInt(-1, 64, true),\n  new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255]),\n);\nassertEqual(\n  sizedInt(Number.MAX_SAFE_INTEGER, 64, true),\n  new Uint8Array([0, 31, 255, 255, 255, 255, 255, 255]),\n);\nassertEqual(\n  sizedInt(Number.MIN_SAFE_INTEGER, 64, true),\n  new Uint8Array([255, 224, 0, 0, 0, 0, 0, 1]),\n);\nassertEqual(\n  sizedInt(Number.MAX_SAFE_INTEGER, 77, true),\n  new BitArray(\n    new Uint8Array([0, 0, 0, 255, 255, 255, 255, 255, 255, 248]),\n    77,\n  ),\n);\nassertEqual(\n  sizedInt(Number.MIN_SAFE_INTEGER, 75, false),\n  new BitArray(new Uint8Array([1, 0, 0, 0, 0, 0, 224, 255, 255, 224]), 75),\n);\nassertEqual(\n  sizedInt(Number(9444732965739289353650176n), 75, true),\n  new BitArray(new Uint8Array([255, 255, 255, 255, 255, 248, 0, 0, 0, 0]), 75),\n);\n\n// bitArraySliceToFloat()\n\nassertEqual(\n  bitArraySliceToFloat(toBitArray([63, 240, 0, 0, 0, 0, 0, 0]), 0, 64, true),\n  1.0,\n);\nassertEqual(\n  bitArraySliceToFloat(toBitArray([0, 0, 0, 0, 0, 0, 240, 63]), 0, 64, false),\n  1.0,\n);\nassertEqual(\n  bitArraySliceToFloat(toBitArray([0xff, 0xc9, 0x74, 0x24, 0x00]), 8, 40, true),\n  -1000000.0,\n);\nassertEqual(\n  bitArraySliceToFloat(toBitArray([0x00, 0x24, 0x74, 0xc9]), 0, 32, false),\n  -1000000.0,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(new Uint8Array([112, 152, 127, 244, 0, 7, 192]), 50, 0),\n    11,\n    43,\n    true,\n  ),\n  -511.25,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(\n      new Uint8Array([8, 0, 0, 0, 1, 129, 39, 103, 129, 254]),\n      79,\n      0,\n    ),\n    7,\n    71,\n    false,\n  ),\n  -5011.75,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(new Uint8Array([212, 152, 127, 244, 0, 7, 192]), 50, 3),\n    11,\n    43,\n    true,\n  ),\n  1.0714967429001753e-19,\n);\n\nassertEqual(\n  bitArraySliceToFloat(new BitArray(new Uint8Array([0x00, 0x00])), 0, 16, true),\n  0.0,\n);\nassertEqual(\n  bitArraySliceToFloat(new BitArray(new Uint8Array([0x3c, 0x00])), 0, 16, true),\n  1.0,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(new Uint8Array([0x00, 0xbc])),\n    0,\n    16,\n    false,\n  ),\n  -1.0,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(new Uint8Array([0xf0, 0x3c])),\n    0,\n    16,\n    false,\n  ),\n  1.234375,\n);\nassertEqual(\n  bitArraySliceToFloat(new BitArray(new Uint8Array([0xfb, 0xff])), 0, 16, true),\n  -65_504.0,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(new Uint8Array([0xff, 0x80])),\n    0,\n    16,\n    false,\n  ),\n  -0.00001519918441772461,\n);\nassertEqual(\n  bitArraySliceToFloat(new BitArray(new Uint8Array([0x7c, 0x00])), 0, 16, true),\n  Infinity,\n);\nassertEqual(\n  bitArraySliceToFloat(\n    new BitArray(new Uint8Array([0x00, 0xfc])),\n    0,\n    16,\n    false,\n  ),\n  -Infinity,\n);\nassertEqual(\n  isNaN(\n    bitArraySliceToFloat(\n      new BitArray(new Uint8Array([0x7e, 0x00])),\n      0,\n      16,\n      true,\n    ),\n  ),\n  true,\n);\n\n// bitArraySliceToInt()\n\nassertEqual(\n  bitArraySliceToInt(toBitArray([0b10011110]), 0, 4, true, false),\n  0b1001,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([0b11001110]), 7, 1),\n    0,\n    4,\n    true,\n    false,\n  ),\n  0b1001,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0b10011110]), 4, 8, true, false),\n  0b1110,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0b10011110]), 1, 6, true, true),\n  0b00111,\n);\nassertEqual(bitArraySliceToInt(toBitArray([0b10011010]), 3, 8, true, true), -6);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0b10011010]), 0, 7, true, true),\n  -51,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([0b11001100, 0b00100000]), 11),\n    1,\n    11,\n    false,\n    false,\n  ),\n  408,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xb6, 0xe3]), 0, 12, true, false),\n  0xb6e,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xb6, 0xe3]), 0, 12, false, false),\n  0xeb6,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xff, 0xb6, 0xe3]), 8, 20, true, false),\n  0xb6e,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xff, 0xb6, 0xe3]), 20, 24, true, false),\n  0x03,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xff, 0xb6, 0xe3]), 8, 20, false, false),\n  0xeb6,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xa5, 0x6c, 0xaa]), 5, 18, true, false),\n  5554,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xa5, 0x6c, 0xaa]), 5, 18, false, true),\n  -3411,\n);\nassertEqual(bitArraySliceToInt(toBitArray([1, 2, 3]), 0, 8, true, false), 1);\nassertEqual(\n  bitArraySliceToInt(toBitArray([160, 2, 3]), 0, 8, false, true),\n  -96,\n);\nassertEqual(bitArraySliceToInt(toBitArray([1, 2, 3]), 0, 16, true, false), 258);\nassertEqual(\n  bitArraySliceToInt(toBitArray([1, 2, 3]), 0, 16, false, false),\n  513,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([1, 160, 3]), 0, 16, false, true),\n  -24575,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([160, 2, 3]), 0, 16, true, false),\n  40962,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([3, 160, 2]), 8, 24, true, true),\n  -24574,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([146, 192, 70, 25, 128]), 33),\n    1,\n    24,\n    true,\n    true,\n  ),\n  1_228_870,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([255, 255, 255, 255]), 0, 32, false, true),\n  -1,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([217, 150, 209, 191, 0]), 33),\n    1,\n    33,\n    true,\n    false,\n  ),\n  3_006_112_638,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([146, 192, 70, 25, 128]), 33),\n    1,\n    33,\n    true,\n    true,\n  ),\n  629_181_491,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([251, 24, 47, 227, 128]), 33),\n    1,\n    33,\n    false,\n    false,\n  ),\n  3_344_904_438,\n);\nassertEqual(\n  bitArraySliceToInt(\n    new BitArray(new Uint8Array([240, 102, 91, 101, 128]), 33),\n    0,\n    33,\n    false,\n    false,\n  ),\n  5_995_456_240,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([231, 255, 255, 255, 254, 123]),\n    0,\n    40,\n    true,\n    true,\n  ),\n  -103_079_215_106,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([0, 231, 255, 255, 253, 123, 17]),\n    1,\n    55,\n    true,\n    false,\n  ),\n  127_543_348_739_464,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([142, 231, 255, 255, 253, 123, 17, 139]),\n    8,\n    62,\n    false,\n    true,\n  ),\n  -8425025061257241,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([142, 231, 255, 255, 253, 123, 17, 139]),\n    7,\n    62,\n    false,\n    true,\n  ),\n  -8293899692933261,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([142, 231, 255, 255, 253, 123, 17]),\n    8,\n    48,\n    true,\n    true,\n  ),\n  -103_079_215_749,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([255, 255, 255, 255, 255, 255, 255]),\n    0,\n    56,\n    true,\n    true,\n  ),\n  -1,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([0x00, 0xaa, 255, 255, 255, 255, 255]),\n    0,\n    56,\n    true,\n    false,\n  ),\n  0xaaffffffffff,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([255, 255, 255, 255, 255, 0xaa, 0x00]),\n    0,\n    56,\n    false,\n    false,\n  ),\n  0xaaffffffffff,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([255, 255, 255, 255, 255, 255, 255]),\n    0,\n    56,\n    true,\n    false,\n  ),\n  Number(0xfffffffffffffen),\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([0xfe, 0x3f]), 4, 12, true, false),\n  0xe3,\n);\nassertEqual(bitArraySliceToInt(toBitArray([253, 94]), 3, 11, true, true), -22);\nassertEqual(\n  bitArraySliceToInt(toBitArray([233, 164]), 3, 15, true, false),\n  1234,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([250, 72]), 3, 15, false, false),\n  1234,\n);\nassertEqual(\n  bitArraySliceToInt(toBitArray([250, 72, 223, 189]), 7, 29, true, false),\n  596983,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([250, 72, 223, 189, 41, 97, 165, 0, 0, 0, 0, 177]),\n    14,\n    85,\n    false,\n    true,\n  ),\n  70821197049655,\n);\nassertEqual(\n  bitArraySliceToInt(\n    toBitArray([250, 72, 223, 189, 41, 97, 165, 0, 0, 0, 0, 177]),\n    14,\n    85,\n    true,\n    true,\n  ),\n  Number(515_906_807_693_217_628_160n),\n);\n\n// Result.isOk\n\nassertEqual(new Ok(1).isOk(), true);\nassertEqual(new Error(1).isOk(), false);\n\n// List.atLeastLength\n\nassertEqual(List.fromArray([]).atLeastLength(0), true);\nassertEqual(List.fromArray([]).atLeastLength(1), false);\nassertEqual(List.fromArray([]).atLeastLength(-1), true);\nassertEqual(List.fromArray([1]).atLeastLength(0), true);\nassertEqual(List.fromArray([1]).atLeastLength(1), true);\nassertEqual(List.fromArray([1]).atLeastLength(2), false);\nassertEqual(List.fromArray([1]).atLeastLength(-1), true);\n\n// List.hasLength\n\nassertEqual(toList([]).hasLength(0), true);\nassertEqual(toList([]).hasLength(1), false);\nassertEqual(toList([]).hasLength(-1), false);\nassertEqual(toList([1]).hasLength(0), false);\nassertEqual(toList([1]).hasLength(1), true);\nassertEqual(toList([1]).hasLength(2), false);\nassertEqual(toList([1, 1]).hasLength(1), false);\nassertEqual(toList([1, 1]).hasLength(2), true);\nassertEqual(toList([1, 1]).hasLength(3), false);\n\n// List iterable interface\n\nassertEqual([...toList([])], []);\nassertEqual([...toList([1, 2, 3])], [1, 2, 3]);\n\n// BitArray.byteSize\n\nassertEqual(new BitArray(new Uint8Array([])).byteSize, 0);\nassertEqual(new BitArray(new Uint8Array([1, 2])).byteSize, 2);\nassertEqual(new BitArray(new Uint8Array([1, 2, 3, 4])).byteSize, 4);\nassertEqual(new BitArray(new Uint8Array([1, 2, 3, 4], 28)).byteSize, 4);\n\n// BitArray\n\nassert(\"numbers are not bit arrays\", !BitArray$isBitArray(123));\nassert(\"strings are not bit arrays\", !BitArray$isBitArray(\"!\"));\nassert(\"results are not bit arrays\", new Ok(\"!\"));\nassert(\n  \"Bit arrays are bit arrays\",\n  BitArray$isBitArray(BitArray$BitArray(new Uint8Array([]))),\n);\n\n// Byte aligned bit array\n{\n  const bitArray = BitArray$BitArray(new Uint8Array([1, 2, 3]));\n  assertEqual(bitArray.bitSize, 3 * 8);\n  assertEqual(bitArray.byteSize, 3);\n  assertEqual(bitArray.bitOffset, 0);\n  assertEqual(bitArray.rawBuffer, new Uint8Array([1, 2, 3]));\n  assertEqual(\n    BitArray$BitArray$data(bitArray),\n    new DataView(new Uint8Array([1, 2, 3]).buffer),\n  );\n}\n\n// Non-byte aligned bit array\n{\n  const bitArray = BitArray$BitArray(new Uint8Array([1, 2, 3]), 23, 1);\n  assertEqual(bitArray.bitSize, 23);\n  assertEqual(bitArray.byteSize, 3);\n  assertEqual(bitArray.bitOffset, 1);\n  assertEqual(bitArray.rawBuffer, new Uint8Array([1, 2, 3]));\n  assertThrows(\"BitArray$BitArray$data of un-aligned bit array\", () => {\n    BitArray$BitArray$data(bitArray);\n  });\n}\n\nassertEqual(\n  BitArray$BitArray(new Uint8Array([])),\n  new BitArray(new Uint8Array([])),\n);\n\n//\n// Division\n//\n\nassertEqual(divideInt(1, 0), 0);\nassertEqual(divideInt(1, 1), 1);\nassertEqual(divideInt(1, 2), 0);\nassertEqual(divideInt(3, 2), 1);\nassertEqual(divideInt(11, 3), 3);\nassertEqual(divideInt(-1, 0), 0);\nassertEqual(divideInt(-1, 1), -1);\nassertEqual(divideInt(-1, 2), -0);\nassertEqual(divideInt(-3, 2), -1);\nassertEqual(divideInt(-11, 3), -3);\nassertEqual(divideInt(1, -1), -1);\nassertEqual(divideInt(1, -2), 0);\nassertEqual(divideInt(3, -2), -1);\nassertEqual(divideInt(11, -3), -3);\nassertEqual(divideInt(-1, -1), 1);\nassertEqual(divideInt(-1, -2), 0);\nassertEqual(divideInt(-3, -2), 1);\nassertEqual(divideInt(-11, -3), 3);\n\nassertEqual(divideFloat(1.5, 0.0), 0.0);\nassertEqual(divideFloat(1.5, 2.0), 0.75);\nassertEqual(divideFloat(1.5, 2.5), 0.6);\nassertEqual(divideFloat(-1.5, 0.0), -0.0);\nassertEqual(divideFloat(-1.5, 2.0), -0.75);\nassertEqual(divideFloat(-1.5, 2.5), -0.6);\nassertEqual(divideFloat(1.5, -0.0), -0.0);\nassertEqual(divideFloat(1.5, -2.0), -0.75);\nassertEqual(divideFloat(1.5, -2.5), -0.6);\nassertEqual(divideFloat(-1.5, -0.0), 0.0);\nassertEqual(divideFloat(-1.5, -2.0), 0.75);\nassertEqual(divideFloat(-1.5, -2.5), 0.6);\n\n// Record updates\n\nassertEqual(new Ok(1).withFields({ 0: 2 }), new Ok(2));\nassertEqual(new Error(1).withFields({ 0: 2 }), new Error(2));\n\nassertEqual(\n  new ExampleRecordImpl(1, 2, 3).withFields({}),\n  new ExampleRecordImpl(1, 2, 3),\n);\nassertEqual(\n  new ExampleRecordImpl(1, 2, 3).withFields({ boop: 6, 0: 40 }),\n  new ExampleRecordImpl(40, 2, 6),\n);\nassertEqual(\n  new ExampleRecordImpl(1, 2, 3).withFields({ boop: 4, detail: 5, 0: 6 }),\n  new ExampleRecordImpl(6, 5, 4),\n);\n\n//\n// Summary\n//\n\nconsole.log(`\n\n${passes + failures} tests\n${passes} passes\n${failures} failures\n`);\n\nif (failures) process.exit(1);\n"
  },
  {
    "path": "test/language/.gitignore",
    "content": "build\n"
  },
  {
    "path": "test/language/Makefile",
    "content": ".PHONY: build\nbuild: clean erlang nodejs deno\n\n.PHONY: clean\nclean:\n\trm -rf build\n\n.PHONY: erlang\nerlang:\n\t@echo test/language on Erlang\n\tcargo run --quiet -- test --target erlang\n\n.PHONY: nodejs\nnodejs:\n\t@echo test/language on JavaScript with Node\n\tcargo run --quiet -- test --target javascript --runtime nodejs\n\n.PHONY: deno\ndeno:\n\t@echo test/language on JavaScript with Deno\n\tcargo run --quiet -- test --target javascript --runtime deno\n\n.PHONY: bun\nbun:\n\t@echo test/language on JavaScript with Bun\n\tcargo run --quiet -- test --target javascript --runtime bun\n"
  },
  {
    "path": "test/language/gleam.toml",
    "content": "name = \"language\"\nversion = \"1.0.0\"\n\n[dev_dependencies]\ngleeunit = \">= 1.9.0 and < 2.0.0\"\n\n[javascript.deno]\nallow_read = [\n  \"./build\",\n  \"gleam.toml\",\n  \"test\"\n]\n"
  },
  {
    "path": "test/language/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.68.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"F7FAEBD8EF260664E86A46C8DBA23508D1D11BB3BCC6EE1B89B3BC3E5C83FF1E\" },\n  { name = \"gleeunit\", version = \"1.9.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C\" },\n]\n\n[requirements]\ngleeunit = { version = \">= 1.9.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/language/src/language.gleam",
    "content": "pub fn main() {\n  Nil\n}\n"
  },
  {
    "path": "test/language/test/ffi.gleam",
    "content": "pub type Dynamic\n\n@external(erlang, \"ffi_erlang\", \"print\")\n@external(javascript, \"./ffi_javascript.mjs\", \"print\")\npub fn print(a: String) -> Nil\n\n@external(erlang, \"ffi_erlang\", \"append\")\n@external(javascript, \"./ffi_javascript.mjs\", \"append\")\npub fn append(a: String, b: String) -> String\n\n@external(erlang, \"ffi_erlang\", \"to_string\")\n@external(javascript, \"./ffi_javascript.mjs\", \"toString\")\npub fn to_string(a: anything) -> String\n\n@external(erlang, \"ffi_erlang\", \"file_exists\")\n@external(javascript, \"./ffi_javascript.mjs\", \"fileExists\")\npub fn file_exists(a: String) -> Bool\n\n@external(erlang, \"ffi_erlang\", \"halt\")\n@external(javascript, \"./ffi_javascript.mjs\", \"halt\")\npub fn halt(a: Int) -> Nil\n\n@external(erlang, \"ffi_erlang\", \"to_dynamic\")\n@external(javascript, \"./ffi_javascript.mjs\", \"toDynamic\")\npub fn to_dynamic(a: x) -> Dynamic\n\n@external(erlang, \"ffi_erlang\", \"to_codepoint\")\n@external(javascript, \"./ffi_javascript.mjs\", \"toCodepoint\")\npub fn utf_codepoint(a: Int) -> UtfCodepoint\n\n@external(erlang, \"ffi_erlang\", \"read_uint16_from_bit_array\")\n@external(javascript, \"./ffi_javascript.mjs\", \"readUint16FromBitArray\")\npub fn read_uint16_from_bit_array(a: BitArray) -> Int\n"
  },
  {
    "path": "test/language/test/ffi_erlang.erl",
    "content": "-module(ffi_erlang).\n\n-export([\n    to_string/1, append/2, print/1, file_exists/1, halt/1, to_dynamic/1, to_codepoint/1,\n    read_uint16_from_bit_array/1\n]).\n\nappend(A, B) ->\n    <<A/binary, B/binary>>.\n\nprint(S) ->\n    io:format(\"~s\", [S]),\n    nil.\n\nto_string(Term) ->\n    List = io_lib:format(\"~p\", [Term]),\n    iolist_to_binary(List).\n\nfile_exists(Path) ->\n    filelib:is_regular(Path).\n\nhalt(Code) ->\n    erlang:halt(Code).\n\nto_dynamic(X) ->\n    X.\n\nto_codepoint(X) -> X.\n\nread_uint16_from_bit_array(BitArray) ->\n    <<Value:16/big-unsigned-integer, _/binary>> = BitArray,\n    Value.\n"
  },
  {
    "path": "test/language/test/ffi_javascript.mjs",
    "content": "import { UtfCodepoint, BitArray$BitArray$data } from \"./gleam.mjs\";\n\nlet fs;\n\nif (!globalThis.Deno) {\n  fs = await import(\"fs\");\n}\n\nexport function append(a, b) {\n  return a + b;\n}\n\nexport function print(string) {\n  if (globalThis.Deno) {\n    globalThis.Deno.stdout.writeSync(new TextEncoder().encode(string));\n  } else {\n    process.stdout.write(string);\n  }\n  return string;\n}\n\nexport function toString(a) {\n  let sanitise = (_k, v) => (typeof v === \"bigint\" ? `${v}n` : v);\n  try {\n    return JSON.stringify(a, sanitise);\n  } catch (_error) {\n    return \"//<unprintable-cyclical-data>\";\n  }\n}\n\nexport function fileExists(path) {\n  if (globalThis.Deno) {\n    try {\n      Deno.statSync(path);\n      return true;\n    } catch {\n      return false;\n    }\n  } else {\n    return fs.existsSync(path);\n  }\n}\n\nexport function halt(code) {\n  if (globalThis.Deno) {\n    Deno.exit(code);\n  } else {\n    process.exit(code);\n  }\n}\n\nexport function toDynamic(a) {\n  return a;\n}\n\nexport function toCodepoint(x) {\n  return new UtfCodepoint(x);\n}\n\nexport function readUint16FromBitArray(bitArray) {\n  return BitArray$BitArray$data(bitArray).getUint16(0);\n}\n"
  },
  {
    "path": "test/language/test/ffi_typescript.ts",
    "content": "export function append(a: string, b: string) {\n  return a + b;\n}\n"
  },
  {
    "path": "test/language/test/importable.gleam",
    "content": "pub type NoFields {\n  NoFields\n}\n\n/// This function has argument names that are not valid in Erlang or JavaScript\npub fn bad_argument_names(in, class, receive) {\n  #(in, class, receive)\n}\n\n/// This custom type has label names that are not valid in Erlang or JavaScript\npub type BadLabelNames {\n  BadLabelNames(in: String, class: String, receive: String)\n}\n\npub const ints_in_bit_array = <<1, 2, 3>>\n\npub const string_in_bit_array = <<\"Gleam\":utf8>>\n\npub const data = <<\n  0x1,\n  2,\n  2:size(16),\n  0x4:size(32),\n  \"Gleam\":utf8,\n  4.2:float,\n  <<<<1, 2, 3>>:bits, \"Gleam\":utf8, 1024>>:bits,\n>>\n\npub fn get_bit_array() {\n  <<\n    0x1,\n    2,\n    2:size(16),\n    0x4:size(32),\n    \"Gleam\":utf8,\n    4.2:float,\n    <<<<1, 2, 3>>:bits, \"Gleam\":utf8, 1024>>:bits,\n  >>\n}\n\npub const language = \"gleam\"\n\npub type Movie {\n  Movie(title: String)\n}\n\npub const war_games = Movie(\"WarGames\")\n"
  },
  {
    "path": "test/language/test/language/alternative_pattern.gleam",
    "content": "fn make_int_zero() {\n  0\n}\n\npub fn numbers_test() {\n  let int = 4\n  let int_2 = case int {\n    1 | 2 | 3 | 4 -> 0\n    _ -> 1\n  }\n  assert 0 == int_2\n}\n\npub fn lists_test() {\n  let ints = [1, 2]\n  let int = case ints {\n    [0] | [1, 2] -> 0\n    _ -> 1\n  }\n  assert 0 == int\n}\n\npub fn assignment_test() {\n  let ints = [1, 2]\n  let int = case ints {\n    [x] | [_, x] -> x\n    _ -> 0\n  }\n  assert 2 == int\n}\n\npub fn multiple_assignment_test() {\n  let ints = [1, 2, 3]\n  let value = case ints {\n    [x, y] | [x, y, 3] -> #(x, y)\n    _ -> #(0, 0)\n  }\n  assert #(1, 2) == value\n}\n\npub fn guard_test() {\n  let int_two = make_int_zero() + 2\n  let ints = [1, 2]\n  let int = case ints {\n    [x] | [_, x] if x == int_two -> x\n    _ -> 0\n  }\n  assert 2 == int\n}\n\npub fn guard_left_hand_side_test() {\n  let int_one = make_int_zero() + 1\n  let ints = [1]\n  let int = case ints {\n    [x] | [_, x] if x == int_one -> x\n    _ -> 0\n  }\n  assert 1 == int\n}\n"
  },
  {
    "path": "test/language/test/language/anonymous_function_test.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/1637\npub fn anonymous_function_test() {\n  let f = fn(x) {\n    let x = x\n    x\n  }\n  assert 1 == f(1)\n}\n\npub fn immutable_scope_test() {\n  let x = 1\n  let f = fn() { x }\n  let x = 2\n  assert f() == 1\n  assert x == 2\n}\n\ntype FnBox {\n  FnBox(f: fn(Int) -> Int)\n}\n\npub fn call_record_access_test() {\n  let b = FnBox(f: fn(x) { x })\n  assert b.f(5) == 5\n}\n\npub fn call_tuple_access_test() {\n  let t = #(fn(x) { x })\n  assert t.0(5) == 5\n}\n"
  },
  {
    "path": "test/language/test/language/assertion_test.gleam",
    "content": "pub fn let_assert_ok_discard_test() {\n  let result = {\n    let x = ok_one()\n    let assert Ok(_) = x\n  }\n  assert Ok(1) == result\n}\n\npub fn let_assert_ok_bind_test() {\n  let x = ok_one()\n  let assert Ok(x) = x\n  assert 1 == x\n}\n\nfn ok_one() -> Result(Int, a) {\n  Ok(1)\n}\n"
  },
  {
    "path": "test/language/test/language/bit_array_dynamic_size_test.gleam",
    "content": "pub fn dynamic_size_1_test() {\n  let size = 8\n  let assert <<value:size(size)>> = <<42>>\n  assert value == 42\n}\n\npub fn dynamic_size_2_test() {\n  let size = 3\n  let other_size = 5\n  let third_size = 8\n  let assert <<\n    value:size(size),\n    second:size(other_size),\n    last:size(third_size),\n  >> = <<5:3, 8:5, 128>>\n  assert #(value, second, last) == #(5, 8, 128)\n}\n\npub fn dynamic_size_3_test() {\n  let size = 2\n  let assert <<first_bytes:bytes-size(size), _rest:bytes>> = <<1, 2, 3, 4>>\n  assert first_bytes == <<1, 2>>\n}\n\npub fn dynamic_size_4_test() {\n  let size = 6\n  let assert <<bits:bits-size(size), _rest:bits>> = <<0b10010100, 6, 2938>>\n  assert bits == <<0b100101:6>>\n}\n\npub fn dynamic_size_5_test() {\n  let size = 7\n  let assert <<123:size(size)>> = <<123:7>>\n}\n\npub fn dynamic_size_6_test() {\n  let size = 4\n  let size = size + 2\n  let assert <<value:size(size)>> = <<61:6>>\n  assert value == 61\n}\n"
  },
  {
    "path": "test/language/test/language/bit_array_match_test.gleam",
    "content": "import importable\n\npub fn match_1_test() {\n  let assert <<1, x>> = <<1, 2>>\n  assert x == 2\n}\n\npub fn match_2_test() {\n  let assert <<a:8>> = <<1>>\n  assert a == 1\n}\n\npub fn match_3_test() {\n  let assert <<a:16, b:8>> = <<1, 2, 3>>\n  assert #(a, b) == #(258, 3)\n}\n\npub fn match_4_test() {\n  let assert <<a:int-32-little-signed, b:signed-big-24>> = <<\n    255, 255, 255, 255, 255, 216, 240,\n  >>\n  assert #(a, b) == #(-1, -10_000)\n}\n\npub fn match_5_test() {\n  let assert <<a:16-unsigned, b:40-signed-little>> = <<\n    255, 255, 255, 255, 240, 216, 255,\n  >>\n  assert #(a, b) == #(65_535, -655_294_465)\n}\n\npub fn match_6_test() {\n  let assert <<a:64-signed>> = <<255, 255, 255, 255, 255, 255, 255, 255>>\n  assert a == -1\n}\n\npub fn match_7_test() {\n  let assert <<a:56-big-unsigned>> = <<0x00, 0xaa, 255, 255, 255, 255, 255>>\n  assert a == 0xaaffffffffff\n}\n\npub fn match_8_test() {\n  let assert <<a:56-little-unsigned>> = <<255, 255, 255, 255, 255, 0xaa, 0x00>>\n  assert a == 0xaaffffffffff\n}\n\npub fn match_9_test() {\n  let assert <<a:float, b:int>> = <<63, 240, 0, 0, 0, 0, 0, 0, 1>>\n  assert #(a, b) == #(1.0, 1)\n}\n\npub fn match_10_test() {\n  let assert <<a:float>> = <<1.23:float>>\n  assert a == 1.23\n}\n\npub fn match_11_test() {\n  let assert <<a:float-32>> = <<63, 176, 0, 0>>\n  assert a == 1.375\n}\n\npub fn match_12_test() {\n  let assert <<a:64-float-little>> = <<61, 10, 215, 163, 112, 61, 18, 64>>\n  assert a == 4.56\n}\n\npub fn match_13_test() {\n  let assert <<a:float-16>> = <<0, 0>>\n  assert a == 0.0\n}\n\npub fn match_14_test() {\n  let assert <<a:float-16>> = <<0x3C, 0xF0>>\n  assert a == 1.234375\n}\n\npub fn match_15_test() {\n  let assert <<a:float-16-little>> = <<0xFF, 0xFB>>\n  assert a == -65_504.0\n}\n\npub fn match_16_test() {\n  let assert <<_, rest:bytes>> = <<1>>\n  assert rest == <<>>\n}\n\npub fn match_17_test() {\n  let assert <<_, rest:bytes>> = <<1, 2, 3>>\n  assert rest == <<2, 3>>\n}\n\npub fn match_18_test() {\n  let assert <<x:2-bytes, _:bytes>> = <<1, 2, 3>>\n  assert x == <<1, 2>>\n}\n\npub fn match_19_test() {\n  assert <<\n      0x1,\n      2,\n      2:size(16),\n      0x4:size(32),\n      \"Gleam\":utf8,\n      4.2:float,\n      <<<<1, 2, 3>>:bits, \"Gleam\":utf8, 1024>>:bits,\n    >>\n    == importable.get_bit_array()\n}\n\npub fn match_20_test() {\n  assert <<\n      0x1,\n      2,\n      2:size(16),\n      0x4:size(32),\n      \"Gleam\":utf8,\n      4.2:float,\n      <<<<1, 2, 3>>:bits, \"Gleam\":utf8, 1024>>:bits,\n    >>\n    == importable.data\n}\n\npub fn match_21_test() {\n  assert <<71, 108, 101, 97, 109>> == <<\"Gleam\":utf8>>\n}\n\npub fn match_22_test() {\n  let assert <<i:40-signed, _:bits>> = <<231, 255, 255, 255, 254, 123>>\n  assert i == -103_079_215_106\n}\n\npub fn match_23_test() {\n  let assert <<_, i:40-signed, _:bits>> = <<142, 231, 255, 255, 253, 123, 17>>\n  assert i == -103_079_215_749\n}\n\n// https://github.com/gleam-lang/gleam/issues/4712\npub fn multiple_variable_segments_test() {\n  let assert <<a, b:size(a), c:size(b)>> = <<2, 3:2, 7:3>>\n  assert a + b + c == 12\n}\n"
  },
  {
    "path": "test/language/test/language/bit_array_test.gleam",
    "content": "import ffi\nimport gleam/bit_array\n\npub fn utf8_emoji_equal_test() {\n  let left = <<\"Gleam\":utf8, \"👍\":utf8>>\n  let right = <<\"Gleam\":utf8, \"👍\":utf8>>\n  assert left == right\n}\n\npub fn utf8_emoji_not_equal_test() {\n  let left = <<\"Gleam\":utf8, \"👍\":utf8>>\n  let right = <<\"👍\":utf8>>\n  assert left != right\n}\n\npub fn utf8_ascii_test() {\n  let left = <<\"abc\":utf8>>\n  let right = <<97, 98, 99>>\n  assert left == right\n}\n\npub fn utf8_unicode_escape_test() {\n  let left = <<\"😀\":utf8>>\n  let right = <<\"\\u{1F600}\":utf8>>\n  assert left == right\n}\n\npub fn nested_bit_array_test() {\n  let left = <<<<1>>:bits, 2>>\n  let right = <<1, 2>>\n  assert left == right\n}\n\npub fn int_segment_test() {\n  let left = <<1>>\n  let right = <<1:int>>\n  assert left == right\n}\n\npub fn int_16_test() {\n  let left = <<80_000:16>>\n  let right = <<56, 128>>\n  assert left == right\n}\n\npub fn negative_int_16_test() {\n  let left = <<-80_000:16>>\n  let right = <<199, 128>>\n  assert left == right\n}\n\npub fn negative_int_64_test() {\n  let left = <<-1:64>>\n  let right = <<255, 255, 255, 255, 255, 255, 255, 255>>\n  assert left == right\n}\n\npub fn negative_int_56_test() {\n  let left = <<-489_391_639_457_909_760:56>>\n  let right = <<53, 84, 229, 150, 16, 180, 0>>\n  assert left == right\n}\n\npub fn float_16_zero_test() {\n  let left = <<0, 0>>\n  let right = <<0.0:float-16>>\n  assert left == right\n}\n\npub fn float_16_little_negative_test() {\n  let left = <<0x00, 0xbc>>\n  let right = <<-1.0:float-16-little>>\n  assert left == right\n}\n\npub fn float_16_little_test() {\n  let left = <<0xf0, 0x3c>>\n  let right = <<1.234375:float-16-little>>\n  assert left == right\n}\n\npub fn float_16_negative_large_test() {\n  let left = <<0xfb, 0xff>>\n  let right = <<-65_504.0:float-16>>\n  assert left == right\n}\n\npub fn float_64_test() {\n  let left = <<63, 240, 0, 0, 0, 0, 0, 0>>\n  let right = <<1.0:float>>\n  assert left == right\n}\n\npub fn float_32_test() {\n  let left = <<63, 128, 0, 0>>\n  let right = <<1.0:float-32>>\n  assert left == right\n}\n\npub fn float_64_little_test() {\n  let left = <<0, 0, 0, 0, 0, 0, 240, 63>>\n  let right = <<1.0:float-64-little>>\n  assert left == right\n}\n\npub fn float_64_big_test() {\n  let left = <<63, 240, 0, 0, 0, 0, 0, 0>>\n  let right = <<1.0:float-64-big>>\n  assert left == right\n}\n\npub fn pattern_match_utf8_test() {\n  let result = case <<0x20, \"😀👍\":utf8, 0x20>> {\n    <<\" \":utf8, \"😀👍\":utf8, 0x20>> -> True\n    _ -> False\n  }\n  assert result == True\n}\n\npub fn pattern_match_bytes_sliced_test() {\n  let assert <<_, b:bytes-3, _>> = <<1, 2, 3, 4, 5>>\n  let assert <<_, rest:bytes>> = b\n  assert rest == <<3, 4>>\n}\n\npub fn matching_zero_length_segment_test() {\n  let size = 0\n  let data = <<>>\n  let result = case data {\n    <<_:bytes-size(size), _:bytes>> -> \"ok\"\n    _ -> \"this cause should not be reached\"\n  }\n  assert result == \"ok\"\n}\n\npub fn float_16_erlang_test() {\n  let left = <<60, 0>>\n  let right = <<1.0:float-16>>\n  assert left == right\n}\n\n// https://github.com/gleam-lang/gleam/issues/3375\npub fn assignment_int_pattern_test() {\n  let assert <<10 as a, _>> = <<10, 20>>\n  assert a == 10\n}\n\npub fn assignment_float_pattern_test() {\n  let assert <<3.14 as pi:float>> = <<3.14>>\n  assert pi == 3.14\n}\n\npub fn assignment_string_pattern_test() {\n  let assert <<\"Hello\" as h:utf8, \", world!\">> = <<\"Hello, world!\">>\n  assert h == \"Hello\"\n}\n\n@target(erlang)\npub fn pattern_match_utf16_codepoint_little_test() {\n  let assert <<codepoint:utf16_codepoint-little>> = <<\"🌍\":utf16-little>>\n  assert codepoint == ffi.utf_codepoint(127_757)\n}\n\n@target(erlang)\npub fn pattern_match_utf32_codepoint_little_test() {\n  let assert <<codepoint:utf32_codepoint-little>> = <<\"🌍\":utf32-little>>\n  assert codepoint == ffi.utf_codepoint(127_757)\n}\n\npub fn unicode_overflow_test() {\n  // In erlang, literally creating binaries can cause entries to overflow.\n  // For example `<<\"🌵\">> == <<\"5\">>` evaluates to true.\n  // This checks that we are not doing that.\n  // See: https://github.com/gleam-lang/gleam/issues/457\n  let string = \"5\"\n  assert \"🌵\" != string\n}\n\npub fn sliced_bit_array_data_view_offset_test() {\n  let data = <<0xAA, 0xBB, 0xCC, 0xDD>>\n  let assert Ok(sliced) = bit_array.slice(data, 1, 3)\n  assert sliced == <<0xBB, 0xCC, 0xDD>>\n  let value = ffi.read_uint16_from_bit_array(sliced)\n  assert value == 48_076\n}\n\npub fn sliced_bit_array_data_view_byte_length_test() {\n  let data = <<0xAA, 0xBB, 0xCC, 0xDD>>\n  let assert Ok(sliced) = bit_array.slice(data, 1, 2)\n  assert sliced == <<0xBB, 0xCC>>\n}\n"
  },
  {
    "path": "test/language/test/language/block_test.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/1991\npub fn block_scoping_test() {\n  let x = 1\n  let _ = {\n    let x = 2\n    x\n  }\n  assert x == 1\n}\n"
  },
  {
    "path": "test/language/test/language/bool_negation_test.gleam",
    "content": "pub fn negation_true_test() {\n  assert !True == False\n}\n\npub fn negation_false_test() {\n  assert !False == True\n}\n\n// This would crash if the right hand side evaluated\npub fn negation_true_and_panic_test() {\n  let bool = !True\n  bool && panic\n}\n\n// This would crash if the right hand side evaluated\npub fn negation_false_or_panic_test() {\n  let bool = !False\n  bool || panic\n}\n"
  },
  {
    "path": "test/language/test/language/build_files_test.gleam",
    "content": "import ffi\n\n@target(javascript)\npub fn typescript_file_included_test() {\n  let path = \"./build/dev/javascript/language/ffi_typescript.ts\"\n  assert ffi.file_exists(path)\n}\n\n@target(erlang)\npub fn typescript_file_included_test() {\n  let path = \"./build/dev/erlang/language/_gleam_artefacts/ffi_typescript.ts\"\n  assert ffi.file_exists(path)\n}\n"
  },
  {
    "path": "test/language/test/language/clause_guard_test.gleam",
    "content": "import importable\n\n// Constructor functions are used rather than literals to stop the Erlang\n// compiler being clever and complaining about the guards always having the\n// same result\n\nfn true() {\n  True\n}\n\nfn false() {\n  False\n}\n\nfn make_int_zero() {\n  0\n}\n\nfn make_float_zero() {\n  0.0\n}\n\nfn make_pair(a, b) {\n  #(a, b)\n}\n\nfn make_ok(value) {\n  Ok(value)\n}\n\nfn make_error(reason) {\n  Error(reason)\n}\n\npub fn var_true_test() {\n  let true_ = true()\n  assert 0\n    == case Nil {\n      _ if true_ -> 0\n      _ -> 1\n    }\n}\n\npub fn var_false_test() {\n  let false_ = false()\n  assert 1\n    == case Nil {\n      _ if false_ -> 0\n      _ -> 1\n    }\n}\n\npub fn int_equals_match_test() {\n  let int_zero = make_int_zero()\n  assert 0\n    == case Nil {\n      _ if int_zero == int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_equals_nomatch_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 1\n    == case Nil {\n      _ if int_zero == int_one -> 0\n      _ -> 1\n    }\n}\n\npub fn int_not_equals_match_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 0\n    == case Nil {\n      _ if int_zero != int_one -> 0\n      _ -> 1\n    }\n}\n\npub fn int_not_equals_nomatch_test() {\n  let int_zero = make_int_zero()\n  assert 1\n    == case Nil {\n      _ if int_zero != int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn record_equals_match_test() {\n  let ok = make_ok(1)\n  assert 0\n    == case Nil {\n      _ if ok == ok -> 0\n      _ -> 1\n    }\n}\n\npub fn record_equals_nomatch_test() {\n  let ok = make_ok(1)\n  let error = make_error(1)\n  assert 1\n    == case Nil {\n      _ if ok == error -> 0\n      _ -> 1\n    }\n}\n\npub fn record_not_equals_match_test() {\n  let ok = make_ok(1)\n  let error = make_error(1)\n  assert 0\n    == case Nil {\n      _ if ok != error -> 0\n      _ -> 1\n    }\n}\n\npub fn record_not_equals_nomatch_test() {\n  let error = make_error(1)\n  assert 1\n    == case Nil {\n      _ if error != error -> 0\n      _ -> 1\n    }\n}\n\npub fn and_true_true_test() {\n  let true_ = true()\n  assert 0\n    == case Nil {\n      _ if true_ && true_ -> 0\n      _ -> 1\n    }\n}\n\npub fn and_true_false_test() {\n  let true_ = true()\n  let false_ = false()\n  assert 1\n    == case Nil {\n      _ if true_ && false_ -> 0\n      _ -> 1\n    }\n}\n\npub fn and_false_true_test() {\n  let true_ = true()\n  let false_ = false()\n  assert 1\n    == case Nil {\n      _ if false_ && true_ -> 0\n      _ -> 1\n    }\n}\n\npub fn and_false_false_test() {\n  let false_ = false()\n  assert 1\n    == case Nil {\n      _ if false_ && false_ -> 0\n      _ -> 1\n    }\n}\n\npub fn or_true_true_test() {\n  let true_ = true()\n  assert 0\n    == case Nil {\n      _ if true_ || true_ -> 0\n      _ -> 1\n    }\n}\n\npub fn or_true_false_test() {\n  let true_ = true()\n  let false_ = false()\n  assert 0\n    == case Nil {\n      _ if true_ || false_ -> 0\n      _ -> 1\n    }\n}\n\npub fn or_false_true_test() {\n  let true_ = true()\n  let false_ = false()\n  assert 0\n    == case Nil {\n      _ if false_ || true_ -> 0\n      _ -> 1\n    }\n}\n\npub fn or_false_false_test() {\n  let false_ = false()\n  assert 1\n    == case Nil {\n      _ if false_ || false_ -> 0\n      _ -> 1\n    }\n}\n\npub fn float_gt_1_test() {\n  let float_zero = make_float_zero()\n  let float_one = make_float_zero() +. 1.0\n  assert 0\n    == case Nil {\n      _ if float_one >. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn float_gt_2_test() {\n  let float_zero = make_float_zero()\n  assert 1\n    == case Nil {\n      _ if float_zero >. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn float_gte_1_test() {\n  let float_zero = make_float_zero()\n  let float_one = make_float_zero() +. 1.0\n  assert 0\n    == case Nil {\n      _ if float_one >=. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn float_gte_2_test() {\n  let float_zero = make_float_zero()\n  assert 0\n    == case Nil {\n      _ if float_zero >=. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn float_gte_3_test() {\n  let float_zero = make_float_zero()\n  let float_one = make_float_zero() +. 1.0\n  assert 1\n    == case Nil {\n      _ if float_zero >=. float_one -> 0\n      _ -> 1\n    }\n}\n\npub fn float_lt_1_test() {\n  let float_zero = make_float_zero()\n  let float_one = make_float_zero() +. 1.0\n  assert 0\n    == case Nil {\n      _ if float_zero <. float_one -> 0\n      _ -> 1\n    }\n}\n\npub fn float_lt_2_test() {\n  let float_zero = make_float_zero()\n  assert 1\n    == case Nil {\n      _ if float_zero <. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn float_lte_1_test() {\n  let float_zero = make_float_zero()\n  let float_one = make_float_zero() +. 1.0\n  assert 0\n    == case Nil {\n      _ if float_zero <=. float_one -> 0\n      _ -> 1\n    }\n}\n\npub fn float_lte_2_test() {\n  let float_zero = make_float_zero()\n  assert 0\n    == case Nil {\n      _ if float_zero <=. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn float_lte_3_test() {\n  let float_zero = make_float_zero()\n  let float_one = make_float_zero() +. 1.0\n  assert 1\n    == case Nil {\n      _ if float_one <=. float_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_gt_1_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 0\n    == case Nil {\n      _ if int_one > int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_gt_2_test() {\n  let int_zero = make_int_zero()\n  assert 1\n    == case Nil {\n      _ if int_zero > int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_gte_1_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 0\n    == case Nil {\n      _ if int_one >= int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_gte_2_test() {\n  let int_zero = make_int_zero()\n  assert 0\n    == case Nil {\n      _ if int_zero >= int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_gte_3_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 1\n    == case Nil {\n      _ if int_zero >= int_one -> 0\n      _ -> 1\n    }\n}\n\npub fn int_lt_1_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 0\n    == case Nil {\n      _ if int_zero < int_one -> 0\n      _ -> 1\n    }\n}\n\npub fn int_lt_2_test() {\n  let int_zero = make_int_zero()\n  assert 1\n    == case Nil {\n      _ if int_zero < int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_lte_1_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 0\n    == case Nil {\n      _ if int_zero <= int_one -> 0\n      _ -> 1\n    }\n}\n\npub fn int_lte_2_test() {\n  let int_zero = make_int_zero()\n  assert 0\n    == case Nil {\n      _ if int_zero <= int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn int_lte_3_test() {\n  let int_zero = make_int_zero()\n  let int_one = make_int_zero() + 1\n  assert 1\n    == case Nil {\n      _ if int_one <= int_zero -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_1_test() {\n  assert 0\n    == case Nil {\n      _ if 1 + 1 == 2 -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_2_test() {\n  assert 0\n    == case Nil {\n      _ if 47 % 5 == 2 -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_3_test() {\n  assert 0\n    == case Nil {\n      _ if 3 * 5 == 15 -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_4_test() {\n  assert 0\n    == case Nil {\n      _ if 3 * 5 + 1 == 16 -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_5_test() {\n  assert 0\n    == case Nil {\n      _ if 1 + 3 * 5 == 16 -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_6_test() {\n  assert 0\n    == case Nil {\n      _ if 1 - 15 / 5 == -2 -> 0\n      _ -> 1\n    }\n}\n\npub fn arithmetic_7_test() {\n  assert 0\n    == case Nil {\n      _ if 15 / 5 - 1 == 2 -> 0\n      _ -> 1\n    }\n}\n\npub fn tuple_access_1_test() {\n  let tuple_true_false = make_pair(True, False)\n  assert 0\n    == case Nil {\n      _ if tuple_true_false.0 -> 0\n      _ -> 1\n    }\n}\n\npub fn tuple_access_2_test() {\n  let tuple_true_false = make_pair(True, False)\n  assert 1\n    == case Nil {\n      _ if tuple_true_false.1 -> 0\n      _ -> 1\n    }\n}\n\npub fn const_1_test() {\n  let int_zero = make_int_zero()\n  assert 0\n    == case Nil {\n      _ if int_zero == 0 -> 0\n      _ -> 1\n    }\n}\n\npub fn const_2_test() {\n  let int_zero = make_int_zero()\n  assert 1\n    == case Nil {\n      _ if int_zero == 1 -> 0\n      _ -> 1\n    }\n}\n\npub fn const_ok_test() {\n  let ok = make_ok(1)\n  assert 0\n    == case Nil {\n      _ if ok == Ok(1) -> 0\n      _ -> 1\n    }\n}\n\npub fn const_error_test() {\n  let ok = make_ok(1)\n  assert 1\n    == case Nil {\n      _ if ok == Error(1) -> 0\n      _ -> 1\n    }\n}\n\npub fn tuple_with_pattern_var_test() {\n  let x = True\n  let int = case x {\n    a if #(a) == #(True) -> 0\n    _ -> 1\n  }\n  assert 0 == int\n}\n\npub fn module_access_string_const_matches_test() {\n  let string = \"gleam\"\n  assert True\n    == case string {\n      lang if lang == importable.language -> True\n      _ -> False\n    }\n}\n\npub fn module_access_string_const_nomatch_test() {\n  let string = \"python\"\n  assert False\n    == case string {\n      lang if lang == importable.language -> True\n      _ -> False\n    }\n}\n\npub fn module_access_custom_type_const_matches_test() {\n  let string = \"WarGames\"\n  assert True\n    == case string {\n      movie if movie == importable.war_games.title -> True\n      _ -> False\n    }\n}\n\npub fn module_access_custom_type_const_nomatch_test() {\n  let string = \"Gattaca\"\n  assert False\n    == case string {\n      movie if movie == importable.war_games.title -> True\n      _ -> False\n    }\n}\n\n// https://github.com/gleam-lang/gleam/issues/5283\npub fn case_with_guard_does_not_pollute_outer_scope_test() {\n  let a = case 1337 {\n    n if n == 1347 -> 1\n    _ -> 2\n  }\n  let b = case 1337 {\n    n -> 2\n  }\n  assert a == b\n}\n"
  },
  {
    "path": "test/language/test/language/constant_test.gleam",
    "content": "const const_int = 5\n\nconst const_float = 1.0\n\nconst const_string = \"Gleam\"\n\nconst const_nil = Nil\n\nconst const_ok = Ok(1)\n\nconst const_list_empty = []\n\nconst const_list_1 = [1]\n\nconst const_list_2 = [1, 2]\n\npub fn int_test() {\n  assert const_int == 5\n}\n\npub fn float_test() {\n  assert const_float == 1.0\n}\n\npub fn string_test() {\n  assert const_string == \"Gleam\"\n}\n\npub fn nil_test() {\n  assert const_nil == Nil\n}\n\npub fn ok_test() {\n  assert const_ok == Ok(1)\n}\n\npub fn list_empty_test() {\n  assert const_list_empty == []\n}\n\npub fn list_1_test() {\n  assert const_list_1 == [1]\n}\n\npub fn list_2_test() {\n  assert const_list_2 == [1, 2]\n}\n"
  },
  {
    "path": "test/language/test/language/directly_matching_case_subject_test.gleam",
    "content": "// github.com/gleam-lang/gleam/issues/5265\npub fn directly_matching_case_subject_test() {\n  let result = {\n    let x = \"ABC\"\n    case True {\n      True -> {\n        let x = 79\n        0\n      }\n      False -> {\n        let x = True\n        0\n      }\n    }\n    x\n  }\n\n  assert result == \"ABC\"\n}\n"
  },
  {
    "path": "test/language/test/language/equality_test.gleam",
    "content": "pub fn list_eq_1_test() {\n  let left = []\n  let right = []\n  assert left == right\n}\n\npub fn list_eq_2_test() {\n  let left = []\n  let right = [0]\n  assert left != right\n}\n\npub fn list_eq_3_test() {\n  let left = [0]\n  let right = []\n  assert left != right\n}\n\npub fn list_eq_4_test() {\n  let left = [0]\n  let right = [0]\n  assert left == right\n}\n\npub fn list_neq_1_test() {\n  let left = []\n  let right = []\n  assert left == right\n}\n\npub fn list_neq_2_test() {\n  let left = []\n  let right = [0]\n  assert left != right\n}\n\npub fn list_neq_3_test() {\n  let left = [0]\n  let right = []\n  assert left != right\n}\n\npub fn list_neq_4_test() {\n  let left = [0]\n  let right = [0]\n  assert left == right\n}\n\npub fn int_eq_1_test() {\n  let left = 0\n  let right = 0\n  assert left == right\n}\n\npub fn int_neq_1_test() {\n  let left = 0\n  let right = 0\n  assert left == right\n}\n\npub fn int_eq_2_test() {\n  let left = 1\n  let right = 0\n  assert left != right\n}\n\npub fn int_neq_2_test() {\n  let left = 1\n  let right = 0\n  assert left != right\n}\n\npub fn int_eq_3_test() {\n  let left = 1\n  let right = 1\n  assert left == right\n}\n\npub fn int_neq_3_test() {\n  let left = 1\n  let right = 1\n  assert left == right\n}\n\npub fn bit_array_eq_1_test() {\n  let left = <<>>\n  let right = <<>>\n  assert left == right\n}\n\npub fn bit_array_neq_1_test() {\n  let left = <<>>\n  let right = <<>>\n  assert left == right\n}\n\npub fn bit_array_eq_2_test() {\n  let left = <<1, 2>>\n  let right = <<1, 2>>\n  assert left == right\n}\n\npub fn bit_array_neq_2_test() {\n  let left = <<1, 2>>\n  let right = <<1, 2>>\n  assert left == right\n}\n\npub fn bit_array_eq_3_test() {\n  let left = <<1, 2>>\n  let right = <<2>>\n  assert left != right\n}\n\npub fn bit_array_neq_3_test() {\n  let left = <<1, 2>>\n  let right = <<2>>\n  assert left != right\n}\n\npub fn record_ok_eq_1_test() {\n  let left = Ok(1)\n  let right = Ok(1)\n  assert left == right\n}\n\npub fn record_ok_neq_1_test() {\n  let left = Ok(1)\n  let right = Ok(1)\n  assert left == right\n}\n\npub fn record_ok_eq_2_test() {\n  let left = Ok(2)\n  let right = Ok(1)\n  assert left != right\n}\n\npub fn record_ok_neq_2_test() {\n  let left = Ok(2)\n  let right = Ok(1)\n  assert left != right\n}\n\npub fn record_error_eq_1_test() {\n  let left = Error(1)\n  let right = Error(1)\n  assert left == right\n}\n\npub fn record_error_neq_1_test() {\n  let left = Error(1)\n  let right = Error(1)\n  assert left == right\n}\n\npub fn record_error_eq_2_test() {\n  let left = Error(2)\n  let right = Error(1)\n  assert left != right\n}\n\npub fn record_error_neq_2_test() {\n  let left = Error(2)\n  let right = Error(1)\n  assert left != right\n}\n"
  },
  {
    "path": "test/language/test/language/float_test.gleam",
    "content": "pub fn addition_1_test() {\n  assert 0.0 +. 0.0 == 0.0\n}\n\npub fn addition_2_test() {\n  assert 1.0 +. 1.0 == 2.0\n}\n\npub fn addition_3_test() {\n  assert 5.0 +. 1.0 == 6.0\n}\n\npub fn addition_4_test() {\n  assert 1.0 +. 3.0 == 4.0\n}\n\npub fn addition_5_test() {\n  assert 1.0 +. -3.0 == -2.0\n}\n\npub fn subtraction_1_test() {\n  assert 0.0 -. 0.0 == 0.0\n}\n\npub fn subtraction_2_test() {\n  assert 1.0 -. 1.0 == 0.0\n}\n\npub fn subtraction_3_test() {\n  assert 5.0 -. 1.0 == 4.0\n}\n\npub fn subtraction_4_test() {\n  assert 1.0 -. 3.0 == -2.0\n}\n\npub fn subtraction_5_test() {\n  assert 1.0 -. -3.0 == 4.0\n}\n\npub fn subtraction_6_test() {\n  assert 0.5 -. 0.0 == 0.5\n}\n\npub fn subtraction_7_test() {\n  assert 1.0 -. 4.5 == -3.5\n}\n\npub fn multiplication_1_test() {\n  assert 0.0 *. 0.0 == 0.0\n}\n\npub fn multiplication_2_test() {\n  assert 1.0 *. 1.0 == 1.0\n}\n\npub fn multiplication_3_test() {\n  assert 2.0 *. 2.0 == 4.0\n}\n\npub fn multiplication_4_test() {\n  assert 2.0 *. 4.0 == 8.0\n}\n\npub fn multiplication_5_test() {\n  assert -2.0 *. 4.0 == -8.0\n}\n\npub fn multiplication_6_test() {\n  assert 2.0 *. -4.0 == -8.0\n}\n\npub fn precedence_1_test() {\n  assert 2.0 *. 2.0 +. 3.0 == 7.0\n}\n\npub fn precedence_2_test() {\n  assert 2.0 +. 2.0 *. 3.0 == 8.0\n}\n\npub fn precedence_3_test() {\n  assert 2.0 *. { 2.0 +. 3.0 } == 10.0\n}\n\npub fn precedence_4_test() {\n  assert { 2.0 +. 2.0 } *. 3.0 == 12.0\n}\n\npub fn scientific_notation_addition_1_test() {\n  assert 0.0e0 +. 0.0 == 0.0\n}\n\npub fn scientific_notation_addition_2_test() {\n  assert 0.0 +. 0.0e0 == 0.0\n}\n\npub fn scientific_notation_addition_3_test() {\n  assert 0.0e-0 +. 0.0 == 0.0\n}\n\npub fn scientific_notation_addition_4_test() {\n  assert 0.0 +. 0.0e-0 == 0.0\n}\n\npub fn scientific_notation_addition_5_test() {\n  assert 1.0e3 +. 1.0 == 1001.0\n}\n\npub fn scientific_notation_addition_6_test() {\n  assert 5.0 +. 1.0e3 == 1005.0\n}\n\npub fn scientific_notation_addition_7_test() {\n  assert 1.0e5 +. -3.0e5 == -200_000.0\n}\n\npub fn scientific_notation_addition_8_test() {\n  assert 1.0e50 +. -1.0e50 == 0.0\n}\n\npub fn scientific_notation_addition_9_test() {\n  assert 1.0e-3 +. 1.0 == 1.001\n}\n\npub fn scientific_notation_addition_10_test() {\n  assert 5.0 +. 1.0e-3 == 5.001\n}\n\npub fn scientific_notation_addition_11_test() {\n  assert 10.0e-2 +. -3.0e-2 == 0.07\n}\n\npub fn scientific_notation_subtraction_1_test() {\n  assert 0.0e0 -. 0.0 == 0.0\n}\n\npub fn scientific_notation_subtraction_2_test() {\n  assert 0.0 -. 0.0e0 == 0.0\n}\n\npub fn scientific_notation_subtraction_3_test() {\n  assert 0.0e-0 -. 0.0 == 0.0\n}\n\npub fn scientific_notation_subtraction_4_test() {\n  assert 0.0 -. 0.0e-0 == 0.0\n}\n\npub fn scientific_notation_subtraction_5_test() {\n  assert 1.0e3 -. 1.0 == 999.0\n}\n\npub fn scientific_notation_subtraction_6_test() {\n  assert 5.0 -. 1.0e3 == -995.0\n}\n\npub fn scientific_notation_subtraction_7_test() {\n  assert 1.0e5 -. 1.0e5 == 0.0\n}\n\npub fn scientific_notation_subtraction_8_test() {\n  assert 1.0e-3 -. 1.0 == -0.999\n}\n\npub fn scientific_notation_subtraction_9_test() {\n  assert 5.0 -. 1.0e-3 == 4.999\n}\n\npub fn scientific_notation_subtraction_10_test() {\n  assert 10.0e-2 -. -3.0e-2 == 0.13\n}\n\npub fn scientific_notation_multiplication_1_test() {\n  assert 0.0e0 *. 0.0 == 0.0\n}\n\npub fn scientific_notation_multiplication_2_test() {\n  assert 0.0 *. 0.0e0 == 0.0\n}\n\npub fn scientific_notation_multiplication_3_test() {\n  assert 0.0e-0 *. 0.0 == 0.0\n}\n\npub fn scientific_notation_multiplication_4_test() {\n  assert 0.0 *. 0.0e-0 == 0.0\n}\n\npub fn scientific_notation_multiplication_5_test() {\n  assert 2.0e1 *. 2.0e1 == 400.0\n}\n\npub fn scientific_notation_multiplication_6_test() {\n  assert 1.0e-5 *. 1.0e5 == 1.0\n}\n\npub fn scientific_notation_multiplication_7_test() {\n  assert 2.0e5 *. 2.0e-5 == 4.0\n}\n\npub fn scientific_notation_multiplication_8_test() {\n  assert 2.0e5 *. 4.0e-4 == 80.0\n}\n\npub fn scientific_notation_multiplication_9_test() {\n  assert 2.0e-5 *. 2.0e5 == 4.0\n}\n\npub fn scientific_notation_multiplication_10_test() {\n  assert 2.0e5 *. 4.0e-5 == 8.0\n}\n\npub fn scientific_notation_multiplication_11_test() {\n  assert -2.0e-5 *. 2.0e5 == -4.0\n}\n\npub fn scientific_notation_multiplication_12_test() {\n  assert -2.0e5 *. -4.0e-5 == 8.0\n}\n\npub fn divide_by_2_test() {\n  let left = 2.0\n  let right = 2.0\n  assert left /. right == 1.0\n}\n\npub fn divide_by_0_test() {\n  let left = 2.0\n  let right = 0.0\n  assert left /. right == 0.0\n}\n"
  },
  {
    "path": "test/language/test/language/imported_custom_type_test.gleam",
    "content": "import importable.{NoFields}\n\npub fn no_fields_qualified_and_unqualified_test() {\n  assert importable.NoFields == NoFields\n}\n\npub fn no_fields_assert_assignment_test() {\n  let result = {\n    let assert importable.NoFields = importable.NoFields\n  }\n  assert result == importable.NoFields\n}\n\npub fn no_fields_unqualified_assert_assignment_test() {\n  let result = {\n    let assert NoFields = importable.NoFields\n  }\n  assert result == importable.NoFields\n}\n\npub fn no_fields_let_assignment_test() {\n  let result = {\n    let importable.NoFields = importable.NoFields\n  }\n  assert result == importable.NoFields\n}\n\npub fn no_fields_unqualified_let_assignment_test() {\n  let result = {\n    let NoFields = importable.NoFields\n  }\n  assert result == importable.NoFields\n}\n"
  },
  {
    "path": "test/language/test/language/importing_test.gleam",
    "content": "import mod_with_numbers_0123456789\nimport shadowed_module.{ShadowPerson}\n\npub fn mod_with_numbers_test() {\n  assert mod_with_numbers_0123456789.hello() == \"world\"\n}\n\npub fn shadowed_module_test() {\n  let shadowed_module = ShadowPerson(18)\n  let shadowed_module = shadowed_module.celebrate_birthday(shadowed_module)\n  assert shadowed_module.age == 19\n}\n"
  },
  {
    "path": "test/language/test/language/int_negation_test.gleam",
    "content": "pub fn negation_1_test() {\n  let a = 3\n  let b = -a\n  assert -3 == b\n}\n\npub fn negation_2_test() {\n  let a = 3\n  let b = -{ -a }\n  assert 3 == b\n}\n\npub fn negation_3_test() {\n  let a = 3\n  let b = -{ -{ -a } }\n  assert -3 == b\n}\n\npub fn negation_4_test() {\n  let a = 3\n  let b = -a\n  let c = a - -b\n  assert 0 == c\n}\n\npub fn negation_5_test() {\n  let a = 3\n  let b = -a\n  let c = a - -{ -{ -{ -{ -b } } } }\n  assert 0 == c\n}\n\npub fn negation_6_test() {\n  let a = 3\n  let b = -a\n  let c = -a - -b\n  assert -6 == c\n}\n\npub fn negation_7_test() {\n  let abs = fn(value) {\n    case value {\n      value if value > 0 -> value\n      _ -> -value\n    }\n  }\n  assert -6 == -abs(-6)\n}\n"
  },
  {
    "path": "test/language/test/language/int_test.gleam",
    "content": "pub fn addition_1_test() {\n  assert 0 + 0 == 0\n}\n\npub fn addition_2_test() {\n  assert 1 + 1 == 2\n}\n\npub fn addition_3_test() {\n  assert 5 + 1 == 6\n}\n\npub fn addition_4_test() {\n  assert 1 + 3 == 4\n}\n\npub fn addition_5_test() {\n  assert 1 + -3 == -2\n}\n\npub fn subtraction_1_test() {\n  assert 0 - 0 == 0\n}\n\npub fn subtraction_2_test() {\n  assert 1 - 1 == 0\n}\n\npub fn subtraction_3_test() {\n  assert 5 - 1 == 4\n}\n\npub fn subtraction_4_test() {\n  assert 1 - 3 == -2\n}\n\npub fn subtraction_5_test() {\n  assert 1 - -3 == 4\n}\n\npub fn multiplication_1_test() {\n  assert 0 * 0 == 0\n}\n\npub fn multiplication_2_test() {\n  assert 1 * 1 == 1\n}\n\npub fn multiplication_3_test() {\n  assert 2 * 2 == 4\n}\n\npub fn multiplication_4_test() {\n  assert 2 * 4 == 8\n}\n\npub fn multiplication_5_test() {\n  assert -2 * 4 == -8\n}\n\npub fn multiplication_6_test() {\n  assert 2 * -4 == -8\n}\n\npub fn precedence_1_test() {\n  assert 2 * 2 + 3 == 7\n}\n\npub fn precedence_2_test() {\n  assert 2 + 2 * 3 == 8\n}\n\npub fn precedence_3_test() {\n  assert 2 * { 2 + 3 } == 10\n}\n\npub fn precedence_4_test() {\n  assert { 2 + 2 } * 3 == 12\n}\n\npub fn hex_int_test() {\n  let int = 15\n  assert 0xF == int\n}\n\npub fn octal_int_test() {\n  let int = 15\n  assert 0o17 == int\n}\n\npub fn binary_int_test() {\n  let int = 15\n  assert 0b00001111 == int\n}\n\npub fn lex_1_test() {\n  assert 1 - 1 == 0\n}\n\npub fn lex_2_test() {\n  let a = 1\n  assert a - 1 == 0\n}\n\npub fn lex_3_test() {\n  assert 1 - 1 == 0\n}\n\npub fn division_1_test() {\n  assert 1 / 1 == 1\n}\n\npub fn division_2_test() {\n  assert 1 / 0 == 0\n}\n\npub fn division_3_test() {\n  assert 3 / 2 == 1\n}\n\npub fn division_4_test() {\n  assert 3 / 0 == 0\n}\n"
  },
  {
    "path": "test/language/test/language/list_prepend_test.gleam",
    "content": "pub fn prepend_1_test() {\n  let left = [1, ..[]]\n  let right = [1]\n  assert left == right\n}\n\npub fn prepend_2_test() {\n  let left = [1, 2, ..[]]\n  let right = [1, 2]\n  assert left == right\n}\n\npub fn prepend_3_test() {\n  let left = [1, 2, ..[3]]\n  let right = [1, 2, 3]\n  assert left == right\n}\n\npub fn prepend_4_test() {\n  let left = [1, 2, ..[3, 4]]\n  let right = [1, 2, 3, 4]\n  assert left == right\n}\n"
  },
  {
    "path": "test/language/test/language/mixed_arg_match_test.gleam",
    "content": "type Cat {\n  Cat(String, cuteness: Int)\n}\n\ntype NestedCat {\n  NestedCat(Cat, String, cuteness: Int)\n}\n\npub fn matching_second_labelled_arg_as_first_test() {\n  let Cat(cuteness: y, ..) = Cat(\"fluffy\", 10)\n  assert y == 10\n}\n\npub fn matching_both_args_on_position_test() {\n  let Cat(x, y) = Cat(\"fluffy\", 10)\n  assert #(x, y) == #(\"fluffy\", 10)\n}\n\npub fn matching_second_labelled_arg_as_second_test() {\n  let Cat(x, cuteness: y) = Cat(\"fluffy\", 10)\n  assert #(x, y) == #(\"fluffy\", 10)\n}\n\npub fn nested_custom_types_test() {\n  let NestedCat(Cat(x, cuteness: y), cuteness: y2, ..) =\n    NestedCat(Cat(\"fluffy\", 10), \"gleamy\", 100)\n  assert #(x, y, y2) == #(\"fluffy\", 10, 100)\n}\n"
  },
  {
    "path": "test/language/test/language/multiple_case_subject_test.gleam",
    "content": "pub fn wildcard_test() {\n  let x = true()\n  let y = false()\n  let result = case x, y {\n    _, _ -> 0\n  }\n  assert result == 0\n}\n\npub fn no_match_test() {\n  let x = true()\n  let y = false()\n  let result = case x, y {\n    False, True -> 1\n    _, _ -> 0\n  }\n  assert result == 0\n}\n\npub fn match_test() {\n  let x = true()\n  let y = false()\n  let result = case x, y {\n    False, True -> 1\n    _, _ -> 0\n  }\n  assert result == 0\n}\n\npub fn alternative_test() {\n  let x = true()\n  let y = false()\n  let result = case x, y {\n    False, True | True, False -> 1\n    _, _ -> 0\n  }\n  assert result == 1\n}\n\npub fn guard_test() {\n  let x = true()\n  let y = true()\n  let result = case x, y {\n    x, y if x == y -> 1\n    _, _ -> 0\n  }\n  assert result == 1\n}\n\nfn true() -> Bool {\n  True\n}\n\nfn false() -> Bool {\n  False\n}\n"
  },
  {
    "path": "test/language/test/language/non_utf8_string_bit_array_test.gleam",
    "content": "import ffi\n\npub fn utf16_pattern_match_test() {\n  let result = {\n    let assert <<\"Hello, world\":utf16>> = <<\"Hello, world\":utf16>>\n  }\n  assert result == <<\"Hello, world\":utf16>>\n}\n\npub fn utf32_pattern_match_test() {\n  let result = {\n    let assert <<\"Hello, world\":utf32>> = <<\"Hello, world\":utf32>>\n  }\n  assert result == <<\"Hello, world\":utf32>>\n}\n\npub fn utf16_bytes_test() {\n  let left = <<\"Hello, 🌍!\":utf16>>\n  let right = <<\n    0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 216, 60, 223, 13, 0, 33,\n  >>\n  assert left == right\n}\n\npub fn utf32_bytes_test() {\n  let left = <<\"Hello, 🌍!\":utf32>>\n  let right = <<\n    0, 0, 0, 72, 0, 0, 0, 101, 0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0,\n    44, 0, 0, 0, 32, 0, 1, 243, 13, 0, 0, 0, 33,\n  >>\n  assert left == right\n}\n\npub fn utf16_pattern_matching_bytes_test() {\n  let result = {\n    let assert <<\"Hello, 🌍!\":utf16>> = <<\n      0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 216, 60, 223, 13, 0,\n      33,\n    >>\n  }\n  assert result == <<\"Hello, 🌍!\":utf16>>\n}\n\npub fn utf32_pattern_matching_bytes_test() {\n  let result = {\n    let assert <<\"Hello, 🌍!\":utf32>> = <<\n      0, 0, 0, 72, 0, 0, 0, 101, 0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0,\n      0, 44, 0, 0, 0, 32, 0, 1, 243, 13, 0, 0, 0, 33,\n    >>\n  }\n  assert result == <<\"Hello, 🌍!\":utf32>>\n}\n\npub fn utf16_bytes_little_endian_test() {\n  let left = <<\"Hello, 🌍!\":utf16-little>>\n  let right = <<\n    72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 0, 60, 216, 13, 223, 33, 0,\n  >>\n  assert left == right\n}\n\npub fn utf32_bytes_little_endian_test() {\n  let left = <<\"Hello, 🌍!\":utf32-little>>\n  let right = <<\n    72, 0, 0, 0, 101, 0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0, 44, 0,\n    0, 0, 32, 0, 0, 0, 13, 243, 1, 0, 33, 0, 0, 0,\n  >>\n  assert left == right\n}\n\npub fn utf16_pattern_matching_little_endian_test() {\n  let result = {\n    let assert <<\"Hello, 🌍!\":utf16-little>> = <<\n      72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 0, 60, 216, 13, 223, 33,\n      0,\n    >>\n  }\n  assert result == <<\"Hello, 🌍!\":utf16-little>>\n}\n\npub fn utf32_pattern_matching_little_endian_test() {\n  let result = {\n    let assert <<\"Hello, 🌍!\":utf32-little>> = <<\n      72, 0, 0, 0, 101, 0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0, 44, 0,\n      0, 0, 32, 0, 0, 0, 13, 243, 1, 0, 33, 0, 0, 0,\n    >>\n  }\n  assert result == <<\"Hello, 🌍!\":utf32-little>>\n}\n\npub fn utf16_codepoint_test() {\n  // 🌍\n  let codepoint = ffi.utf_codepoint(127_757)\n  let result = <<codepoint:utf16_codepoint>>\n  assert result == <<216, 60, 223, 13>>\n}\n\npub fn utf16_codepoint_little_endian_test() {\n  // 🌍\n  let codepoint = ffi.utf_codepoint(127_757)\n  let result = <<codepoint:utf16_codepoint-little>>\n  assert result == <<60, 216, 13, 223>>\n}\n\npub fn utf32_codepoint_test() {\n  // 🌍\n  let codepoint = ffi.utf_codepoint(127_757)\n  let result = <<codepoint:utf32_codepoint>>\n  assert result == <<0, 1, 243, 13>>\n}\n\npub fn utf32_codepoint_little_endian_test() {\n  // 🌍\n  let codepoint = ffi.utf_codepoint(127_757)\n  let result = <<codepoint:utf32_codepoint-little>>\n  assert result == <<13, 243, 1, 0>>\n}\n"
  },
  {
    "path": "test/language/test/language/pipe_test.gleam",
    "content": "fn identity(x: a) -> a {\n  x\n}\n\nfn pair(x: a, y: b) -> #(a, b) {\n  #(x, y)\n}\n\nfn triplet(x x: a, y y: b, z z: c) -> #(a, b, c) {\n  #(x, y, z)\n}\n\npub fn pipe_last_test() {\n  let result =\n    100\n    |> identity\n  assert 100 == result\n}\n\npub fn pipe_into_anon_test() {\n  let result =\n    100\n    |> fn(x) { x }\n  assert 100 == result\n}\n\npub fn pipe_into_capture_test() {\n  let result =\n    1\n    |> pair(2, _)\n  assert #(2, 1) == result\n}\n\npub fn pipe_first_test() {\n  let result =\n    1\n    |> pair(2)\n  assert #(1, 2) == result\n}\n\npub fn pipe_middle_with_label_requires_false_capture_test() {\n  let result =\n    2\n    |> triplet(z: 3, x: 1)\n  assert #(1, 2, 3) == result\n}\n\npub fn pipe_last_with_label_requires_false_capture_test() {\n  let result =\n    3\n    |> triplet(y: 2, x: 1)\n  assert #(1, 2, 3) == result\n}\n"
  },
  {
    "path": "test/language/test/language/precedence_test.gleam",
    "content": "pub fn precedence_1_test() {\n  assert 7 == 1 + 2 * 3\n}\n\npub fn precedence_2_test() {\n  assert 5 == 3 * 1 + 2\n}\n\npub fn precedence_3_test() {\n  assert 9 == { 1 + 2 } * 3\n}\n\npub fn precedence_4_test() {\n  assert 9 == 3 * { 1 + 2 }\n}\n\npub fn precedence_5_test() {\n  assert 11 == 1 + 2 * 3 + 4\n}\n\npub fn precedence_6_test() {\n  assert 26 == 2 * 3 + 4 * 5\n}\n\npub fn precedence_7_test() {\n  assert 4 == 2 * { 3 + 1 } / 2\n}\n\npub fn precedence_8_test() {\n  assert -17 == 5 + 3 / 3 * 2 - 6 * 4\n}\n\npub fn precedence_9_test() {\n  assert -31 == -5 + -3 / -3 * -2 - -6 * -4\n}\n\npub fn precedence_10_test() {\n  let a = 5\n  let b = 3\n  let c = 3\n  let d = 2\n  let e = 6\n  let f = 4\n  assert -17 == a + b / c * d - e * f\n}\n\npub fn precedence_11_test() {\n  let a = 5\n  let b = 3\n  let c = 3\n  let d = 2\n  let e = 6\n  let f = 4\n  assert -31 == -a + -b / -c * -d - -e * -f\n}\n"
  },
  {
    "path": "test/language/test/language/prelude_test.gleam",
    "content": "import gleam\n\npub fn gleam_ok_test() {\n  let left = Ok(1)\n  let right = gleam.Ok(1)\n  assert left == right\n}\n\npub fn gleam_error_test() {\n  let left = Error(1)\n  let right = gleam.Error(1)\n  assert left == right\n}\n\npub fn gleam_nil_test() {\n  let left = Nil\n  let right = gleam.Nil\n  assert left == right\n}\n"
  },
  {
    "path": "test/language/test/language/record_access_test.gleam",
    "content": "type Person {\n  Person(name: String, age: Int, country: String)\n}\n\npub fn record_access_name_test() {\n  let person = Person(name: \"Quinn\", age: 27, country: \"Canada\")\n  assert person.name == \"Quinn\"\n}\n\npub fn record_access_age_test() {\n  let person = Person(name: \"Quinn\", age: 27, country: \"Canada\")\n  assert person.age == 27\n}\n\n// https://github.com/gleam-lang/gleam/issues/1093\npub fn contextual_info_for_access_test() {\n  let person = Person(name: \"Quinn\", age: 27, country: \"Canada\")\n  let apply = fn(a, f) { f(a) }\n  assert apply(person, fn(x) { x.name }) == \"Quinn\"\n}\n"
  },
  {
    "path": "test/language/test/language/record_update_test.gleam",
    "content": "import record_update\n\ntype Person {\n  Person(name: String, age: Int, country: String)\n}\n\ntype MixedRecord {\n  MixedRecord(Int, Float, labelled_1: Int, labelled_2: String)\n}\n\nfn id(x) {\n  x\n}\n\npub fn unqualified_record_update_test() {\n  let past = Person(\"Quinn\", 27, \"Canada\")\n  let present = Person(..past, country: \"USA\", age: past.age + 1)\n  assert present == Person(\"Quinn\", 28, \"USA\")\n}\n\npub fn qualified_record_update_test() {\n  let module_box = record_update.Box(\"a\", 5)\n  let updated = record_update.Box(..module_box, value: 6)\n  assert updated == record_update.Box(\"a\", 6)\n}\n\n// https://github.com/gleam-lang/gleam/issues/1379\npub fn pipe_in_record_update_test() {\n  let module_box = record_update.Box(\"a\", 5)\n  let updated =\n    record_update.Box(\n      ..module_box,\n      value: 6\n        |> id,\n    )\n  assert updated == record_update.Box(\"a\", 6)\n}\n\npub fn unlabelled_field_in_record_update_test() {\n  let record = MixedRecord(1, 3.14, labelled_1: 3982, labelled_2: \"Something\")\n  let updated = MixedRecord(..record, labelled_1: 12)\n  assert updated == MixedRecord(1, 3.14, 12, \"Something\")\n}\n"
  },
  {
    "path": "test/language/test/language/remainder_test.gleam",
    "content": "pub fn remainder_1_test() {\n  assert 1 % 1 == 0\n}\n\npub fn remainder_2_test() {\n  assert 1 % 0 == 0\n}\n\npub fn remainder_3_test() {\n  assert 3 % 2 == 1\n}\n\npub fn remainder_4_test() {\n  assert 3 % 0 == 0\n}\n\npub fn remainder_5_test() {\n  assert 3 % -2 == 1\n}\n\npub fn remainder_6_test() {\n  assert 3 % -0 == 0\n}\n\npub fn remainder_7_test() {\n  assert -13 % 3 == -1\n}\n\npub fn remainder_8_test() {\n  assert 13 % -3 == 1\n}\n\npub fn remainder_9_test() {\n  assert -13 % -3 == -1\n}\n"
  },
  {
    "path": "test/language/test/language/sized_bit_array_test.gleam",
    "content": "pub fn size_8_literal_test() {\n  let left = <<257:size(8)>>\n  let right = <<1>>\n  assert left == right\n}\n\npub fn size_8_variable_test() {\n  let i = 257\n  let left = <<i:size(8)>>\n  let right = <<1>>\n  assert left == right\n}\n\npub fn size_16_literal_test() {\n  let left = <<257:size(16)>>\n  let right = <<1, 1>>\n  assert left == right\n}\n\npub fn size_16_variable_test() {\n  let i = 257\n  let left = <<i:size(16)>>\n  let right = <<1, 1>>\n  assert left == right\n}\n\npub fn size_24_literal_test() {\n  let left = <<257:size(24)>>\n  let right = <<0, 1, 1>>\n  assert left == right\n}\n\npub fn size_24_variable_test() {\n  let i = 257\n  let left = <<i:size(24)>>\n  let right = <<0, 1, 1>>\n  assert left == right\n}\n\npub fn size_40_literal_test() {\n  let left = <<4_294_967_297:size(40)>>\n  let right = <<1, 0, 0, 0, 1>>\n  assert left == right\n}\n\npub fn size_40_variable_test() {\n  let i = 4_294_967_297\n  let left = <<i:size(40)>>\n  let right = <<1, 0, 0, 0, 1>>\n  assert left == right\n}\n\npub fn size_24_little_literal_test() {\n  let left = <<100_000:24-little>>\n  let right = <<160, 134, 1>>\n  assert left == right\n}\n\npub fn size_24_little_variable_test() {\n  let i = 100_000\n  let left = <<i:24-little>>\n  let right = <<160, 134, 1>>\n  assert left == right\n}\n\npub fn size_32_big_negative_literal_test() {\n  let left = <<-1:32-big>>\n  let right = <<255, 255, 255, 255>>\n  assert left == right\n}\n\npub fn size_32_big_negative_variable_test() {\n  let i = -1\n  let left = <<i:32-big>>\n  let right = <<255, 255, 255, 255>>\n  assert left == right\n}\n\npub fn size_32_little_large_literal_test() {\n  let left = <<100_000_000_000:32-little>>\n  let right = <<0, 232, 118, 72>>\n  assert left == right\n}\n\npub fn size_32_little_large_variable_test() {\n  let i = 100_000_000_000\n  let left = <<i:32-little>>\n  let right = <<0, 232, 118, 72>>\n  assert left == right\n}\n\npub fn negative_size_literal_test() {\n  let left = <<>>\n  let right = <<256:size(-1)>>\n  assert left == right\n}\n\npub fn negative_size_variable_test() {\n  let i = 256\n  let left = <<i:size(-1)>>\n  let right = <<>>\n  assert left == right\n}\n\n// JS Number.MAX_SAFE_INTEGER\npub fn size_64_max_safe_int_literal_test() {\n  let left = <<9_007_199_254_740_991:size(64)>>\n  let right = <<0, 31, 255, 255, 255, 255, 255, 255>>\n  assert left == right\n}\n\npub fn size_64_max_safe_int_variable_test() {\n  let i = 9_007_199_254_740_991\n  let left = <<i:size(64)>>\n  let right = <<0, 31, 255, 255, 255, 255, 255, 255>>\n  assert left == right\n}\n\npub fn size_unit_test() {\n  let i = 9_007_199_254_740_991\n  let left = <<i:size(4)-unit(16)>>\n  let right = <<0, 31, 255, 255, 255, 255, 255, 255>>\n  assert left == right\n}\n\npub fn dynamic_size_unit_test() {\n  let size = 5\n  let left = <<405:size(size)-unit(2)>>\n  let right = <<101, 1:2>>\n  assert left == right\n}\n\npub fn pattern_bits_size_expression_test() {\n  let assert <<len, payload:bits-size(len * 8 - 4)>> = <<4, 1, 2, 3, 4:4>>\n  assert payload == <<1, 2, 3, 4:4>>\n}\n\npub fn pattern_bytes_size_expression_test() {\n  let assert <<len, payload:bytes-size(len / 8 + 2)>> = <<32, 1, 2, 3, 4, 5, 6>>\n  assert payload == <<1, 2, 3, 4, 5, 6>>\n}\n\npub fn pattern_bits_size_with_variable_test() {\n  let additional = 5\n  let assert <<len, payload:bits-size(len + additional * 8)>> = <<\n    8, 1, 2, 3, 4, 5, 6,\n  >>\n  assert payload == <<1, 2, 3, 4, 5, 6>>\n}\n\npub fn pattern_bits_size_block_expression_test() {\n  let assert <<len, payload:bits-size({ len + 1 } * 8)>> = <<3, 1, 2, 3, 4>>\n  assert payload == <<1, 2, 3, 4>>\n}\n\npub fn pattern_negative_size_test() {\n  let result = case <<1, 2, 3, 4>> {\n    <<a, b:size(a - 100_000), _c:size(b)>> -> 1\n    _ -> 2\n  }\n  assert result == 2\n}\n"
  },
  {
    "path": "test/language/test/language/string_pattern_matching_test.gleam",
    "content": "pub fn case_string_prefix_match_test() {\n  let string = \"12345\"\n  let string_2 = case string {\n    \"0\" <> rest -> rest\n    \"123\" <> rest -> rest\n    _ -> \"\"\n  }\n  assert \"45\" == string_2\n}\n\npub fn match_emoji_test() {\n  let string = \"🫥 is neutral dotted\"\n  let string_2 = case string {\n    \"🫥\" <> rest -> rest\n    _ -> panic\n  }\n  assert \" is neutral dotted\" == string_2\n}\n\npub fn match_theta_test() {\n  let string = \"Θ wibble wobble\"\n  let string_2 = case string {\n    \"Θ\" <> rest -> rest\n    _ -> panic\n  }\n  assert \" wibble wobble\" == string_2\n}\n\npub fn match_flag_emoji_test() {\n  let string = \"🇺🇸 is a cluster\"\n  let string_2 = case string {\n    \"🇺🇸\" <> rest -> rest\n    _ -> panic\n  }\n  assert \" is a cluster\" == string_2\n}\n\npub fn match_backslash_test() {\n  let string = \"\\\" is a backslash\"\n  let string_2 = case string {\n    \"\\\"\" <> rest -> rest\n    _ -> panic\n  }\n  assert \" is a backslash\" == string_2\n}\n\npub fn match_newline_test() {\n  let string = \"\\n is a newline\"\n  let string_2 = case string {\n    \"\\n\" <> rest -> rest\n    _ -> panic\n  }\n  assert \" is a newline\" == string_2\n}\n\npub fn match_escaped_newline_test() {\n  let string = \"\\\\n is a newline that escaped\"\n  let string_2 = case string {\n    \"\\\\n\" <> rest -> rest\n    _ -> panic\n  }\n  assert \" is a newline that escaped\" == string_2\n}\n"
  },
  {
    "path": "test/language/test/language/string_test.gleam",
    "content": "pub fn empty_strings_equal_test() {\n  assert \"\" == \"\"\n}\n\npub fn newlines_equal_test() {\n  assert \"\n\" == \"\\n\"\n}\n\npub fn let_assert_string_prefix_test() {\n  let assert \"ab\" <> rest = \"abcdef\"\n  assert \"cdef\" == rest\n}\n"
  },
  {
    "path": "test/language/test/language/tail_call_test.gleam",
    "content": "fn count_down(from i) {\n  case i {\n    0 -> Nil\n    _ -> count_down(i - 1)\n  }\n}\n\nfn tail_recursive_accumulate_down(x, y) {\n  case x {\n    0 -> y\n    _ -> tail_recursive_accumulate_down(x - 1, [x, ..y])\n  }\n}\n\nfn function_shadowed_by_own_argument(function_shadowed_by_own_argument) {\n  function_shadowed_by_own_argument()\n}\n\npub fn ten_million_recursions_doesnt_overflow_the_stack_test() {\n  assert Nil == count_down(from: 10_000_000)\n}\n\n// https://github.com/gleam-lang/gleam/issues/1214\n// https://github.com/gleam-lang/gleam/issues/1380\npub fn arguments_correctly_reassigned_test() {\n  assert [1, 2, 3] == tail_recursive_accumulate_down(3, [])\n}\n\n// https://github.com/gleam-lang/gleam/issues/2400\npub fn function_shadowed_by_own_argument_test() {\n  assert 1 == function_shadowed_by_own_argument(fn() { 1 })\n}\n"
  },
  {
    "path": "test/language/test/language/tuple_access_test.gleam",
    "content": "type ContainsTuple {\n  ContainsTuple(data: #(Int, #(Int, Person)))\n}\n\ntype Person {\n  Person(name: String, age: Int, country: String)\n}\n\n// https://github.com/gleam-lang/gleam/issues/1980\npub fn access_regular_tuple_item_test() {\n  let tup = #(3, 4, 5)\n  let x = tup.0\n  let y = tup.1\n  let z = tup.2\n  assert #(z, y, x) == #(5, 4, 3)\n}\n\npub fn access_nested_tuple_item_test() {\n  let tup = #(#(4, 5), #(6, 7))\n  assert #(tup.0.1, tup.1.1, tup.1.0, tup.0.0) == #(5, 7, 6, 4)\n}\n\npub fn access_deeply_nested_tuple_item_test() {\n  let tup = #(#(5, #(6, 7, #(8))))\n  assert tup.0.1.2.0 == 8\n}\n\npub fn access_nested_struct_in_a_tuple_item_test() {\n  let tup = #(Person(\"Quinn\", 27, \"Canada\"), Person(\"Nikita\", 99, \"Internet\"))\n  assert { tup.0 }.name == \"Quinn\"\n}\n\npub fn access_nested_tuple_in_a_struct_test() {\n  let person = Person(\"Nikita\", 99, \"Internet\")\n  let container = ContainsTuple(#(5, #(6, person)))\n  assert { container.data.1.1 }.name == \"Nikita\"\n}\n\npub fn access_tuple_then_struct_then_tuple_test() {\n  let person = Person(\"Nikita\", 99, \"Internet\")\n  let container = ContainsTuple(#(5, #(6, person)))\n  let tup = #(container)\n  assert { tup.0 }.data.0 == 5\n}\n"
  },
  {
    "path": "test/language/test/language/unaligned_bit_array_expression_test.gleam",
    "content": "pub fn unaligned_1_test() {\n  let left = <<0xFF:6, 0:2>>\n  let right = <<0xFC>>\n  assert left == right\n}\n\npub fn unaligned_2_test() {\n  let left = <<0xFF:6, 0:3, 0x75:9>>\n  let right = <<252, 29, 1:2>>\n  assert left == right\n}\n\npub fn unaligned_3_test() {\n  let left = <<-1:55, 44:11-little, 0x75:9-big>>\n  let right = <<255, 255, 255, 255, 255, 255, 254, 88, 14, 5:3>>\n  assert left == right\n}\n\npub fn unaligned_4_test() {\n  let left = <<0:1, 2:2, 2:3, 1:1>>\n  let right = <<0b0100101:7>>\n  assert left == right\n}\n\npub fn unaligned_5_test() {\n  let left = <<-100:6, -10:32-little, -10:32-big, -100:48-big, -100:48-little>>\n  let right = <<\n    115, 219, 255, 255, 255, 255, 255, 255, 219, 255, 255, 255, 255, 254, 114,\n    115, 255, 255, 255, 255, 63:6,\n  >>\n  assert left == right\n}\n\npub fn unaligned_6_test() {\n  let left = <<2:3, 2.9283123:float-little, -1.375e5:32-float-big>>\n  let right = <<91, 153, 120, 255, 229, 205, 160, 232, 25, 0, 200, 224, 0:3>>\n  assert left == right\n}\n\npub fn unaligned_7_test() {\n  let left = <<\n    7:6,\n    <<1:3>>:bits,\n    <<1, 2, 3>>:bits,\n    1:1,\n    <<-1124.789e4:float-little>>:bits,\n  >>\n  let right = <<28, 128, 129, 1, 192, 0, 0, 16, 8, 157, 25, 112, 1:2>>\n  assert left == right\n}\n\npub fn unaligned_8_test() {\n  let left = <<9_444_732_965_739_289_353_650_176:75>>\n  let right = <<255, 255, 255, 255, 255, 248, 0, 0, 0, 0:size(3)>>\n  assert left == right\n}\n\npub fn unaligned_9_test() {\n  let left = <<0b100101:6>>\n  let right = <<<<0b10010100>>:bits-6>>\n  assert left == right\n}\n\npub fn unaligned_10_test() {\n  let left = <<0xE7>>\n  let right = <<<<0xEC>>:bits-4, 7:4>>\n  assert left == right\n}\n\npub fn unaligned_11_test() {\n  let three = 3\n  let two = 2\n  let left = <<0b11001:5>>\n  let right = <<<<0b11011100>>:bits-size(three), 1:size(two)>>\n  assert left == right\n}\n"
  },
  {
    "path": "test/language/test/language/unaligned_bit_array_pattern_test.gleam",
    "content": "pub fn unaligned_1_test() {\n  let assert <<a:4, b:4, c:3, d:4, e:1>> = <<0xAB, 0b11010101>>\n  assert #(a, b, c, d, e) == #(0xA, 0xB, 0b110, 0b1010, 0b1)\n}\n\npub fn unaligned_2_test() {\n  let assert <<a:12, b:4>> = <<0xB6, 0xE3>>\n  assert #(a, b) == #(0xB6E, 0x03)\n}\n\npub fn unaligned_3_test() {\n  let assert <<a:4, b:12>> = <<0xB6, 0xE3>>\n  assert #(a, b) == #(0x0B, 0x6E3)\n}\n\npub fn unaligned_4_test() {\n  let assert <<a:12-little, b:4>> = <<0xB6, 0xE3>>\n  assert #(a, b) == #(0xEB6, 0x03)\n}\n\npub fn unaligned_5_test() {\n  let assert <<a:4, b:12-little>> = <<0xB6, 0xE3>>\n  assert #(a, b) == #(0x0B, 0x36E)\n}\n\npub fn unaligned_6_test() {\n  let assert <<a:5, b:11>> = <<0xB6, 0xE3>>\n  assert #(a, b) == #(22, 1763)\n}\n\npub fn unaligned_7_test() {\n  let assert <<_:8, a:17>> = <<0xFF, 0xB6, 0xE3, 1:1>>\n  assert a == 93_639\n}\n\npub fn unaligned_8_test() {\n  let assert <<a:17, _:bits>> = <<0xA6, 0xE3, 6:3>>\n  assert a == 85_447\n}\n\npub fn unaligned_9_test() {\n  let assert <<a:17, _:bits>> = <<0xA6, 0xE3, 6:3>>\n  assert a == 85_447\n}\n\npub fn unaligned_10_test() {\n  let assert <<a:7-signed, _:bits>> = <<0b10011010>>\n  assert a == -51\n}\n\npub fn unaligned_11_test() {\n  let assert <<_:5, a:13-big, _:bits>> = <<0xA5, 0x6C, 0xAA>>\n  assert a == 5554\n}\n\npub fn unaligned_12_test() {\n  let assert <<_:5, a:13-little-signed, _:bits>> = <<0xA5, 0x6C, 0xAA>>\n  assert a == -3411\n}\n\npub fn unaligned_13_test() {\n  let assert <<_:3, a:8-big-signed, _:bits>> = <<253, 94>>\n  assert a == -22\n}\n\npub fn unaligned_14_test() {\n  let assert <<_:3, a:12-big-unsigned, _:bits>> = <<233, 164>>\n  assert a == 1234\n}\n\npub fn unaligned_15_test() {\n  let assert <<_:3, a:12-little, _:bits>> = <<250, 72>>\n  assert a == 1234\n}\n\npub fn unaligned_16_test() {\n  let assert <<_:7, a:22, _:bits>> = <<250, 72, 223, 189>>\n  assert a == 596_983\n}\n\npub fn unaligned_17_test() {\n  let assert <<_:1, a:23, _:bits>> = <<146, 192, 70, 25, 1:1>>\n  assert a == 1_228_870\n}\n\npub fn unaligned_18_test() {\n  let assert <<_:1, a:32>> = <<217, 150, 209, 191, 0:1>>\n  assert a == 3_006_112_638\n}\n\npub fn unaligned_19_test() {\n  let assert <<_:1, a:32-signed>> = <<146, 192, 70, 25, 1:1>>\n  assert a == 629_181_491\n}\n\npub fn unaligned_20_test() {\n  let assert <<_:1, a:32-little-unsigned>> = <<251, 24, 47, 227, 1:1>>\n  assert a == 3_344_904_438\n}\n\npub fn unaligned_21_test() {\n  let assert <<a:33-little-unsigned>> = <<240, 102, 91, 101, 1:1>>\n  assert a == 5_995_456_240\n}\n\npub fn unaligned_22_test() {\n  let assert <<a:40-big-signed, _:8>> = <<231, 255, 255, 255, 254, 123>>\n  assert a == -103_079_215_106\n}\n\npub fn unaligned_23_test() {\n  let assert <<_:1, a:54-big-unsigned, _:bits>> = <<\n    0, 231, 255, 255, 253, 123, 17,\n  >>\n  assert a == 127_543_348_739_464\n}\n\npub fn unaligned_24_test() {\n  let assert <<_:8, a:54-little-signed, _:bits>> = <<\n    142, 231, 255, 255, 253, 123, 17, 139,\n  >>\n  assert a == -8_425_025_061_257_241\n}\n\npub fn unaligned_25_test() {\n  let assert <<_:7, a:55-little-signed, _:bits>> = <<\n    142, 231, 255, 255, 253, 123, 17, 139,\n  >>\n  assert a == -8_293_899_692_933_261\n}\n\npub fn unaligned_26_test() {\n  let assert <<_:8, a:40-big-signed, _:8>> = <<\n    142,\n    231,\n    255,\n    255,\n    253,\n    123,\n    17,\n  >>\n  assert a == -103_079_215_749\n}\n\npub fn unaligned_27_test() {\n  let assert <<_:14, a:71-little-signed, _:bits>> = <<\n    250, 72, 223, 189, 41, 97, 165, 0, 0, 0, 0, 177,\n  >>\n  assert a == 70_821_197_049_655\n}\n\npub fn unaligned_28_test() {\n  let assert <<_:14, a:71-big-signed, _:bits>> = <<\n    250, 72, 223, 189, 41, 97, 165, 0, 0, 0, 0, 177,\n  >>\n  assert a == 515_906_807_693_217_628_160\n}\n\npub fn unaligned_29_test() {\n  let assert <<_:11, a:float-32, _:bits>> = <<112, 152, 127, 244, 0, 7, 0:2>>\n  assert a == -511.25\n}\n\npub fn unaligned_30_test() {\n  let assert <<_:7, a:float-little, _:bits>> = <<\n    8, 0, 0, 0, 1, 129, 39, 103, 129, 127:7,\n  >>\n  assert a == -5011.75\n}\n\npub fn unaligned_31_test() {\n  let assert <<a:bits-7, b:bits-3>> = <<0b11001011, 0b01:2>>\n  assert #(a, b) == #(<<0b1100101:7>>, <<0b101:3>>)\n}\n\npub fn unaligned_32_test() {\n  let assert <<a:bits-16, b:bits-13, c:bits-11, d:bits-24>> = <<\n    0x47, 0x9A, 0x25, 0x0C, 0xDA, 0xF1, 0xEE, 0x31,\n  >>\n  assert #(a, b, c, d)\n    == #(<<71, 154>>, <<37, 1:5>>, <<155, 2:3>>, <<0xF1, 0xEE, 0x31>>)\n}\n\npub fn unaligned_33_test() {\n  let assert <<a:bits-3, b:bytes-2, c:bytes>> = <<\n    0b110:3, 0x12, 0xAB, 0x95, 0xFE,\n  >>\n  assert #(a, b, c) == #(<<0b110:3>>, <<0x12, 0xAB>>, <<0x95, 0xFE>>)\n}\n\npub fn unaligned_34_test() {\n  let result = case <<0x12, 0xAB, 0x95, 0xFE>> {\n    <<0x34, _:5, _:bytes>> -> True\n    _ -> False\n  }\n  assert result == False\n}\n"
  },
  {
    "path": "test/language/test/language_test.gleam",
    "content": "import gleeunit\n\npub fn main() {\n  gleeunit.main()\n}\n"
  },
  {
    "path": "test/language/test/mod_with_numbers_0123456789.gleam",
    "content": "pub fn hello() {\n  \"world\"\n}\n"
  },
  {
    "path": "test/language/test/port.gleam",
    "content": "pub type Port\n"
  },
  {
    "path": "test/language/test/record_update.gleam",
    "content": "pub type Box(a) {\n  Box(tag: String, value: a)\n}\n"
  },
  {
    "path": "test/language/test/shadowed_module.gleam",
    "content": "pub type ShadowPerson {\n  ShadowPerson(age: Int)\n}\n\npub fn celebrate_birthday(person: ShadowPerson) -> ShadowPerson {\n  ShadowPerson(age: person.age + 1)\n}\n"
  },
  {
    "path": "test/multi_namespace/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/multi_namespace/README.md",
    "content": "# Multi namespace project\n\nshould not be published!\n"
  },
  {
    "path": "test/multi_namespace/gleam.toml",
    "content": "name = \"multi_namespace\"\nversion = \"1.0.0\"\ndescription = \"Test project for multi namespace\"\nlicences = [\"Apache-2.0\"]\n"
  },
  {
    "path": "test/multi_namespace/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n]\n\n[requirements]\n"
  },
  {
    "path": "test/multi_namespace/src/multi_namespace.gleam",
    "content": "pub fn main() {\n  \"Hello from multi_namespace!\"\n}\n"
  },
  {
    "path": "test/multi_namespace/src/second.gleam",
    "content": "pub fn main() {\n  \"Hello from second!\"\n}\n"
  },
  {
    "path": "test/multi_namespace/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n\techo \"Running: $GLEAM_COMMAND $@\"\n\t$GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Running publish should not publish anything\noutput=$(yes \"n\" | g publish)\nif echo \"$output\" | grep -q \"Your package defines multiple top-level modules\"; then\n    echo \"Publish was correctly prevented with warning\"\nelse\n    echo \"Expected publish to be aborted\"\n    exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/multi_namespace_not_top_level/.gitignore",
    "content": "*.beam\n*.ez\nbuild\nmanifest.toml\n"
  },
  {
    "path": "test/multi_namespace_not_top_level/README.md",
    "content": "# Multi namespace project\n\nshould not be published!\n"
  },
  {
    "path": "test/multi_namespace_not_top_level/gleam.toml",
    "content": "name = \"multi_namespace\"\nversion = \"1.0.0\"\ndescription = \"Test project for multi namespace\"\nlicences = [\"Apache-2.0\"]\n"
  },
  {
    "path": "test/multi_namespace_not_top_level/src/module1/sub.gleam",
    "content": "pub fn main() {\n  \"Hello from multi_namespace!\"\n}\n"
  },
  {
    "path": "test/multi_namespace_not_top_level/src/module2/sub.gleam",
    "content": "pub fn main() {\n  \"Hello from second!\"\n}\n"
  },
  {
    "path": "test/multi_namespace_not_top_level/test.sh",
    "content": "#!/bin/sh\n\n# https://github.com/gleam-lang/gleam/pull/4445\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n\techo \"Running: $GLEAM_COMMAND $@\"\n\t$GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Running publish should not print the warning\noutput=$(yes \"n\" | g publish)\nif echo \"$output\" | grep -q \"Your package defines multiple top-level modules\"; then\n    echo \"Expected warning to be printed\"\n    exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/package.jsonc",
    "content": "// An idea for how generated docs could contain information on modules within\n// the package in a machine readable format.\n{\n  \"publishing-gleam-version\": \"0.20.0\",\n  \"name\": \"my_package\",\n  \"modules\": {\n    \"my_module\": {\n      \"documentation\": \"...\",\n      \"types\": {\n        // pub type MyType1 { One Two(String) }\n        \"MyType1\": {\n          \"documentation\": \"...\",\n          \"parameters\": 0,\n          \"constructors\": [\"One\", \"Two\"]\n        },\n        // pub type MyType2\n        \"MyType2\": {\n          \"documentation\": \"...\",\n          \"parameters\": 0,\n          \"constructors\": []\n        },\n        // pub type MyType3(a) { One(a, Int) }\n        \"MyType3\": {\n          \"documentation\": \"...\",\n          \"parameters\": 1,\n          \"constructors\": [\"One\"]\n        },\n        // pub type MyType4(a, b)\n        \"MyType4\": {\n          \"documentation\": \"...\",\n          \"parameters\": 2,\n          \"constructors\": []\n        },\n        // pub opaque type MyType5(a, b) { One Two }\n        \"MyType5\": {\n          \"documentation\": \"...\",\n          \"parameters\": 2,\n          \"constructors\": []\n        }\n      },\n      \"values\": {\n        // pub const nil_constant = Nil\n        \"nil_constant\": {\n          \"documentation\": \"...\",\n          \"type\": { \"kind\": \"Nil\" }\n        },\n        // pub const tuple_constant = #(1, \"2\", 3.0)\n        \"tuple_constant\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Tuple\",\n            \"elements\": [\n              { \"kind\": \"Int\" },\n              { \"kind\": \"String\" },\n              { \"kind\": \"Float\" }\n            ]\n          }\n        },\n        // pub const ok_constant = Ok(1)\n        \"ok_constant\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Result\",\n            \"ok\": { \"kind\": \"Int\" },\n            \"error\": { \"kind\": \"Variable\", \"id\": 0 }\n          }\n        },\n        // pub const error_constant = Error(Nil)\n        \"error_constant\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Result\",\n            \"ok\": { \"kind\": \"Nil\" },\n            \"error\": { \"kind\": \"Variable\", \"id\": 0 }\n          }\n        },\n        // pub const empty_list_constant = []\n        \"empty_list_constant\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"List\",\n            \"elements\": { \"kind\": \"Variable\", \"id\": 0 }\n          }\n        },\n        // pub const int_list_constant = [1, 2, 3]\n        \"int_list_constant\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"List\",\n            \"elements\": { \"kind\": \"Int\" }\n          }\n        },\n        // pub type Wibble { Wobble(String) }\n        // pub const custom_type_constant1 = Wobble(\"Hi\")\n        \"custom_type_constant1\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Named\",\n            \"package\": \"my_package\",\n            \"module\": \"my_module\",\n            \"parameters\": []\n          }\n        },\n        // pub type Blip(a) { Blap(a) }\n        // pub const custom_type_constant2 = Blap(1)\n        \"custom_type_constant2\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Named\",\n            \"package\": \"my_package\",\n            \"module\": \"my_module\",\n            \"parameters\": [\n              { \"kind\": \"Int\" }\n            ]\n          }\n        },\n        // import some/module\n        // pub const imported_custom_type: module.Something = module.SomethingConstructor\n        \"imported_custom_type\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Named\",\n            \"package\": \"other_package\",\n            \"module\": \"some/module\",\n            \"parameters\": []\n          }\n        },\n        // pub fn main() -> Nil { ... }\n        \"main\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Fn\",\n            \"parameters\": [],\n            \"return\": { \"kind\": \"Nil\" }\n          }\n        },\n        // pub fn multiply(x: Int, x: Int) -> Int { ... }\n        \"multiply\": {\n          \"documentation\": \"...\",\n          \"type\": {\n            \"kind\": \"Fn\",\n            \"parameters\": [\n              { \"kind\": \"Int\" },\n              { \"kind\": \"Int\" }\n            ],\n            \"return\": { \"kind\": \"Int\" }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "test/project_deno/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/project_deno/README.md",
    "content": "# Project\n\nA test Gleam project using the Deno runtime.\n\nIt covers these features:\n\n- Deno runtime specific configuration, including\n  - `location` - used to configure [`--location`](https://docs.deno.com/runtime/manual/runtime/location_api) flag which sets the [`location`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) global from the web.\n\n## Quick start\n\n```sh\ngleam run\ngleam test\n```\n"
  },
  {
    "path": "test/project_deno/gleam.toml",
    "content": "name = \"project\"\nversion = \"0.1.0\"\ntarget = \"javascript\"\n\n[javascript]\ntypescript_declarations = true\nruntime = \"deno\"\n\n[javascript.deno]\nlocation = \"http://localhost:8080\"\n\n[dependencies]\ngleam_stdlib = \"~> 0.18\"\ngleam_erlang = \"~> 0.23\"\n\n[dev_dependencies]\n"
  },
  {
    "path": "test/project_deno/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_erlang\", version = \"0.24.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_erlang\", source = \"hex\", outer_checksum = \"26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0\" },\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n]\n\n[requirements]\ngleam_erlang = { version = \"~> 0.23\" }\ngleam_stdlib = { version = \"~> 0.18\" }\n"
  },
  {
    "path": "test/project_deno/src/project.gleam",
    "content": "pub type Location {\n  Location(\n    href: String,\n    origin: String,\n    protocol: String,\n    host: String,\n    hostname: String,\n    port: String,\n    pathname: String,\n    search: String,\n    hash: String,\n  )\n}\n\npub fn main() {\n  location()\n}\n\n@external(javascript, \"./project_ffi.mjs\", \"location\")\nfn location() -> Location\n"
  },
  {
    "path": "test/project_deno/src/project_ffi.mjs",
    "content": "export function location() {\n  return globalThis.location;\n}\n"
  },
  {
    "path": "test/project_deno/test/project_test.gleam",
    "content": "import project\n\npub fn main() {\n  let location = project.main()\n  let assert \"http://localhost:8080/\" = location.href\n  let assert \"http://localhost:8080\" = location.origin\n  let assert \"http:\" = location.protocol\n  let assert \"localhost:8080\" = location.host\n  let assert \"localhost\" = location.hostname\n  let assert \"8080\" = location.port\n  let assert \"/\" = location.pathname\n  let assert \"\" = location.search\n  let assert \"\" = location.hash\n}\n"
  },
  {
    "path": "test/project_erlang/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/project_erlang/README.md",
    "content": "# Project\n\nA test Gleam project.\n\nIt covers these features:\n\n- Downloading packages\n  - Specified in config.dependencies\n  - Specified in config.dev_dependencies\n- Importing packages\n  - Specified in config.dependencies\n  - Specified in config.dev_dependencies\n- Compilation of Gleam code\n  - in src\n  - in test\n- Compilation of locally defined Erlang modules\n  - in src\n  - in test\n- Importing of Erlang header files\n  - in src\n  - in test\n- Importing Gleam src code into test\n\n## Quick start\n\n```sh\ngleam run\ngleam test\n```\n"
  },
  {
    "path": "test/project_erlang/gleam.toml",
    "content": "name = \"project\"\nversion = \"0.1.0\"\n\n[dependencies]\n# These are Gleam deps\ngleam_stdlib = \"~> 0.18\"\ngleam_erlang = \"~> 0.5\"\n\n# This is a rebar3 dep that uses files in ./priv\ncertifi = \"~> 2.8\"\n# This is a rebar3 dep that uses files in ./ebin\ncowboy = \"~> 2.9\"\n# This is a mix dep that uses files in ./priv\ncountries = \"~> 1.6\"\n\n# This is both a mix and a rebar3 dep!\n# We want to default to using rebar3 as that is the build tool that is more\n# likely to be installed.\nssl_verify_fun = \"~> 1.1\"\n\n# This is a rebar3 dep that calls make to compile C into a .so file that is\n# loaded at runtime from ./priv\n# TODO: replace this with a package with a nif that compiles super fast. Perhaps\n# just a hello world.\nbcrypt = \"~> 1.1\"\n# This is a rebar3 dep that output files in $REBAR_BARE_COMPILER_OUTPUT_DIR/priv\n# and requires absolute paths\nezstd = \"~> 1.1\"\n\n# This is a rebar3 dep where the application name (hpack, used by the BEAM)\n# doesn't match the package name (hpack_erl, used by Hex).\nhpack_erl = \"~> 0.1\"\ngleam_javascript = \"~> 0.7\"\n\n[dev_dependencies]\ngleeunit = \"~> 1.0\"\n"
  },
  {
    "path": "test/project_erlang/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"bcrypt\", version = \"1.2.1\", build_tools = [\"rebar3\"], requirements = [\"poolboy\"], otp_app = \"bcrypt\", source = \"hex\", outer_checksum = \"DC4973B57C0F76C86D5275C8056E12878BB5526876481EC799D015A7B19515B6\" },\n  { name = \"certifi\", version = \"2.12.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"certifi\", source = \"hex\", outer_checksum = \"EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C\" },\n  { name = \"countries\", version = \"1.6.0\", build_tools = [\"mix\"], requirements = [\"yamerl\"], otp_app = \"countries\", source = \"hex\", outer_checksum = \"A1E4D0FDD2A799F16A95AE2E842EDEAABD9AC7639624AC5E139C54DA7A6BCCB0\" },\n  { name = \"cowboy\", version = \"2.10.0\", build_tools = [\"make\", \"rebar3\"], requirements = [\"cowlib\", \"ranch\"], otp_app = \"cowboy\", source = \"hex\", outer_checksum = \"3AFDCCB7183CC6F143CB14D3CF51FA00E53DB9EC80CDCD525482F5E99BC41D6B\" },\n  { name = \"cowlib\", version = \"2.12.1\", build_tools = [\"make\", \"rebar3\"], requirements = [], otp_app = \"cowlib\", source = \"hex\", outer_checksum = \"163B73F6367A7341B33C794C4E88E7DBFE6498AC42DCD69EF44C5BC5507C8DB0\" },\n  { name = \"ezstd\", version = \"1.1.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"ezstd\", source = \"hex\", outer_checksum = \"28CFA0ED6CC3922095AD5BA0F23392A1664273358B17184BAA909868361184E7\" },\n  { name = \"gleam_erlang\", version = \"0.24.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_erlang\", source = \"hex\", outer_checksum = \"26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0\" },\n  { name = \"gleam_javascript\", version = \"0.7.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_javascript\", source = \"hex\", outer_checksum = \"EEA30D1ABF62B06FC378764D598DF041303CFA33A6586BFF4C4BFEFFA83DBDBE\" },\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n  { name = \"gleeunit\", version = \"1.0.2\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D\" },\n  { name = \"hpack_erl\", version = \"0.3.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"hpack\", source = \"hex\", outer_checksum = \"D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0\" },\n  { name = \"poolboy\", version = \"1.5.2\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"poolboy\", source = \"hex\", outer_checksum = \"DAD79704CE5440F3D5A3681C8590B9DC25D1A561E8F5A9C995281012860901E3\" },\n  { name = \"ranch\", version = \"1.8.0\", build_tools = [\"make\", \"rebar3\"], requirements = [], otp_app = \"ranch\", source = \"hex\", outer_checksum = \"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5\" },\n  { name = \"ssl_verify_fun\", version = \"1.1.7\", build_tools = [\"mix\", \"rebar3\", \"make\"], requirements = [], otp_app = \"ssl_verify_fun\", source = \"hex\", outer_checksum = \"FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8\" },\n  { name = \"yamerl\", version = \"0.10.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"yamerl\", source = \"hex\", outer_checksum = \"346ADB2963F1051DC837A2364E4ACF6EB7D80097C0F53CBDC3046EC8EC4B4E6E\" },\n]\n\n[requirements]\nbcrypt = { version = \"~> 1.1\" }\ncertifi = { version = \"~> 2.8\" }\ncountries = { version = \"~> 1.6\" }\ncowboy = { version = \"~> 2.9\" }\nezstd = { version = \"~> 1.1\" }\ngleam_erlang = { version = \"~> 0.5\" }\ngleam_javascript = { version = \"~> 0.7\" }\ngleam_stdlib = { version = \"~> 0.18\" }\ngleeunit = { version = \"~> 1.0\" }\nhpack_erl = { version = \"~> 0.1\" }\nssl_verify_fun = { version = \"~> 1.1\" }\n"
  },
  {
    "path": "test/project_erlang/priv/hello.txt",
    "content": "Hello, Joe!\n"
  },
  {
    "path": "test/project_erlang/src/elixir_file.ex",
    "content": "defmodule ElixirFile do\n  def main() do\n    \"Hello, from the Elixir module!\"\n  end\nend\n\ndefmodule ElixirFileAgain do\n  def main() do\n    \"Hello, from another Elixir module!\"\n  end\nend\n"
  },
  {
    "path": "test/project_erlang/src/erlang_file.erl",
    "content": "-module(erlang_file).\n\n-export([main/0]).\n\n-include(\"erlang_header.hrl\").\n\nmain() ->\n  String = header_function(),\n  <<\"Hello, from the Erlang module!\\n\"/utf8, String/binary>>.\n"
  },
  {
    "path": "test/project_erlang/src/erlang_header.hrl",
    "content": "header_function() ->\n  <<\"Hello, from the Erlang header!\">>.\n"
  },
  {
    "path": "test/project_erlang/src/project.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello, from Gleam compiled to Erlang!\")\n  io.println(erlang_function())\n  io.println(elixir_function())\n  io.println(another_elixir_function())\n}\n\n@external(erlang, \"erlang_file\", \"main\")\nfn erlang_function() -> String\n\n@external(erlang, \"Elixir.ElixirFile\", \"main\")\nfn elixir_function() -> String\n\n@external(erlang, \"Elixir.ElixirFileAgain\", \"main\")\nfn another_elixir_function() -> String\n"
  },
  {
    "path": "test/project_erlang/test/elixir_test_file.ex",
    "content": "defmodule ElixirTestFile do\n  def main() do\n    \"Hello, from the Elixir test module!\"\n  end\nend\n"
  },
  {
    "path": "test/project_erlang/test/erlang_test_file.erl",
    "content": "-module(erlang_test_file).\n\n-export([main/0]).\n\n-include(\"erlang_test_header.hrl\").\n\nmain() ->\n  String = header_function(),\n  <<\"Hello, from the Erlang test module!\\n\"/utf8, String/binary>>.\n"
  },
  {
    "path": "test/project_erlang/test/erlang_test_header.hrl",
    "content": "header_function() ->\n  <<\"Hello, from the Erlang test header!\">>.\n"
  },
  {
    "path": "test/project_erlang/test/project_test.gleam",
    "content": "import gleam/io\nimport gleam/dynamic.{type Dynamic}\nimport project\nimport gleeunit\nimport gleam/erlang/atom.{from_string as atom_from_string}\n\npub fn main() {\n  project.main()\n  io.println(\"Hello, from the Gleam test module!\")\n  io.println(erlang_function())\n  io.println(elixir_function())\n  gleeunit.main()\n}\n\npub fn rebar3_dep_function_test() {\n  io.println(\"Testing calling a rebar3 library (that uses headers)\")\n  rebar3_dep_function()\n}\n\npub fn mix_dep_function_test() {\n  io.println(\"Testing calling a mix library\")\n  mix_dep_function()\n}\n\n@external(erlang, \"erlang_test_file\", \"main\")\nfn erlang_function() -> String\n\n@external(erlang, \"certifi\", \"cacertfile\")\nfn rebar3_dep_function() -> Dynamic\n\n@external(erlang, \"Elixir.ElixirTestFile\", \"main\")\nfn elixir_function() -> String\n\n@external(erlang, \"Elixir.Countries\", \"all\")\nfn mix_dep_function() -> Dynamic\n\n// Testing for this bug in metadata encoding.\n// https://github.com/gleam-lang/gleam/commit/c8f3bd0ddbf61c27ea35f37297058ecca7515f6c\npub fn name_test() {\n  let assert True = atom.from_string(\"ok\") == atom_from_string(\"ok\")\n}\n"
  },
  {
    "path": "test/project_erlang_windows/.gitignore",
    "content": "*.beam\n*.ez\nbuild\nerl_crash.dump\n"
  },
  {
    "path": "test/project_erlang_windows/gleam.toml",
    "content": "name = \"project\"\nversion = \"0.1.0\"\n\n[dependencies]\n# These are Gleam deps\ngleam_stdlib = \"~> 0.32\"\ngleam_erlang = \"~> 0.23\"\n\n# This is a rebar3 dep that uses files in ./priv\ncertifi = \"~> 2.12\"\n# This is a rebar3 dep that uses files in ./ebin\ncowboy = \"~> 2.10\"\n# This is a mix dep that uses files in ./priv\ncountries = \"~> 1.6\"\n\n[dev_dependencies]\ngleeunit = \"~> 1.0\"\n"
  },
  {
    "path": "test/project_erlang_windows/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"certifi\", version = \"2.12.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"certifi\", source = \"hex\", outer_checksum = \"EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C\" },\n  { name = \"countries\", version = \"1.6.0\", build_tools = [\"mix\"], requirements = [\"yamerl\"], otp_app = \"countries\", source = \"hex\", outer_checksum = \"A1E4D0FDD2A799F16A95AE2E842EDEAABD9AC7639624AC5E139C54DA7A6BCCB0\" },\n  { name = \"cowboy\", version = \"2.10.0\", build_tools = [\"make\", \"rebar3\"], requirements = [\"ranch\", \"cowlib\"], otp_app = \"cowboy\", source = \"hex\", outer_checksum = \"3AFDCCB7183CC6F143CB14D3CF51FA00E53DB9EC80CDCD525482F5E99BC41D6B\" },\n  { name = \"cowlib\", version = \"2.12.1\", build_tools = [\"make\", \"rebar3\"], requirements = [], otp_app = \"cowlib\", source = \"hex\", outer_checksum = \"163B73F6367A7341B33C794C4E88E7DBFE6498AC42DCD69EF44C5BC5507C8DB0\" },\n  { name = \"gleam_erlang\", version = \"0.24.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_erlang\", source = \"hex\", outer_checksum = \"26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0\" },\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n  { name = \"gleeunit\", version = \"1.0.2\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D\" },\n  { name = \"ranch\", version = \"1.8.0\", build_tools = [\"make\", \"rebar3\"], requirements = [], otp_app = \"ranch\", source = \"hex\", outer_checksum = \"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5\" },\n  { name = \"yamerl\", version = \"0.10.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"yamerl\", source = \"hex\", outer_checksum = \"346ADB2963F1051DC837A2364E4ACF6EB7D80097C0F53CBDC3046EC8EC4B4E6E\" },\n]\n\n[requirements]\ncertifi = { version = \"~> 2.12\" }\ncountries = { version = \"~> 1.6\" }\ncowboy = { version = \"~> 2.10\" }\ngleam_erlang = { version = \"~> 0.23\" }\ngleam_stdlib = { version = \"~> 0.32\" }\ngleeunit = { version = \"~> 1.0\" }\n"
  },
  {
    "path": "test/project_erlang_windows/priv/hello.txt",
    "content": "Hello, Joe!\n"
  },
  {
    "path": "test/project_erlang_windows/src/elixir_file.ex",
    "content": "defmodule ElixirFile do\n  def main() do\n    \"Hello, from the Elixir module!\"\n  end\nend\n\ndefmodule ElixirFileAgain do\n  def main() do\n    \"Hello, from another Elixir module!\"\n  end\nend\n"
  },
  {
    "path": "test/project_erlang_windows/src/erlang_file.erl",
    "content": "-module(erlang_file).\n\n-export([main/0]).\n\n-include(\"erlang_header.hrl\").\n\nmain() ->\n  String = header_function(),\n  <<\"Hello, from the Erlang module!\\n\"/utf8, String/binary>>.\n"
  },
  {
    "path": "test/project_erlang_windows/src/erlang_header.hrl",
    "content": "header_function() ->\n  <<\"Hello, from the Erlang header!\">>.\n"
  },
  {
    "path": "test/project_erlang_windows/src/project.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello, from Gleam compiled to Erlang!\")\n  io.println(erlang_function())\n  io.println(elixir_function())\n  io.println(another_elixir_function())\n}\n\n@external(erlang, \"erlang_file\", \"main\")\nfn erlang_function() -> String\n\n@external(erlang, \"Elixir.ElixirFile\", \"main\")\nfn elixir_function() -> String\n\n@external(erlang, \"Elixir.ElixirFileAgain\", \"main\")\nfn another_elixir_function() -> String\n"
  },
  {
    "path": "test/project_erlang_windows/test/elixir_test_file.ex",
    "content": "defmodule ElixirTestFile do\n  def main() do\n    \"Hello, from the Elixir test module!\"\n  end\nend\n"
  },
  {
    "path": "test/project_erlang_windows/test/erlang_test_file.erl",
    "content": "-module(erlang_test_file).\n\n-export([main/0]).\n\n-include(\"erlang_test_header.hrl\").\n\nmain() ->\n  String = header_function(),\n  <<\"Hello, from the Erlang test module!\\n\"/utf8, String/binary>>.\n"
  },
  {
    "path": "test/project_erlang_windows/test/erlang_test_header.hrl",
    "content": "header_function() ->\n  <<\"Hello, from the Erlang test header!\">>.\n"
  },
  {
    "path": "test/project_erlang_windows/test/project_test.gleam",
    "content": "import gleam/io\nimport gleam/dynamic.{type Dynamic}\nimport project\nimport gleeunit\nimport gleam/erlang/atom.{from_string as atom_from_string}\n\npub fn main() {\n  project.main()\n  io.println(\"Hello, from the Gleam test module!\")\n  io.println(erlang_function())\n  io.println(elixir_function())\n  gleeunit.main()\n}\n\npub fn rebar3_dep_function_test() {\n  io.println(\"Testing calling a rebar3 library (that uses headers)\")\n  rebar3_dep_function()\n}\n\npub fn mix_dep_function_test() {\n  io.println(\"Testing calling a mix library\")\n  mix_dep_function()\n}\n\n@external(erlang, \"erlang_test_file\", \"main\")\nfn erlang_function() -> String\n\n@external(erlang, \"certifi\", \"cacertfile\")\nfn rebar3_dep_function() -> Dynamic\n\n@external(erlang, \"Elixir.ElixirTestFile\", \"main\")\nfn elixir_function() -> String\n\n@external(erlang, \"Elixir.Countries\", \"all\")\nfn mix_dep_function() -> Dynamic\n\n// Testing for this bug in metadata encoding.\n// https://github.com/gleam-lang/gleam/commit/c8f3bd0ddbf61c27ea35f37297058ecca7515f6c\npub fn name_test() {\n  let assert True = atom.from_string(\"ok\") == atom_from_string(\"ok\")\n}\n"
  },
  {
    "path": "test/project_git_deps/.gitignore",
    "content": "build\n"
  },
  {
    "path": "test/project_git_deps/gleam.toml",
    "content": "name = \"git_deps\"\nversion = \"0.1.0\"\ndescription = \"Test project to test git dependencies\"\nlicences = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = { git = \"https://github.com/gleam-lang/stdlib.git\", ref = \"957b83b\" }\n"
  },
  {
    "path": "test/project_git_deps/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.54.0\", build_tools = [\"gleam\"], requirements = [], source = \"git\", repo = \"https://github.com/gleam-lang/stdlib.git\", commit = \"957b83bbb6103aa0d96c148ce7409243681cf1ab\" },\n]\n\n[requirements]\ngleam_stdlib = { git = \"https://github.com/gleam-lang/stdlib.git\", ref = \"957b83b\" }\n"
  },
  {
    "path": "test/project_git_deps/src/git_deps.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  // gleam/io is provided via a git dependency\n  io.println(\"Hello, world!\")\n}\n"
  },
  {
    "path": "test/project_javascript/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/project_javascript/README.md",
    "content": "# Project\n\nA test Gleam project.\n\nIt covers these features:\n\n- Downloading packages\n  - Specified in config.dependencies\n- Importing packages\n  - Specified in config.dependencies\n- Compilation of Gleam code\n  - in src\n  - in test\n- Importing Gleam src code into test\n\nThese features are not tested yet\n\n- Downloading packages\n  - Specified in config.dev_dependencies\n- Importing packages\n  - Specified in config.dev_dependencies\n- Compilation of locally defined JavaScript modules\n  - in src\n  - in test\n- Importing Gleam src code into test\n\n## Quick start\n\n```sh\ngleam run\ngleam test\n```\n"
  },
  {
    "path": "test/project_javascript/gleam.toml",
    "content": "name = \"project\"\nversion = \"0.1.0\"\ntarget = \"javascript\"\n\n[javascript]\ntypescript_declarations = true\nruntime = \"node\"\n\n[dependencies]\ngleam_stdlib = \"~> 0.18\"\ngleam_erlang = \"~> 0.23\"\n\n[dev_dependencies]\n"
  },
  {
    "path": "test/project_javascript/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_erlang\", version = \"0.24.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_erlang\", source = \"hex\", outer_checksum = \"26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0\" },\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n]\n\n[requirements]\ngleam_erlang = { version = \"~> 0.23\" }\ngleam_stdlib = { version = \"~> 0.18\" }\n"
  },
  {
    "path": "test/project_javascript/src/project.gleam",
    "content": "pub fn main() {\n  println(\"Hello, from project_javascript!\")\n}\n\n@external(erlang, \"erlang\", \"display\")\n@external(javascript, \"./project_ffi.mjs\", \"log\")\nfn println(a: String) -> Nil\n"
  },
  {
    "path": "test/project_javascript/src/project_ffi.mjs",
    "content": "export function log(x) {\n  console.log(x);\n}\n"
  },
  {
    "path": "test/project_javascript/test/project_test.gleam",
    "content": "import project\n\npub fn main() {\n  project.main()\n}\n"
  },
  {
    "path": "test/project_path_deps/.gitignore",
    "content": "*.beam\n*.ez\nbuild\nerl_crash.dump\n"
  },
  {
    "path": "test/project_path_deps/README.md",
    "content": "This directory contains four projects used in CI test `test/project_path_deps`.\n\nThe dependency graph of these projects is as follows:\n\n```\n         _-> project_b -_\n        /                v\nproject_a                project_d\n        \\                ^\n         '-> project_c -'\n```\n\n"
  },
  {
    "path": "test/project_path_deps/project_a/gleam.toml",
    "content": "name = \"project_a\"\nversion = \"0.1.0\"\n\n[dependencies]\nproject_b = { path = \"../project_b\" }\nproject_c = { path = \"../project_c\" }\n\n[dev_dependencies]\ngleeunit = \"~> 1.0\"\n"
  },
  {
    "path": "test/project_path_deps/project_a/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.34.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016\" },\n  { name = \"gleeunit\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"D3682ED8C5F9CAE1C928F2506DE91625588CC752495988CBE0F5653A42A6F334\" },\n  { name = \"project_b\", version = \"0.1.0\", build_tools = [\"gleam\"], requirements = [\"project_d\"], source = \"local\", path = \"../project_b\" },\n  { name = \"project_c\", version = \"0.1.0\", build_tools = [\"gleam\"], requirements = [\"project_b\"], source = \"local\", path = \"../project_c\" },\n  { name = \"project_d\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [], source = \"local\", path = \"../project_d\" },\n]\n\n[requirements]\ngleeunit = { version = \"~> 1.0\" }\nproject_b = { path = \"../project_b\" }\nproject_c = { path = \"../project_c\" }\n"
  },
  {
    "path": "test/project_path_deps/project_a/src/project_a.gleam",
    "content": "import project_b\nimport project_c\n\npub type TypeA {\n  VariantB(project_b.TypeB)\n  VariantC(project_c.TypeC)\n}\n\npub fn main() {\n  let _ = VariantB(project_b.new(\"thing\", \"name\"))\n  let _ = VariantC(project_c.new(\"thing\"))\n}\n"
  },
  {
    "path": "test/project_path_deps/project_a/test/project_a_test.gleam",
    "content": "import gleeunit\nimport gleeunit/should\n\npub fn main() {\n  gleeunit.main()\n}\n\n// gleeunit test functions end in `_test`\npub fn hello_world_test() {\n  1\n  |> should.equal(1)\n}\n"
  },
  {
    "path": "test/project_path_deps/project_b/gleam.toml",
    "content": "name = \"project_b\"\nversion = \"0.1.0\"\ndescription = \"A Gleam project\"\n\n[dependencies]\nproject_d = { path = \"../project_d\" }\n"
  },
  {
    "path": "test/project_path_deps/project_b/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"project_d\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [], source = \"local\", path = \"../project_d\" },\n]\n\n[requirements]\nproject_d = { path = \"../project_d\" }\n"
  },
  {
    "path": "test/project_path_deps/project_b/src/project_b.gleam",
    "content": "import project_d\n\npub type TypeB {\n  ConstructorB(contained: project_d.TypeD, name: String)\n}\n\npub fn new(contained, name) {\n  ConstructorB(project_d.ConstructorD(contained), name)\n}\n"
  },
  {
    "path": "test/project_path_deps/project_c/gleam.toml",
    "content": "name = \"project_c\"\nversion = \"0.1.0\"\n\n[dependencies]\nproject_b = { path = \"../project_b\" }\n"
  },
  {
    "path": "test/project_path_deps/project_c/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"project_b\", version = \"0.1.0\", build_tools = [\"gleam\"], requirements = [\"project_d\"], source = \"local\", path = \"../project_b\" },\n  { name = \"project_d\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [], source = \"local\", path = \"../project_d\" },\n]\n\n[requirements]\nproject_b = { path = \"../project_b\" }\n"
  },
  {
    "path": "test/project_path_deps/project_c/src/project_c.gleam",
    "content": "import project_d\n\npub type TypeC {\n  ConstructorC(project_d.TypeD)\n}\n\npub fn new(str) {\n  ConstructorC(project_d.ConstructorD(str))\n}\n"
  },
  {
    "path": "test/project_path_deps/project_d/gleam.toml",
    "content": "name = \"project_d\"\nversion = \"1.0.0\"\n\n[dev_dependencies]\n# This dependency is not used by any of the other packages in this project, and\n# it is is only used by this package in dev mode, so it will not be in the other\n# packages at all.\n# The test file for this package imports this dep, so if there is a bug in the\n# build tool and it attempts to compile the test deps for a path dep it will\n# fail.\ngleam_bitwise = \"~> 1.2\"\n"
  },
  {
    "path": "test/project_path_deps/project_d/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_bitwise\", version = \"1.3.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_bitwise\", source = \"hex\", outer_checksum = \"B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC\" },\n]\n\n[requirements]\ngleam_bitwise = { version = \"~> 1.2\" }\n"
  },
  {
    "path": "test/project_path_deps/project_d/src/project_d.gleam",
    "content": "pub type TypeD {\n  ConstructorD(String)\n}\n"
  },
  {
    "path": "test/project_path_deps/project_d/test/project_d_test.gleam",
    "content": "import gleam/bitwise\n\npub fn main() {\n  bitwise.and(1, 2)\n}\n"
  },
  {
    "path": "test/publishing_default_main/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/publishing_default_main/gleam.toml",
    "content": "name = \"default_main\"\nversion = \"1.0.0\"\ndescription = \"Test project for default main\"\nlicences = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = \">= 0.44.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/publishing_default_main/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.62.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.44.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/publishing_default_main/src/default_main/one.gleam",
    "content": "pub fn one() {\n  \"hello from one!\"\n}\n"
  },
  {
    "path": "test/publishing_default_main/src/default_main/two.gleam",
    "content": "pub fn two() {\n  \"hello from two!\"\n}\n"
  },
  {
    "path": "test/publishing_default_main/src/default_main.gleam",
    "content": "import gleam/io\n\npub fn main() -> Nil {\n  io.println(\"Hello from default_main!\")\n}\n"
  },
  {
    "path": "test/publishing_default_main/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Running publish should not publish anything\nif yes \"n\" | g publish; then\n  echo \"Expected publish to fail, but it succeeded\"\n  exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/publishing_default_readme/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/publishing_default_readme/README.md",
    "content": "# default_readme\n\n[![Package Version](https://img.shields.io/hexpm/v/default_readme)](https://hex.pm/packages/default_readme)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/default_readme/)\n\n```sh\ngleam add default_readme@1\n```\n```gleam\nimport default_readme\n\npub fn main() -> Nil {\n  // TODO: An example of the project in use\n}\n```\n\nFurther documentation can be found at <https://hexdocs.pm/default_readme>.\n\n## Development\n\n```sh\ngleam run   # Run the project\ngleam test  # Run the tests\n```\n"
  },
  {
    "path": "test/publishing_default_readme/gleam.toml",
    "content": "name = \"default_readme\"\nversion = \"1.0.0\"\ndescription = \"Test project for default readme\"\nlicences = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = \">= 0.44.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/publishing_default_readme/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.62.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.44.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/publishing_default_readme/src/default_readme.gleam",
    "content": "import gleam/io\n\n/// This tests that a project with a default readme doesn't get published.\n///\npub fn main() -> Nil {\n  greeting()\n  first_line()\n  second_line()\n}\n\nfn greeting() {\n  io.println(\"Hello from default_readme!\")\n}\n\nfn first_line() {\n  io.println(\"Here we have some additional code so that this is not mistaken\")\n}\n\nfn second_line() {\n  io.println(\"for a default main project, that would be rejected as well!\")\n}\n"
  },
  {
    "path": "test/publishing_default_readme/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Running publish should not publish anything\nif yes \"n\" | g publish; then\n  echo \"Expected publish to fail, but it succeeded\"\n  exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/publishing_empty_readme/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/publishing_empty_readme/README.md",
    "content": ""
  },
  {
    "path": "test/publishing_empty_readme/gleam.toml",
    "content": "name = \"empty_readme\"\nversion = \"1.0.0\"\ndescription = \"Test project for empty readme\"\nlicences = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = \">= 0.44.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/publishing_empty_readme/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.62.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.44.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/publishing_empty_readme/src/empty_readme.gleam",
    "content": "import gleam/io\n\n/// This tests that a project with an empty readme doesn't get published.\n///\npub fn main() -> Nil {\n  greeting()\n  first_line()\n  second_line()\n}\n\nfn greeting() {\n  io.println(\"Hello from empty_readme!\")\n}\n\nfn first_line() {\n  io.println(\"Here we have some additional code so that this is not mistaken\")\n}\n\nfn second_line() {\n  io.println(\"for a default main project, that would be rejected as well!\")\n}\n"
  },
  {
    "path": "test/publishing_empty_readme/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Running publish should not publish anything\nif yes \"n\" | g publish; then\n  echo \"Expected publish to fail, but it succeeded\"\n  exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/publishing_no_readme/.gitignore",
    "content": "*.beam\n*.ez\nbuild\n"
  },
  {
    "path": "test/publishing_no_readme/gleam.toml",
    "content": "name = \"no_readme\"\nversion = \"1.0.0\"\ndescription = \"Test project for no readme\"\nlicences = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = \">= 0.44.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/publishing_no_readme/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.62.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.44.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/publishing_no_readme/src/no_readme.gleam",
    "content": "import gleam/io\n\n/// This tests that a project with no readme doesn't get published.\n///\npub fn main() -> Nil {\n  greeting()\n  first_line()\n  second_line()\n}\n\nfn greeting() {\n  io.println(\"Hello from no_readme!\")\n}\n\nfn first_line() {\n  io.println(\"Here we have some additional code so that this is not mistaken\")\n}\n\nfn second_line() {\n  io.println(\"for a default main project, that would be rejected as well!\")\n}\n"
  },
  {
    "path": "test/publishing_no_readme/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n  echo \"Running: $GLEAM_COMMAND $@\"\n  $GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho Running publish should not publish anything\nif yes \"n\" | g publish; then\n  echo \"Expected publish to fail, but it succeeded\"\n  exit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/root_package_not_compiled_when_running_dep/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "test/root_package_not_compiled_when_running_dep/README.md",
    "content": "# root_package_not_compiled_when_running_dep\n\nThis package is used to check that the compiler can compile and run a dependency\neven if the root package has compilation errors.\n\nSo one can do `gleam run -m <dependency-module>` even if their own code doesn't\ncompile.\n"
  },
  {
    "path": "test/root_package_not_compiled_when_running_dep/gleam.toml",
    "content": "name = \"root_package_not_compiled_when_running_dep\"\nversion = \"1.0.0\"\n\n# Fill out these fields if you intend to generate HTML documentation or publish\n# your project to the Hex package manager.\n#\n# description = \"\"\n# licences = [\"Apache-2.0\"]\n# repository = { type = \"github\", user = \"\", repo = \"\" }\n# links = [{ title = \"Website\", href = \"\" }]\n#\n# For a full reference of all the available options, you can have a look at\n# https://gleam.run/writing-gleam/gleam-toml/.\n\n[dependencies]\ngleam_stdlib = \">= 0.34.0 and < 2.0.0\"\nhello_joe = \">= 1.0.0 and < 2.0.0\"\n\n[dev_dependencies]\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/root_package_not_compiled_when_running_dep/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.40.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181\" },\n  { name = \"gleeunit\", version = \"1.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13\" },\n  { name = \"hello_joe\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"hello_joe\", source = \"hex\", outer_checksum = \"CC896BC24A45528DE6C59A705171E2DD9F1EA4C3C031428E4A533539EF461519\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.34.0 and < 2.0.0\" }\ngleeunit = { version = \">= 1.0.0 and < 2.0.0\" }\nhello_joe = { version = \">= 1.0.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/root_package_not_compiled_when_running_dep/src/root_package_not_compiled_when_running_dep.gleam",
    "content": "pub fn main() {\n  compilation_error\n}\n"
  },
  {
    "path": "test/root_package_not_compiled_when_running_dep/test.sh",
    "content": "#!/bin/sh\n\nset -eu\n\nGLEAM_COMMAND=${GLEAM_COMMAND:-\"cargo run --quiet --\"}\n\ng() {\n\techo \"Running: $GLEAM_COMMAND $@\"\n\t$GLEAM_COMMAND \"$@\"\n}\n\necho Resetting the build directory to get to a known state\nrm -fr build\n\necho This should succeed regardless of root package compilation errors as it is a dependency module\ng run --module=hello_joe\ng run --module=hello_joe --target=erlang\ng run --module=hello_joe --target=javascript\n\necho Running for Erlang should fail, even if previously a Erlang dependency was built\nif g run --target=erlang; then\n\techo \"Expected run to fail\"\n\texit 1\nfi\n\necho Running for JavaScript should fail, even if previously a JavaScript dependency was built\nif g run --target=javascript; then\n\techo \"Expected run to fail\"\n\texit 1\nfi\n\necho\necho Success! 💖\necho\n"
  },
  {
    "path": "test/running_modules/.gitignore",
    "content": "build\n"
  },
  {
    "path": "test/running_modules/Makefile",
    "content": ".PHONY: test-all\ntest-all:\n\t@echo test/running_modules\n\t@./run_tests.sh\n"
  },
  {
    "path": "test/running_modules/README.md",
    "content": "# Running Modules\n\nTests running modules with the `gleam run -m` command on all targets and runtimes.\nThe `test` directory is required for gleeunit to run in the running a dependency\nmodule tests.\n"
  },
  {
    "path": "test/running_modules/dev/module_dev.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"This is the default dev module\")\n}\n"
  },
  {
    "path": "test/running_modules/dev/module_in_dev.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello from dev/\")\n}\n"
  },
  {
    "path": "test/running_modules/dev/nested/module_in_dev.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello from dev/nested!\")\n}\n"
  },
  {
    "path": "test/running_modules/dev/wrong_dev_arity.gleam",
    "content": "import gleam/io\n\npub fn main(something) {\n  io.println(something)\n}\n"
  },
  {
    "path": "test/running_modules/gleam.toml",
    "content": "name = \"module\"\nversion = \"0.1.0\"\ndescription = \"A Gleam project\"\n\n[dependencies]\ngleam_stdlib = \">= 0.58.0 and < 2.0.0\"\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n\n[javascript.deno]\nallow_read = true\n"
  },
  {
    "path": "test/running_modules/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.58.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"091F2D2C4A3A4E2047986C47E2C2C9D728A4E068ABB31FDA17B0D347E6248467\" },\n  { name = \"gleeunit\", version = \"1.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.58.0 and < 2.0.0\" }\ngleeunit = { version = \">= 1.0.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/running_modules/run_tests.sh",
    "content": "#/usr/bin/env sh\n\nset -eu\n\nshould_succeed() {\n    echo\n    echo Running: \"$@\"\n    cargo run -- $@ > /dev/null 2>&1\n    if [ $? -ne 0 ]\n    then\n        echo ERROR: Command should have succeeded\n        exit 1\n    else\n        echo Test Passed '(command run successfully)'\n    fi\n}\nshould_fail() {\n    echo\n    echo Running: \"$@\"\n\n    EXIT_CODE=0\n    cargo run -- $@ > /dev/null 2>&1 || EXIT_CODE=$?\n\n    if [ $EXIT_CODE -eq 0 ]\n    then\n        echo ERROR: Command should have failed\n        exit 1\n    else\n        echo Test Passed '(command errored as expected)'\n    fi\n}\n\n# No module\nshould_succeed run --target erlang\nshould_succeed run --target javascript --runtime nodejs\nshould_succeed run --target javascript --runtime deno\n\n# Module from same package\nshould_succeed run --module module --target erlang\nshould_succeed run --module module --target javascript --runtime nodejs\nshould_succeed run --module module --target javascript --runtime deno\n\n# Nested module from same package\nshould_succeed run --module module/sub_module --target erlang\nshould_succeed run --module module/sub_module --target javascript --runtime nodejs\nshould_succeed run --module module/sub_module --target javascript --runtime deno\n\n# Dependency package\nshould_succeed run --module gleeunit --target erlang\nshould_succeed run --module gleeunit --target javascript --runtime nodejs\nshould_succeed run --module gleeunit --target javascript --runtime deno\n\n# Unknown module\nshould_fail run --module doesnt_exist\n\n# Unknown module should only belong as a package or in src/ and test/\nshould_fail run --module src/doesnt_exist\n\n# No main function\nshould_fail run --module module/no_main_function\n\n# Main function with wrong arity\nshould_fail run --module module/wrong_arity\nshould_fail run --module wrong_test_arity\nshould_fail run --module wrong_dev_arity\n\n# Test modules\nshould_succeed test --target erlang\nshould_succeed test --target javascript --runtime nodejs\nshould_succeed test --target javascript --runtime deno\n\nshould_succeed run --module module_in_test --target erlang\nshould_succeed run --module module_in_test --target javascript --runtime nodejs\nshould_succeed run --module module_in_test --target javascript --runtime deno\n\n# Nested module in test\nshould_succeed run --module nested/module_in_test --target erlang\nshould_succeed run --module nested/module_in_test --target javascript --runtime nodejs\nshould_succeed run --module nested/module_in_test --target javascript --runtime deno\n\n\n# Dev modules\nshould_succeed dev --target erlang\nshould_succeed dev --target javascript --runtime nodejs\nshould_succeed dev --target javascript --runtime deno\n\nshould_succeed run --module module_in_dev --target erlang\nshould_succeed run --module module_in_dev --target javascript --runtime nodejs\nshould_succeed run --module module_in_dev --target javascript --runtime deno\n\n# Nested module in dev\nshould_succeed run --module nested/module_in_dev --target erlang\nshould_succeed run --module nested/module_in_dev --target javascript --runtime nodejs\nshould_succeed run --module nested/module_in_dev --target javascript --runtime deno\n\n"
  },
  {
    "path": "test/running_modules/src/module/no_main_function.gleam",
    "content": "\n"
  },
  {
    "path": "test/running_modules/src/module/sub_module.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"sub module\")\n}\n"
  },
  {
    "path": "test/running_modules/src/module/wrong_arity.gleam",
    "content": "pub fn main(arg: Int) -> Nil {\n  Nil\n}\n"
  },
  {
    "path": "test/running_modules/src/module.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"top level module\")\n}\n"
  },
  {
    "path": "test/running_modules/test/module_in_test.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello from test/\")\n}\n"
  },
  {
    "path": "test/running_modules/test/module_test.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Default test module\")\n}\n"
  },
  {
    "path": "test/running_modules/test/nested/module_in_test.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello from test/nested!\")\n}\n"
  },
  {
    "path": "test/running_modules/test/wrong_test_arity.gleam",
    "content": "import gleam/io\n\npub fn main(something) {\n  io.println(something)\n}\n"
  },
  {
    "path": "test/subdir_ffi/.gitignore",
    "content": "*.beam\n*.ez\nbuild\nerl_crash.dump\n"
  },
  {
    "path": "test/subdir_ffi/Makefile",
    "content": ".PHONY: build\nbuild: clean erlang nodejs deno bun\n\n.PHONY: clean\nclean:\n\trm -rf build\n\n.PHONY: erlang\nerlang:\n\t@echo test/subdir_ffi on Erlang\n\tcargo run --quiet -- test --target erlang\n\n.PHONY: nodejs\nnodejs:\n\t@echo test/subdir_ffi on JavaScript with Node\n\tcargo run --quiet -- test --target javascript --runtime nodejs\n\n.PHONY: deno\ndeno:\n\t@echo test/subdir_ffi on JavaScript with Deno\n\tcargo run --quiet -- test --target javascript --runtime deno\n\n.PHONY: bun\nbun:\n\t@echo test/subdir_ffi on JavaScript with Bun\n\tcargo run --quiet -- test --target javascript --runtime bun\n"
  },
  {
    "path": "test/subdir_ffi/README.md",
    "content": "# subdir_ffi\n\nThis package is used to check if the compiler properly supports FFI files (such\nas `.mjs`, `.erl` and `.hrl`) in subdirectories.\n\nTest across all targets and runtimes by running `make`.\n"
  },
  {
    "path": "test/subdir_ffi/gleam.toml",
    "content": "name = \"subdir_ffi\"\nversion = \"1.0.0\"\n\n# Fill out these fields if you intend to generate HTML documentation or publish\n# your project to the Hex package manager.\n#\n# description = \"\"\n# licences = [\"Apache-2.0\"]\n# repository = { type = \"github\", user = \"\", repo = \"\" }\n# links = [{ title = \"Website\", href = \"\" }]\n#\n# For a full reference of all the available options, you can have a look at\n# https://gleam.run/writing-gleam/gleam-toml/.\n\n[dependencies]\ngleam_stdlib = \">= 0.34.0 and < 2.0.0\"\n\n[dev_dependencies]\ngleeunit = \">= 1.0.0 and < 2.0.0\"\n"
  },
  {
    "path": "test/subdir_ffi/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"gleam_stdlib\", version = \"0.40.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181\" },\n  { name = \"gleeunit\", version = \"1.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13\" },\n]\n\n[requirements]\ngleam_stdlib = { version = \">= 0.34.0 and < 2.0.0\" }\ngleeunit = { version = \">= 1.0.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test/subdir_ffi/src/headers/submodule_ffi_header.hrl",
    "content": "header_function() ->\n  <<\"Hello, from the nested Erlang header!\">>.\n"
  },
  {
    "path": "test/subdir_ffi/src/nested/submodule.gleam",
    "content": "pub fn submodule_main() {\n  parent_println(message())\n  parent_println(elixir_message())\n}\n\n@external(erlang, \"project_ffi\", \"log\")\n@external(javascript, \"../project_ffi.mjs\", \"log\")\nfn parent_println(a: String) -> Nil\n\n@external(erlang, \"submodule_ffi\", \"main\")\n@external(javascript, \"./submodule_ffi.mjs\", \"main\")\nfn message() -> String\n\n@external(erlang, \"Elixir.ElixirFile\", \"main\")\n@external(javascript, \"./submodule_ffi.mjs\", \"main\")\nfn elixir_message() -> String\n"
  },
  {
    "path": "test/subdir_ffi/src/nested/submodule_ffi.erl",
    "content": "-module(submodule_ffi).\n\n-export([main/0, main2/0]).\n\n-include(\"../headers/submodule_ffi_header.hrl\").\n\nmain() ->\n  String = header_function(),\n  <<\"Hello, from the nested Erlang module!\\n\"/utf8, String/binary>>.\n\nmain2() ->\n  String = header_function(),\n  <<\"Hello again, from the nested Erlang module!\\n\"/utf8, String/binary>>.\n"
  },
  {
    "path": "test/subdir_ffi/src/nested/submodule_ffi.ex",
    "content": "defmodule ElixirFile do\n  def main() do\n    \"Hello, from the Elixir module!\"\n  end\nend\n\ndefmodule ElixirFileAgain do\n  def main() do\n    \"Hello, from another Elixir module!\"\n  end\nend\n"
  },
  {
    "path": "test/subdir_ffi/src/nested/submodule_ffi.mjs",
    "content": "export function main(x) {\n  return \"Hello from the nested JavaScript native module!\";\n}\n\nexport function main2(x) {\n  return \"Hello again from the nested JavaScript native module!\";\n}\n"
  },
  {
    "path": "test/subdir_ffi/src/project.gleam",
    "content": "import nested/submodule\n\npub fn main() {\n  println(\"Hello from subdir_ffi!\")\n  submodule.submodule_main()\n  println(subdir_message())\n  println(subdir_elixir_message())\n}\n\n@external(erlang, \"project_ffi\", \"log\")\n@external(javascript, \"./project_ffi.mjs\", \"log\")\nfn println(a: String) -> Nil\n\n@external(erlang, \"submodule_ffi\", \"main2\")\n@external(javascript, \"./nested/submodule_ffi.mjs\", \"main2\")\nfn subdir_message() -> String\n\n@external(erlang, \"Elixir.ElixirFileAgain\", \"main\")\n@external(javascript, \"./nested/submodule_ffi.mjs\", \"main2\")\nfn subdir_elixir_message() -> String\n"
  },
  {
    "path": "test/subdir_ffi/src/project_ffi.erl",
    "content": "-module(project_ffi).\n\n-export([log/1]).\n\nlog(Message) ->\n  erlang:display(Message).\n"
  },
  {
    "path": "test/subdir_ffi/src/project_ffi.mjs",
    "content": "export function log(x) {\n  console.log(x);\n}\n"
  },
  {
    "path": "test/subdir_ffi/test/subdir_ffi_test.gleam",
    "content": "import project\n\npub fn main() {\n  project.main()\n}\n"
  },
  {
    "path": "test/unicode_path ⭐/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "test/unicode_path ⭐/Makefile",
    "content": ".PHONY: build\nbuild:\n\trm -fr build\n\tcargo run --quiet -- build --target erlang\n"
  },
  {
    "path": "test/unicode_path ⭐/gleam.toml",
    "content": "name = \"unicode_path\"\nversion = \"1.0.0\""
  },
  {
    "path": "test/unicode_path ⭐/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n]\n\n[requirements]\n"
  },
  {
    "path": "test/unicode_path ⭐/src/unicode_path.gleam",
    "content": "pub fn main() {\n  Nil\n}\n"
  },
  {
    "path": "test-community-packages/.gitignore",
    "content": "*.beam\n*.ez\n/build\nerl_crash.dump\n"
  },
  {
    "path": "test-community-packages/README.md",
    "content": "# test_community_packages\n\n[![Package Version](https://img.shields.io/hexpm/v/test_community_packages)](https://hex.pm/packages/test_community_packages)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/test_community_packages/)\n\n```sh\ngleam add test_community_packages\n```\n```gleam\nimport test_community_packages\n\npub fn main() {\n  // TODO: An example of the project in use\n}\n```\n\nFurther documentation can be found at <https://hexdocs.pm/test_community_packages>.\n\n## Development\n\n```sh\ngleam run   # Run the project\ngleam test  # Run the tests\ngleam shell # Run an Erlang shell\n```\n"
  },
  {
    "path": "test-community-packages/gleam.toml",
    "content": "name = \"test_community_packages\"\nversion = \"1.0.0\"\n\n# Fill out these fields if you intend to generate HTML documentation or publish\n# your project to the Hex package manager.\n#\n# description = \"\"\n# licences = [\"Apache-2.0\"]\n# repository = { type = \"github\", user = \"username\", repo = \"project\" }\n# links = [{ title = \"Website\", href = \"https://gleam.run\" }]\n#\n# For a full reference of all the available options, you can have a look at\n# https://gleam.run/writing-gleam/gleam-toml/.\n\n[dependencies]\ngleam_stdlib = \">= 0.36.0 and < 1.0.0\"\nargamak = \">= 1.1.0 and < 2.0.0\"\nargv = \">= 1.0.2 and < 2.0.0\"\naws4_request = \">= 0.1.1 and < 1.0.0\"\nbigi = \">= 2.1.0 and < 3.0.0\"\nbirdie = \">= 1.1.0 and < 2.0.0\"\ncgi = \">= 1.0.1 and < 2.0.0\"\nconversation = \">= 1.4.3 and < 2.0.0\"\nedit_distance = \">= 2.0.1 and < 3.0.0\"\nenvoy = \">= 1.0.1 and < 2.0.0\"\nexception = \">= 2.0.0 and < 3.0.0\"\nexercism_test_runner = \">= 1.7.0 and < 2.0.0\"\nfilepath = \">= 0.2.0 and < 1.0.0\"\ngap = \">= 1.1.3 and < 2.0.0\"\ngen_core_erlang = \">= 0.5.1 and < 1.0.0\"\ngen_gleam = \">= 0.3.1 and < 1.0.0\"\nglance = \">= 0.8.2 and < 1.0.0\"\nglance_printer = \">= 1.1.0 and < 2.0.0\"\nglatus = \">= 1.0.0 and < 2.0.0\"\ngleam_community_ansi = \">= 1.4.0 and < 2.0.0\"\ngleam_community_colour = \">= 1.4.0 and < 2.0.0\"\ngleam_community_maths = \">= 1.1.0 and < 2.0.0\"\ngleam_crypto = \">= 1.3.0 and < 2.0.0\"\ngleam_elli = \">= 2.4.0 and < 3.0.0\"\ngleam_erlang = \">= 0.25.0 and < 1.0.0\"\ngleam_fetch = \">= 0.4.0 and < 1.0.0\"\ngleam_hackney = \">= 1.2.0 and < 2.0.0\"\ngleam_http = \">= 3.6.0 and < 4.0.0\"\ngleam_httpc = \">= 2.2.0 and < 3.0.0\"\ngleam_javascript = \">= 0.8.0 and < 1.0.0\"\ngleam_json = \">= 0.7.0 and < 1.0.0\"\ngleam_otp = \">= 0.10.0 and < 1.0.0\"\ngleam_pgo = \">= 0.6.1 and < 1.0.0\"\ngleam_sendgrid = \">= 0.2.0 and < 1.0.0\"\ngleamy_bench = \">= 0.4.0 and < 1.0.0\"\nglearray = \">= 0.2.1 and < 1.0.0\"\ngleescript = \">= 1.0.0 and < 2.0.0\"\nglen = \">= 2.0.0 and < 3.0.0\"\nglenvy = \">= 0.5.1 and < 1.0.0\"\nglesha = \">= 0.1.3 and < 1.0.0\"\nglexer = \">= 0.7.0 and < 1.0.0\"\nglisten = \">= 2.0.0 and < 3.0.0\"\nglobe = \">= 0.1.0 and < 1.0.0\"\ngsv = \">= 1.4.0 and < 2.0.0\"\nhtmb = \">= 2.0.0 and < 3.0.0\"\nhtmgrrrl = \">= 0.3.0 and < 1.0.0\"\nids = \">= 0.12.0 and < 1.0.0\"\niso_8859 = \">= 2.0.0 and < 3.0.0\"\njot = \">= 0.3.1 and < 1.0.0\"\njustin = \">= 1.0.1 and < 2.0.0\"\nlustre = \">= 3.1.4 and < 4.0.0\"\nlustre_http = \">= 0.5.0 and < 1.0.0\"\nlustre_ui = \">= 0.4.0 and < 1.0.0\"\nlustre_websocket = \">= 0.7.6 and < 1.0.0\"\nmarceau = \">= 1.1.0 and < 2.0.0\"\nmineflayer = \">= 0.1.0 and < 1.0.0\"\nmist = \">= 1.0.0 and < 2.0.0\"\nmug = \">= 0.2.0 and < 1.0.0\"\nnakai = \">= 0.9.0 and < 1.0.0\"\nnibble = \">= 1.1.0 and < 2.0.0\"\noutil = \">= 0.5.0 and < 1.0.0\"\nphony = \">= 1.1.6 and < 2.0.0\"\nplinth = \">= 0.1.13 and < 1.0.0\"\nprng = \">= 3.0.2 and < 4.0.0\"\nprocess_waiter = \">= 1.0.0 and < 2.0.0\"\npuddle = \">= 0.5.0 and < 1.0.0\"\npunycode = \">= 0.1.1 and < 1.0.0\"\nradish = \">= 0.13.0 and < 1.0.0\"\nranger = \">= 1.2.0 and < 2.0.0\"\nrank = \">= 1.0.0 and < 2.0.0\"\nrepeatedly = \">= 2.1.1 and < 3.0.0\"\nsimplifile = \">= 1.5.1 and < 2.0.0\"\nsnag = \">= 0.3.0 and < 1.0.0\"\nspinner = \">= 1.1.0 and < 2.0.0\"\ntestbldr = \">= 1.1.0 and < 2.0.0\"\ntom = \">= 0.3.0 and < 1.0.0\"\nwimp = \">= 1.1.0 and < 2.0.0\"\nwisp = \">= 0.14.0 and < 1.0.0\"\nzeptomail = \">= 1.0.0 and < 2.0.0\"\njwt = \">= 0.1.11 and < 1.0.0\"\njasper = \">= 1.2.0 and < 2.0.0\"\nimmutable_lru = \">= 1.0.1 and < 2.0.0\"\nxmleam = \">= 1.1.4 and < 2.0.0\"\npears = \">= 0.3.0 and < 1.0.0\"\ntyped_headers = \">= 1.1.2 and < 2.0.0\"\nreactive_signal = \">= 0.0.1 and < 1.0.0\"\nnanoworker = \">= 0.0.2 and < 1.0.0\"\nfile_streams = \">= 0.3.1 and < 1.0.0\"\nmorse_code_translator = \">= 2.0.0 and < 3.0.0\"\ngleeunit = \">= 1.1.2 and < 2.0.0\"\n"
  },
  {
    "path": "test-community-packages/manifest.toml",
    "content": "# This file was generated by Gleam\n# You typically do not need to edit this file\n\npackages = [\n  { name = \"argamak\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"nx\"], otp_app = \"argamak\", source = \"hex\", outer_checksum = \"4124DD1D004D43D9F9734A3274BE063F2770940C773BDE21AFFC43EB45572C9A\" },\n  { name = \"argv\", version = \"1.0.2\", build_tools = [\"gleam\"], requirements = [], otp_app = \"argv\", source = \"hex\", outer_checksum = \"BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D\" },\n  { name = \"aws4_request\", version = \"0.1.1\", build_tools = [\"gleam\"], requirements = [\"gleam_crypto\", \"gleam_http\", \"gleam_stdlib\"], otp_app = \"aws4_request\", source = \"hex\", outer_checksum = \"90B1DB6E2A7F0396CD4713850B14B3A910331B5BA76D051E411D1499AAA2EA9A\" },\n  { name = \"backoff\", version = \"1.1.6\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"backoff\", source = \"hex\", outer_checksum = \"CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39\" },\n  { name = \"base64url\", version = \"0.0.1\", build_tools = [\"rebar\"], requirements = [], otp_app = \"base64url\", source = \"hex\", outer_checksum = \"FAB09B20E3F5DB886725544CBCF875B8E73EC93363954EB8A1A9ED834AA8C1F9\" },\n  { name = \"bigi\", version = \"2.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"bigi\", source = \"hex\", outer_checksum = \"B6F7CAF319F13F32DB4331A750534912A9AEE1C195DD8E5DA83A42A4AD390274\" },\n  { name = \"birdie\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"argv\", \"filepath\", \"gap\", \"glance\", \"gleam_community_ansi\", \"gleam_erlang\", \"gleam_stdlib\", \"gleeunit\", \"justin\", \"rank\", \"simplifile\", \"trie_again\"], otp_app = \"birdie\", source = \"hex\", outer_checksum = \"DE7BEE4C76A52E91E72800531B6E5B41093D06FA90C7F6D9FDE768BCE714FAA7\" },\n  { name = \"birl\", version = \"1.6.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"ranger\"], otp_app = \"birl\", source = \"hex\", outer_checksum = \"976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497\" },\n  { name = \"certifi\", version = \"2.12.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"certifi\", source = \"hex\", outer_checksum = \"EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C\" },\n  { name = \"cgi\", version = \"1.0.1\", build_tools = [\"gleam\"], requirements = [\"envoy\", \"gleam_http\", \"gleam_stdlib\"], otp_app = \"cgi\", source = \"hex\", outer_checksum = \"CEAF4AE877A115E1C03810289924B5102073F5FB1B786C5F28BA241BAC632042\" },\n  { name = \"complex\", version = \"0.5.0\", build_tools = [\"mix\"], requirements = [], otp_app = \"complex\", source = \"hex\", outer_checksum = \"2683BD3C184466CFB94FAD74CBFDDFAA94B860E27AD4CA1BFFE3BFF169D91EF1\" },\n  { name = \"conversation\", version = \"1.4.3\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_javascript\", \"gleam_stdlib\"], otp_app = \"conversation\", source = \"hex\", outer_checksum = \"908B46F60444442785A495197D482558AD8B849C3714A38FAA1940358CC8CCCD\" },\n  { name = \"edit_distance\", version = \"2.0.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"edit_distance\", source = \"hex\", outer_checksum = \"A1E485C69A70210223E46E63985FA1008B8B2DDA9848B7897469171B29020C05\" },\n  { name = \"elli\", version = \"3.3.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"elli\", source = \"hex\", outer_checksum = \"698B13B33D05661DB9FE7EFCBA41B84825A379CCE86E486CF6AFF9285BE0CCF8\" },\n  { name = \"envoy\", version = \"1.0.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"envoy\", source = \"hex\", outer_checksum = \"CFAACCCFC47654F7E8B75E614746ED924C65BD08B1DE21101548AC314A8B6A41\" },\n  { name = \"exception\", version = \"2.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"exception\", source = \"hex\", outer_checksum = \"F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA\" },\n  { name = \"exercism_test_runner\", version = \"1.7.0\", build_tools = [\"gleam\"], requirements = [\"argv\", \"gap\", \"glance\", \"gleam_community_ansi\", \"gleam_erlang\", \"gleam_json\", \"gleam_stdlib\", \"simplifile\"], otp_app = \"exercism_test_runner\", source = \"hex\", outer_checksum = \"2FC1BADB19BEC2AE77BFD2D3A606A014C85412A7B874CAFC4BA8CF04B0B257CD\" },\n  { name = \"file_streams\", version = \"0.3.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"file_streams\", source = \"hex\", outer_checksum = \"4064B4ED044460D6BD53A9654AABBC7D38A471D8805A0FF17DF511FE219396B4\" },\n  { name = \"filepath\", version = \"0.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"filepath\", source = \"hex\", outer_checksum = \"FC1B1B29438A5BA6C990F8047A011430BEC0C5BA638BFAA62718C4EAEFE00435\" },\n  { name = \"gap\", version = \"1.1.3\", build_tools = [\"gleam\"], requirements = [\"gleam_community_ansi\", \"gleam_stdlib\"], otp_app = \"gap\", source = \"hex\", outer_checksum = \"6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291\" },\n  { name = \"gen_core_erlang\", version = \"0.5.1\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_stdlib\"], otp_app = \"gen_core_erlang\", source = \"hex\", outer_checksum = \"07B01FF8515B6B8E9CAF7CFD3D0100D713C61E4B8F8A88E586A9D88457C9A127\" },\n  { name = \"gen_gleam\", version = \"0.3.1\", build_tools = [\"gleam\"], requirements = [\"filepath\", \"gleam_stdlib\", \"simplifile\"], otp_app = \"gen_gleam\", source = \"hex\", outer_checksum = \"19CD1648B44246BDA137936AFD4A09EFF4DFB7C48FA1D5A2C18EF39CDCFB6CD8\" },\n  { name = \"glam\", version = \"1.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"glam\", source = \"hex\", outer_checksum = \"02E0311862B9669C3E8CE73FA5A95D8FA457C6ACB48D95FBE808ABFAE0A1CEB0\" },\n  { name = \"glance\", version = \"0.8.2\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"glexer\"], otp_app = \"glance\", source = \"hex\", outer_checksum = \"ACF09457E8B564AD7A0D823DAFDD326F58263C01ACB0D432A9BEFDEDD1DA8E73\" },\n  { name = \"glance_printer\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"glam\", \"glance\", \"gleam_stdlib\"], otp_app = \"glance_printer\", source = \"hex\", outer_checksum = \"3140D4DD3F6C9119C60F2BA994F728D04E56014498A9C6C994814003EA115DE7\" },\n  { name = \"glatus\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_json\", \"gleam_stdlib\"], otp_app = \"glatus\", source = \"hex\", outer_checksum = \"8D1C5D7F3AC7FB0616D14C3BD8930F8D3F427EC195086FE24D60745CF5900C7D\" },\n  { name = \"gleam_bitwise\", version = \"1.3.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_bitwise\", source = \"hex\", outer_checksum = \"B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC\" },\n  { name = \"gleam_community_ansi\", version = \"1.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_community_colour\", \"gleam_stdlib\"], otp_app = \"gleam_community_ansi\", source = \"hex\", outer_checksum = \"FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4\" },\n  { name = \"gleam_community_colour\", version = \"1.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_json\", \"gleam_stdlib\"], otp_app = \"gleam_community_colour\", source = \"hex\", outer_checksum = \"795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE\" },\n  { name = \"gleam_community_maths\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_community_maths\", source = \"hex\", outer_checksum = \"E30C61A75051DAF7CFD77C4FBAA04140FDA0B5D831955E7A74521E5576E2780D\" },\n  { name = \"gleam_crypto\", version = \"1.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_crypto\", source = \"hex\", outer_checksum = \"ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7\" },\n  { name = \"gleam_elli\", version = \"2.4.0\", build_tools = [\"gleam\"], requirements = [\"elli\", \"gleam_erlang\", \"gleam_http\", \"gleam_otp\", \"gleam_stdlib\"], otp_app = \"gleam_elli\", source = \"hex\", outer_checksum = \"433F5AF4ED92C55F3EBA8942610E974254EEF90F484AF26E3D775E33338DE832\" },\n  { name = \"gleam_erlang\", version = \"0.25.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_erlang\", source = \"hex\", outer_checksum = \"054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373\" },\n  { name = \"gleam_fetch\", version = \"0.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_javascript\", \"gleam_stdlib\"], otp_app = \"gleam_fetch\", source = \"hex\", outer_checksum = \"7446410A44A1D1328F5BC1FF4FC9CBD1570479EA69349237B3F82E34521CCC10\" },\n  { name = \"gleam_hackney\", version = \"1.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_stdlib\", \"hackney\"], otp_app = \"gleam_hackney\", source = \"hex\", outer_checksum = \"066B1A55D37DBD61CC72A1C4EDE43C6015B1797FAF3818C16FE476534C7B6505\" },\n  { name = \"gleam_http\", version = \"3.6.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_http\", source = \"hex\", outer_checksum = \"8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51\" },\n  { name = \"gleam_httpc\", version = \"2.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_stdlib\"], otp_app = \"gleam_httpc\", source = \"hex\", outer_checksum = \"CF76C71002DEECF6DC5D9CA83D962728FAE166B57926BE442D827004D3C7DF1B\" },\n  { name = \"gleam_javascript\", version = \"0.8.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleam_javascript\", source = \"hex\", outer_checksum = \"14D5B7E1A70681E0776BF0A0357F575B822167960C844D3D3FA114D3A75F05A8\" },\n  { name = \"gleam_json\", version = \"0.7.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"thoas\"], otp_app = \"gleam_json\", source = \"hex\", outer_checksum = \"CB405BD93A8828BCD870463DE29375E7B2D252D9D124C109E5B618AAC00B86FC\" },\n  { name = \"gleam_otp\", version = \"0.10.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_stdlib\"], otp_app = \"gleam_otp\", source = \"hex\", outer_checksum = \"0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B\" },\n  { name = \"gleam_pgo\", version = \"0.6.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"pgo\"], otp_app = \"gleam_pgo\", source = \"hex\", outer_checksum = \"18A4940471BA798AA1FB85CD6E6D035A7403F66C4A2F19CDD471E0DA450C3633\" },\n  { name = \"gleam_sendgrid\", version = \"0.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_json\", \"gleam_stdlib\"], otp_app = \"gleam_sendgrid\", source = \"hex\", outer_checksum = \"15DA0C569F0B318C42E145D2604C8307D0CA0A03DC6CE947A453B7DDFFC64C17\" },\n  { name = \"gleam_stdlib\", version = \"0.36.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"gleam_stdlib\", source = \"hex\", outer_checksum = \"C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4\" },\n  { name = \"gleamy_bench\", version = \"0.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleamy_bench\", source = \"hex\", outer_checksum = \"B094BD02EAD14BBF24B8A790C1BD4ECAADBBF17B0503DE46EC74DAD9F4930FE9\" },\n  { name = \"glearray\", version = \"0.2.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"glearray\", source = \"hex\", outer_checksum = \"908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4\" },\n  { name = \"gleescript\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"filepath\", \"gleam_erlang\", \"gleam_stdlib\", \"simplifile\", \"snag\", \"tom\"], otp_app = \"gleescript\", source = \"hex\", outer_checksum = \"F7C152E206167000420F90983E4D4A076703292AAC4335A9248BA46D380841AC\" },\n  { name = \"gleeunit\", version = \"1.1.2\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gleeunit\", source = \"hex\", outer_checksum = \"72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B\" },\n  { name = \"glen\", version = \"2.0.0\", build_tools = [\"gleam\"], requirements = [\"conversation\", \"gleam_community_ansi\", \"gleam_http\", \"gleam_javascript\", \"gleam_stdlib\", \"marceau\"], otp_app = \"glen\", source = \"hex\", outer_checksum = \"63224B9BD0994ABCE4E8D6B3C94520D59A5E70CC807ED61BA9CFA32368CA1DBF\" },\n  { name = \"glenvy\", version = \"0.5.1\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_stdlib\", \"nibble\", \"simplifile\"], otp_app = \"glenvy\", source = \"hex\", outer_checksum = \"4D1090DC984DB3184CC5E151F240FBE9ED6EBE302B69DC0B6CC222DD4C74357E\" },\n  { name = \"glesha\", version = \"0.1.3\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"glesha\", source = \"hex\", outer_checksum = \"8DC5F211670C12870FC36C211B8C0A0FFB07BC83708484174CAE1F9DA4B8AF9F\" },\n  { name = \"glexer\", version = \"0.7.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"glexer\", source = \"hex\", outer_checksum = \"4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE\" },\n  { name = \"glint\", version = \"0.14.0\", build_tools = [\"gleam\"], requirements = [\"gleam_community_ansi\", \"gleam_community_colour\", \"gleam_stdlib\", \"snag\"], otp_app = \"glint\", source = \"hex\", outer_checksum = \"21AB16D5A50D4EF34DF935915FDBEE06B2DAEDEE3FCC8584C6E635A866566B38\" },\n  { name = \"glisten\", version = \"2.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_otp\", \"gleam_stdlib\"], otp_app = \"glisten\", source = \"hex\", outer_checksum = \"CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314\" },\n  { name = \"globe\", version = \"0.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"globe\", source = \"hex\", outer_checksum = \"803B1B983238AF34627AA1135050838388468364D64B1660A7F973F66E9B6C3B\" },\n  { name = \"gsv\", version = \"1.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"gsv\", source = \"hex\", outer_checksum = \"4D6B08A60D38AB8D6605822B50A120E2BCDE1F3F2EA9DD3BBBEC3350CFB15D3F\" },\n  { name = \"hackney\", version = \"1.20.1\", build_tools = [\"rebar3\"], requirements = [\"certifi\", \"idna\", \"metrics\", \"mimerl\", \"parse_trans\", \"ssl_verify_fun\", \"unicode_util_compat\"], otp_app = \"hackney\", source = \"hex\", outer_checksum = \"FE9094E5F1A2A2C0A7D10918FEE36BFEC0EC2A979994CFF8CFE8058CD9AF38E3\" },\n  { name = \"hpack_erl\", version = \"0.3.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"hpack\", source = \"hex\", outer_checksum = \"D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0\" },\n  { name = \"htmb\", version = \"2.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"htmb\", source = \"hex\", outer_checksum = \"915186FE1759EB8B78CBDC01228D0B7ED74DA2E64B08B4115525E293B036C428\" },\n  { name = \"htmerl\", version = \"0.1.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"htmerl\", source = \"hex\", outer_checksum = \"D932F76EA33C318A79F41A429FDBEAE30820390DDB72BA89F38EEF32FEC36395\" },\n  { name = \"htmgrrrl\", version = \"0.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"htmerl\"], otp_app = \"htmgrrrl\", source = \"hex\", outer_checksum = \"983492567967DAA64776E005B9E70353368B14E6F87D543E01308B48A7A0398F\" },\n  { name = \"idna\", version = \"6.1.1\", build_tools = [\"rebar3\"], requirements = [\"unicode_util_compat\"], otp_app = \"idna\", source = \"hex\", outer_checksum = \"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA\" },\n  { name = \"ids\", version = \"0.12.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_otp\", \"gleam_stdlib\"], otp_app = \"ids\", source = \"hex\", outer_checksum = \"C0772022F69E6C91825115F6C7053F1AE2F5567A31650229B7B8749F8F429F3C\" },\n  { name = \"immutable_lru\", version = \"1.0.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"immutable_lru\", source = \"hex\", outer_checksum = \"D3AA3FDE2AAE9B5CF48D825A75E9D0D7ECAD8085AB4A25B068C7C2E456E81F29\" },\n  { name = \"iso_8859\", version = \"2.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"iso_8859\", source = \"hex\", outer_checksum = \"B296DC9587480C7A7D1E6862F888844956E03A1CD99ECE7713970515C0AA4F6A\" },\n  { name = \"jasper\", version = \"1.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"pears\"], otp_app = \"jasper\", source = \"hex\", outer_checksum = \"F86B8D44B72A1623940A947605AEC348A87BBC8D0570F3484EC74EF4FE2C0B53\" },\n  { name = \"jot\", version = \"0.3.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"jot\", source = \"hex\", outer_checksum = \"574A2DACA106E9B4826C9F3F2D3911844C7826D554C08E404696CC16F85E0392\" },\n  { name = \"jsx\", version = \"2.8.3\", build_tools = [\"mix\", \"rebar3\"], requirements = [], otp_app = \"jsx\", source = \"hex\", outer_checksum = \"FC3499FED7A726995AA659143A248534ADC754EBD16CCD437CD93B649A95091F\" },\n  { name = \"justin\", version = \"1.0.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"justin\", source = \"hex\", outer_checksum = \"7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD\" },\n  { name = \"jwt\", version = \"0.1.11\", build_tools = [\"rebar3\"], requirements = [\"base64url\", \"jsx\"], otp_app = \"jwt\", source = \"hex\", outer_checksum = \"B483FBB786D1BD050B3C551D323112D604E5B0F9CF9DC5671ADEEC462C2E36BB\" },\n  { name = \"logging\", version = \"1.0.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"logging\", source = \"hex\", outer_checksum = \"82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39\" },\n  { name = \"lustre\", version = \"3.1.4\", build_tools = [\"gleam\"], requirements = [\"argv\", \"gleam_community_ansi\", \"gleam_stdlib\", \"glint\"], otp_app = \"lustre\", source = \"hex\", outer_checksum = \"E651E39189F55473837FB7386C06BAED7276B37B5058302CAC880F89C25CB4E9\" },\n  { name = \"lustre_http\", version = \"0.5.0\", build_tools = [\"gleam\"], requirements = [\"gleam_fetch\", \"gleam_http\", \"gleam_javascript\", \"gleam_json\", \"gleam_stdlib\", \"lustre\"], otp_app = \"lustre_http\", source = \"hex\", outer_checksum = \"7D7D91EB7C59177E7C2ECCF7D0BE530DDFF86264AE1BEF473E6F9F8C6C62CEB0\" },\n  { name = \"lustre_ui\", version = \"0.4.0\", build_tools = [\"gleam\"], requirements = [\"gleam_community_colour\", \"gleam_stdlib\", \"lustre\"], otp_app = \"lustre_ui\", source = \"hex\", outer_checksum = \"9FE07E26EABDB13F7CB29F90AD8763618040729BF16E5F451A6ED584C52AA093\" },\n  { name = \"lustre_websocket\", version = \"0.7.6\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\", \"lustre\"], otp_app = \"lustre_websocket\", source = \"hex\", outer_checksum = \"E9773508D3FF9EF7A36EB86826D89879214B26641F7AEC8B44B2A95579D21BBD\" },\n  { name = \"marceau\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [], otp_app = \"marceau\", source = \"hex\", outer_checksum = \"1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81\" },\n  { name = \"metrics\", version = \"1.0.1\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"metrics\", source = \"hex\", outer_checksum = \"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16\" },\n  { name = \"mimerl\", version = \"1.2.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"mimerl\", source = \"hex\", outer_checksum = \"F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323\" },\n  { name = \"mineflayer\", version = \"0.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"mineflayer\", source = \"hex\", outer_checksum = \"77AFA091107A42AD63D0FE6C417CE9E4984CE33C9225DCE8C802DD625A684262\" },\n  { name = \"mist\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"birl\", \"gleam_erlang\", \"gleam_http\", \"gleam_otp\", \"gleam_stdlib\", \"glisten\", \"hpack_erl\", \"logging\"], otp_app = \"mist\", source = \"hex\", outer_checksum = \"7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C\" },\n  { name = \"morse_code_translator\", version = \"2.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"morse_code_translator\", source = \"hex\", outer_checksum = \"29492E275B5BAAFB7748CD6DA12BA16E6D2CCF5F202C672231F36F61DD63F291\" },\n  { name = \"mug\", version = \"0.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_stdlib\"], otp_app = \"mug\", source = \"hex\", outer_checksum = \"35064CE144C23AD60842F44C989D70DD7A8923B8A74885F06E09B73DD3CC5283\" },\n  { name = \"nakai\", version = \"0.9.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"nakai\", source = \"hex\", outer_checksum = \"F6FFED9EF4B0E14C7A09B2FB87B42D3A93EFE024FD0299C11F041E92321163A6\" },\n  { name = \"nanoworker\", version = \"0.0.2\", build_tools = [\"gleam\"], requirements = [\"gleam_javascript\", \"gleam_stdlib\"], otp_app = \"nanoworker\", source = \"hex\", outer_checksum = \"78508877B313F01596CD2ABE2F3A866DC3C7AADE82DAFBB45396F8ED89EC2A14\" },\n  { name = \"nibble\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"nibble\", source = \"hex\", outer_checksum = \"2D9045E2CB12421783745113FD74DAC593EE3C2CCB74EA56E981ACEC0D442C20\" },\n  { name = \"nx\", version = \"0.7.1\", build_tools = [\"mix\"], requirements = [\"complex\", \"telemetry\"], otp_app = \"nx\", source = \"hex\", outer_checksum = \"E3DDD6A3F2A9BAC79C67B3933368C25BB5EC814A883FC68ABA8FD8A236751777\" },\n  { name = \"opentelemetry_api\", version = \"1.3.0\", build_tools = [\"rebar3\", \"mix\"], requirements = [\"opentelemetry_semantic_conventions\"], otp_app = \"opentelemetry_api\", source = \"hex\", outer_checksum = \"B9E5FF775FD064FA098DBA3C398490B77649A352B40B0B730A6B7DC0BDD68858\" },\n  { name = \"opentelemetry_semantic_conventions\", version = \"0.2.0\", build_tools = [\"rebar3\", \"mix\"], requirements = [], otp_app = \"opentelemetry_semantic_conventions\", source = \"hex\", outer_checksum = \"D61FA1F5639EE8668D74B527E6806E0503EFC55A42DB7B5F39939D84C07D6895\" },\n  { name = \"outil\", version = \"0.5.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"outil\", source = \"hex\", outer_checksum = \"ED5DD5E3333AF18782E3A30136879BFFAE86293B0E4598FAEF6DBC389186E29C\" },\n  { name = \"parse_trans\", version = \"3.4.1\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"parse_trans\", source = \"hex\", outer_checksum = \"620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A\" },\n  { name = \"pears\", version = \"0.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"pears\", source = \"hex\", outer_checksum = \"F823EDF5C7F8606A0B7764C071B6EE8515FC341D6FC69902E81120633DF7E983\" },\n  { name = \"pg_types\", version = \"0.4.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"pg_types\", source = \"hex\", outer_checksum = \"B02EFA785CAECECF9702C681C80A9CA12A39F9161A846CE17B01FB20AEEED7EB\" },\n  { name = \"pgo\", version = \"0.14.0\", build_tools = [\"rebar3\"], requirements = [\"backoff\", \"opentelemetry_api\", \"pg_types\"], otp_app = \"pgo\", source = \"hex\", outer_checksum = \"71016C22599936E042DC0012EE4589D24C71427D266292F775EBF201D97DF9C9\" },\n  { name = \"phony\", version = \"1.1.6\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"phony\", source = \"hex\", outer_checksum = \"64836B3DC384EECB8D117E6AB01A888ABEE65EBB33998B660A7238C41EB7AC66\" },\n  { name = \"plinth\", version = \"0.1.13\", build_tools = [\"gleam\"], requirements = [\"gleam_javascript\", \"gleam_json\", \"gleam_stdlib\"], otp_app = \"plinth\", source = \"hex\", outer_checksum = \"F4E20F8739D4D704BB69C8336B5E178D346EB69775BF263DC15B2A77B113A63C\" },\n  { name = \"prng\", version = \"3.0.2\", build_tools = [\"gleam\"], requirements = [\"gleam_bitwise\", \"gleam_stdlib\"], otp_app = \"prng\", source = \"hex\", outer_checksum = \"C61B103F9AF5031ADAA35187CCE7130845EF5088D88FD084E5995D4FBEC9D745\" },\n  { name = \"process_waiter\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_stdlib\"], otp_app = \"process_waiter\", source = \"hex\", outer_checksum = \"51D27A90BA736449D5447673FF295348D23462F9D9D4BD3E6794F507D65463D2\" },\n  { name = \"puddle\", version = \"0.5.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_otp\", \"gleam_stdlib\"], otp_app = \"puddle\", source = \"hex\", outer_checksum = \"1D199F61CAB692DA84CE8153C9351DC21C68C62BCE75782AFAAD5EE780144806\" },\n  { name = \"punycode\", version = \"0.1.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"punycode\", source = \"hex\", outer_checksum = \"BBEC025DE579CDD4F69578290E71DBC50B6CDAC17F8D1A1732EBA7E027526F60\" },\n  { name = \"radish\", version = \"0.13.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_otp\", \"gleam_stdlib\", \"mug\"], otp_app = \"radish\", source = \"hex\", outer_checksum = \"AEB090E74EE001D285CBEC474F91F201738363E167353B26D723B94AF65B6C1E\" },\n  { name = \"ranger\", version = \"1.2.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"ranger\", source = \"hex\", outer_checksum = \"1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C\" },\n  { name = \"rank\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"rank\", source = \"hex\", outer_checksum = \"5660E361F0E49CBB714CC57CC4C89C63415D8986F05B2DA0C719D5642FAD91C9\" },\n  { name = \"reactive_signal\", version = \"0.0.1\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_otp\", \"gleam_stdlib\"], otp_app = \"reactive_signal\", source = \"hex\", outer_checksum = \"735335DABE0513637641ACC425C2EAEE0EBDB7F1E38E6095F2AF20A3F835518E\" },\n  { name = \"repeatedly\", version = \"2.1.1\", build_tools = [\"gleam\"], requirements = [], otp_app = \"repeatedly\", source = \"hex\", outer_checksum = \"38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79\" },\n  { name = \"simplifile\", version = \"1.5.1\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"simplifile\", source = \"hex\", outer_checksum = \"C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7\" },\n  { name = \"snag\", version = \"0.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"snag\", source = \"hex\", outer_checksum = \"54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC\" },\n  { name = \"spinner\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_community_ansi\", \"gleam_erlang\", \"gleam_stdlib\", \"glearray\", \"repeatedly\"], otp_app = \"spinner\", source = \"hex\", outer_checksum = \"200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F\" },\n  { name = \"ssl_verify_fun\", version = \"1.1.7\", build_tools = [\"mix\", \"rebar3\", \"make\"], requirements = [], otp_app = \"ssl_verify_fun\", source = \"hex\", outer_checksum = \"FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8\" },\n  { name = \"telemetry\", version = \"1.2.1\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"telemetry\", source = \"hex\", outer_checksum = \"DAD9CE9D8EFFC621708F99EAC538EF1CBE05D6A874DD741DE2E689C47FEAFED5\" },\n  { name = \"testbldr\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_erlang\", \"gleam_stdlib\", \"simplifile\"], otp_app = \"testbldr\", source = \"hex\", outer_checksum = \"D4B4EE780E522E2C41386DA454B748971FC59CA8F710F138466E505FBFF01C86\" },\n  { name = \"thoas\", version = \"0.4.1\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"thoas\", source = \"hex\", outer_checksum = \"4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E\" },\n  { name = \"tom\", version = \"0.3.0\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"tom\", source = \"hex\", outer_checksum = \"0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577\" },\n  { name = \"trie_again\", version = \"1.1.2\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"trie_again\", source = \"hex\", outer_checksum = \"5B19176F52B1BD98831B57FDC97BD1F88C8A403D6D8C63471407E78598E27184\" },\n  { name = \"typed_headers\", version = \"1.1.2\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"typed_headers\", source = \"hex\", outer_checksum = \"352DE5BE502DF1B33F8B49BEB07A01295222A6A99311F9C3E09C1F071038B07C\" },\n  { name = \"unicode_util_compat\", version = \"0.7.0\", build_tools = [\"rebar3\"], requirements = [], otp_app = \"unicode_util_compat\", source = \"hex\", outer_checksum = \"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521\" },\n  { name = \"wimp\", version = \"1.1.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_json\", \"gleam_stdlib\"], otp_app = \"wimp\", source = \"hex\", outer_checksum = \"2C4C33992D503F51F2787103FEF345B3D5C097B566146B587CB370AAAF48DD84\" },\n  { name = \"wisp\", version = \"0.14.0\", build_tools = [\"gleam\"], requirements = [\"exception\", \"gleam_crypto\", \"gleam_erlang\", \"gleam_http\", \"gleam_json\", \"gleam_stdlib\", \"logging\", \"marceau\", \"mist\", \"simplifile\"], otp_app = \"wisp\", source = \"hex\", outer_checksum = \"9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684\" },\n  { name = \"xmleam\", version = \"1.1.4\", build_tools = [\"gleam\"], requirements = [\"gleam_stdlib\"], otp_app = \"xmleam\", source = \"hex\", outer_checksum = \"A747975444CE3343B6728AB217A1C44888A38060DFA41CA0C0B41D3E06417981\" },\n  { name = \"zeptomail\", version = \"1.0.0\", build_tools = [\"gleam\"], requirements = [\"gleam_http\", \"gleam_json\", \"gleam_stdlib\"], otp_app = \"zeptomail\", source = \"hex\", outer_checksum = \"D41269BE9F0E4BC52598E54E5AD087B386A44E97F49DA3D9C34CF554A5CB8A71\" },\n]\n\n[requirements]\nargamak = { version = \">= 1.1.0 and < 2.0.0\" }\nargv = { version = \">= 1.0.2 and < 2.0.0\" }\naws4_request = { version = \">= 0.1.1 and < 1.0.0\" }\nbigi = { version = \">= 2.1.0 and < 3.0.0\" }\nbirdie = { version = \">= 1.1.0 and < 2.0.0\" }\ncgi = { version = \">= 1.0.1 and < 2.0.0\" }\nconversation = { version = \">= 1.4.3 and < 2.0.0\" }\nedit_distance = { version = \">= 2.0.1 and < 3.0.0\" }\nenvoy = { version = \">= 1.0.1 and < 2.0.0\" }\nexception = { version = \">= 2.0.0 and < 3.0.0\" }\nexercism_test_runner = { version = \">= 1.7.0 and < 2.0.0\" }\nfile_streams = { version = \">= 0.3.1 and < 1.0.0\" }\nfilepath = { version = \">= 0.2.0 and < 1.0.0\" }\ngap = { version = \">= 1.1.3 and < 2.0.0\" }\ngen_core_erlang = { version = \">= 0.5.1 and < 1.0.0\" }\ngen_gleam = { version = \">= 0.3.1 and < 1.0.0\" }\nglance = { version = \">= 0.8.2 and < 1.0.0\" }\nglance_printer = { version = \">= 1.1.0 and < 2.0.0\" }\nglatus = { version = \">= 1.0.0 and < 2.0.0\" }\ngleam_community_ansi = { version = \">= 1.4.0 and < 2.0.0\" }\ngleam_community_colour = { version = \">= 1.4.0 and < 2.0.0\" }\ngleam_community_maths = { version = \">= 1.1.0 and < 2.0.0\" }\ngleam_crypto = { version = \">= 1.3.0 and < 2.0.0\" }\ngleam_elli = { version = \">= 2.4.0 and < 3.0.0\" }\ngleam_erlang = { version = \">= 0.25.0 and < 1.0.0\" }\ngleam_fetch = { version = \">= 0.4.0 and < 1.0.0\" }\ngleam_hackney = { version = \">= 1.2.0 and < 2.0.0\" }\ngleam_http = { version = \">= 3.6.0 and < 4.0.0\" }\ngleam_httpc = { version = \">= 2.2.0 and < 3.0.0\" }\ngleam_javascript = { version = \">= 0.8.0 and < 1.0.0\" }\ngleam_json = { version = \">= 0.7.0 and < 1.0.0\" }\ngleam_otp = { version = \">= 0.10.0 and < 1.0.0\" }\ngleam_pgo = { version = \">= 0.6.1 and < 1.0.0\" }\ngleam_sendgrid = { version = \">= 0.2.0 and < 1.0.0\" }\ngleam_stdlib = { version = \">= 0.36.0 and < 1.0.0\" }\ngleamy_bench = { version = \">= 0.4.0 and < 1.0.0\" }\nglearray = { version = \">= 0.2.1 and < 1.0.0\" }\ngleescript = { version = \">= 1.0.0 and < 2.0.0\" }\ngleeunit = { version = \">= 1.1.2 and < 2.0.0\" }\nglen = { version = \">= 2.0.0 and < 3.0.0\" }\nglenvy = { version = \">= 0.5.1 and < 1.0.0\" }\nglesha = { version = \">= 0.1.3 and < 1.0.0\" }\nglexer = { version = \">= 0.7.0 and < 1.0.0\" }\nglisten = { version = \">= 2.0.0 and < 3.0.0\" }\nglobe = { version = \">= 0.1.0 and < 1.0.0\" }\ngsv = { version = \">= 1.4.0 and < 2.0.0\" }\nhtmb = { version = \">= 2.0.0 and < 3.0.0\" }\nhtmgrrrl = { version = \">= 0.3.0 and < 1.0.0\" }\nids = { version = \">= 0.12.0 and < 1.0.0\" }\nimmutable_lru = { version = \">= 1.0.1 and < 2.0.0\" }\niso_8859 = { version = \">= 2.0.0 and < 3.0.0\" }\njasper = { version = \">= 1.2.0 and < 2.0.0\" }\njot = { version = \">= 0.3.1 and < 1.0.0\" }\njustin = { version = \">= 1.0.1 and < 2.0.0\" }\njwt = { version = \">= 0.1.11 and < 1.0.0\" }\nlustre = { version = \">= 3.1.4 and < 4.0.0\" }\nlustre_http = { version = \">= 0.5.0 and < 1.0.0\" }\nlustre_ui = { version = \">= 0.4.0 and < 1.0.0\" }\nlustre_websocket = { version = \">= 0.7.6 and < 1.0.0\" }\nmarceau = { version = \">= 1.1.0 and < 2.0.0\" }\nmineflayer = { version = \">= 0.1.0 and < 1.0.0\" }\nmist = { version = \">= 1.0.0 and < 2.0.0\" }\nmorse_code_translator = { version = \">= 2.0.0 and < 3.0.0\" }\nmug = { version = \">= 0.2.0 and < 1.0.0\" }\nnakai = { version = \">= 0.9.0 and < 1.0.0\" }\nnanoworker = { version = \">= 0.0.2 and < 1.0.0\" }\nnibble = { version = \">= 1.1.0 and < 2.0.0\" }\noutil = { version = \">= 0.5.0 and < 1.0.0\" }\npears = { version = \">= 0.3.0 and < 1.0.0\" }\nphony = { version = \">= 1.1.6 and < 2.0.0\" }\nplinth = { version = \">= 0.1.13 and < 1.0.0\" }\nprng = { version = \">= 3.0.2 and < 4.0.0\" }\nprocess_waiter = { version = \">= 1.0.0 and < 2.0.0\" }\npuddle = { version = \">= 0.5.0 and < 1.0.0\" }\npunycode = { version = \">= 0.1.1 and < 1.0.0\" }\nradish = { version = \">= 0.13.0 and < 1.0.0\" }\nranger = { version = \">= 1.2.0 and < 2.0.0\" }\nrank = { version = \">= 1.0.0 and < 2.0.0\" }\nreactive_signal = { version = \">= 0.0.1 and < 1.0.0\" }\nrepeatedly = { version = \">= 2.1.1 and < 3.0.0\" }\nsimplifile = { version = \">= 1.5.1 and < 2.0.0\" }\nsnag = { version = \">= 0.3.0 and < 1.0.0\" }\nspinner = { version = \">= 1.1.0 and < 2.0.0\" }\ntestbldr = { version = \">= 1.1.0 and < 2.0.0\" }\ntom = { version = \">= 0.3.0 and < 1.0.0\" }\ntyped_headers = { version = \">= 1.1.2 and < 2.0.0\" }\nwimp = { version = \">= 1.1.0 and < 2.0.0\" }\nwisp = { version = \">= 0.14.0 and < 1.0.0\" }\nxmleam = { version = \">= 1.1.4 and < 2.0.0\" }\nzeptomail = { version = \">= 1.0.0 and < 2.0.0\" }\n"
  },
  {
    "path": "test-community-packages/src/test_community_packages.gleam",
    "content": "import gleam/io\n\npub fn main() {\n  io.println(\"Hello from test_community_packages!\")\n}\n"
  },
  {
    "path": "test-community-packages/test/test_community_packages_test.gleam",
    "content": "import gleeunit\nimport gleeunit/should\n\npub fn main() {\n  gleeunit.main()\n}\n\n// gleeunit test functions end in `_test`\npub fn hello_world_test() {\n  1\n  |> should.equal(1)\n}\n"
  },
  {
    "path": "test-helpers-rs/Cargo.toml",
    "content": "[package]\nname = \"test-helpers-rs\"\nversion = \"0.1.0\"\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\ngleam-core = { path = \"../compiler-core\" }\nwalkdir = \"2\"\n\ntoml.workspace = true\nim.workspace = true\nitertools.workspace = true\nregex.workspace = true\ncamino.workspace = true\n\n[dev-dependencies]\ninsta.workspace = true\n"
  },
  {
    "path": "test-helpers-rs/src/lib.rs",
    "content": "use camino::{Utf8Path, Utf8PathBuf};\nuse gleam_core::{\n    io::{Content, FileSystemWriter, memory::InMemoryFileSystem},\n    version::COMPILER_VERSION,\n};\nuse itertools::Itertools;\nuse regex::Regex;\nuse std::{collections::HashMap, fmt::Write, sync::LazyLock};\n\n#[derive(Debug)]\npub struct TestCompileOutput {\n    pub files: HashMap<Utf8PathBuf, Content>,\n    pub warnings: Vec<gleam_core::Warning>,\n}\n\nimpl TestCompileOutput {\n    pub fn as_overview_text(&self) -> String {\n        let mut buffer = String::new();\n        for (path, content) in self.files.iter().sorted_by(|a, b| a.0.cmp(b.0)) {\n            let normalised_path = if path.as_str().contains(\"cases\") {\n                path.as_str()\n                    .split(\"cases\")\n                    .skip(1)\n                    .collect::<String>()\n                    .as_str()\n                    .replace('\\\\', \"/\")\n                    .split('/')\n                    .skip(1)\n                    .join(\"/\")\n            } else {\n                path.as_str().replace('\\\\', \"/\")\n            };\n            buffer.push_str(\"//// \");\n            buffer.push_str(&normalised_path);\n            buffer.push('\\n');\n\n            let extension = path.extension();\n\n            match content {\n                _ if extension == Some(\"cache\") => buffer.push_str(\"<.cache binary>\"),\n                Content::Binary(data) => write!(buffer, \"<{} byte binary>\", data.len()).unwrap(),\n\n                Content::Text(_) if normalised_path.ends_with(\"@@main.erl\") => {\n                    write!(buffer, \"<erlang entrypoint>\").unwrap()\n                }\n\n                Content::Text(text) => {\n                    let format_path = |caps: &regex::Captures| {\n                        caps.get(1)\n                            .expect(\"file path\")\n                            .as_str()\n                            .replace(\"\\\\\\\\\", \"/\")\n                    };\n                    let text = FILE_LINE_REGEX.replace_all(text, |caps: &regex::Captures| {\n                        let path = format_path(caps);\n                        let line_number = caps.get(2).expect(\"line number\").as_str();\n                        format!(\"-file(\\\"{path}\\\", {line_number}).\")\n                    });\n                    let text = FILEPATH_MACRO_REGEX\n                        .replace_all(text.to_string().as_str(), |caps: &regex::Captures| {\n                            let path = format_path(caps);\n                            format!(\"-define(FILEPATH, \\\"{path}\\\").\")\n                        })\n                        .replace(COMPILER_VERSION, \"<gleam compiler version string>\");\n                    buffer.push_str(&text)\n                }\n            };\n            buffer.push('\\n');\n            buffer.push('\\n');\n        }\n\n        for warning in self.warnings.iter().map(|w| w.to_pretty_string()).sorted() {\n            write!(buffer, \"//// Warning\\n{}\", normalise_diagnostic(&warning)).unwrap();\n            buffer.push('\\n');\n            buffer.push('\\n');\n        }\n\n        buffer\n    }\n}\n\npub fn to_in_memory_filesystem(path: &Utf8Path) -> InMemoryFileSystem {\n    let fs = InMemoryFileSystem::new();\n\n    let files = walkdir::WalkDir::new(path)\n        .follow_links(true)\n        .into_iter()\n        .filter_map(Result::ok)\n        .filter(|entry| entry.file_type().is_file())\n        .map(|entry| entry.into_path());\n\n    for fullpath in files {\n        let content = std::fs::read(&fullpath).unwrap();\n        let path = fullpath.strip_prefix(path).unwrap();\n        fs.write_bytes(Utf8Path::from_path(path).unwrap(), &content)\n            .unwrap();\n    }\n\n    fs\n}\n\nstatic FILE_LINE_REGEX: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r#\"-file\\(\"([^\"]+)\", (\\d+)\\)\\.\"#).expect(\"Invalid regex\"));\n\nstatic FILEPATH_MACRO_REGEX: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r#\"-define\\(FILEPATH, \"([^\"]+)\"\\)\\.\"#).expect(\"Invalid regex\"));\n\npub fn normalise_diagnostic(text: &str) -> String {\n    // There is an extra ^ on Windows in some error messages' code\n    // snippets.\n    // I've not managed to determine why this is yet (it is especially\n    // tricky without a Windows computer) so for now we just squash them\n    // in these cross-platform tests.\n    Regex::new(r\"\\^+\")\n        .expect(\"^ sequence regex\")\n        .replace_all(text, \"^\")\n        .replace('\\\\', \"/\")\n}\n"
  },
  {
    "path": "test-output/Cargo.toml",
    "content": "[package]\nname = \"test-output\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\ngleam-core = { path = \"../compiler-core\" }\ngleam-cli = { path = \"../compiler-cli\" }\ntest-helpers-rs = { path = \"../test-helpers-rs\" }\ncamino = { workspace = true, features = [\"serde1\"] }\n\n[dev-dependencies]\ninsta.workspace = true\n"
  },
  {
    "path": "test-output/cases/.gitignore",
    "content": "**/build\n**/manifest.toml\n"
  },
  {
    "path": "test-output/cases/echo_bitarray/gleam.toml",
    "content": "name = \"echo_bitarray\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_bitarray/src/main.gleam",
    "content": "pub fn main() {\n  echo <<>>\n  echo <<1, 2, 3>>\n  echo <<1, 2, 3:2>>\n}\n"
  },
  {
    "path": "test-output/cases/echo_bool/gleam.toml",
    "content": "name = \"echo_bool\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_bool/src/main.gleam",
    "content": "pub fn main() {\n  echo True\n  echo False\n}\n"
  },
  {
    "path": "test-output/cases/echo_charlist/gleam.toml",
    "content": "name = \"echo_charlist\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_charlist/src/main.gleam",
    "content": "pub fn main() {\n  echo [72, 101, 108, 108, 111, 44, 32, 74, 111, 101, 33]\n}\n"
  },
  {
    "path": "test-output/cases/echo_circular_reference/gleam.toml",
    "content": "name = \"echo_circular_reference\"\nversion = \"1.0.0\"\ntarget = \"javascript\"\n"
  },
  {
    "path": "test-output/cases/echo_circular_reference/src/main.gleam",
    "content": "pub fn main() {\n  echo circular_reference()\n  Nil\n}\n\ntype Thing\n\n@external(javascript, \"./main_ffi.mjs\", \"circular_reference\")\nfn circular_reference() -> Thing\n"
  },
  {
    "path": "test-output/cases/echo_circular_reference/src/main_ffi.mjs",
    "content": "export function circular_reference() {\n  const x = [];\n  x.push(x);\n  return x;\n}\n"
  },
  {
    "path": "test-output/cases/echo_custom_type/gleam.toml",
    "content": "name = \"echo_custom_type\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_custom_type/src/main.gleam",
    "content": "pub type Wibble {\n  Wibble(a: Int, b: String)\n  Wobble(a: List(Float))\n  Woo\n}\n\npub fn main() {\n  echo Wibble(1, \"hello\")\n  echo Wobble([1.0, 1.1])\n  echo Woo\n}\n"
  },
  {
    "path": "test-output/cases/echo_dict/gleam.toml",
    "content": "name = \"echo_tuple\"\nversion = \"1.0.0\"\n\n[dependencies]\ngleam_stdlib = \">= 0.34.0 and < 2.0.0\"\n\n[dev_dependencies]\n"
  },
  {
    "path": "test-output/cases/echo_dict/src/main.gleam",
    "content": "import gleam/dict\n\npub fn main() {\n  echo dict.new()\n  echo dict.from_list([#(1, \"hello\"), #(2, \"world!\")])\n}\n"
  },
  {
    "path": "test-output/cases/echo_float/gleam.toml",
    "content": "name = \"echo_float\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_float/src/main.gleam",
    "content": "pub fn main() {\n  echo 1.0\n  echo 2.1\n  echo 11.11\n}\n"
  },
  {
    "path": "test-output/cases/echo_function/gleam.toml",
    "content": "name = \"echo_custom_type\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_function/src/main.gleam",
    "content": "pub fn main() {\n  echo fn(n) { n + 1 }\n  echo private\n}\n\nfn private() {\n  1\n}\n"
  },
  {
    "path": "test-output/cases/echo_importing_module_named_inspect/gleam.toml",
    "content": "name = \"echo_importing_module_named_inspect\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_importing_module_named_inspect/src/inspect.gleam",
    "content": "pub const x = Nil\n"
  },
  {
    "path": "test-output/cases/echo_importing_module_named_inspect/src/main.gleam",
    "content": "import inspect\n\npub fn main() {\n  echo inspect.x\n}\n"
  },
  {
    "path": "test-output/cases/echo_int/gleam.toml",
    "content": "name = \"echo_int\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_int/src/main.gleam",
    "content": "pub fn main() {\n  echo 1\n  echo 2\n  echo 100_000\n}\n"
  },
  {
    "path": "test-output/cases/echo_list/gleam.toml",
    "content": "name = \"echo_list\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_list/src/main.gleam",
    "content": "pub fn main() {\n  echo []\n  echo [1, 2, 3]\n}\n"
  },
  {
    "path": "test-output/cases/echo_nil/gleam.toml",
    "content": "name = \"echo_nil\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_nil/src/main.gleam",
    "content": "pub fn main() {\n  echo Nil\n}\n"
  },
  {
    "path": "test-output/cases/echo_non_record_atom_tag/gleam.toml",
    "content": "name = \"echo_non_record_atom_tag\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_non_record_atom_tag/src/main.gleam",
    "content": "pub fn main() {\n  echo #(to_atom(\"UP\"), 1, 2)\n  echo #(to_atom(\"down\"), 12.34)\n  echo #(to_atom(\"Both\"), \"ok\")\n}\n\npub type Atom\n\n@external(erlang, \"erlang\", \"binary_to_atom\")\npub fn to_atom(string: String) -> Atom\n"
  },
  {
    "path": "test-output/cases/echo_singleton/gleam.toml",
    "content": "name = \"echo_circular_reference\"\nversion = \"1.0.0\"\ntarget = \"javascript\"\n"
  },
  {
    "path": "test-output/cases/echo_singleton/src/main.gleam",
    "content": "import thing\n\npub fn main() {\n  echo #(1, singleton(), singleton())\n  Nil\n}\n\n@external(javascript, \"./main_ffi.mjs\", \"singleton\")\nfn singleton() -> thing.Thing {\n  thing.Thing\n}\n"
  },
  {
    "path": "test-output/cases/echo_singleton/src/main_ffi.mjs",
    "content": "import { Thing } from \"./thing.mjs\";\n\nconst it = new Thing();\n\nexport function singleton() {\n  return it;\n}\n"
  },
  {
    "path": "test-output/cases/echo_singleton/src/thing.gleam",
    "content": "pub type Thing {\n  Thing\n}\n"
  },
  {
    "path": "test-output/cases/echo_string/gleam.toml",
    "content": "name = \"echo_string\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_string/src/main.gleam",
    "content": "pub fn main() {\n  echo \"hello world\"\n  echo \"multiline\nstring\"\n  echo \"string with\\t\\r\\nescaped chars\"\n}\n"
  },
  {
    "path": "test-output/cases/echo_tuple/gleam.toml",
    "content": "name = \"echo_tuple\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_tuple/src/main.gleam",
    "content": "pub fn main() {\n  echo #()\n  echo #(True, 1, \"hello\")\n}\n"
  },
  {
    "path": "test-output/cases/echo_with_message/gleam.toml",
    "content": "name = \"echo_bitarray\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/echo_with_message/src/main.gleam",
    "content": "pub fn main() {\n  let message = \"message\"\n\n  echo 1 as \"message1\"\n\n  1\n  |> echo as { message <> \"2\" }\n  |> fn(n) { n + 1 }\n  |> echo as \"message3\"\n}\n"
  },
  {
    "path": "test-output/cases/linked_process_exit/gleam.toml",
    "content": "name = \"linked_process_exit\"\nversion = \"1.0.0\"\n"
  },
  {
    "path": "test-output/cases/linked_process_exit/src/main.gleam",
    "content": "@external(erlang, \"main_ffi\", \"spawn_and_exit\")\nfn spawn_and_exit() -> Nil\n\npub fn main() {\n  spawn_and_exit()\n}\n"
  },
  {
    "path": "test-output/cases/linked_process_exit/src/main_ffi.erl",
    "content": "-module(main_ffi).\n-export([spawn_and_exit/0]).\n\n%% Spawn a linked process that exits with a non-standard reason.\n%% This tests that the @@main.erl template handles exit reasons\n%% that aren't {Reason, StackTrace} tuples (issue #4766).\nspawn_and_exit() ->\n    spawn_link(fun() ->\n        exit({shutdown, <<\"test reason\">>})\n    end),\n    %% Wait briefly to ensure the linked process exits and kills us\n    receive after 100 -> nil end.\n"
  },
  {
    "path": "test-output/src/lib.rs",
    "content": "#[cfg(test)]\nmod tests;\n"
  },
  {
    "path": "test-output/src/tests/echo.rs",
    "content": "use std::{io::Read, process::Stdio};\n\nuse camino::{Utf8Path, Utf8PathBuf};\nuse gleam_core::{\n    build::{Runtime, Target},\n    io::Command,\n    paths::ProjectPaths,\n};\n\nuse gleam_cli::{\n    fs,\n    run::{self, Which},\n};\n\nfn run_and_produce_pretty_snapshot(\n    target: Option<Target>,\n    runtime: Option<Runtime>,\n    project_directory: Utf8PathBuf,\n) -> String {\n    let project_root = fs::get_project_root(project_directory).expect(\"project root\");\n    let paths = ProjectPaths::new(project_root);\n\n    let output = run_and_capture_output(&paths, \"main\", target, runtime)\n        // Since the echo output's contains a path we will replace the `\\` with a `/`\n        // so that the snapshot doesn't fail on Windows in CI.\n        .replace(\"src\\\\\", \"src/\");\n\n    let main_module_content =\n        fs::read(paths.src_directory().join(\"main.gleam\")).expect(\"read main module\");\n\n    format!(\n        \"--- main.gleam ----------------------\n{main_module_content}\n\n--- gleam run output ----------------\n{output}\n\"\n    )\n}\n\nfn run_and_capture_output(\n    paths: &ProjectPaths,\n    main_module: &str,\n    target: Option<Target>,\n    runtime: Option<Runtime>,\n) -> String {\n    fs::delete_directory(&paths.build_directory()).expect(\"delete build directory content\");\n\n    let Command {\n        program,\n        args,\n        env,\n        cwd: _,\n        stdio: _,\n    } = run::setup(\n        paths,\n        vec![],\n        target,\n        runtime,\n        Some(main_module.into()),\n        Which::Src,\n        true,\n    )\n    .expect(\"run setup\");\n\n    let mut process = std::process::Command::new(&program)\n        .args(args)\n        .stdin(Stdio::null())\n        .stdout(Stdio::null())\n        .stderr(Stdio::piped())\n        .envs(env.iter().map(|pair| (&pair.0, &pair.1)))\n        .current_dir(paths.root())\n        .spawn()\n        .unwrap_or_else(|e| panic!(\"Failed to spawn process '{}': {}\", &program, &e));\n\n    let mut stderr = process.stderr.take().expect(\"take stderr\");\n    let mut output = String::new();\n    let _ = stderr.read_to_string(&mut output).expect(\"read stderr\");\n    let _ = process.wait().expect(\"run with no errors\");\n    output\n}\n\nmacro_rules! assert_echo {\n    ($project_name: expr) => {\n        let snapshot_name = snapshot_name(None, None, $project_name);\n        insta::allow_duplicates! {\n            assert_echo!(&snapshot_name, Some(Target::Erlang), None, $project_name);\n            assert_echo!(&snapshot_name, Some(Target::JavaScript), Some(Runtime::Bun), $project_name);\n            assert_echo!(&snapshot_name, Some(Target::JavaScript), Some(Runtime::Deno), $project_name);\n            assert_echo!(&snapshot_name, Some(Target::JavaScript), Some(Runtime::NodeJs), $project_name);\n        }\n    };\n\n    ($target: expr, $project_name: expr) => {\n        let snapshot_name = snapshot_name(Some($target), None, $project_name);\n        match $target {\n            Target::JavaScript => insta::allow_duplicates! {\n                assert_echo!(&snapshot_name, Some($target), Some(Runtime::Bun), $project_name);\n                assert_echo!(&snapshot_name, Some($target), Some(Runtime::Deno), $project_name);\n                assert_echo!(&snapshot_name, Some($target), Some(Runtime::NodeJs), $project_name);\n            },\n            Target::Erlang => {\n                assert_echo!(&snapshot_name, Some($target), None, $project_name);\n            }\n        }\n    };\n\n    ($snapshot_name: expr, $target: expr, $runtime: expr, $project_name: expr) => {\n        let path = fs::canonicalise(&Utf8Path::new(\"../test-output/cases\").join($project_name))\n            .expect(\"canonicalise path\");\n        let output = run_and_produce_pretty_snapshot($target, $runtime, path);\n        insta::assert_snapshot!($snapshot_name.to_string(), output);\n    };\n}\n\nfn snapshot_name(target: Option<Target>, runtime: Option<Runtime>, suffix: &str) -> String {\n    let show_target = |target: Target| match target {\n        Target::Erlang => \"erlang\",\n        Target::JavaScript => \"javascript\",\n    };\n    let show_runtime = |runtime: Runtime| match runtime {\n        Runtime::NodeJs => \"nodejs\",\n        Runtime::Deno => \"deno\",\n        Runtime::Bun => \"bun\",\n    };\n    let prefix = match (target, runtime) {\n        (None, None) => \"\".into(),\n        (None, Some(runtime)) => format!(\"{}-\", show_runtime(runtime)),\n        (Some(target), None) => format!(\"{}-\", show_target(target)),\n        (Some(target), Some(runtime)) => {\n            format!(\"{}-{}-\", show_target(target), show_runtime(runtime))\n        }\n    };\n    format!(\"{prefix}{suffix}\")\n}\n\n#[test]\nfn echo_bitarray() {\n    assert_echo!(Target::JavaScript, \"echo_bitarray\");\n    assert_echo!(Target::Erlang, \"echo_bitarray\");\n}\n\n#[test]\nfn echo_bool() {\n    assert_echo!(\"echo_bool\");\n}\n\n#[test]\nfn echo_charlist() {\n    assert_echo!(\"echo_charlist\");\n}\n\n#[test]\nfn echo_custom_type() {\n    assert_echo!(Target::Erlang, \"echo_custom_type\");\n    assert_echo!(Target::JavaScript, \"echo_custom_type\");\n}\n\n#[test]\nfn echo_dict() {\n    assert_echo!(\"echo_dict\");\n}\n\n#[test]\nfn echo_float() {\n    assert_echo!(Target::Erlang, \"echo_float\");\n    assert_echo!(Target::JavaScript, \"echo_float\");\n}\n\n#[test]\nfn echo_function() {\n    assert_echo!(\"echo_function\");\n}\n\n#[test]\nfn echo_importing_module_named_inspect() {\n    assert_echo!(\"echo_importing_module_named_inspect\");\n}\n\n#[test]\nfn echo_int() {\n    assert_echo!(\"echo_int\");\n}\n\n#[test]\nfn echo_list() {\n    assert_echo!(\"echo_list\");\n}\n\n#[test]\nfn echo_nil() {\n    assert_echo!(\"echo_nil\");\n}\n\n#[test]\nfn echo_string() {\n    assert_echo!(\"echo_string\");\n}\n\n#[test]\nfn echo_tuple() {\n    assert_echo!(\"echo_tuple\");\n}\n\n#[test]\nfn echo_non_record_atom_tag() {\n    assert_echo!(Target::Erlang, \"echo_non_record_atom_tag\");\n}\n\n#[test]\nfn echo_circular_reference() {\n    assert_echo!(Target::JavaScript, \"echo_circular_reference\");\n}\n\n#[test]\nfn echo_singleton() {\n    assert_echo!(\"echo_singleton\");\n}\n\n#[test]\nfn echo_with_message() {\n    assert_echo!(\"echo_with_message\");\n}\n\n#[test]\nfn linked_process_exit() {\n    assert_echo!(Target::Erlang, \"linked_process_exit\");\n}\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_bool.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo True\n  echo False\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\nTrue\n\u001b[90msrc/main.gleam:3\u001b[39m\nFalse\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_charlist.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nassertion_line: 139\nexpression: output\nsnapshot_kind: text\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo [72, 101, 108, 108, 111, 44, 32, 74, 111, 101, 33]\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\ncharlist.from_string(\"Hello, Joe!\")\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_dict.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\nimport gleam/dict\n\npub fn main() {\n  echo dict.new()\n  echo dict.from_list([#(1, \"hello\"), #(2, \"world!\")])\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:4\u001b[39m\ndict.from_list([])\n\u001b[90msrc/main.gleam:5\u001b[39m\ndict.from_list([#(1, \"hello\"), #(2, \"world!\")])\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_function.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo fn(n) { n + 1 }\n  echo private\n}\n\nfn private() {\n  1\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n//fn(a) { ... }\n\u001b[90msrc/main.gleam:3\u001b[39m\n//fn() { ... }\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_importing_module_named_inspect.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\nimport inspect\n\npub fn main() {\n  echo inspect.x\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:4\u001b[39m\nNil\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_int.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo 1\n  echo 2\n  echo 100_000\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n1\n\u001b[90msrc/main.gleam:3\u001b[39m\n2\n\u001b[90msrc/main.gleam:4\u001b[39m\n100000\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_list.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo []\n  echo [1, 2, 3]\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n[]\n\u001b[90msrc/main.gleam:3\u001b[39m\n[1, 2, 3]\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_nil.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo Nil\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\nNil\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_singleton.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nassertion_line: 206\nexpression: output\nsnapshot_kind: text\n---\n--- main.gleam ----------------------\nimport thing\n\npub fn main() {\n  echo #(1, singleton(), singleton())\n  Nil\n}\n\n@external(javascript, \"./main_ffi.mjs\", \"singleton\")\nfn singleton() -> thing.Thing {\n  thing.Thing\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:4\u001b[39m\n#(1, Thing, Thing)\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_string.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo \"hello world\"\n  echo \"multiline\nstring\"\n  echo \"string with\\t\\r\\nescaped chars\"\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n\"hello world\"\n\u001b[90msrc/main.gleam:3\u001b[39m\n\"multiline\\nstring\"\n\u001b[90msrc/main.gleam:5\u001b[39m\n\"string with\\t\\r\\nescaped chars\"\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_tuple.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo #()\n  echo #(True, 1, \"hello\")\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n#()\n\u001b[90msrc/main.gleam:3\u001b[39m\n#(True, 1, \"hello\")\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__echo_with_message.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  let message = \"message\"\n\n  echo 1 as \"message1\"\n\n  1\n  |> echo as { message <> \"2\" }\n  |> fn(n) { n + 1 }\n  |> echo as \"message3\"\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:4\u001b[39m message1\n1\n\u001b[90msrc/main.gleam:7\u001b[39m message2\n1\n\u001b[90msrc/main.gleam:9\u001b[39m message3\n2\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__erlang-echo_bitarray.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo <<>>\n  echo <<1, 2, 3>>\n  echo <<1, 2, 3:2>>\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n\"\"\n\u001b[90msrc/main.gleam:3\u001b[39m\n\"\\u{0001}\\u{0002}\\u{0003}\"\n\u001b[90msrc/main.gleam:4\u001b[39m\n<<1, 2, 3:size(2)>>\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__erlang-echo_custom_type.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub type Wibble {\n  Wibble(a: Int, b: String)\n  Wobble(a: List(Float))\n  Woo\n}\n\npub fn main() {\n  echo Wibble(1, \"hello\")\n  echo Wobble([1.0, 1.1])\n  echo Woo\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:8\u001b[39m\nWibble(1, \"hello\")\n\u001b[90msrc/main.gleam:9\u001b[39m\nWobble([1.0, 1.1])\n\u001b[90msrc/main.gleam:10\u001b[39m\nWoo\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__erlang-echo_float.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo 1.0\n  echo 2.1\n  echo 11.11\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n1.0\n\u001b[90msrc/main.gleam:3\u001b[39m\n2.1\n\u001b[90msrc/main.gleam:4\u001b[39m\n11.11\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__erlang-echo_non_record_atom_tag.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo #(to_atom(\"UP\"), 1, 2)\n  echo #(to_atom(\"down\"), 12.34)\n  echo #(to_atom(\"Both\"), \"ok\")\n}\n\npub type Atom\n\n@external(erlang, \"erlang\", \"binary_to_atom\")\npub fn to_atom(string: String) -> Atom\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n#(atom.create(\"UP\"), 1, 2)\n\u001b[90msrc/main.gleam:3\u001b[39m\nDown(12.34)\n\u001b[90msrc/main.gleam:4\u001b[39m\n#(atom.create(\"Both\"), \"ok\")\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__erlang-linked_process_exit.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\n@external(erlang, \"main_ffi\", \"spawn_and_exit\")\nfn spawn_and_exit() -> Nil\n\npub fn main() {\n  spawn_and_exit()\n}\n\n\n--- gleam run output ----------------\n\u001b[31;1mruntime error\u001b[39m: Erlang exit\u001b[0m\n\nAn error occurred outside of Gleam.\n\nexit reason:\n  {shutdown,<<\"test reason\">>}\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__javascript-echo_bitarray.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo <<>>\n  echo <<1, 2, 3>>\n  echo <<1, 2, 3:2>>\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n<<>>\n\u001b[90msrc/main.gleam:3\u001b[39m\n<<1, 2, 3>>\n\u001b[90msrc/main.gleam:4\u001b[39m\n<<1, 2, 3:size(2)>>\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__javascript-echo_circular_reference.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nassertion_line: 201\nexpression: output\nsnapshot_kind: text\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo circular_reference()\n  Nil\n}\n\ntype Thing\n\n@external(javascript, \"./main_ffi.mjs\", \"circular_reference\")\nfn circular_reference() -> Thing\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n#(//js(circular reference))\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__javascript-echo_custom_type.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub type Wibble {\n  Wibble(a: Int, b: String)\n  Wobble(a: List(Float))\n  Woo\n}\n\npub fn main() {\n  echo Wibble(1, \"hello\")\n  echo Wobble([1.0, 1.1])\n  echo Woo\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:8\u001b[39m\nWibble(a: 1, b: \"hello\")\n\u001b[90msrc/main.gleam:9\u001b[39m\nWobble(a: [1, 1.1])\n\u001b[90msrc/main.gleam:10\u001b[39m\nWoo\n"
  },
  {
    "path": "test-output/src/tests/snapshots/test_output__tests__echo__javascript-echo_float.snap",
    "content": "---\nsource: test-output/src/tests/echo.rs\nexpression: output\n---\n--- main.gleam ----------------------\npub fn main() {\n  echo 1.0\n  echo 2.1\n  echo 11.11\n}\n\n\n--- gleam run output ----------------\n\u001b[90msrc/main.gleam:2\u001b[39m\n1\n\u001b[90msrc/main.gleam:3\u001b[39m\n2.1\n\u001b[90msrc/main.gleam:4\u001b[39m\n11.11\n"
  },
  {
    "path": "test-output/src/tests.rs",
    "content": "#[cfg(test)]\nmod echo;\n"
  },
  {
    "path": "test-package-compiler/.gitignore",
    "content": "cases/*/build\ncases/*/manifest.toml\n"
  },
  {
    "path": "test-package-compiler/Cargo.toml",
    "content": "[package]\nname = \"test-package-compiler\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\ngleam-core = { path = \"../compiler-core\" }\ntest-helpers-rs = { path = \"../test-helpers-rs\" }\ntoml.workspace = true\nim.workspace = true\nitertools.workspace = true\nregex.workspace = true\ncamino.workspace = true\n\n[dev-dependencies]\ninsta.workspace = true\n"
  },
  {
    "path": "test-package-compiler/build.rs",
    "content": "use std::path::PathBuf;\n\npub fn main() {\n    println!(\"cargo:rerun-if-changed=cases\");\n\n    let mut module = \"//! This file is generated by build.rs\n//! Do not edit it directly, instead add new test cases to ./cases\n\"\n    .to_string();\n\n    let cases = PathBuf::from(\"./cases\");\n\n    let mut names: Vec<_> = std::fs::read_dir(&cases)\n        .unwrap()\n        .map(|entry| entry.unwrap().file_name().into_string().unwrap())\n        .collect();\n    names.sort();\n\n    for name in names {\n        let path = cases.join(&name);\n        let path = path.to_str().unwrap().replace('\\\\', \"/\");\n        module.push_str(&format!(\n            r#\"\n#[rustfmt::skip]\n#[test]\nfn {name}() {{\n    let output = crate::prepare(\"{path}\");\n    insta::assert_snapshot!(\n        \"{name}\",\n        output,\n        \"{path}\",\n    );\n}}\n\"#\n        ));\n    }\n\n    let out = PathBuf::from(\"./src/generated_tests.rs\");\n    std::fs::write(out, module).unwrap();\n}\n"
  },
  {
    "path": "test-package-compiler/cases/alias_unqualified_import/gleam.toml",
    "content": "# https://github.com/gleam-lang/gleam/issues/303\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/alias_unqualified_import/src/one.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/303\npub fn id(x) {\n  x\n}\n\npub type Empty {\n  Empty\n}\n"
  },
  {
    "path": "test-package-compiler/cases/alias_unqualified_import/src/two.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/303\nimport one.{Empty as E, id as i}\n\npub fn make() {\n  i(E)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/dev_importing_test/dev/one.gleam",
    "content": "// This import will fail because the `two` module is in the `test` directory and\n// as such isn't permitted to be imported into the `dev` directory.\nimport two\n"
  },
  {
    "path": "test-package-compiler/cases/dev_importing_test/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/dev_importing_test/test/two.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module/gleam.toml",
    "content": "name = \"duplicate_module_dev\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module/src/main.gleam",
    "content": "// There is another module with the same name in the `test` directory.\npub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module/test/main.gleam",
    "content": "// There is another module with the same name in the `src` directory.\npub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module_dev/dev/main.gleam",
    "content": "// There is another module with the same name in the `src` directory.\npub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module_dev/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module_dev/src/main.gleam",
    "content": "// There is another module with the same name in the `dev` directory.\npub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module_test_dev/dev/main.gleam",
    "content": "// There is another module with the same name in the `test` directory.\npub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module_test_dev/gleam.toml",
    "content": "name = \"duplicate_module\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/duplicate_module_test_dev/test/main.gleam",
    "content": "// There is another module with the same name in the `dev` directory.\npub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/empty_module_warning/gleam.toml",
    "content": "name = \"empty_module_warning\"\nversion = \"1.0.0\"\ndescription = \"Test package with empty modules\"\nlicences = [\"Apache-2.0\"]\n\n[dependencies]\ngleam_stdlib = \">= 0.44.0 and < 2.0.0\""
  },
  {
    "path": "test-package-compiler/cases/empty_module_warning/src/empty.gleam",
    "content": "// This is an empty module"
  },
  {
    "path": "test-package-compiler/cases/empty_module_warning/src/internal.gleam",
    "content": "@internal\npub fn private_function() -> Nil {\n  Nil\n}\n"
  },
  {
    "path": "test-package-compiler/cases/empty_module_warning/src/private.gleam",
    "content": "fn private_function() -> Nil {\n  Nil\n}\n"
  },
  {
    "path": "test-package-compiler/cases/empty_module_warning/src/public.gleam",
    "content": "pub fn main() {\n  \"This module has public definitions\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_app_generation/gleam.toml",
    "content": "# This config file has a bunch of properties that will be entered into the\n# Erlang .app file\n\nname = \"my_erlang_application\" # <-\nversion = \"0.1.0\"              # <-\ndescription = \"It's very cool\" # <-\n\ntarget = \"erlang\"\n\n[erlang]\nextra_applications = [\"inets\", \"ssl\"] # <-\napplication_start_module = \"my_erlang_application_sup\" # <-\n\n[dependencies] # <-\ngleam_stdlib = \"~> 1337.0\"\ngleam_otp = \"~> 1337.0\"\n\n[dev_dependencies] # <-\nmidas = \"~> 1337.0\"\nsimple_json = \"~> 1337.0\"\n\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_app_generation/src/main.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_app_generation_with_argument/gleam.toml",
    "content": "# This config file has a bunch of properties that will be entered into the\n# Erlang .app file\n\nname = \"my_erlang_application\" # <-\nversion = \"0.1.0\"              # <-\ndescription = \"It's very cool\" # <-\n\ntarget = \"erlang\"\n\n[erlang]\nextra_applications = [\"inets\", \"ssl\"] # <-\napplication_start_module = \"my_erlang_application_sup\" # <-\napplication_start_argument = \"[1, two]\" # <-\n\n[dependencies] # <-\ngleam_stdlib = \"~> 1337.0\"\ngleam_otp = \"~> 1337.0\"\n\n[dev_dependencies] # <-\nmidas = \"~> 1337.0\"\nsimple_json = \"~> 1337.0\"\n\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_app_generation_with_argument/src/main.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_bug_752/gleam.toml",
    "content": "# https://github.com/gleam-lang/gleam/issues/752\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_bug_752/src/one.gleam",
    "content": "pub type One(a) {\n  One(a)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_bug_752/src/two.gleam",
    "content": "import one.{type One}\n\npub type Two(b) {\n  Two(thing: One(Int))\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_empty/gleam.toml",
    "content": "name = \"hello_joe\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_empty/src/empty.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_escape_names/gleam.toml",
    "content": "# https://github.com/gleam-lang/gleam/issues/340\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_escape_names/src/one.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/340\npub fn receive(x) {\n  x\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_escape_names/src/two.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/340\nimport one.{receive}\n\npub fn qualified_call() {\n  one.receive(1)\n}\n\npub fn qualified_value() {\n  one.receive\n}\n\npub fn unqualified_call() {\n  receive(1)\n}\n\npub fn unqualified_value() {\n  receive\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_import/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_import/src/one.gleam",
    "content": "import two\n\npub fn unbox(x) {\n  let two.Box(i) = x\n  i\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_import/src/two.gleam",
    "content": "pub type Box {\n  Box(Int)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_import_shadowing_prelude/gleam.toml",
    "content": "# https://github.com/gleam-lang/gleam/issues/1495\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_import_shadowing_prelude/src/one.gleam",
    "content": "pub type Error {\n  // This constructor shadows the Error constructor in the prelude.\n  Error\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_import_shadowing_prelude/src/two.gleam",
    "content": "// This import shadows the Error type in the prelude.\nimport one.{Error}\n\npub fn main() {\n  Error\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_nested/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_nested/src/one/two.gleam",
    "content": "pub fn main() {\n  \"Hi there\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_nested_qualified_constant/gleam.toml",
    "content": "# https://github.com/gleam-lang/gleam/issues/922#issuecomment-803272624\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_nested_qualified_constant/src/one/two.gleam",
    "content": "pub type A {\n  A\n}\n"
  },
  {
    "path": "test-package-compiler/cases/erlang_nested_qualified_constant/src/two.gleam",
    "content": "// This module uses imports in a way which previously failed to compile due a\n// compiler bug.\n//\n// https://github.com/gleam-lang/gleam/issues/922#issuecomment-803272624\n//\nimport one/two\n\npub const x = two.A\n"
  },
  {
    "path": "test-package-compiler/cases/hello_joe/gleam.toml",
    "content": "name = \"hello_joe\"\nversion = \"0.1.0\"\n"
  },
  {
    "path": "test-package-compiler/cases/hello_joe/src/hello_joe.gleam",
    "content": "pub fn main() {\n  \"Hello, Joe!\"\n}\n"
  },
  {
    "path": "test-package-compiler/cases/import_cycle/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/import_cycle/src/one.gleam",
    "content": "import one\n"
  },
  {
    "path": "test-package-compiler/cases/import_cycle_multi/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/import_cycle_multi/src/one.gleam",
    "content": "import two\n"
  },
  {
    "path": "test-package-compiler/cases/import_cycle_multi/src/three.gleam",
    "content": "import one\n"
  },
  {
    "path": "test-package-compiler/cases/import_cycle_multi/src/two.gleam",
    "content": "import three\n"
  },
  {
    "path": "test-package-compiler/cases/import_shadowed_name_warning/gleam.toml",
    "content": "# This should emit no warnings.\n# https://github.com/gleam-lang/otp/pull/22\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/import_shadowed_name_warning/src/one.gleam",
    "content": "// https://github.com/gleam-lang/otp/pull/22\n\npub type Port\n"
  },
  {
    "path": "test-package-compiler/cases/import_shadowed_name_warning/src/two.gleam",
    "content": "//// https://github.com/gleam-lang/otp/pull/22\n\n// No warning should be emitted about this imported type. The compiler does not\n// confuse it for the value constructor defined below.\nimport one.{type Port}\n\ntype Shadowing {\n  // This value constructor has the same name as the imported type.\n  Port\n}\n\n// Here the type is used.\n@external(erlang, \"wibble\", \"wobble\")\npub fn use_type(port: Port) -> Nil\n"
  },
  {
    "path": "test-package-compiler/cases/imported_constants/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/imported_constants/src/one.gleam",
    "content": "pub type A {\n  A\n}\n\npub type B {\n  B(A, A)\n}\n\npub type User {\n  User(name: String, score: Int)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/imported_constants/src/two.gleam",
    "content": "import one.{A, A as C, B, B as D, User, User as XUser}\n\n/// For these statements we use the records in a qualified fashion\npub const qualified_const_a = one.A\n\npub fn qualified_fn_a() {\n  qualified_const_a\n}\n\npub const qualified_const_b = one.B(one.A, one.A)\n\npub fn qualified_fn_b() {\n  qualified_const_b\n}\n\n/// For these statements we use the records in a unqualified fashion\npub const unqualified_const_a = A\n\npub fn unqualified_fn_a() {\n  unqualified_const_a\n}\n\npub const unqualified_const_b = B(A, A)\n\npub fn unqualified_fn_b() {\n  unqualified_const_b\n}\n\n/// For these statements we use the records in a unqualified and also aliased\n/// fashion\npub const aliased_const_a = C\n\npub fn aliased_fn_a() {\n  aliased_const_a\n}\n\npub const aliased_const_b = D(C, C)\n\npub fn aliased_fn_b() {\n  aliased_const_b\n}\n\n/// For these statements we use the accessors for the record from the other\n/// module\npub fn accessors(user: one.User) {\n  let name = user.name\n  let score = user.score\n  #(name, score)\n}\n\n/// For these statements we use destructure the record\npub fn destructure_qualified(user) {\n  let one.User(name: name, score: score) = user\n  #(name, score)\n}\n\npub fn destructure_unqualified(user) {\n  let User(name: name, score: score) = user\n  #(name, score)\n}\n\npub fn destructure_aliased(user) {\n  let XUser(name: name, score: score) = user\n  #(name, score)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/imported_external_fns/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/imported_external_fns/src/one.gleam",
    "content": "@external(erlang, \"thing\", \"new\")\npub fn thing() -> Nil\n\n// https://github.com/gleam-lang/gleam/issues/4507\n@external(erlang, \"the.thing\", \"make.new\")\npub fn escaped_thing() -> Nil\n"
  },
  {
    "path": "test-package-compiler/cases/imported_external_fns/src/three.gleam",
    "content": "@external(erlang, \"thing\", \"new\")\npub fn thing() -> Nil\n\n// https://github.com/gleam-lang/gleam/issues/4507\n@external(erlang, \"the.thing\", \"make.new\")\npub fn escaped_thing() -> Nil\n"
  },
  {
    "path": "test-package-compiler/cases/imported_external_fns/src/two.gleam",
    "content": "import one.{\n  escaped_thing, escaped_thing as xescaped_thing, thing, thing as xthing,\n}\nimport three as aliased\n\n// Assigning a function to constants\n\nconst const_qualified = one.thing\n\nconst const_qualified_aliased = aliased.thing\n\nconst const_unqualified = thing\n\nconst const_unqualified_aliased = xthing\n\nconst escaped_const_qualified = one.escaped_thing\n\nconst escaped_const_qualified_aliased = aliased.escaped_thing\n\nconst escaped_const_unqualified = escaped_thing\n\nconst escaped_const_unqualified_aliased = xescaped_thing\n\npub fn the_consts() {\n  let _ = const_qualified\n  let _ = const_qualified_aliased\n  let _ = const_unqualified\n  let _ = const_unqualified_aliased\n  let _ = escaped_const_qualified\n  let _ = escaped_const_qualified_aliased\n  let _ = escaped_const_unqualified\n  let _ = escaped_const_unqualified_aliased\n  const_qualified()\n  const_qualified_aliased()\n  const_unqualified()\n  const_unqualified_aliased()\n  escaped_const_qualified()\n  escaped_const_qualified_aliased()\n  escaped_const_unqualified()\n  escaped_const_unqualified_aliased()\n}\n\n// Referencing in a function\n\npub fn fn_reference_qualified() {\n  one.thing\n}\n\npub fn fn_reference_qualified_aliased() {\n  aliased.thing\n}\n\npub fn fn_reference_unqualified() {\n  thing\n}\n\npub fn fn_reference_unqualified_aliased() {\n  xthing\n}\n\n// Calling the function\n\npub fn fn_call_qualified() {\n  one.thing()\n}\n\npub fn fn_call_qualified_aliased() {\n  aliased.thing()\n}\n\npub fn fn_call_unqualified() {\n  thing()\n}\n\npub fn fn_call_unqualified_aliased() {\n  xthing()\n}\n\n// Referencing a function as an argument\n\npub fn argument_reference_qualified() {\n  x(one.escaped_thing)\n}\n\npub fn argument_reference_qualified_aliased() {\n  x(aliased.escaped_thing)\n}\n\npub fn argument_reference_unqualified() {\n  x(escaped_thing)\n}\n\npub fn argument_reference_unqualified_aliased() {\n  x(xescaped_thing)\n}\n\nfn x(_) {\n  Nil\n}\n"
  },
  {
    "path": "test-package-compiler/cases/imported_record_constructors/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/imported_record_constructors/src/one/one.gleam",
    "content": "pub type A {\n  A\n}\n\npub type B {\n  B(A, A)\n}\n\npub type User {\n  User(name: String, score: Int)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/imported_record_constructors/src/one/two.gleam",
    "content": "pub type A {\n  A\n}\n\npub type B {\n  B(A, A)\n}\n\npub type User {\n  User(name: String, score: Int)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/imported_record_constructors/src/two.gleam",
    "content": "import one/one.{A, A as C, B, B as D, User, User as XUser}\nimport one/two as aliased\n\n/// For these statements we use the records in a qualified fashion\npub const qualified_const_a = one.A\n\npub fn qualified_fn_a() {\n  qualified_const_a\n}\n\npub const qualified_const_b = one.B(one.A, one.A)\n\npub fn qualified_fn_b() {\n  qualified_const_b\n}\n\npub const qualified_aliased_const_a = aliased.A\n\npub fn qualified_aliased_fn_a() {\n  qualified_aliased_const_a\n}\n\npub const qualified_aliased_const_b = aliased.B(aliased.A, aliased.A)\n\npub fn qualified_aliased_fn_b() {\n  qualified_aliased_const_b\n}\n\n/// For these statements we use the records in a unqualified fashion\npub const unqualified_const_a = A\n\npub fn unqualified_fn_a() {\n  unqualified_const_a\n}\n\npub const unqualified_const_b = B(A, A)\n\npub fn unqualified_fn_b() {\n  unqualified_const_b\n}\n\n/// For these statements we use the records in a unqualified and also aliased\n/// fashion\npub const aliased_const_a = C\n\npub fn aliased_fn_a() {\n  aliased_const_a\n}\n\npub const aliased_const_b = D(C, C)\n\npub fn aliased_fn_b() {\n  aliased_const_b\n}\n\n/// For these statements we use the accessors for the record from the other\n/// module\npub fn accessors(user: one.User) {\n  let name = user.name\n  let score = user.score\n  #(name, score)\n}\n\n/// For these statements we use destructure the record\npub fn destructure_qualified(user) {\n  let one.User(name: name, score: score) = user\n  #(name, score)\n}\n\npub fn destructure_qualified_aliased(user) {\n  let aliased.User(name: name, score: score) = user\n  #(name, score)\n}\n\npub fn destructure_unqualified(user) {\n  let User(name: name, score: score) = user\n  #(name, score)\n}\n\npub fn destructure_aliased(user) {\n  let XUser(name: name, score: score) = user\n  #(name, score)\n}\n\n/// For these statements we use update the record\npub fn update_qualified(user) {\n  one.User(..user, name: \"wibble\")\n}\n\npub fn update_qualified_aliased(user) {\n  aliased.User(..user, name: \"wibble\")\n}\n\npub fn update_unqualified(user) {\n  User(..user, name: \"wibble\")\n}\n\npub fn update_aliased(user) {\n  XUser(..user, name: \"wibble\")\n}\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_d_ts/gleam.toml",
    "content": "name = \"hello\"\nversion = \"0.1.0\"\ntarget = \"javascript\"\n\n[javascript]\ntypescript_declarations = true\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_d_ts/src/hello.gleam",
    "content": "pub type Wibble {\n  Woo\n}\n\npub fn wobble() -> Wibble {\n  Woo\n}\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_empty/gleam.toml",
    "content": "name = \"hello_joe\"\nversion = \"0.1.0\"\ntarget = \"javascript\"\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_empty/src/empty.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_import/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"javascript\"\n\n[javascript]\ntypescript_declarations = true\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_import/src/one/two.gleam",
    "content": "pub type A {\n  A\n}\n"
  },
  {
    "path": "test-package-compiler/cases/javascript_import/src/two.gleam",
    "content": "import one/two\n\npub const x = two.A\n"
  },
  {
    "path": "test-package-compiler/cases/not_overwriting_erlang_module/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/not_overwriting_erlang_module/src/app/code.gleam",
    "content": "// This module is named \"app/code\".\n//\n// The last segment is the same as a built in Erlang module, but it is in the\n// \"app\" namespace, so it doesn't clash with Erlang. This should compile\n// successfully.\n"
  },
  {
    "path": "test-package-compiler/cases/opaque_type_accessor/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/opaque_type_accessor/src/one.gleam",
    "content": "pub opaque type User {\n  User(name: String, score: Int)\n}\n\n// These operations are permitted in this module as it is the one that defined\n// the custom type\n\npub fn construct() {\n  User(name: \"Alim\", score: 10)\n}\n\npub fn accessors(user: User) {\n  let name = user.name\n  let score = user.score\n  #(name, score)\n}\n\npub fn destructure(user: User) {\n  let User(name: name, score: score) = user\n  #(name, score)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/opaque_type_accessor/src/two.gleam",
    "content": "import one.{type User}\n\n// This operation is not permitted because the type is opaque and this module\n// did not define the custom type.\n\npub fn accessors(user: User) {\n  let name = user.name\n  let score = user.score\n  #(name, score)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/opaque_type_destructure/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/opaque_type_destructure/src/one.gleam",
    "content": "pub opaque type User {\n  User(name: String, score: Int)\n}\n\n// These operations are permitted in this module as it is the one that defined\n// the custom type\n\npub fn construct() {\n  User(name: \"Alim\", score: 10)\n}\n\npub fn accessors(user: User) {\n  let name = user.name\n  let score = user.score\n  #(name, score)\n}\n\npub fn destructure(user: User) {\n  let User(name: name, score: score) = user\n  #(name, score)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/opaque_type_destructure/src/two.gleam",
    "content": "import one\n\n// This operation is not permitted because the type is opaque and this module\n// did not define the custom type.\n\npub fn destructure(user: one.User) {\n  let one.User(name: name, score: score) = user\n  #(name, score)\n}\n"
  },
  {
    "path": "test-package-compiler/cases/overwriting_erlang_module/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/overwriting_erlang_module/src/code.gleam",
    "content": "// This module is named \"code\".\n//\n// If you were to compile this and load it into the Erlang virtual machine it\n// would replace the built-in \"code\" module. That would be _bad_. You'd get\n// super cryptic error messages and likely not know what is happening. This did\n// happen fairly often with new folks, so now the build tool ensures you don't\n// use one of these Erlang names.\n//\n// This test case ensures this is true.\n"
  },
  {
    "path": "test-package-compiler/cases/src_importing_dev/dev/two.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/src_importing_dev/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/src_importing_dev/src/one.gleam",
    "content": "// This import will fail because the `two` module is in the `dev` directory and\n// as such isn't permitted to be imported into the `src` directory.\nimport two\n"
  },
  {
    "path": "test-package-compiler/cases/src_importing_test/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/src_importing_test/src/one.gleam",
    "content": "// This import will fail because the `two` module is in the `test` directory and\n// as such isn't permitted to be imported into the `src` directory.\nimport two\n"
  },
  {
    "path": "test-package-compiler/cases/src_importing_test/test/two.gleam",
    "content": "\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_constant/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_constant/src/one.gleam",
    "content": "pub type A {\n  A\n}\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_constant/src/two.gleam",
    "content": "import one\n\npub const it = one.B\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_expression/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_expression/src/one.gleam",
    "content": "pub type A {\n  A\n}\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_expression/src/two.gleam",
    "content": "import one\n\npub fn it() {\n  one.B\n}\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_import/gleam.toml",
    "content": "name = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_import/src/one.gleam",
    "content": "pub type A {\n  A\n}\n"
  },
  {
    "path": "test-package-compiler/cases/unknown_module_field_in_import/src/two.gleam",
    "content": "import one.{B}\n"
  },
  {
    "path": "test-package-compiler/cases/variable_or_module/gleam.toml",
    "content": "# Distinguish between a module and a value with the same local name.\n# https://github.com/gleam-lang/gleam/issues/807\nname = \"importy\"\nversion = \"0.1.0\"\ntarget = \"erlang\"\n"
  },
  {
    "path": "test-package-compiler/cases/variable_or_module/src/main.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/807\nimport power.{type Power}\n\npub fn module_function(power: Power) {\n  // Here we are referring to the `power` module's function, not a field on the\n  // `Power` record.\n  power.to_int(power)\n}\n\npub fn record_field(power: Power) {\n  // Here we are referring to the `Power` record's field.\n  power.value\n}\n"
  },
  {
    "path": "test-package-compiler/cases/variable_or_module/src/power.gleam",
    "content": "// https://github.com/gleam-lang/gleam/issues/807\npub type Power {\n  Power(value: Int)\n}\n\npub fn to_int(p: Power) {\n  p.value * 9000\n}\n"
  },
  {
    "path": "test-package-compiler/src/generated_tests.rs",
    "content": "//! This file is generated by build.rs\n//! Do not edit it directly, instead add new test cases to ./cases\n\n#[rustfmt::skip]\n#[test]\nfn alias_unqualified_import() {\n    let output = crate::prepare(\"./cases/alias_unqualified_import\");\n    insta::assert_snapshot!(\n        \"alias_unqualified_import\",\n        output,\n        \"./cases/alias_unqualified_import\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn dev_importing_test() {\n    let output = crate::prepare(\"./cases/dev_importing_test\");\n    insta::assert_snapshot!(\n        \"dev_importing_test\",\n        output,\n        \"./cases/dev_importing_test\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn duplicate_module() {\n    let output = crate::prepare(\"./cases/duplicate_module\");\n    insta::assert_snapshot!(\n        \"duplicate_module\",\n        output,\n        \"./cases/duplicate_module\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn duplicate_module_dev() {\n    let output = crate::prepare(\"./cases/duplicate_module_dev\");\n    insta::assert_snapshot!(\n        \"duplicate_module_dev\",\n        output,\n        \"./cases/duplicate_module_dev\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn duplicate_module_test_dev() {\n    let output = crate::prepare(\"./cases/duplicate_module_test_dev\");\n    insta::assert_snapshot!(\n        \"duplicate_module_test_dev\",\n        output,\n        \"./cases/duplicate_module_test_dev\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn empty_module_warning() {\n    let output = crate::prepare(\"./cases/empty_module_warning\");\n    insta::assert_snapshot!(\n        \"empty_module_warning\",\n        output,\n        \"./cases/empty_module_warning\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_app_generation() {\n    let output = crate::prepare(\"./cases/erlang_app_generation\");\n    insta::assert_snapshot!(\n        \"erlang_app_generation\",\n        output,\n        \"./cases/erlang_app_generation\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_app_generation_with_argument() {\n    let output = crate::prepare(\"./cases/erlang_app_generation_with_argument\");\n    insta::assert_snapshot!(\n        \"erlang_app_generation_with_argument\",\n        output,\n        \"./cases/erlang_app_generation_with_argument\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_bug_752() {\n    let output = crate::prepare(\"./cases/erlang_bug_752\");\n    insta::assert_snapshot!(\n        \"erlang_bug_752\",\n        output,\n        \"./cases/erlang_bug_752\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_empty() {\n    let output = crate::prepare(\"./cases/erlang_empty\");\n    insta::assert_snapshot!(\n        \"erlang_empty\",\n        output,\n        \"./cases/erlang_empty\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_escape_names() {\n    let output = crate::prepare(\"./cases/erlang_escape_names\");\n    insta::assert_snapshot!(\n        \"erlang_escape_names\",\n        output,\n        \"./cases/erlang_escape_names\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_import() {\n    let output = crate::prepare(\"./cases/erlang_import\");\n    insta::assert_snapshot!(\n        \"erlang_import\",\n        output,\n        \"./cases/erlang_import\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_import_shadowing_prelude() {\n    let output = crate::prepare(\"./cases/erlang_import_shadowing_prelude\");\n    insta::assert_snapshot!(\n        \"erlang_import_shadowing_prelude\",\n        output,\n        \"./cases/erlang_import_shadowing_prelude\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_nested() {\n    let output = crate::prepare(\"./cases/erlang_nested\");\n    insta::assert_snapshot!(\n        \"erlang_nested\",\n        output,\n        \"./cases/erlang_nested\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn erlang_nested_qualified_constant() {\n    let output = crate::prepare(\"./cases/erlang_nested_qualified_constant\");\n    insta::assert_snapshot!(\n        \"erlang_nested_qualified_constant\",\n        output,\n        \"./cases/erlang_nested_qualified_constant\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn hello_joe() {\n    let output = crate::prepare(\"./cases/hello_joe\");\n    insta::assert_snapshot!(\n        \"hello_joe\",\n        output,\n        \"./cases/hello_joe\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn import_cycle() {\n    let output = crate::prepare(\"./cases/import_cycle\");\n    insta::assert_snapshot!(\n        \"import_cycle\",\n        output,\n        \"./cases/import_cycle\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn import_cycle_multi() {\n    let output = crate::prepare(\"./cases/import_cycle_multi\");\n    insta::assert_snapshot!(\n        \"import_cycle_multi\",\n        output,\n        \"./cases/import_cycle_multi\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn import_shadowed_name_warning() {\n    let output = crate::prepare(\"./cases/import_shadowed_name_warning\");\n    insta::assert_snapshot!(\n        \"import_shadowed_name_warning\",\n        output,\n        \"./cases/import_shadowed_name_warning\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn imported_constants() {\n    let output = crate::prepare(\"./cases/imported_constants\");\n    insta::assert_snapshot!(\n        \"imported_constants\",\n        output,\n        \"./cases/imported_constants\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn imported_external_fns() {\n    let output = crate::prepare(\"./cases/imported_external_fns\");\n    insta::assert_snapshot!(\n        \"imported_external_fns\",\n        output,\n        \"./cases/imported_external_fns\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn imported_record_constructors() {\n    let output = crate::prepare(\"./cases/imported_record_constructors\");\n    insta::assert_snapshot!(\n        \"imported_record_constructors\",\n        output,\n        \"./cases/imported_record_constructors\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn javascript_d_ts() {\n    let output = crate::prepare(\"./cases/javascript_d_ts\");\n    insta::assert_snapshot!(\n        \"javascript_d_ts\",\n        output,\n        \"./cases/javascript_d_ts\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn javascript_empty() {\n    let output = crate::prepare(\"./cases/javascript_empty\");\n    insta::assert_snapshot!(\n        \"javascript_empty\",\n        output,\n        \"./cases/javascript_empty\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn javascript_import() {\n    let output = crate::prepare(\"./cases/javascript_import\");\n    insta::assert_snapshot!(\n        \"javascript_import\",\n        output,\n        \"./cases/javascript_import\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn not_overwriting_erlang_module() {\n    let output = crate::prepare(\"./cases/not_overwriting_erlang_module\");\n    insta::assert_snapshot!(\n        \"not_overwriting_erlang_module\",\n        output,\n        \"./cases/not_overwriting_erlang_module\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn opaque_type_accessor() {\n    let output = crate::prepare(\"./cases/opaque_type_accessor\");\n    insta::assert_snapshot!(\n        \"opaque_type_accessor\",\n        output,\n        \"./cases/opaque_type_accessor\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn opaque_type_destructure() {\n    let output = crate::prepare(\"./cases/opaque_type_destructure\");\n    insta::assert_snapshot!(\n        \"opaque_type_destructure\",\n        output,\n        \"./cases/opaque_type_destructure\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn overwriting_erlang_module() {\n    let output = crate::prepare(\"./cases/overwriting_erlang_module\");\n    insta::assert_snapshot!(\n        \"overwriting_erlang_module\",\n        output,\n        \"./cases/overwriting_erlang_module\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn src_importing_dev() {\n    let output = crate::prepare(\"./cases/src_importing_dev\");\n    insta::assert_snapshot!(\n        \"src_importing_dev\",\n        output,\n        \"./cases/src_importing_dev\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn src_importing_test() {\n    let output = crate::prepare(\"./cases/src_importing_test\");\n    insta::assert_snapshot!(\n        \"src_importing_test\",\n        output,\n        \"./cases/src_importing_test\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn unknown_module_field_in_constant() {\n    let output = crate::prepare(\"./cases/unknown_module_field_in_constant\");\n    insta::assert_snapshot!(\n        \"unknown_module_field_in_constant\",\n        output,\n        \"./cases/unknown_module_field_in_constant\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn unknown_module_field_in_expression() {\n    let output = crate::prepare(\"./cases/unknown_module_field_in_expression\");\n    insta::assert_snapshot!(\n        \"unknown_module_field_in_expression\",\n        output,\n        \"./cases/unknown_module_field_in_expression\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn unknown_module_field_in_import() {\n    let output = crate::prepare(\"./cases/unknown_module_field_in_import\");\n    insta::assert_snapshot!(\n        \"unknown_module_field_in_import\",\n        output,\n        \"./cases/unknown_module_field_in_import\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn variable_or_module() {\n    let output = crate::prepare(\"./cases/variable_or_module\");\n    insta::assert_snapshot!(\n        \"variable_or_module\",\n        output,\n        \"./cases/variable_or_module\",\n    );\n}\n"
  },
  {
    "path": "test-package-compiler/src/lib.rs",
    "content": "#[cfg(test)]\nmod generated_tests;\n\nuse camino::Utf8PathBuf;\nuse gleam_core::{\n    build::{\n        ErlangAppCodegenConfiguration, Mode, NullTelemetry, Outcome, StaleTracker, Target,\n        TargetCodegenConfiguration,\n    },\n    config::PackageConfig,\n    io::{FileSystemReader, FileSystemWriter},\n    warning::{VectorWarningEmitterIO, WarningEmitter},\n};\nuse std::{\n    collections::{HashMap, HashSet},\n    rc::Rc,\n};\n\npub fn prepare(path: &str) -> String {\n    let root = Utf8PathBuf::from(path).canonicalize_utf8().unwrap();\n\n    let toml = std::fs::read_to_string(root.join(\"gleam.toml\")).unwrap();\n    let config: PackageConfig = toml::from_str(&toml).unwrap();\n\n    let target = match config.target {\n        Target::Erlang => TargetCodegenConfiguration::Erlang {\n            app_file: Some(ErlangAppCodegenConfiguration {\n                include_dev_deps: true,\n                package_name_overrides: HashMap::new(),\n            }),\n        },\n        Target::JavaScript => TargetCodegenConfiguration::JavaScript {\n            emit_typescript_definitions: config.javascript.typescript_declarations,\n            prelude_location: Utf8PathBuf::from(\"../prelude.mjs\"),\n        },\n    };\n\n    let ids = gleam_core::uid::UniqueIdGenerator::new();\n    let mut modules = im::HashMap::new();\n    let warnings = VectorWarningEmitterIO::default();\n    let warning_emitter = WarningEmitter::new(Rc::new(warnings.clone()));\n    let filesystem = test_helpers_rs::to_in_memory_filesystem(&root);\n    let initial_files = filesystem.files();\n    let root = Utf8PathBuf::from(\"\");\n    let out = Utf8PathBuf::from(\"/out/lib/the_package\");\n    let lib = Utf8PathBuf::from(\"/out/lib\");\n    let mut compiler = gleam_core::build::PackageCompiler::new(\n        &config,\n        Mode::Dev,\n        &root,\n        &out,\n        &lib,\n        &target,\n        ids,\n        filesystem.clone(),\n    );\n    compiler.write_entrypoint = false;\n    compiler.write_metadata = true;\n    compiler.compile_beam_bytecode = false;\n    compiler.copy_native_files = false;\n    let result = compiler.compile(\n        &warning_emitter,\n        &mut modules,\n        &mut im::HashMap::new(),\n        &mut StaleTracker::default(),\n        &mut HashSet::new(),\n        &NullTelemetry,\n    );\n    match result {\n        Outcome::Ok(_) => {\n            for path in initial_files {\n                if filesystem.is_file(&path) {\n                    filesystem.delete_file(&path).unwrap();\n                }\n            }\n            let files = filesystem.into_contents();\n            let warnings = warnings.take();\n            test_helpers_rs::TestCompileOutput { files, warnings }.as_overview_text()\n        }\n        Outcome::TotalFailure(error) | Outcome::PartialFailure(_, error) => {\n            test_helpers_rs::normalise_diagnostic(&error.pretty_string())\n        }\n    }\n}\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__alias_unqualified_import.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/alias_unqualified_import\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<85 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export([id/1]).\n-export_type([empty/0]).\n\n-type empty() :: empty.\n\n-file(\"src/one.gleam\", 2).\n-spec id(I) -> I.\nid(X) ->\n    X.\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<96 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([make/0]).\n\n-file(\"src/two.gleam\", 4).\n-spec make() -> one:empty().\nmake() ->\n    one:id(empty).\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__dev_importing_test.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/dev_importing_test\"\n---\nerror: Dev importing test module\n  ┌─ dev/one.gleam:3:1\n  │\n3 │ import two\n  │ ^ Imported here\n\nThe development module `one` is importing the test module `two`.\n\nTest modules should only contain test-related code, and not general\ndevelopment code. Perhaps move the `two` module to the dev directory.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__duplicate_module.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/duplicate_module\"\n---\nerror: Duplicate module\n\nThe module `main` is defined multiple times.\n\nIt is first defined at src/main.gleam\nIt is defined a second time at test/main.gleam\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__duplicate_module_dev.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/duplicate_module_dev\"\n---\nerror: Duplicate module\n\nThe module `main` is defined multiple times.\n\nIt is first defined at src/main.gleam\nIt is defined a second time at dev/main.gleam\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__duplicate_module_test_dev.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/duplicate_module_test_dev\"\n---\nerror: Duplicate module\n\nThe module `main` is defined multiple times.\n\nIt is first defined at test/main.gleam\nIt is defined a second time at dev/main.gleam\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__empty_module_warning.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/empty_module_warning\"\n---\n//// /out/lib/the_package/_gleam_artefacts/empty.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/empty.cache_meta\n<53 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/empty.erl\n-module(empty).\n\n\n//// /out/lib/the_package/_gleam_artefacts/internal.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/internal.cache_meta\n<69 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/internal.erl\n-module(internal).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/internal.gleam\").\n-export([private_function/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"src/internal.gleam\", 2).\n?DOC(false).\n-spec private_function() -> nil.\nprivate_function() ->\n    nil.\n\n\n//// /out/lib/the_package/_gleam_artefacts/private.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/private.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/private.erl\n-module(private).\n\n\n//// /out/lib/the_package/_gleam_artefacts/public.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/public.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/public.erl\n-module(public).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/public.gleam\").\n-export([main/0]).\n\n-file(\"src/public.gleam\", 1).\n-spec main() -> binary().\nmain() ->\n    <<\"This module has public definitions\"/utf8>>.\n\n\n//// /out/lib/the_package/ebin/empty_module_warning.app\n{application, empty_module_warning, [\n    {vsn, \"1.0.0\"},\n    {applications, [gleam_stdlib]},\n    {description, \"Test package with empty modules\"},\n    {modules, [empty,\n               internal,\n               private,\n               public]},\n    {registered, []}\n]}.\n\n\n//// Warning\nwarning: Empty module\n\nModule 'empty' contains no public definitions.\nHint: You can safely remove this module.\n\n\n\n//// Warning\nwarning: Unused private function\n  ┌─ src/private.gleam:1:1\n  │\n1 │ fn private_function() -> Nil {\n  │ ^ This private function is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_app_generation\"\n---\n//// /out/lib/the_package/_gleam_artefacts/main.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/main.cache_meta\n<57 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/main.erl\n-module(main).\n\n\n//// /out/lib/the_package/ebin/my_erlang_application.app\n{application, my_erlang_application, [\n    {mod, {'my_erlang_application_sup', []}},\n    {vsn, \"0.1.0\"},\n    {applications, [gleam_otp,\n                    gleam_stdlib,\n                    inets,\n                    midas,\n                    simple_json,\n                    ssl]},\n    {description, \"It's very cool\"},\n    {modules, [main]},\n    {registered, []}\n]}.\n\n\n//// Warning\nwarning: Empty module\n\nModule 'main' contains no public definitions.\nHint: You can safely remove this module.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation_with_argument.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_app_generation_with_argument\"\n---\n//// /out/lib/the_package/_gleam_artefacts/main.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/main.cache_meta\n<57 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/main.erl\n-module(main).\n\n\n//// /out/lib/the_package/ebin/my_erlang_application.app\n{application, my_erlang_application, [\n    {mod, {'my_erlang_application_sup', [1, two]}},\n    {vsn, \"0.1.0\"},\n    {applications, [gleam_otp,\n                    gleam_stdlib,\n                    inets,\n                    midas,\n                    simple_json,\n                    ssl]},\n    {description, \"It's very cool\"},\n    {modules, [main]},\n    {registered, []}\n]}.\n\n\n//// Warning\nwarning: Empty module\n\nModule 'main' contains no public definitions.\nHint: You can safely remove this module.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_bug_752.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_bug_752\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export_type([one/1]).\n\n-type one(I) :: {one, I}.\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<92 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export_type([two/1]).\n\n-type two(K) :: {two, one:one(integer())} | {gleam_phantom, K}.\n\n\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n\n\n//// /out/lib/the_package/include/two_Two.hrl\n-record(two, {thing :: one:one(integer())}).\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_empty.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_empty\"\n---\n//// /out/lib/the_package/_gleam_artefacts/empty.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/empty.cache_meta\n<57 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/empty.erl\n-module(empty).\n\n\n//// /out/lib/the_package/ebin/hello_joe.app\n{application, hello_joe, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [empty]},\n    {registered, []}\n]}.\n\n\n//// Warning\nwarning: Empty module\n\nModule 'empty' contains no public definitions.\nHint: You can safely remove this module.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_escape_names.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_escape_names\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<69 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export(['receive'/1]).\n\n-file(\"src/one.gleam\", 2).\n-spec 'receive'(I) -> I.\n'receive'(X) ->\n    X.\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<144 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([qualified_call/0, qualified_value/0, unqualified_call/0, unqualified_value/0]).\n\n-file(\"src/two.gleam\", 4).\n-spec qualified_call() -> integer().\nqualified_call() ->\n    one:'receive'(1).\n\n-file(\"src/two.gleam\", 8).\n-spec qualified_value() -> fun((Q) -> Q).\nqualified_value() ->\n    fun one:'receive'/1.\n\n-file(\"src/two.gleam\", 12).\n-spec unqualified_call() -> integer().\nunqualified_call() ->\n    one:'receive'(1).\n\n-file(\"src/two.gleam\", 16).\n-spec unqualified_value() -> fun((S) -> S).\nunqualified_value() ->\n    fun one:'receive'/1.\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_import\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<96 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export([unbox/1]).\n\n-file(\"src/one.gleam\", 3).\n-spec unbox(two:box()) -> integer().\nunbox(X) ->\n    {box, I} = X,\n    I.\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export_type([box/0]).\n\n-type box() :: {box, integer()}.\n\n\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import_shadowing_prelude.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_import_shadowing_prelude\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<69 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export_type([error/0]).\n\n-type error() :: error.\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<96 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([main/0]).\n\n-file(\"src/two.gleam\", 4).\n-spec main() -> one:error().\nmain() ->\n    error.\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_nested\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.erl\n-module(one@two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one/two.gleam\").\n-export([main/0]).\n\n-file(\"src/one/two.gleam\", 1).\n-spec main() -> binary().\nmain() ->\n    <<\"Hi there\"/utf8>>.\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one@two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested_qualified_constant.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/erlang_nested_qualified_constant\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.erl\n-module(one@two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one/two.gleam\").\n-export_type([a/0]).\n\n-type a() :: a.\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<108 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one@two,\n               two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__hello_joe.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/hello_joe\"\n---\n//// /out/lib/the_package/_gleam_artefacts/hello_joe.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/hello_joe.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/hello_joe.erl\n-module(hello_joe).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/hello_joe.gleam\").\n-export([main/0]).\n\n-file(\"src/hello_joe.gleam\", 1).\n-spec main() -> binary().\nmain() ->\n    <<\"Hello, Joe!\"/utf8>>.\n\n\n//// /out/lib/the_package/ebin/hello_joe.app\n{application, hello_joe, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [hello_joe]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_cycle.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/import_cycle\"\n---\nerror: Import cycle\n  ┌─ src/one.gleam:1:1\n  │\n1 │ import one\n  │ ^ Imported here\n\nThe import statements for these modules form a cycle:\n\n    ┌─────┐\n    │     one\n    └─────┘\nGleam doesn't support dependency cycles like these, please break the\ncycle to continue.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_cycle_multi.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/import_cycle_multi\"\n---\nerror: Import cycle\n  ┌─ src/three.gleam:1:1\n  │\n1 │ import one\n  │ ^ Imported here\n  │\n  ┌─ src/two.gleam:1:1\n  │\n1 │ import three\n  │ ------------ Imported here\n  │\n  ┌─ src/one.gleam:1:1\n  │\n1 │ import two\n  │ ---------- Imported here\n\nThe import statements for these modules form a cycle:\n\n    ┌─────┐\n    │     three\n    │     ↓\n    │     two\n    │     ↓\n    │     one\n    └─────┘\nGleam doesn't support dependency cycles like these, please break the\ncycle to continue.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_shadowed_name_warning.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/import_shadowed_name_warning\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export_type([port_/0]).\n\n-type port_() :: any().\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<128 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([use_type/1]).\n-export_type([shadowing/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n?MODULEDOC(\" https://github.com/gleam-lang/otp/pull/22\\n\").\n\n-type shadowing() :: port.\n\n-file(\"src/two.gleam\", 14).\n-spec use_type(one:port_()) -> nil.\nuse_type(Port) ->\n    wibble:wobble(Port).\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n\n\n//// Warning\nwarning: Unused private constructor\n  ┌─ src/two.gleam:9:3\n  │\n9 │   Port\n  │   ^ This private constructor is never used\n\nHint: You can safely remove it.\n\n\n\n//// Warning\nwarning: Unused private type\n  ┌─ src/two.gleam:7:1\n  │\n7 │ type Shadowing {\n  │ ^ This private type is never used\n\nHint: You can safely remove it.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_constants.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/imported_constants\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<97 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export_type([a/0, b/0, user/0]).\n\n-type a() :: a.\n\n-type b() :: {b, a(), a()}.\n\n-type user() :: {user, binary(), integer()}.\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<332 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([accessors/1, destructure_qualified/1, destructure_unqualified/1, destructure_aliased/1, qualified_fn_a/0, qualified_fn_b/0, unqualified_fn_a/0, unqualified_fn_b/0, aliased_fn_a/0, aliased_fn_b/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"src/two.gleam\", 45).\n?DOC(\n    \" For these statements we use the accessors for the record from the other\\n\"\n    \" module\\n\"\n).\n-spec accessors(one:user()) -> {binary(), integer()}.\naccessors(User) ->\n    Name = erlang:element(2, User),\n    Score = erlang:element(3, User),\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 52).\n?DOC(\" For these statements we use destructure the record\\n\").\n-spec destructure_qualified(one:user()) -> {binary(), integer()}.\ndestructure_qualified(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 57).\n-spec destructure_unqualified(one:user()) -> {binary(), integer()}.\ndestructure_unqualified(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 62).\n-spec destructure_aliased(one:user()) -> {binary(), integer()}.\ndestructure_aliased(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 6).\n-spec qualified_fn_a() -> one:a().\nqualified_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 12).\n-spec qualified_fn_b() -> one:b().\nqualified_fn_b() ->\n    {b, a, a}.\n\n-file(\"src/two.gleam\", 19).\n-spec unqualified_fn_a() -> one:a().\nunqualified_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 25).\n-spec unqualified_fn_b() -> one:b().\nunqualified_fn_b() ->\n    {b, a, a}.\n\n-file(\"src/two.gleam\", 33).\n-spec aliased_fn_a() -> one:a().\naliased_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 39).\n-spec aliased_fn_b() -> one:b().\naliased_fn_b() ->\n    {b, a, a}.\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               two]},\n    {registered, []}\n]}.\n\n\n//// /out/lib/the_package/include/one_User.hrl\n-record(user, {name :: binary(), score :: integer()}).\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_external_fns.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/imported_external_fns\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.cache_meta\n<77 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one.erl\n-module(one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one.gleam\").\n-export([thing/0, escaped_thing/0]).\n\n-file(\"src/one.gleam\", 2).\n-spec thing() -> nil.\nthing() ->\n    thing:new().\n\n-file(\"src/one.gleam\", 6).\n-spec escaped_thing() -> nil.\nescaped_thing() ->\n    'the.thing':'make.new'().\n\n\n//// /out/lib/the_package/_gleam_artefacts/three.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/three.cache_meta\n<77 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/three.erl\n-module(three).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/three.gleam\").\n-export([thing/0, escaped_thing/0]).\n\n-file(\"src/three.gleam\", 2).\n-spec thing() -> nil.\nthing() ->\n    thing:new().\n\n-file(\"src/three.gleam\", 6).\n-spec escaped_thing() -> nil.\nescaped_thing() ->\n    'the.thing':'make.new'().\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<489 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([fn_reference_qualified/0, fn_reference_qualified_aliased/0, fn_reference_unqualified/0, fn_reference_unqualified_aliased/0, fn_call_qualified/0, fn_call_qualified_aliased/0, fn_call_unqualified/0, fn_call_unqualified_aliased/0, argument_reference_qualified/0, argument_reference_qualified_aliased/0, argument_reference_unqualified/0, argument_reference_unqualified_aliased/0, the_consts/0]).\n\n-file(\"src/two.gleam\", 45).\n-spec fn_reference_qualified() -> fun(() -> nil).\nfn_reference_qualified() ->\n    fun thing:new/0.\n\n-file(\"src/two.gleam\", 49).\n-spec fn_reference_qualified_aliased() -> fun(() -> nil).\nfn_reference_qualified_aliased() ->\n    fun thing:new/0.\n\n-file(\"src/two.gleam\", 53).\n-spec fn_reference_unqualified() -> fun(() -> nil).\nfn_reference_unqualified() ->\n    fun thing:new/0.\n\n-file(\"src/two.gleam\", 57).\n-spec fn_reference_unqualified_aliased() -> fun(() -> nil).\nfn_reference_unqualified_aliased() ->\n    fun thing:new/0.\n\n-file(\"src/two.gleam\", 63).\n-spec fn_call_qualified() -> nil.\nfn_call_qualified() ->\n    thing:new().\n\n-file(\"src/two.gleam\", 67).\n-spec fn_call_qualified_aliased() -> nil.\nfn_call_qualified_aliased() ->\n    thing:new().\n\n-file(\"src/two.gleam\", 71).\n-spec fn_call_unqualified() -> nil.\nfn_call_unqualified() ->\n    thing:new().\n\n-file(\"src/two.gleam\", 75).\n-spec fn_call_unqualified_aliased() -> nil.\nfn_call_unqualified_aliased() ->\n    thing:new().\n\n-file(\"src/two.gleam\", 97).\n-spec x(any()) -> nil.\nx(_) ->\n    nil.\n\n-file(\"src/two.gleam\", 81).\n-spec argument_reference_qualified() -> nil.\nargument_reference_qualified() ->\n    x(fun 'the.thing':'make.new'/0).\n\n-file(\"src/two.gleam\", 85).\n-spec argument_reference_qualified_aliased() -> nil.\nargument_reference_qualified_aliased() ->\n    x(fun 'the.thing':'make.new'/0).\n\n-file(\"src/two.gleam\", 89).\n-spec argument_reference_unqualified() -> nil.\nargument_reference_unqualified() ->\n    x(fun 'the.thing':'make.new'/0).\n\n-file(\"src/two.gleam\", 93).\n-spec argument_reference_unqualified_aliased() -> nil.\nargument_reference_unqualified_aliased() ->\n    x(fun 'the.thing':'make.new'/0).\n\n-file(\"src/two.gleam\", 24).\n-spec the_consts() -> nil.\nthe_consts() ->\n    _ = fun thing:new/0,\n    _ = fun thing:new/0,\n    _ = fun thing:new/0,\n    _ = fun thing:new/0,\n    _ = fun 'the.thing':'make.new'/0,\n    _ = fun 'the.thing':'make.new'/0,\n    _ = fun 'the.thing':'make.new'/0,\n    _ = fun 'the.thing':'make.new'/0,\n    thing:new(),\n    thing:new(),\n    thing:new(),\n    thing:new(),\n    'the.thing':'make.new'(),\n    'the.thing':'make.new'(),\n    'the.thing':'make.new'(),\n    'the.thing':'make.new'().\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one,\n               three,\n               two]},\n    {registered, []}\n]}.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_record_constructors.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/imported_record_constructors\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one@one.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@one.cache_meta\n<97 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@one.erl\n-module(one@one).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one/one.gleam\").\n-export_type([a/0, b/0, user/0]).\n\n-type a() :: a.\n\n-type b() :: {b, a(), a()}.\n\n-type user() :: {user, binary(), integer()}.\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache_meta\n<97 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.erl\n-module(one@two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/one/two.gleam\").\n-export_type([a/0, b/0, user/0]).\n\n-type a() :: a.\n\n-type b() :: {b, a(), a()}.\n\n-type user() :: {user, binary(), integer()}.\n\n\n\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<499 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.erl\n-module(two).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/two.gleam\").\n-export([accessors/1, destructure_qualified/1, destructure_qualified_aliased/1, destructure_unqualified/1, destructure_aliased/1, update_qualified/1, update_qualified_aliased/1, update_unqualified/1, update_aliased/1, qualified_fn_a/0, qualified_fn_b/0, qualified_aliased_fn_a/0, qualified_aliased_fn_b/0, unqualified_fn_a/0, unqualified_fn_b/0, aliased_fn_a/0, aliased_fn_b/0]).\n\n-if(?OTP_RELEASE >= 27).\n-define(MODULEDOC(Str), -moduledoc(Str)).\n-define(DOC(Str), -doc(Str)).\n-else.\n-define(MODULEDOC(Str), -compile([])).\n-define(DOC(Str), -compile([])).\n-endif.\n\n-file(\"src/two.gleam\", 58).\n?DOC(\n    \" For these statements we use the accessors for the record from the other\\n\"\n    \" module\\n\"\n).\n-spec accessors(one@one:user()) -> {binary(), integer()}.\naccessors(User) ->\n    Name = erlang:element(2, User),\n    Score = erlang:element(3, User),\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 65).\n?DOC(\" For these statements we use destructure the record\\n\").\n-spec destructure_qualified(one@one:user()) -> {binary(), integer()}.\ndestructure_qualified(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 70).\n-spec destructure_qualified_aliased(one@two:user()) -> {binary(), integer()}.\ndestructure_qualified_aliased(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 75).\n-spec destructure_unqualified(one@one:user()) -> {binary(), integer()}.\ndestructure_unqualified(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 80).\n-spec destructure_aliased(one@one:user()) -> {binary(), integer()}.\ndestructure_aliased(User) ->\n    {user, Name, Score} = User,\n    {Name, Score}.\n\n-file(\"src/two.gleam\", 86).\n?DOC(\" For these statements we use update the record\\n\").\n-spec update_qualified(one@one:user()) -> one@one:user().\nupdate_qualified(User) ->\n    {user, <<\"wibble\"/utf8>>, erlang:element(3, User)}.\n\n-file(\"src/two.gleam\", 90).\n-spec update_qualified_aliased(one@two:user()) -> one@two:user().\nupdate_qualified_aliased(User) ->\n    {user, <<\"wibble\"/utf8>>, erlang:element(3, User)}.\n\n-file(\"src/two.gleam\", 94).\n-spec update_unqualified(one@one:user()) -> one@one:user().\nupdate_unqualified(User) ->\n    {user, <<\"wibble\"/utf8>>, erlang:element(3, User)}.\n\n-file(\"src/two.gleam\", 98).\n-spec update_aliased(one@one:user()) -> one@one:user().\nupdate_aliased(User) ->\n    {user, <<\"wibble\"/utf8>>, erlang:element(3, User)}.\n\n-file(\"src/two.gleam\", 7).\n-spec qualified_fn_a() -> one@one:a().\nqualified_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 13).\n-spec qualified_fn_b() -> one@one:b().\nqualified_fn_b() ->\n    {b, a, a}.\n\n-file(\"src/two.gleam\", 19).\n-spec qualified_aliased_fn_a() -> one@two:a().\nqualified_aliased_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 25).\n-spec qualified_aliased_fn_b() -> one@two:b().\nqualified_aliased_fn_b() ->\n    {b, a, a}.\n\n-file(\"src/two.gleam\", 32).\n-spec unqualified_fn_a() -> one@one:a().\nunqualified_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 38).\n-spec unqualified_fn_b() -> one@one:b().\nunqualified_fn_b() ->\n    {b, a, a}.\n\n-file(\"src/two.gleam\", 46).\n-spec aliased_fn_a() -> one@one:a().\naliased_fn_a() ->\n    a.\n\n-file(\"src/two.gleam\", 52).\n-spec aliased_fn_b() -> one@one:b().\naliased_fn_b() ->\n    {b, a, a}.\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [one@one,\n               one@two,\n               two]},\n    {registered, []}\n]}.\n\n\n//// /out/lib/the_package/include/one@one_User.hrl\n-record(user, {name :: binary(), score :: integer()}).\n\n\n//// /out/lib/the_package/include/one@two_User.hrl\n-record(user, {name :: binary(), score :: integer()}).\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__javascript_d_ts.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/javascript_d_ts\"\n---\n//// /out/lib/the_package/_gleam_artefacts/hello.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/hello.cache_meta\n<81 byte binary>\n\n//// /out/lib/the_package/gleam.d.mts\nexport * from \"../prelude.mjs\";\nexport type * from \"../prelude.d.mts\";\n\n\n//// /out/lib/the_package/gleam.mjs\nexport * from \"../prelude.mjs\";\n\n\n//// /out/lib/the_package/hello.d.mts\nimport type * as _ from \"./gleam.d.mts\";\n\nexport class Woo extends _.CustomType {}\nexport function Wibble$Woo(): Wibble$;\nexport function Wibble$isWoo(value: any): value is Wibble$;\n\nexport type Wibble$ = Woo;\n\nexport function wobble(): Wibble$;\n\n\n//// /out/lib/the_package/hello.mjs\n/// <reference types=\"./hello.d.mts\" />\nimport { CustomType as $CustomType } from \"./gleam.mjs\";\n\nexport class Woo extends $CustomType {}\nexport const Wibble$Woo = () => new Woo();\nexport const Wibble$isWoo = (value) => value instanceof Woo;\n\nexport function wobble() {\n  return new Woo();\n}\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__javascript_empty.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/javascript_empty\"\n---\n//// /out/lib/the_package/_gleam_artefacts/empty.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/empty.cache_meta\n<57 byte binary>\n\n//// /out/lib/the_package/empty.mjs\nexport {}\n\n\n//// /out/lib/the_package/gleam.mjs\nexport * from \"../prelude.mjs\";\n\n\n//// Warning\nwarning: Empty module\n\nModule 'empty' contains no public definitions.\nHint: You can safely remove this module.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__javascript_import.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/javascript_import\"\n---\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/one@two.cache_meta\n<65 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/two.cache_meta\n<88 byte binary>\n\n//// /out/lib/the_package/gleam.d.mts\nexport * from \"../prelude.mjs\";\nexport type * from \"../prelude.d.mts\";\n\n\n//// /out/lib/the_package/gleam.mjs\nexport * from \"../prelude.mjs\";\n\n\n//// /out/lib/the_package/one/two.d.mts\nimport type * as _ from \"../gleam.d.mts\";\n\nexport class A extends _.CustomType {}\nexport function A$A(): A$;\nexport function A$isA(value: any): value is A$;\n\nexport type A$ = A;\n\n\n//// /out/lib/the_package/one/two.mjs\n/// <reference types=\"./two.d.mts\" />\nimport { CustomType as $CustomType } from \"../gleam.mjs\";\n\nexport class A extends $CustomType {}\nexport const A$A = () => new A();\nexport const A$isA = (value) => value instanceof A;\n\n\n//// /out/lib/the_package/two.d.mts\nimport type * as $two from \"./one/two.d.mts\";\n\nexport const x: $two.A$;\n\n\n//// /out/lib/the_package/two.mjs\n/// <reference types=\"./two.d.mts\" />\nimport * as $two from \"./one/two.mjs\";\n\nexport const x = /* @__PURE__ */ new $two.A();\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__not_overwriting_erlang_module.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/not_overwriting_erlang_module\"\n---\n//// /out/lib/the_package/_gleam_artefacts/app@code.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/app@code.cache_meta\n<73 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/app@code.erl\n-module(app@code).\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [app@code]},\n    {registered, []}\n]}.\n\n\n//// Warning\nwarning: Empty module\n\nModule 'app/code' contains no public definitions.\nHint: You can safely remove this module.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__opaque_type_accessor.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/opaque_type_accessor\"\n---\nerror: Unknown record field\n  ┌─ src/two.gleam:7:19\n  │\n7 │   let name = user.name\n  │                   ^ This field does not exist\n\nThe value being accessed has this type:\n\n    User\n\nIt does not have any fields.\n\nerror: Unknown record field\n  ┌─ src/two.gleam:8:20\n  │\n8 │   let score = user.score\n  │                    ^ This field does not exist\n\nThe value being accessed has this type:\n\n    User\n\nIt does not have any fields.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__opaque_type_destructure.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/opaque_type_destructure\"\n---\nerror: Unknown module value\n  ┌─ src/two.gleam:7:7\n  │\n7 │   let one.User(name: name, score: score) = user\n  │       ^\n\nThe module `one` does not have a `User` value.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__overwriting_erlang_module.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/overwriting_erlang_module\"\n---\nerror: Erlang module name collision\n\nThe module `src/code.gleam` compiles to an Erlang module named `code`.\n\nBy default Erlang includes a module with the same name so if we were to\ncompile and load your module it would overwrite the Erlang one, potentially\ncausing confusing errors and crashes.\n\nHint: Rename this module and try again.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__src_importing_dev.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/src_importing_dev\"\n---\nerror: App importing dev module\n  ┌─ src/one.gleam:3:1\n  │\n3 │ import two\n  │ ^ Imported here\n\nThe application module `one` is importing the development module `two`.\n\nDevelopment modules are not included in production builds so application\nmodules cannot import them. Perhaps move the `two` module to the src\ndirectory.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__src_importing_test.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/src_importing_test\"\n---\nerror: App importing test module\n  ┌─ src/one.gleam:3:1\n  │\n3 │ import two\n  │ ^ Imported here\n\nThe application module `one` is importing the test module `two`.\n\nTest modules are not included in production builds so application modules\ncannot import them. Perhaps move the `two` module to the src directory.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__unknown_module_field_in_constant.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/unknown_module_field_in_constant\"\n---\nerror: Unknown module value\n  ┌─ src/two.gleam:3:16\n  │\n3 │ pub const it = one.B\n  │                ^ Did you mean `A`?\n\nThe module `one` does not have a `B` value.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__unknown_module_field_in_expression.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/unknown_module_field_in_expression\"\n---\nerror: Unknown module value\n  ┌─ src/two.gleam:4:7\n  │\n4 │   one.B\n  │       ^ Did you mean `A`?\n\nThe module `one` does not have a `B` value.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__unknown_module_field_in_import.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/unknown_module_field_in_import\"\n---\nerror: Unknown module value\n  ┌─ src/two.gleam:1:13\n  │\n1 │ import one.{B}\n  │             ^ Did you mean `A`?\n\nThe module `one` does not have a `B` value.\n"
  },
  {
    "path": "test-package-compiler/src/snapshots/test_package_compiler__generated_tests__variable_or_module.snap",
    "content": "---\nsource: test-package-compiler/src/generated_tests.rs\nexpression: \"./cases/variable_or_module\"\n---\n//// /out/lib/the_package/_gleam_artefacts/main.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/main.cache_meta\n<126 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/main.erl\n-module(main).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/main.gleam\").\n-export([module_function/1, record_field/1]).\n\n-file(\"src/main.gleam\", 4).\n-spec module_function(power:power()) -> integer().\nmodule_function(Power) ->\n    power:to_int(Power).\n\n-file(\"src/main.gleam\", 10).\n-spec record_field(power:power()) -> integer().\nrecord_field(Power) ->\n    erlang:element(2, Power).\n\n\n//// /out/lib/the_package/_gleam_artefacts/power.cache\n<.cache binary>\n\n//// /out/lib/the_package/_gleam_artefacts/power.cache_meta\n<85 byte binary>\n\n//// /out/lib/the_package/_gleam_artefacts/power.erl\n-module(power).\n-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).\n-define(FILEPATH, \"src/power.gleam\").\n-export([to_int/1]).\n-export_type([power/0]).\n\n-type power() :: {power, integer()}.\n\n-file(\"src/power.gleam\", 6).\n-spec to_int(power()) -> integer().\nto_int(P) ->\n    erlang:element(2, P) * 9000.\n\n\n//// /out/lib/the_package/ebin/importy.app\n{application, importy, [\n    {vsn, \"0.1.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, [main,\n               power]},\n    {registered, []}\n]}.\n\n\n//// /out/lib/the_package/include/power_Power.hrl\n-record(power, {value :: integer()}).\n"
  },
  {
    "path": "test-project-compiler/.gitignore",
    "content": "cases/*/build\ncases/*/manifest.toml\nsupport/*/build\nsupport/*/manifest.toml\n"
  },
  {
    "path": "test-project-compiler/Cargo.toml",
    "content": "[package]\nname = \"test-project-compiler\"\nversion = \"1.15.1\"\nauthors = [\"Louis Pilfold <louis@lpil.uk>\"]\nedition = \"2024\"\nlicense = \"Apache-2.0\"\n\n[dependencies]\ngleam-core = { path = \"../compiler-core\" }\ntest-helpers-rs = { path = \"../test-helpers-rs\" }\ntoml.workspace = true\nim.workspace = true\nitertools.workspace = true\nregex.workspace = true\ncamino.workspace = true\n\n[dev-dependencies]\ninsta.workspace = true\n"
  },
  {
    "path": "test-project-compiler/build.rs",
    "content": "use std::path::PathBuf;\n\npub fn main() {\n    println!(\"cargo:rerun-if-changed=cases\");\n\n    let mut module = \"//! This file is generated by build.rs\n//! Do not edit it directly, instead add new test cases to ./cases\n\nuse gleam_core::build::Mode;\n\"\n    .to_string();\n\n    let cases = PathBuf::from(\"./cases\");\n\n    let mut names: Vec<_> = std::fs::read_dir(&cases)\n        .unwrap()\n        .map(|entry| entry.unwrap().file_name().into_string().unwrap())\n        .collect();\n    names.sort();\n\n    for name in names {\n        let path = cases.join(&name);\n        let path = path.to_str().unwrap().replace('\\\\', \"/\");\n        module.push_str(&testcase(&name, &path, \"Dev\"));\n        module.push_str(&testcase(&name, &path, \"Prod\"));\n        module.push_str(&testcase(&name, &path, \"Lsp\"));\n    }\n\n    let out = PathBuf::from(\"./src/generated_tests.rs\");\n    std::fs::write(out, module).unwrap();\n}\n\nfn testcase(name: &str, path: &str, mode: &str) -> String {\n    format!(\n        r#\"\n#[rustfmt::skip]\n#[test]\nfn {name}() {{\n    let output = crate::prepare(\"{path}\", Mode::{mode});\n    insta::assert_snapshot!(\n        \"{name}\",\n        output,\n        \"{path}\",\n    );\n}}\n\"#,\n        name = format!(\"{name}_{}\", mode.to_lowercase())\n    )\n}\n"
  },
  {
    "path": "test-project-compiler/cases/with_dep/gleam.toml",
    "content": "name = \"example\"\nversion = \"1.0.0\"\n\n[dependencies]\npackage_a = { path = \"../support/package_a\" }\n"
  },
  {
    "path": "test-project-compiler/cases/with_dep/src/example.gleam",
    "content": "pub fn main() {\n  0\n}\n"
  },
  {
    "path": "test-project-compiler/cases/with_dev_dep/gleam.toml",
    "content": "name = \"example\"\nversion = \"1.0.0\"\n\n[dev_dependencies]\npackage_a = { path = \"../support/package_a\" }\n"
  },
  {
    "path": "test-project-compiler/cases/with_dev_dep/src/example.gleam",
    "content": "pub fn main() {\n  0\n}\n"
  },
  {
    "path": "test-project-compiler/src/generated_tests.rs",
    "content": "//! This file is generated by build.rs\n//! Do not edit it directly, instead add new test cases to ./cases\n\nuse gleam_core::build::Mode;\n\n#[rustfmt::skip]\n#[test]\nfn with_dep_dev() {\n    let output = crate::prepare(\"./cases/with_dep\", Mode::Dev);\n    insta::assert_snapshot!(\n        \"with_dep_dev\",\n        output,\n        \"./cases/with_dep\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn with_dep_prod() {\n    let output = crate::prepare(\"./cases/with_dep\", Mode::Prod);\n    insta::assert_snapshot!(\n        \"with_dep_prod\",\n        output,\n        \"./cases/with_dep\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn with_dep_lsp() {\n    let output = crate::prepare(\"./cases/with_dep\", Mode::Lsp);\n    insta::assert_snapshot!(\n        \"with_dep_lsp\",\n        output,\n        \"./cases/with_dep\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn with_dev_dep_dev() {\n    let output = crate::prepare(\"./cases/with_dev_dep\", Mode::Dev);\n    insta::assert_snapshot!(\n        \"with_dev_dep_dev\",\n        output,\n        \"./cases/with_dev_dep\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn with_dev_dep_prod() {\n    let output = crate::prepare(\"./cases/with_dev_dep\", Mode::Prod);\n    insta::assert_snapshot!(\n        \"with_dev_dep_prod\",\n        output,\n        \"./cases/with_dev_dep\",\n    );\n}\n\n#[rustfmt::skip]\n#[test]\nfn with_dev_dep_lsp() {\n    let output = crate::prepare(\"./cases/with_dev_dep\", Mode::Lsp);\n    insta::assert_snapshot!(\n        \"with_dev_dep_lsp\",\n        output,\n        \"./cases/with_dev_dep\",\n    );\n}\n"
  },
  {
    "path": "test-project-compiler/src/lib.rs",
    "content": "#[cfg(test)]\nmod generated_tests;\n\nuse camino::Utf8PathBuf;\nuse gleam_core::{\n    analyse::TargetSupport,\n    build::{Codegen, Compile, Mode, NullTelemetry, Options, ProjectCompiler, Telemetry},\n    config::PackageConfig,\n    io::{FileSystemReader, FileSystemWriter},\n    paths::ProjectPaths,\n    warning::VectorWarningEmitterIO,\n};\nuse std::rc::Rc;\n\npub fn prepare(path: &str, mode: Mode) -> String {\n    let root = Utf8PathBuf::from(path).canonicalize_utf8().unwrap();\n    let filesystem = test_helpers_rs::to_in_memory_filesystem(&root);\n    let initial_files = filesystem.files();\n\n    let toml = std::fs::read_to_string(root.join(\"gleam.toml\")).unwrap();\n    let config: PackageConfig = toml::from_str(&toml).unwrap();\n    let warnings = VectorWarningEmitterIO::default();\n    let telemetry: &'static dyn Telemetry = &NullTelemetry;\n\n    let options = Options {\n        mode,\n        target: None,\n        compile: Compile::All,\n        codegen: Codegen::All,\n        warnings_as_errors: false,\n        root_target_support: TargetSupport::Enforced,\n        no_print_progress: true,\n    };\n\n    let compiler = ProjectCompiler::new(\n        config,\n        options,\n        vec![],\n        telemetry,\n        Rc::new(warnings.clone()),\n        ProjectPaths::new(root),\n        filesystem.clone(),\n    );\n\n    compiler.compile().unwrap();\n\n    for path in initial_files {\n        if filesystem.is_file(&path) {\n            filesystem.delete_file(&path).unwrap();\n        }\n    }\n    let files = filesystem.into_contents();\n    let warnings = warnings.take();\n    test_helpers_rs::TestCompileOutput { files, warnings }.as_overview_text()\n}\n"
  },
  {
    "path": "test-project-compiler/src/snapshots/test_project_compiler__generated_tests__with_dep_dev.snap",
    "content": "---\nsource: test-project-compiler/src/generated_tests.rs\nexpression: \"./cases/with_dep\"\n---\n//// with_dep/build/dev/erlang/example/_gleam_artefacts/example@@main.erl\n<erlang entrypoint>\n\n//// with_dep/build/dev/erlang/example/ebin/example.app\n{application, example, [\n    {vsn, \"1.0.0\"},\n    {applications, [package_a]},\n    {description, \"\"},\n    {modules, []},\n    {registered, []}\n]}.\n\n\n//// with_dep/build/dev/erlang/gleam_version\n<gleam compiler version string>\n"
  },
  {
    "path": "test-project-compiler/src/snapshots/test_project_compiler__generated_tests__with_dep_lsp.snap",
    "content": "---\nsource: test-project-compiler/src/generated_tests.rs\nexpression: \"./cases/with_dep\"\n---\n//// with_dep/build/lsp/erlang/example/_gleam_artefacts/example@@main.erl\n<erlang entrypoint>\n\n//// with_dep/build/lsp/erlang/example/ebin/example.app\n{application, example, [\n    {vsn, \"1.0.0\"},\n    {applications, [package_a]},\n    {description, \"\"},\n    {modules, []},\n    {registered, []}\n]}.\n\n\n//// with_dep/build/lsp/erlang/gleam_version\n<gleam compiler version string>\n"
  },
  {
    "path": "test-project-compiler/src/snapshots/test_project_compiler__generated_tests__with_dep_prod.snap",
    "content": "---\nsource: test-project-compiler/src/generated_tests.rs\nexpression: \"./cases/with_dep\"\n---\n//// with_dep/build/prod/erlang/example/_gleam_artefacts/example@@main.erl\n<erlang entrypoint>\n\n//// with_dep/build/prod/erlang/example/ebin/example.app\n{application, example, [\n    {vsn, \"1.0.0\"},\n    {applications, [package_a]},\n    {description, \"\"},\n    {modules, []},\n    {registered, []}\n]}.\n\n\n//// with_dep/build/prod/erlang/gleam_version\n<gleam compiler version string>\n"
  },
  {
    "path": "test-project-compiler/src/snapshots/test_project_compiler__generated_tests__with_dev_dep_dev.snap",
    "content": "---\nsource: test-project-compiler/src/generated_tests.rs\nexpression: \"./cases/with_dev_dep\"\n---\n//// with_dev_dep/build/dev/erlang/example/_gleam_artefacts/example@@main.erl\n<erlang entrypoint>\n\n//// with_dev_dep/build/dev/erlang/example/ebin/example.app\n{application, example, [\n    {vsn, \"1.0.0\"},\n    {applications, [package_a]},\n    {description, \"\"},\n    {modules, []},\n    {registered, []}\n]}.\n\n\n//// with_dev_dep/build/dev/erlang/gleam_version\n<gleam compiler version string>\n"
  },
  {
    "path": "test-project-compiler/src/snapshots/test_project_compiler__generated_tests__with_dev_dep_lsp.snap",
    "content": "---\nsource: test-project-compiler/src/generated_tests.rs\nexpression: \"./cases/with_dev_dep\"\n---\n//// with_dev_dep/build/lsp/erlang/example/_gleam_artefacts/example@@main.erl\n<erlang entrypoint>\n\n//// with_dev_dep/build/lsp/erlang/example/ebin/example.app\n{application, example, [\n    {vsn, \"1.0.0\"},\n    {applications, [package_a]},\n    {description, \"\"},\n    {modules, []},\n    {registered, []}\n]}.\n\n\n//// with_dev_dep/build/lsp/erlang/gleam_version\n<gleam compiler version string>\n"
  },
  {
    "path": "test-project-compiler/src/snapshots/test_project_compiler__generated_tests__with_dev_dep_prod.snap",
    "content": "---\nsource: test-project-compiler/src/generated_tests.rs\nexpression: \"./cases/with_dev_dep\"\n---\n//// with_dev_dep/build/prod/erlang/example/_gleam_artefacts/example@@main.erl\n<erlang entrypoint>\n\n//// with_dev_dep/build/prod/erlang/example/ebin/example.app\n{application, example, [\n    {vsn, \"1.0.0\"},\n    {applications, []},\n    {description, \"\"},\n    {modules, []},\n    {registered, []}\n]}.\n\n\n//// with_dev_dep/build/prod/erlang/gleam_version\n<gleam compiler version string>\n"
  },
  {
    "path": "test-project-compiler/support/package_a/gleam.toml",
    "content": "name = \"package_a\"\nversion = \"1.0.0\"\n\n[dependencies]\n\n[dev_dependencies]\n"
  },
  {
    "path": "test-project-compiler/support/package_a/src/package_a.gleam",
    "content": "pub fn main() {\n  \"package_a\"\n}\n"
  }
]